1 2 #include <assert.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <time.h> 6 #ifdef _WIN32 7 # include <windows.h> 8 #elif defined(HAVE_PTHREAD) 9 # include <pthread.h> 10 #endif 11 12 #include "core.h" 13 #include "crypto_generichash.h" 14 #include "crypto_onetimeauth.h" 15 #include "crypto_scalarmult.h" 16 #include "crypto_stream_chacha20.h" 17 #include "crypto_stream_salsa20.h" 18 #include "randombytes.h" 19 #include "runtime.h" 20 #include "utils.h" 21 #include "private/implementations.h" 22 #include "private/mutex.h" 23 24 #if !defined(_MSC_VER) && 1 25 # warning *** This is unstable, untested, development code. 26 # warning It might not compile. It might not work as expected. 27 # warning It might be totally insecure. 28 # warning Do not use this in production. 29 # warning Use releases available at https://download.libsodium.org/libsodium/releases/ instead. 30 # warning Alternatively, use the "stable" branch in the git repository. 31 #endif 32 33 #if !defined(_MSC_VER) && (!defined(CONFIGURED) || CONFIGURED != 1) 34 # warning *** The library is being compiled using an undocumented method. 35 # warning This is not supported. It has not been tested, it might not 36 # warning work as expected, and performance is likely to be suboptimal. 37 #endif 38 39 static volatile int initialized; 40 static volatile int locked; 41 42 int 43 sodium_init(void) 44 { 45 if (sodium_crit_enter() != 0) { 46 return -1; /* LCOV_EXCL_LINE */ 47 } 48 if (initialized != 0) { 49 if (sodium_crit_leave() != 0) { 50 return -1; /* LCOV_EXCL_LINE */ 51 } 52 return 1; 53 } 54 _sodium_runtime_get_cpu_features(); 55 randombytes_stir(); 56 _sodium_alloc_init(); 57 _crypto_pwhash_argon2_pick_best_implementation(); 58 _crypto_generichash_blake2b_pick_best_implementation(); 59 _crypto_onetimeauth_poly1305_pick_best_implementation(); 60 _crypto_scalarmult_curve25519_pick_best_implementation(); 61 _crypto_stream_chacha20_pick_best_implementation(); 62 _crypto_stream_salsa20_pick_best_implementation(); 63 initialized = 1; 64 if (sodium_crit_leave() != 0) { 65 return -1; /* LCOV_EXCL_LINE */ 66 } 67 return 0; 68 } 69 70 #ifdef _WIN32 71 72 static CRITICAL_SECTION _sodium_lock; 73 static volatile LONG _sodium_lock_initialized; 74 75 int 76 _sodium_crit_init(void) 77 { 78 LONG status = 0L; 79 80 while ((status = InterlockedCompareExchange(&_sodium_lock_initialized, 81 1L, 0L)) == 1L) { 82 Sleep(0); 83 } 84 85 switch (status) { 86 case 0L: 87 InitializeCriticalSection(&_sodium_lock); 88 return InterlockedExchange(&_sodium_lock_initialized, 2L) == 1L ? 0 : -1; 89 case 2L: 90 return 0; 91 default: /* should never be reached */ 92 return -1; 93 } 94 } 95 96 int 97 sodium_crit_enter(void) 98 { 99 if (_sodium_crit_init() != 0) { 100 return -1; /* LCOV_EXCL_LINE */ 101 } 102 EnterCriticalSection(&_sodium_lock); 103 assert(locked == 0); 104 locked = 1; 105 106 return 0; 107 } 108 109 int 110 sodium_crit_leave(void) 111 { 112 if (locked == 0) { 113 # ifdef EPERM 114 errno = EPERM; 115 # endif 116 return -1; 117 } 118 locked = 0; 119 LeaveCriticalSection(&_sodium_lock); 120 121 return 0; 122 } 123 124 #elif defined(HAVE_PTHREAD) && !defined(__EMSCRIPTEN__) 125 126 static pthread_mutex_t _sodium_lock = PTHREAD_MUTEX_INITIALIZER; 127 128 int 129 sodium_crit_enter(void) 130 { 131 int ret; 132 133 if ((ret = pthread_mutex_lock(&_sodium_lock)) == 0) { 134 assert(locked == 0); 135 locked = 1; 136 } 137 return ret; 138 } 139 140 int 141 sodium_crit_leave(void) 142 { 143 int ret; 144 145 if (locked == 0) { 146 # ifdef EPERM 147 errno = EPERM; 148 # endif 149 return -1; 150 } 151 locked = 0; 152 153 return pthread_mutex_unlock(&_sodium_lock); 154 } 155 156 #elif defined(HAVE_ATOMIC_OPS) && !defined(__EMSCRIPTEN__) && !defined(__native_client__) 157 158 static volatile int _sodium_lock; 159 160 int 161 sodium_crit_enter(void) 162 { 163 # ifdef HAVE_NANOSLEEP 164 struct timespec q; 165 memset(&q, 0, sizeof q); 166 # endif 167 while (__sync_lock_test_and_set(&_sodium_lock, 1) != 0) { 168 # ifdef HAVE_NANOSLEEP 169 (void) nanosleep(&q, NULL); 170 # elif defined(__x86_64__) || defined(__i386__) 171 __asm__ __volatile__ ("pause"); 172 # endif 173 } 174 return 0; 175 } 176 177 int 178 sodium_crit_leave(void) 179 { 180 __sync_lock_release(&_sodium_lock); 181 182 return 0; 183 } 184 185 #else 186 187 int 188 sodium_crit_enter(void) 189 { 190 return 0; 191 } 192 193 int 194 sodium_crit_leave(void) 195 { 196 return 0; 197 } 198 199 #endif 200 201 static void (*_misuse_handler)(void); 202 203 void 204 sodium_misuse(void) 205 { 206 void (*handler)(void); 207 208 (void) sodium_crit_leave(); 209 if (sodium_crit_enter() == 0) { 210 handler = _misuse_handler; 211 if (handler != NULL) { 212 handler(); 213 } 214 } 215 /* LCOV_EXCL_START */ 216 abort(); 217 } 218 /* LCOV_EXCL_STOP */ 219 220 int 221 sodium_set_misuse_handler(void (*handler)(void)) 222 { 223 if (sodium_crit_enter() != 0) { 224 return -1; /* LCOV_EXCL_LINE */ 225 } 226 _misuse_handler = handler; 227 if (sodium_crit_leave() != 0) { 228 return -1; /* LCOV_EXCL_LINE */ 229 } 230 return 0; 231 } 232