aboutsummaryrefslogtreecommitdiffstats
path: root/src/_cffi_src/openssl
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2016-11-13 15:55:22 -0500
committerPaul Kehrer <paul.l.kehrer@gmail.com>2016-11-13 12:55:22 -0800
commitd862933de5c344fcdf99ab2f43f3bf8da65f3e41 (patch)
tree16d73c47a45f939336fe5e41bf45293097a5a222 /src/_cffi_src/openssl
parent562b9a905596f3e58b27be584a9532aa3a4dc833 (diff)
downloadcryptography-d862933de5c344fcdf99ab2f43f3bf8da65f3e41.tar.gz
cryptography-d862933de5c344fcdf99ab2f43f3bf8da65f3e41.tar.bz2
cryptography-d862933de5c344fcdf99ab2f43f3bf8da65f3e41.zip
C locking callback (#3226)
* Remove Python OpenSSL locking callback and replace it with one in C The Python OpenSSL locking callback is unsafe; if GC is triggered during the callback's invocation, it can result in the callback being invoked reentrantly, which can lead to deadlocks. This patch replaces it with one in C that gets built at compile time via cffi along with the rest of the OpenSSL binding. * fixes for some issues * unused * revert these changes * these two for good measure * missing param * sigh, syntax * delete tests that assumed an ability to mess with locks * style fixes * licensing stuff * utf8 * Unicode. Huh. What it isn't good for, absolutely nothing.
Diffstat (limited to 'src/_cffi_src/openssl')
-rw-r--r--src/_cffi_src/openssl/callbacks.py73
1 files changed, 72 insertions, 1 deletions
diff --git a/src/_cffi_src/openssl/callbacks.py b/src/_cffi_src/openssl/callbacks.py
index 5ae89b18..4a6b4d37 100644
--- a/src/_cffi_src/openssl/callbacks.py
+++ b/src/_cffi_src/openssl/callbacks.py
@@ -12,6 +12,9 @@ INCLUDES = """
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
+#include <openssl/crypto.h>
+
+#include <pythread.h>
"""
TYPES = """
@@ -37,6 +40,7 @@ extern "Python" int Cryptography_rand_status(void);
"""
FUNCTIONS = """
+int _setup_ssl_threads(void);
"""
MACROS = """
@@ -50,4 +54,71 @@ if cffi.__version_info__ < (1, 4, 0) or sys.version_info >= (3, 5):
# backwards compatibility for old cffi version on PyPy
# and Python >=3.5 (https://github.com/pyca/cryptography/issues/2970)
TYPES = "static const long Cryptography_STATIC_CALLBACKS;"
- CUSTOMIZATIONS = "static const long Cryptography_STATIC_CALLBACKS = 0;"
+ CUSTOMIZATIONS = """static const long Cryptography_STATIC_CALLBACKS = 0;
+"""
+
+CUSTOMIZATIONS += """
+/* This code is derived from the locking code found in the Python _ssl module's
+ locking callback for OpenSSL.
+
+ Copyright 2001-2016 Python Software Foundation; All Rights Reserved.
+*/
+
+static unsigned int _ssl_locks_count = 0;
+static PyThread_type_lock *_ssl_locks = NULL;
+
+static void _ssl_thread_locking_function(int mode, int n, const char *file,
+ int line) {
+ /* this function is needed to perform locking on shared data
+ structures. (Note that OpenSSL uses a number of global data
+ structures that will be implicitly shared whenever multiple
+ threads use OpenSSL.) Multi-threaded applications will
+ crash at random if it is not set.
+
+ locking_function() must be able to handle up to
+ CRYPTO_num_locks() different mutex locks. It sets the n-th
+ lock if mode & CRYPTO_LOCK, and releases it otherwise.
+
+ file and line are the file number of the function setting the
+ lock. They can be useful for debugging.
+ */
+
+ if ((_ssl_locks == NULL) ||
+ (n < 0) || ((unsigned)n >= _ssl_locks_count)) {
+ return;
+ }
+
+ if (mode & CRYPTO_LOCK) {
+ PyThread_acquire_lock(_ssl_locks[n], 1);
+ } else {
+ PyThread_release_lock(_ssl_locks[n]);
+ }
+}
+
+int _setup_ssl_threads(void) {
+ unsigned int i;
+
+ if (_ssl_locks == NULL) {
+ _ssl_locks_count = CRYPTO_num_locks();
+ _ssl_locks = PyMem_New(PyThread_type_lock, _ssl_locks_count);
+ if (_ssl_locks == NULL) {
+ PyErr_NoMemory();
+ return 0;
+ }
+ memset(_ssl_locks, 0, sizeof(PyThread_type_lock) * _ssl_locks_count);
+ for (i = 0; i < _ssl_locks_count; i++) {
+ _ssl_locks[i] = PyThread_allocate_lock();
+ if (_ssl_locks[i] == NULL) {
+ unsigned int j;
+ for (j = 0; j < i; j++) {
+ PyThread_free_lock(_ssl_locks[j]);
+ }
+ PyMem_Free(_ssl_locks);
+ return 0;
+ }
+ }
+ CRYPTO_set_locking_callback(_ssl_thread_locking_function);
+ }
+ return 1;
+}
+"""