Branch data Line data Source code
1 : : /* 2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 : : * 4 : : * Licensed under the Apache License, Version 2.0 (the "License"). 5 : : * You may not use this file except in compliance with the License. 6 : : * A copy of the License is located at 7 : : * 8 : : * http://aws.amazon.com/apache2.0 9 : : * 10 : : * or in the "license" file accompanying this file. This file is distributed 11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 : : * express or implied. See the License for the specific language governing 13 : : * permissions and limitations under the License. 14 : : */ 15 : : 16 : : #include "crypto/s2n_locking.h" 17 : : 18 : : #include <openssl/crypto.h> 19 : : #include <pthread.h> 20 : : 21 : : #include "crypto/s2n_openssl.h" 22 : : #include "utils/s2n_mem.h" 23 : : #include "utils/s2n_safety.h" 24 : : 25 : : /* Writing multithreaded applications using Openssl-1.0.2 26 : : * requires calling CRYPTO_set_locking_callback. 27 : : * If the callback is not set, locks are no-ops and unexpected 28 : : * behavior may occur, particularly for RSA and X509. 29 : : * 30 : : * In the past s2n-tls relied on customers setting the callback 31 : : * themselves, but that seems unnecessary since other parts of 32 : : * the library (like fork detection) already rely on the pthreads library. 33 : : * 34 : : * For more information: 35 : : * https://www.openssl.org/blog/blog/2017/02/21/threads/ 36 : : * https://www.openssl.org/docs/man1.0.2/man3/threads.html 37 : : */ 38 : : 39 : : #define S2N_MUTEXES(mem) ((pthread_mutex_t *) (void *) (mem).data) 40 : : 41 : : /* While the locking-related APIs "exist" in later versions of 42 : : * Openssl, they tend to be placeholders or hardcoded values like: 43 : : * #define CRYPTO_get_locking_callback() (NULL) 44 : : * So the code will compile with strange warnings / errors like 45 : : * loop conditions always being false. 46 : : */ 47 : : #if !(S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0)) 48 : : 49 : : static struct s2n_blob mutexes_mem = { 0 }; 50 : : static size_t mutexes_count = 0; 51 : : 52 : : static void s2n_locking_cb(int mode, int n, char *file, int line) 53 : : { 54 : : pthread_mutex_t *mutexes = S2N_MUTEXES(mutexes_mem); 55 : : if (!mutexes_mem.data || n < 0 || (size_t) n >= mutexes_count) { 56 : : return; 57 : : } 58 : : 59 : : if (mode & CRYPTO_LOCK) { 60 : : pthread_mutex_lock(&(mutexes[n])); 61 : : } else { 62 : : pthread_mutex_unlock(&(mutexes[n])); 63 : : } 64 : : } 65 : : 66 : : S2N_RESULT s2n_locking_init(void) 67 : : { 68 : : if (CRYPTO_get_locking_callback() != NULL) { 69 : : return S2N_RESULT_OK; 70 : : } 71 : : 72 : : int num_locks = CRYPTO_num_locks(); 73 : : RESULT_ENSURE_GTE(num_locks, 0); 74 : : 75 : : RESULT_GUARD_POSIX(s2n_realloc(&mutexes_mem, num_locks * sizeof(pthread_mutex_t))); 76 : : 77 : : pthread_mutex_t *mutexes = S2N_MUTEXES(mutexes_mem); 78 : : mutexes_count = 0; 79 : : for (size_t i = 0; i < (size_t) num_locks; i++) { 80 : : RESULT_ENSURE_EQ(pthread_mutex_init(&(mutexes[i]), NULL), 0); 81 : : mutexes_count++; 82 : : } 83 : : 84 : : CRYPTO_set_locking_callback((void (*)()) s2n_locking_cb); 85 : : return S2N_RESULT_OK; 86 : : } 87 : : 88 : : S2N_RESULT s2n_locking_cleanup(void) 89 : : { 90 : : if (CRYPTO_get_locking_callback() == (void (*)()) s2n_locking_cb) { 91 : : CRYPTO_set_locking_callback(NULL); 92 : : } 93 : : 94 : : pthread_mutex_t *mutexes = S2N_MUTEXES(mutexes_mem); 95 : : if (mutexes) { 96 : : while (mutexes_count > 0) { 97 : : RESULT_ENSURE_EQ(pthread_mutex_destroy(&(mutexes[mutexes_count - 1])), 0); 98 : : mutexes_count--; 99 : : } 100 : : RESULT_GUARD_POSIX(s2n_free(&mutexes_mem)); 101 : : } 102 : : 103 : : return S2N_RESULT_OK; 104 : : } 105 : : 106 : : #else 107 : : 108 : : S2N_RESULT s2n_locking_init(void) 109 : 545 : { 110 : 545 : return S2N_RESULT_OK; 111 : 545 : } 112 : : 113 : : S2N_RESULT s2n_locking_cleanup(void) 114 : 545 : { 115 : 545 : return S2N_RESULT_OK; 116 : 545 : } 117 : : 118 : : #endif