# 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 INCLUDES = """ #include #include #include #include #include """ TYPES = """ typedef struct { char *password; int length; int called; int error; int maxsize; } CRYPTOGRAPHY_PASSWORD_DATA; """ FUNCTIONS = """ int _setup_ssl_threads(void); int Cryptography_pem_password_cb(char *, int, int, void *); """ MACROS = """ """ 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; } typedef struct { char *password; int length; int called; int error; int maxsize; } CRYPTOGRAPHY_PASSWORD_DATA; int Cryptography_pem_password_cb(char *buf, int size, int rwflag, void *userdata) { /* The password cb is only invoked if OpenSSL decides the private key is encrypted. So this path only occurs if it needs a password */ CRYPTOGRAPHY_PASSWORD_DATA *st = (CRYPTOGRAPHY_PASSWORD_DATA *)userdata; st->called += 1; st->maxsize = size; if (st->length == 0) { st->error = -1; return 0; } else if (st->length < size) { memcpy(buf, st->password, st->length); return st->length; } else { st->error = -2; return 0; } } """