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