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
sodium_init(void)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
_sodium_crit_init(void)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
sodium_crit_enter(void)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
sodium_crit_leave(void)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
sodium_crit_enter(void)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
sodium_crit_leave(void)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
sodium_crit_enter(void)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
sodium_crit_leave(void)178 sodium_crit_leave(void)
179 {
180 __sync_lock_release(&_sodium_lock);
181
182 return 0;
183 }
184
185 #else
186
187 int
sodium_crit_enter(void)188 sodium_crit_enter(void)
189 {
190 return 0;
191 }
192
193 int
sodium_crit_leave(void)194 sodium_crit_leave(void)
195 {
196 return 0;
197 }
198
199 #endif
200
201 static void (*_misuse_handler)(void);
202
203 void
sodium_misuse(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
sodium_set_misuse_handler(void (* handler)(void))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