aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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.