aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2015-11-19 16:18:04 +0100
committerPaul Kehrer <paul.l.kehrer@gmail.com>2016-01-07 11:38:34 -0800
commit830af271de1c9c3589bcce12cc08573850141f51 (patch)
treecf637035244e6c0de8edef31b4161cbe23f1f39f
parent7d79649e8d9fc6a4994c814022c5b584ef2670f7 (diff)
downloadcryptography-830af271de1c9c3589bcce12cc08573850141f51.tar.gz
cryptography-830af271de1c9c3589bcce12cc08573850141f51.tar.bz2
cryptography-830af271de1c9c3589bcce12cc08573850141f51.zip
Port callbacks to new static callback
cffi 1.4.0 will introduce a new API to create static callbacks. Contrary to the old callback API, static callbacks no longer depend on libffi's dynamic code generation for closures. Static code has some benefits over dynamic generation. For example the code is faster. Also it doesn't need writeable and executable memory mappings, which makes it compatible with SELinux's deny execmem policy. The branch depends on PR #2488. https://bitbucket.org/cffi/cffi/issues/232/static-callbacks Closes: #2477 Signed-off-by: Christian Heimes <cheimes@redhat.com>
-rw-r--r--setup.py4
-rw-r--r--src/_cffi_src/build_openssl.py1
-rw-r--r--src/_cffi_src/openssl/callbacks.py111
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py23
-rw-r--r--src/cryptography/hazmat/bindings/openssl/binding.py34
5 files changed, 157 insertions, 16 deletions
diff --git a/setup.py b/setup.py
index 3b67e8ff..f79b0e25 100644
--- a/setup.py
+++ b/setup.py
@@ -54,8 +54,8 @@ if platform.python_implementation() == "PyPy":
"upgrade PyPy to use this library."
)
else:
- requirements.append("cffi>=1.1.0")
- setup_requirements.append("cffi>=1.1.0")
+ requirements.append("cffi>=1.4.1")
+ setup_requirements.append("cffi>=1.4.1")
# If you add a new dep here you probably need to add it in the tox.ini as well
test_requirements = [
diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py
index c47b3082..ebbe8865 100644
--- a/src/_cffi_src/build_openssl.py
+++ b/src/_cffi_src/build_openssl.py
@@ -90,6 +90,7 @@ ffi = build_ffi_for_binding(
"x509v3",
"x509_vfy",
"pkcs7",
+ "callbacks",
],
pre_include=_OSX_PRE_INCLUDE,
post_include=_OSX_POST_INCLUDE,
diff --git a/src/_cffi_src/openssl/callbacks.py b/src/_cffi_src/openssl/callbacks.py
new file mode 100644
index 00000000..8ab64fbf
--- /dev/null
+++ b/src/_cffi_src/openssl/callbacks.py
@@ -0,0 +1,111 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import cffi
+
+INCLUDES = """
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+"""
+
+TYPES = """
+static const long Cryptography_STATIC_CALLBACKS;
+
+/* crypto.h
+ * CRYPTO_set_locking_callback
+ * void (*cb)(int mode, int type, const char *file, int line)
+ */
+extern "Python" void Cryptography_locking_cb(int, int, const char *, int);
+
+/* pem.h
+ * int pem_password_cb(char *buf, int size, int rwflag, void *userdata);
+ */
+extern "Python" int Cryptography_pem_password_cb(char *, int, int, void *);
+
+/* rand.h
+ * int (*bytes)(unsigned char *buf, int num);
+ * int (*status)(void);
+ */
+extern "Python" int Cryptography_rand_bytes(unsigned char *, int);
+extern "Python" int Cryptography_rand_status(void);
+
+/* ssl.h
+ *
+ * SSL_CTX_set_cert_verify_callback
+ * int (*cert_verify_callback)(X509_STORE_CTX *ctx, void *userdata)
+ */
+extern "Python" int Cryptography_cert_verify_cb(
+ X509_STORE_CTX *, void *);
+
+/* SSL_CTX_set_info_callback
+ * void (*info_callback)(const SSL *ssl, int type, int val)
+ */
+extern "Python" void Cryptography_ssl_info_cb(
+ const SSL *, int, int);
+
+/* SSL_CTX_set_msg_callback
+ * void (*info_callback)(int write_p, int version, int content_type,
+ * const void *buf, size_t len, SSL *ssl, void *arg)
+ */
+extern "Python" void Cryptography_msg_cb(
+ int, int, int, const void *, size_t, SSL *, void *);
+
+/* SSL_CTX_set_client_cert_cb
+ * int (*client_cert_cb) (SSL *ssl, X509 **x509, EVP_PKEY **pkey)
+ */
+extern "Python" int Cryptography_client_cert_cb(
+ SSL *, X509 **, EVP_PKEY **);
+
+/* SSL_CTX_set_next_protos_advertised_cb
+ * int (*cb)(SSL *ssl, const unsigned char **out, unsigned int *outlen,
+ * void *arg
+ */
+extern "Python" int Cryptography_next_proto_advertised_cb(
+ SSL *, const unsigned char **, unsigned int *, void *);
+
+/* SSL_CTX_set_next_proto_select_cb
+ * int (*cb) (SSL *ssl, unsigned char **out, unsigned char *outlen,
+ * const unsigned char *in, unsigned int inlen, void *arg)
+ */
+extern "Python" int Cryptography_next_proto_select_cb(
+ SSL *, unsigned char **, unsigned char *, const unsigned char *,
+ unsigned int, void *);
+
+/* SSL_CTX_set_alpn_select_cb
+ * int (*cb) (SSL *ssl, const unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen, void *arg)
+ */
+extern "Python" int Cryptography_alpn_select_cb(
+ SSL *, const unsigned char **, unsigned char *, const unsigned char *,
+ unsigned int, void *arg);
+
+/* tls1.h
+ * SSL_CTX_set_tlsext_servername_callback
+ */
+extern "Python" int Cryptography_tlsext_servername_cb(
+ const SSL *, int *, void *);
+
+/* x509_vfy.h
+ * int (*verify_cb)(int ok, X509_STORE_CTX *ctx)
+ */
+extern "Python" int Cryptography_verify_cb(int, X509_STORE_CTX *);
+"""
+
+FUNCTIONS = """
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+static const long Cryptography_STATIC_CALLBACKS = 1;
+"""
+
+if cffi.__version_info__ < (1, 4, 0):
+ # backwards compatibility for old cffi version on PyPy
+ TYPES = "static const long Cryptography_STATIC_CALLBACKS;"
+ CUSTOMIZATIONS = "static const long Cryptography_STATIC_CALLBACKS = 0;"
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 30ad9766..9dfe2d4f 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -43,7 +43,6 @@ from cryptography.hazmat.backends.openssl.x509 import (
)
from cryptography.hazmat.bindings._openssl import ffi as _ffi
from cryptography.hazmat.bindings.openssl import binding
-from cryptography.hazmat.bindings._openssl import ffi as _ffi
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
from cryptography.hazmat.primitives.asymmetric.padding import (
@@ -649,7 +648,21 @@ class _PasswordUserdata(object):
self.exception = None
+@binding.ffi_callback("int (char *, int, int, void *)",
+ name="Cryptography_pem_password_cb")
def _pem_password_cb(buf, size, writing, userdata_handle):
+ """
+ A pem_password_cb function pointer that copied the password to
+ OpenSSL as required and returns the number of bytes copied.
+
+ typedef int pem_password_cb(char *buf, int size,
+ int rwflag, void *userdata);
+
+ Useful for decrypting PKCS8 files and so on.
+
+ The userdata pointer must point to a cffi handle of a
+ _PasswordUserdata instance.
+ """
ud = _ffi.from_handle(userdata_handle)
ud.called += 1
@@ -1140,13 +1153,7 @@ class Backend(object):
# globally. The backend is passed in as userdata argument.
userdata = _PasswordUserdata(password=password)
-
- pem_password_cb = self._ffi.callback(
- "int (char *, int, int, void *)",
- _pem_password_cb,
- )
-
- return pem_password_cb, userdata
+ return _pem_password_cb, userdata
def _mgf1_hash_supported(self, algorithm):
if self._lib.Cryptography_HAS_MGF1_MD:
diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py
index 8e419439..1cfe8162 100644
--- a/src/cryptography/hazmat/bindings/openssl/binding.py
+++ b/src/cryptography/hazmat/bindings/openssl/binding.py
@@ -14,7 +14,6 @@ from cryptography.exceptions import InternalError
from cryptography.hazmat.bindings._openssl import ffi, lib
from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES
-
_OpenSSLError = collections.namedtuple("_OpenSSLError",
["code", "lib", "func", "reason"])
@@ -45,7 +44,28 @@ def _openssl_assert(lib, ok):
)
-@ffi.callback("int (*)(unsigned char *, int)", error=-1)
+def ffi_callback(signature, name, **kwargs):
+ """Callback dispatcher
+
+ The ffi_callback() dispatcher keeps callbacks compatible between dynamic
+ and static callbacks.
+ """
+ def wrapper(func):
+ if lib.Cryptography_STATIC_CALLBACKS:
+ # def_extern() returns a decorator that sets the internal
+ # function pointer and returns the original function unmodified.
+ ffi.def_extern(name=name, **kwargs)(func)
+ callback = getattr(lib, name)
+ else:
+ # callback() wraps the function in a cdata function.
+ callback = ffi.callback(signature, **kwargs)(func)
+ return callback
+ return wrapper
+
+
+@ffi_callback("int (*)(unsigned char *, int)",
+ name="Cryptography_rand_bytes",
+ error=-1)
def _osrandom_rand_bytes(buf, size):
signed = ffi.cast("char *", buf)
result = os.urandom(size)
@@ -53,7 +73,7 @@ def _osrandom_rand_bytes(buf, size):
return 1
-@ffi.callback("int (*)(void)")
+@ffi_callback("int (*)(void)", name="Cryptography_rand_status")
def _osrandom_rand_status():
return 1
@@ -88,7 +108,8 @@ class Binding(object):
_osrandom_engine_name = ffi.new("const char[]", b"osrandom_engine")
_osrandom_method = ffi.new(
"RAND_METHOD *",
- dict(bytes=_osrandom_rand_bytes, pseudorand=_osrandom_rand_bytes,
+ dict(bytes=_osrandom_rand_bytes,
+ pseudorand=_osrandom_rand_bytes,
status=_osrandom_rand_status)
)
@@ -140,10 +161,11 @@ class Binding(object):
cls._ensure_ffi_initialized()
if not cls._lock_cb_handle:
- cls._lock_cb_handle = cls.ffi.callback(
+ wrapper = ffi_callback(
"void(int, int, const char *, int)",
- cls._lock_cb
+ name="Cryptography_locking_cb",
)
+ cls._lock_cb_handle = wrapper(cls._lock_cb)
# Use Python's implementation if available, importing _ssl triggers
# the setup for this.