Home | History | Annotate | Line # | Download | only in sodium
      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) && 0
     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