]>
Commit | Line | Data |
---|---|---|
714a1bb3 P |
1 | /* |
2 | * Copyright 2011-2020 The OpenSSL Project Authors. All Rights Reserved. | |
3 | * | |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
10 | #include <string.h> | |
11 | #include <openssl/crypto.h> | |
12 | #include <openssl/err.h> | |
13 | #include <openssl/rand.h> | |
f000e828 | 14 | #include <openssl/evp.h> |
714a1bb3 P |
15 | #include "crypto/rand.h" |
16 | #include "drbg_local.h" | |
17 | #include "internal/thread_once.h" | |
18 | #include "crypto/cryptlib.h" | |
f000e828 P |
19 | #include "prov/seeding.h" |
20 | #include "prov/rand_pool.h" | |
21 | #include "prov/provider_ctx.h" | |
22 | #include "prov/providercommonerr.h" | |
714a1bb3 P |
23 | |
24 | /* | |
25 | * Support framework for NIST SP 800-90A DRBG | |
26 | * | |
27 | * See manual page PROV_DRBG(7) for a general overview. | |
28 | * | |
29 | * The OpenSSL model is to have new and free functions, and that new | |
30 | * does all initialization. That is not the NIST model, which has | |
31 | * instantiation and un-instantiate, and re-use within a new/free | |
32 | * lifecycle. (No doubt this comes from the desire to support hardware | |
33 | * DRBG, where allocation of resources on something like an HSM is | |
34 | * a much bigger deal than just re-setting an allocated resource.) | |
35 | */ | |
36 | ||
714a1bb3 P |
37 | /* NIST SP 800-90A DRBG recommends the use of a personalization string. */ |
38 | static const char ossl_pers_string[] = DRBG_DEFAULT_PERS_STRING; | |
39 | ||
714a1bb3 P |
40 | static const OSSL_DISPATCH *find_call(const OSSL_DISPATCH *dispatch, |
41 | int function); | |
42 | ||
f000e828 P |
43 | static int rand_drbg_restart(PROV_DRBG *drbg); |
44 | ||
714a1bb3 P |
45 | int drbg_lock(void *vctx) |
46 | { | |
47 | PROV_DRBG *drbg = vctx; | |
48 | ||
49 | if (drbg == NULL || drbg->lock == NULL) | |
50 | return 1; | |
51 | return CRYPTO_THREAD_write_lock(drbg->lock); | |
52 | } | |
53 | ||
54 | void drbg_unlock(void *vctx) | |
55 | { | |
56 | PROV_DRBG *drbg = vctx; | |
57 | ||
58 | if (drbg != NULL && drbg->lock != NULL) | |
59 | CRYPTO_THREAD_unlock(drbg->lock); | |
60 | } | |
61 | ||
62 | static int drbg_lock_parent(PROV_DRBG *drbg) | |
63 | { | |
64 | void *parent = drbg->parent; | |
714a1bb3 | 65 | |
f000e828 P |
66 | if (parent != NULL |
67 | && drbg->parent_lock != NULL | |
68 | && !drbg->parent_lock(parent)) { | |
69 | ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED); | |
70 | return 0; | |
714a1bb3 P |
71 | } |
72 | return 1; | |
73 | } | |
74 | ||
75 | static void drbg_unlock_parent(PROV_DRBG *drbg) | |
76 | { | |
77 | void *parent = drbg->parent; | |
714a1bb3 | 78 | |
f000e828 P |
79 | if (parent != NULL && drbg->parent_unlock != NULL) |
80 | drbg->parent_unlock(parent); | |
714a1bb3 P |
81 | } |
82 | ||
f000e828 | 83 | static int get_parent_strength(PROV_DRBG *drbg, unsigned int *str) |
714a1bb3 P |
84 | { |
85 | OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; | |
714a1bb3 | 86 | void *parent = drbg->parent; |
f000e828 | 87 | int res; |
714a1bb3 | 88 | |
f000e828 P |
89 | if (drbg->parent_get_ctx_params == NULL) { |
90 | ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH); | |
714a1bb3 P |
91 | return 0; |
92 | } | |
f000e828 P |
93 | |
94 | *params = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, str); | |
714a1bb3 | 95 | if (!drbg_lock_parent(drbg)) { |
f000e828 | 96 | ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT); |
714a1bb3 P |
97 | return 0; |
98 | } | |
f000e828 P |
99 | res = drbg->parent_get_ctx_params(parent, params); |
100 | drbg_unlock_parent(drbg); | |
101 | if (!res) { | |
102 | ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH); | |
714a1bb3 P |
103 | return 0; |
104 | } | |
714a1bb3 P |
105 | return 1; |
106 | } | |
107 | ||
108 | static unsigned int get_parent_reseed_count(PROV_DRBG *drbg) | |
109 | { | |
110 | OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; | |
714a1bb3 P |
111 | void *parent = drbg->parent; |
112 | unsigned int r; | |
113 | ||
f000e828 | 114 | *params = OSSL_PARAM_construct_uint(OSSL_DRBG_PARAM_RESEED_CTR, &r); |
714a1bb3 | 115 | if (!drbg_lock_parent(drbg)) { |
f000e828 | 116 | ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT); |
714a1bb3 P |
117 | goto err; |
118 | } | |
f000e828 | 119 | if (!drbg->parent_get_ctx_params(parent, params)) { |
714a1bb3 | 120 | drbg_unlock_parent(drbg); |
f000e828 | 121 | ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_RESEED_PROP_CTR); |
714a1bb3 P |
122 | goto err; |
123 | } | |
124 | drbg_unlock_parent(drbg); | |
125 | return r; | |
126 | ||
127 | err: | |
f000e828 | 128 | r = tsan_load(&drbg->reseed_counter) - 2; |
714a1bb3 P |
129 | if (r == 0) |
130 | r = UINT_MAX; | |
131 | return r; | |
132 | } | |
133 | ||
714a1bb3 P |
134 | /* |
135 | * Implements the get_entropy() callback (see RAND_DRBG_set_callbacks()) | |
136 | * | |
137 | * If the DRBG has a parent, then the required amount of entropy input | |
138 | * is fetched using the parent's RAND_DRBG_generate(). | |
139 | * | |
140 | * Otherwise, the entropy is polled from the system entropy sources | |
f000e828 | 141 | * using prov_pool_acquire_entropy(). |
714a1bb3 P |
142 | * |
143 | * If a random pool has been added to the DRBG using RAND_add(), then | |
144 | * its entropy will be used up first. | |
145 | */ | |
146 | static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout, | |
f000e828 P |
147 | int entropy, size_t min_len, |
148 | size_t max_len, int prediction_resistance) | |
714a1bb3 P |
149 | { |
150 | size_t ret = 0; | |
151 | size_t entropy_available = 0; | |
152 | RAND_POOL *pool; | |
f000e828 | 153 | unsigned int p_str; |
714a1bb3 P |
154 | |
155 | if (drbg->parent != NULL) { | |
156 | if (!get_parent_strength(drbg, &p_str)) | |
157 | return 0; | |
158 | if (drbg->strength > p_str) { | |
159 | /* | |
160 | * We currently don't support the algorithm from NIST SP 800-90C | |
161 | * 10.1.2 to use a weaker DRBG as source | |
162 | */ | |
f000e828 | 163 | RANDerr(0, PROV_R_PARENT_STRENGTH_TOO_WEAK); |
714a1bb3 P |
164 | return 0; |
165 | } | |
166 | } | |
167 | ||
168 | if (drbg->seed_pool != NULL) { | |
169 | pool = drbg->seed_pool; | |
170 | pool->entropy_requested = entropy; | |
171 | } else { | |
f000e828 P |
172 | pool = rand_pool_new(entropy, 1, min_len, max_len); |
173 | if (pool == NULL) { | |
174 | ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); | |
714a1bb3 | 175 | return 0; |
f000e828 | 176 | } |
714a1bb3 P |
177 | } |
178 | ||
179 | if (drbg->parent != NULL) { | |
180 | size_t bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); | |
181 | unsigned char *buffer = rand_pool_add_begin(pool, bytes_needed); | |
182 | ||
183 | if (buffer != NULL) { | |
184 | size_t bytes = 0; | |
185 | ||
186 | /* | |
187 | * Get random data from parent. Include our address as additional input, | |
188 | * in order to provide some additional distinction between different | |
189 | * DRBG child instances. | |
190 | * Our lock is already held, but we need to lock our parent before | |
191 | * generating bits from it. (Note: taking the lock will be a no-op | |
192 | * if locking if drbg->parent->lock == NULL.) | |
193 | */ | |
f000e828 P |
194 | if (drbg->parent_generate == NULL) |
195 | goto err; | |
714a1bb3 | 196 | drbg_lock_parent(drbg); |
f000e828 P |
197 | if (drbg->parent_generate(drbg->parent, buffer, bytes_needed, |
198 | drbg->strength, prediction_resistance, | |
199 | (unsigned char *)&drbg, | |
200 | sizeof(drbg)) != 0) | |
714a1bb3 | 201 | bytes = bytes_needed; |
714a1bb3 | 202 | drbg_unlock_parent(drbg); |
f000e828 | 203 | drbg->parent_reseed_counter = get_parent_reseed_count(drbg); |
714a1bb3 P |
204 | |
205 | rand_pool_add_end(pool, bytes, 8 * bytes); | |
206 | entropy_available = rand_pool_entropy_available(pool); | |
207 | } | |
208 | } else { | |
209 | /* Get entropy by polling system entropy sources. */ | |
f000e828 | 210 | entropy_available = prov_pool_acquire_entropy(pool); |
714a1bb3 P |
211 | } |
212 | ||
213 | if (entropy_available > 0) { | |
214 | ret = rand_pool_length(pool); | |
215 | *pout = rand_pool_detach(pool); | |
216 | } | |
217 | ||
f000e828 | 218 | err: |
714a1bb3 P |
219 | if (drbg->seed_pool == NULL) |
220 | rand_pool_free(pool); | |
221 | return ret; | |
222 | } | |
223 | ||
224 | /* | |
225 | * Implements the cleanup_entropy() callback (see RAND_DRBG_set_callbacks()) | |
226 | * | |
227 | */ | |
228 | static void prov_drbg_cleanup_entropy(PROV_DRBG *drbg, | |
229 | unsigned char *out, size_t outlen) | |
230 | { | |
f000e828 P |
231 | OSSL_PARAM params[3], *p = params; |
232 | ||
233 | if (drbg->get_entropy_fn != NULL) { | |
234 | if (drbg->cleanup_entropy_fn != NULL) { | |
235 | *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_SIZE, | |
236 | &outlen); | |
237 | *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA, | |
238 | (void **)&out, 0); | |
239 | *p = OSSL_PARAM_construct_end(); | |
240 | ||
241 | drbg->cleanup_entropy_fn(params, drbg->callback_arg); | |
242 | } | |
243 | } else if (drbg->seed_pool == NULL) { | |
244 | OPENSSL_secure_clear_free(out, outlen); | |
714a1bb3 P |
245 | } |
246 | } | |
f000e828 P |
247 | |
248 | static size_t get_entropy(PROV_DRBG *drbg, unsigned char **pout, int entropy, | |
249 | size_t min_len, size_t max_len, | |
250 | int prediction_resistance) | |
251 | { | |
252 | if (drbg->get_entropy_fn != NULL) { | |
253 | OSSL_PARAM params[6], *p = params; | |
254 | OSSL_PARAM out[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; | |
255 | ||
256 | *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_ENTROPY_REQUIRED, | |
257 | &entropy); | |
258 | *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_PREDICTION_RESISTANCE, | |
259 | &prediction_resistance); | |
260 | *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MIN_LENGTH, | |
261 | &min_len); | |
262 | *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MAX_LENGTH, | |
263 | &max_len); | |
264 | *p = OSSL_PARAM_construct_end(); | |
265 | *out = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA, | |
266 | (void **)pout, 0); | |
267 | ||
268 | if (drbg->get_entropy_fn(params, out, drbg->callback_arg)) | |
269 | return out->return_size; | |
270 | ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_ENTROPY); | |
271 | return 0; | |
272 | } | |
273 | ||
274 | #ifdef FIPS_MODULE | |
275 | if (drbg->parent == NULL) | |
276 | return prov_crngt_get_entropy(drbg, pout, entropy, min_len, max_len, | |
277 | prediction_resistance); | |
278 | #endif | |
279 | ||
280 | return prov_drbg_get_entropy(drbg, pout, entropy, min_len, max_len, | |
281 | prediction_resistance); | |
282 | } | |
283 | ||
284 | static void cleanup_entropy(PROV_DRBG *drbg, unsigned char *out, size_t outlen) | |
285 | { | |
286 | #ifdef FIPS_MODULE | |
287 | if (drbg->parent == NULL) | |
288 | prov_crngt_cleanup_entropy(drbg, out, outlen); | |
289 | else | |
714a1bb3 | 290 | #endif |
f000e828 P |
291 | prov_drbg_cleanup_entropy(drbg, out, outlen); |
292 | } | |
714a1bb3 P |
293 | |
294 | #ifndef PROV_RAND_GET_RANDOM_NONCE | |
295 | typedef struct prov_drbg_nonce_global_st { | |
296 | CRYPTO_RWLOCK *rand_nonce_lock; | |
297 | int rand_nonce_count; | |
298 | } PROV_DRBG_NONCE_GLOBAL; | |
299 | ||
300 | /* | |
301 | * drbg_ossl_ctx_new() calls drgb_setup() which calls rand_drbg_get_nonce() | |
302 | * which needs to get the rand_nonce_lock out of the OPENSSL_CTX...but since | |
303 | * drbg_ossl_ctx_new() hasn't finished running yet we need the rand_nonce_lock | |
304 | * to be in a different global data object. Otherwise we will go into an | |
305 | * infinite recursion loop. | |
306 | */ | |
307 | static void *prov_drbg_nonce_ossl_ctx_new(OPENSSL_CTX *libctx) | |
308 | { | |
309 | PROV_DRBG_NONCE_GLOBAL *dngbl = OPENSSL_zalloc(sizeof(*dngbl)); | |
310 | ||
311 | if (dngbl == NULL) | |
312 | return NULL; | |
313 | ||
314 | dngbl->rand_nonce_lock = CRYPTO_THREAD_lock_new(); | |
315 | if (dngbl->rand_nonce_lock == NULL) { | |
316 | OPENSSL_free(dngbl); | |
317 | return NULL; | |
318 | } | |
319 | ||
320 | return dngbl; | |
321 | } | |
322 | ||
323 | static void prov_drbg_nonce_ossl_ctx_free(void *vdngbl) | |
324 | { | |
325 | PROV_DRBG_NONCE_GLOBAL *dngbl = vdngbl; | |
326 | ||
327 | if (dngbl == NULL) | |
328 | return; | |
329 | ||
330 | CRYPTO_THREAD_lock_free(dngbl->rand_nonce_lock); | |
331 | ||
332 | OPENSSL_free(dngbl); | |
333 | } | |
334 | ||
335 | static const OPENSSL_CTX_METHOD drbg_nonce_ossl_ctx_method = { | |
336 | prov_drbg_nonce_ossl_ctx_new, | |
337 | prov_drbg_nonce_ossl_ctx_free, | |
338 | }; | |
339 | ||
340 | /* Get a nonce from the operating system */ | |
341 | static size_t prov_drbg_get_nonce(PROV_DRBG *drbg, | |
342 | unsigned char **pout, | |
343 | int entropy, size_t min_len, size_t max_len) | |
344 | { | |
f000e828 | 345 | size_t ret = 0, n; |
714a1bb3 | 346 | RAND_POOL *pool; |
f000e828 P |
347 | unsigned char *buf = NULL; |
348 | OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(drbg->provctx); | |
714a1bb3 | 349 | PROV_DRBG_NONCE_GLOBAL *dngbl |
f000e828 | 350 | = openssl_ctx_get_data(libctx, OPENSSL_CTX_DRBG_NONCE_INDEX, |
714a1bb3 | 351 | &drbg_nonce_ossl_ctx_method); |
f000e828 P |
352 | OSSL_PARAM params[5], *p = params; |
353 | OSSL_PARAM out[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; | |
714a1bb3 P |
354 | struct { |
355 | void *instance; | |
356 | int count; | |
357 | } data; | |
358 | ||
714a1bb3 P |
359 | if (dngbl == NULL) |
360 | return 0; | |
361 | ||
f000e828 P |
362 | if (drbg->get_nonce_fn != NULL) { |
363 | *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_ENTROPY_REQUIRED, | |
364 | &entropy); | |
365 | *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MIN_LENGTH, | |
366 | &min_len); | |
367 | *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MAX_LENGTH, | |
368 | &max_len); | |
369 | *p = OSSL_PARAM_construct_end(); | |
370 | *out = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA, | |
371 | (void **)pout, 0); | |
372 | ||
373 | if (drbg->get_nonce_fn(params, out, drbg->callback_arg)) | |
374 | return out->return_size; | |
375 | ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_NONCE); | |
376 | return 0; | |
377 | } | |
378 | if (drbg->parent != NULL) { | |
379 | if (drbg->parent_nonce != NULL) { | |
380 | n = drbg->parent_nonce(drbg->parent, NULL, 0, drbg->min_noncelen, | |
381 | drbg->max_noncelen); | |
382 | if (n > 0 && (buf = OPENSSL_malloc(n)) != NULL) { | |
383 | ret = drbg->parent_nonce(drbg->parent, buf, 0, | |
384 | drbg->min_noncelen, | |
385 | drbg->max_noncelen); | |
386 | if (ret == n) { | |
387 | *pout = buf; | |
388 | return ret; | |
389 | } | |
390 | OPENSSL_free(buf); | |
391 | } | |
392 | } | |
393 | } | |
394 | ||
395 | /* Use the built in nonce source */ | |
714a1bb3 P |
396 | memset(&data, 0, sizeof(data)); |
397 | pool = rand_pool_new(0, 0, min_len, max_len); | |
398 | if (pool == NULL) | |
399 | return 0; | |
400 | ||
f000e828 | 401 | if (prov_pool_add_nonce_data(pool) == 0) |
714a1bb3 P |
402 | goto err; |
403 | ||
404 | data.instance = drbg; | |
405 | CRYPTO_atomic_add(&dngbl->rand_nonce_count, 1, &data.count, | |
406 | dngbl->rand_nonce_lock); | |
407 | ||
408 | if (rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0) == 0) | |
409 | goto err; | |
410 | ||
411 | ret = rand_pool_length(pool); | |
412 | *pout = rand_pool_detach(pool); | |
413 | ||
414 | err: | |
415 | rand_pool_free(pool); | |
416 | ||
417 | return ret; | |
418 | } | |
714a1bb3 | 419 | |
f000e828 P |
420 | static void prov_drbg_clear_nonce(PROV_DRBG *drbg, unsigned char *nonce, |
421 | size_t noncelen) | |
714a1bb3 | 422 | { |
f000e828 P |
423 | OSSL_PARAM params[3], *p = params; |
424 | ||
425 | if (drbg->get_nonce_fn != NULL) { | |
426 | if (drbg->cleanup_nonce_fn != NULL) { | |
427 | *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_SIZE, | |
428 | &noncelen); | |
429 | *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA, | |
430 | (void **)&nonce, 0); | |
431 | *p = OSSL_PARAM_construct_end(); | |
432 | ||
433 | drbg->cleanup_nonce_fn(params, drbg->callback_arg); | |
434 | } | |
435 | } else { | |
436 | OPENSSL_clear_free(nonce, noncelen); | |
437 | } | |
714a1bb3 | 438 | } |
f000e828 P |
439 | #else |
440 | # define prov_drbg_clear_nonce(drbg, nonce, len) \ | |
441 | OPENSSL_clear_free((nonce), (len)) | |
442 | #endif /* PROV_RAND_GET_RANDOM_NONCE */ | |
714a1bb3 P |
443 | |
444 | /* | |
445 | * Instantiate |drbg|, after it has been initialized. Use |pers| and | |
446 | * |perslen| as prediction-resistance input. | |
447 | * | |
448 | * Requires that drbg->lock is already locked for write, if non-null. | |
449 | * | |
450 | * Returns 1 on success, 0 on failure. | |
451 | */ | |
f000e828 | 452 | int PROV_DRBG_instantiate(PROV_DRBG *drbg, unsigned int strength, |
714a1bb3 | 453 | int prediction_resistance, |
f000e828 | 454 | const unsigned char *pers, size_t perslen) |
714a1bb3 P |
455 | { |
456 | unsigned char *nonce = NULL, *entropy = NULL; | |
457 | size_t noncelen = 0, entropylen = 0; | |
458 | size_t min_entropy, min_entropylen, max_entropylen; | |
714a1bb3 P |
459 | |
460 | if (strength > drbg->strength) { | |
f000e828 | 461 | PROVerr(0, PROV_R_INSUFFICIENT_DRBG_STRENGTH); |
714a1bb3 P |
462 | goto end; |
463 | } | |
464 | min_entropy = drbg->strength; | |
465 | min_entropylen = drbg->min_entropylen; | |
466 | max_entropylen = drbg->max_entropylen; | |
467 | ||
468 | if (pers == NULL) { | |
469 | pers = (const unsigned char *)ossl_pers_string; | |
470 | perslen = sizeof(ossl_pers_string); | |
471 | } | |
472 | if (perslen > drbg->max_perslen) { | |
f000e828 | 473 | PROVerr(0, PROV_R_PERSONALISATION_STRING_TOO_LONG); |
714a1bb3 P |
474 | goto end; |
475 | } | |
476 | ||
f000e828 P |
477 | if (drbg->state != EVP_RAND_STATE_UNINITIALISED) { |
478 | if (drbg->state == EVP_RAND_STATE_ERROR) | |
479 | PROVerr(0, PROV_R_IN_ERROR_STATE); | |
714a1bb3 | 480 | else |
f000e828 | 481 | PROVerr(0, PROV_R_ALREADY_INSTANTIATED); |
714a1bb3 P |
482 | goto end; |
483 | } | |
484 | ||
f000e828 | 485 | drbg->state = EVP_RAND_STATE_ERROR; |
714a1bb3 P |
486 | |
487 | if (drbg->min_noncelen > 0) { | |
f000e828 P |
488 | if (drbg->parent_nonce != NULL) { |
489 | noncelen = drbg->parent_nonce(drbg->parent, NULL, drbg->strength, | |
490 | drbg->min_noncelen, | |
491 | drbg->max_noncelen); | |
492 | if (noncelen == 0) { | |
493 | PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE); | |
494 | goto end; | |
495 | } | |
496 | nonce = OPENSSL_malloc(noncelen); | |
497 | if (nonce == NULL) { | |
498 | PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE); | |
499 | goto end; | |
500 | } | |
501 | if (noncelen != drbg->parent_nonce(drbg->parent, nonce, | |
502 | drbg->strength, | |
503 | drbg->min_noncelen, | |
504 | drbg->max_noncelen)) { | |
505 | PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE); | |
506 | OPENSSL_free(nonce); | |
507 | } | |
714a1bb3 | 508 | #ifndef PROV_RAND_GET_RANDOM_NONCE |
f000e828 | 509 | } else if (drbg->parent != NULL) { |
714a1bb3 | 510 | #endif |
f000e828 P |
511 | /* |
512 | * NIST SP800-90Ar1 section 9.1 says you can combine getting | |
513 | * the entropy and nonce in 1 call by increasing the entropy | |
514 | * with 50% and increasing the minimum length to accommodate | |
515 | * the length of the nonce. We do this in case a nonce is | |
516 | * required and there is no parental nonce capability. | |
517 | */ | |
518 | min_entropy += drbg->strength / 2; | |
519 | min_entropylen += drbg->min_noncelen; | |
520 | max_entropylen += drbg->max_noncelen; | |
714a1bb3 P |
521 | } |
522 | #ifndef PROV_RAND_GET_RANDOM_NONCE | |
523 | else { /* parent == NULL */ | |
524 | noncelen = prov_drbg_get_nonce(drbg, &nonce, drbg->strength / 2, | |
525 | drbg->min_noncelen, | |
526 | drbg->max_noncelen); | |
527 | if (noncelen < drbg->min_noncelen | |
528 | || noncelen > drbg->max_noncelen) { | |
f000e828 | 529 | PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE); |
714a1bb3 P |
530 | goto end; |
531 | } | |
532 | } | |
533 | #endif | |
534 | } | |
535 | ||
f000e828 | 536 | drbg->reseed_next_counter = tsan_load(&drbg->reseed_counter); |
714a1bb3 P |
537 | if (drbg->reseed_next_counter) { |
538 | drbg->reseed_next_counter++; | |
f000e828 | 539 | if (!drbg->reseed_next_counter) |
714a1bb3 P |
540 | drbg->reseed_next_counter = 1; |
541 | } | |
542 | ||
543 | entropylen = get_entropy(drbg, &entropy, min_entropy, | |
544 | min_entropylen, max_entropylen, | |
545 | prediction_resistance); | |
546 | if (entropylen < min_entropylen | |
547 | || entropylen > max_entropylen) { | |
f000e828 | 548 | PROVerr(0, PROV_R_ERROR_RETRIEVING_ENTROPY); |
714a1bb3 P |
549 | goto end; |
550 | } | |
551 | ||
f000e828 P |
552 | if (!drbg->instantiate(drbg, entropy, entropylen, nonce, noncelen, |
553 | pers, perslen)) { | |
554 | PROVerr(0, PROV_R_ERROR_INSTANTIATING_DRBG); | |
714a1bb3 P |
555 | goto end; |
556 | } | |
557 | ||
f000e828 | 558 | drbg->state = EVP_RAND_STATE_READY; |
714a1bb3 P |
559 | drbg->reseed_gen_counter = 1; |
560 | drbg->reseed_time = time(NULL); | |
f000e828 | 561 | tsan_store(&drbg->reseed_counter, drbg->reseed_next_counter); |
714a1bb3 P |
562 | |
563 | end: | |
564 | if (entropy != NULL) | |
565 | cleanup_entropy(drbg, entropy, entropylen); | |
f000e828 P |
566 | prov_drbg_clear_nonce(drbg, nonce, noncelen); |
567 | if (drbg->state == EVP_RAND_STATE_READY) | |
714a1bb3 P |
568 | return 1; |
569 | return 0; | |
570 | } | |
571 | ||
f000e828 P |
572 | /* |
573 | * Uninstantiate |drbg|. Must be instantiated before it can be used. | |
574 | * | |
575 | * Requires that drbg->lock is already locked for write, if non-null. | |
576 | * | |
577 | * Returns 1 on success, 0 on failure. | |
578 | */ | |
579 | int PROV_DRBG_uninstantiate(PROV_DRBG *drbg) | |
580 | { | |
581 | drbg->state = EVP_RAND_STATE_UNINITIALISED; | |
582 | return 1; | |
583 | } | |
584 | ||
714a1bb3 P |
585 | /* |
586 | * Reseed |drbg|, mixing in the specified data | |
587 | * | |
588 | * Requires that drbg->lock is already locked for write, if non-null. | |
589 | * | |
590 | * Returns 1 on success, 0 on failure. | |
591 | */ | |
592 | int PROV_DRBG_reseed(PROV_DRBG *drbg, int prediction_resistance, | |
593 | const unsigned char *ent, size_t ent_len, | |
f000e828 | 594 | const unsigned char *adin, size_t adinlen) |
714a1bb3 P |
595 | { |
596 | unsigned char *entropy = NULL; | |
597 | size_t entropylen = 0; | |
598 | ||
f000e828 P |
599 | if (drbg->state != EVP_RAND_STATE_READY) { |
600 | /* try to recover from previous errors */ | |
601 | rand_drbg_restart(drbg); | |
602 | ||
603 | if (drbg->state == EVP_RAND_STATE_ERROR) { | |
604 | PROVerr(0, PROV_R_IN_ERROR_STATE); | |
605 | return 0; | |
606 | } | |
607 | if (drbg->state == EVP_RAND_STATE_UNINITIALISED) { | |
608 | PROVerr(0, PROV_R_NOT_INSTANTIATED); | |
609 | return 0; | |
610 | } | |
714a1bb3 | 611 | } |
f000e828 P |
612 | |
613 | if (ent != NULL) { | |
614 | if (ent_len < drbg->min_entropylen) { | |
615 | RANDerr(0, RAND_R_ENTROPY_OUT_OF_RANGE); | |
616 | drbg->state = EVP_RAND_STATE_ERROR; | |
617 | return 0; | |
618 | } | |
619 | if (ent_len > drbg->max_entropylen) { | |
620 | RANDerr(0, RAND_R_ENTROPY_INPUT_TOO_LONG); | |
621 | drbg->state = EVP_RAND_STATE_ERROR; | |
622 | return 0; | |
623 | } | |
714a1bb3 P |
624 | } |
625 | ||
626 | if (adin == NULL) { | |
627 | adinlen = 0; | |
628 | } else if (adinlen > drbg->max_adinlen) { | |
f000e828 | 629 | PROVerr(0, PROV_R_ADDITIONAL_INPUT_TOO_LONG); |
714a1bb3 P |
630 | return 0; |
631 | } | |
632 | ||
f000e828 | 633 | drbg->state = EVP_RAND_STATE_ERROR; |
714a1bb3 | 634 | |
f000e828 | 635 | drbg->reseed_next_counter = tsan_load(&drbg->reseed_counter); |
714a1bb3 P |
636 | if (drbg->reseed_next_counter) { |
637 | drbg->reseed_next_counter++; | |
f000e828 | 638 | if (!drbg->reseed_next_counter) |
714a1bb3 P |
639 | drbg->reseed_next_counter = 1; |
640 | } | |
641 | ||
f000e828 P |
642 | if (ent != NULL) { |
643 | #ifdef FIP_MODULE | |
644 | /* | |
645 | * NIST SP-800-90A mandates that entropy *shall not* be provided | |
646 | * by the consuming application. Instead the data is added as additional | |
647 | * input. | |
648 | * | |
649 | * (NIST SP-800-90Ar1, Sections 9.1 and 9.2) | |
650 | */ | |
651 | if (!drbg->reseed(drbg, NULL, 0, ent, ent_len)) { | |
652 | ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED); | |
653 | return 0; | |
654 | } | |
655 | #else | |
656 | if (!drbg->reseed(drbg, ent, ent_len, adin, adinlen)) { | |
657 | ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED); | |
658 | return 0; | |
659 | } | |
660 | /* There isn't much point adding the same additional input twice */ | |
661 | adin = NULL; | |
662 | adinlen = 0; | |
663 | #endif | |
664 | } | |
665 | ||
666 | /* Reseed using our sources in addition */ | |
714a1bb3 P |
667 | entropylen = get_entropy(drbg, &entropy, drbg->strength, |
668 | drbg->min_entropylen, drbg->max_entropylen, | |
669 | prediction_resistance); | |
670 | if (entropylen < drbg->min_entropylen | |
671 | || entropylen > drbg->max_entropylen) { | |
f000e828 | 672 | PROVerr(0, PROV_R_ERROR_RETRIEVING_ENTROPY); |
714a1bb3 P |
673 | goto end; |
674 | } | |
675 | ||
f000e828 | 676 | if (!drbg->reseed(drbg, entropy, entropylen, adin, adinlen)) |
714a1bb3 P |
677 | goto end; |
678 | ||
f000e828 | 679 | drbg->state = EVP_RAND_STATE_READY; |
714a1bb3 P |
680 | drbg->reseed_gen_counter = 1; |
681 | drbg->reseed_time = time(NULL); | |
f000e828 P |
682 | tsan_store(&drbg->reseed_counter, drbg->reseed_next_counter); |
683 | if (drbg->parent != NULL) | |
684 | drbg->parent_reseed_counter = get_parent_reseed_count(drbg); | |
714a1bb3 P |
685 | |
686 | end: | |
f000e828 P |
687 | cleanup_entropy(drbg, entropy, entropylen); |
688 | if (drbg->state == EVP_RAND_STATE_READY) | |
714a1bb3 P |
689 | return 1; |
690 | return 0; | |
691 | } | |
692 | ||
693 | /* | |
694 | * Generate |outlen| bytes into the buffer at |out|. Reseed if we need | |
695 | * to or if |prediction_resistance| is set. Additional input can be | |
696 | * sent in |adin| and |adinlen|. | |
697 | * | |
698 | * Requires that drbg->lock is already locked for write, if non-null. | |
699 | * | |
700 | * Returns 1 on success, 0 on failure. | |
701 | * | |
702 | */ | |
703 | int PROV_DRBG_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen, | |
f000e828 P |
704 | unsigned int strength, int prediction_resistance, |
705 | const unsigned char *adin, size_t adinlen) | |
714a1bb3 P |
706 | { |
707 | int fork_id; | |
708 | int reseed_required = 0; | |
709 | ||
f000e828 P |
710 | if (drbg->state != EVP_RAND_STATE_READY) { |
711 | /* try to recover from previous errors */ | |
712 | rand_drbg_restart(drbg); | |
713 | ||
714 | if (drbg->state == EVP_RAND_STATE_ERROR) { | |
715 | PROVerr(0, PROV_R_IN_ERROR_STATE); | |
714a1bb3 P |
716 | return 0; |
717 | } | |
f000e828 P |
718 | if (drbg->state == EVP_RAND_STATE_UNINITIALISED) { |
719 | PROVerr(0, PROV_R_NOT_INSTANTIATED); | |
714a1bb3 P |
720 | return 0; |
721 | } | |
722 | } | |
f000e828 P |
723 | if (strength > drbg->strength) { |
724 | PROVerr(0, PROV_R_INSUFFICIENT_DRBG_STRENGTH); | |
725 | return 0; | |
726 | } | |
714a1bb3 P |
727 | |
728 | if (outlen > drbg->max_request) { | |
f000e828 | 729 | PROVerr(0, PROV_R_REQUEST_TOO_LARGE_FOR_DRBG); |
714a1bb3 P |
730 | return 0; |
731 | } | |
732 | if (adinlen > drbg->max_adinlen) { | |
f000e828 | 733 | PROVerr(0, PROV_R_ADDITIONAL_INPUT_TOO_LONG); |
714a1bb3 P |
734 | return 0; |
735 | } | |
736 | ||
737 | fork_id = openssl_get_fork_id(); | |
738 | ||
739 | if (drbg->fork_id != fork_id) { | |
740 | drbg->fork_id = fork_id; | |
741 | reseed_required = 1; | |
742 | } | |
743 | ||
744 | if (drbg->reseed_interval > 0) { | |
745 | if (drbg->reseed_gen_counter > drbg->reseed_interval) | |
746 | reseed_required = 1; | |
747 | } | |
748 | if (drbg->reseed_time_interval > 0) { | |
749 | time_t now = time(NULL); | |
750 | if (now < drbg->reseed_time | |
751 | || now - drbg->reseed_time >= drbg->reseed_time_interval) | |
752 | reseed_required = 1; | |
753 | } | |
f000e828 P |
754 | if (drbg->parent != NULL |
755 | && get_parent_reseed_count(drbg) != drbg->parent_reseed_counter) | |
756 | reseed_required = 1; | |
714a1bb3 P |
757 | |
758 | if (reseed_required || prediction_resistance) { | |
759 | if (!PROV_DRBG_reseed(drbg, prediction_resistance, NULL, 0, | |
f000e828 P |
760 | adin, adinlen)) { |
761 | PROVerr(0, PROV_R_RESEED_ERROR); | |
714a1bb3 P |
762 | return 0; |
763 | } | |
764 | adin = NULL; | |
765 | adinlen = 0; | |
766 | } | |
767 | ||
f000e828 P |
768 | if (!drbg->generate(drbg, out, outlen, adin, adinlen)) { |
769 | drbg->state = EVP_RAND_STATE_ERROR; | |
770 | PROVerr(0, PROV_R_GENERATE_ERROR); | |
714a1bb3 P |
771 | return 0; |
772 | } | |
773 | ||
774 | drbg->reseed_gen_counter++; | |
775 | ||
776 | return 1; | |
777 | } | |
778 | ||
714a1bb3 | 779 | /* |
f000e828 P |
780 | * Restart |drbg|, using the specified entropy or additional input |
781 | * | |
782 | * Tries its best to get the drbg instantiated by all means, | |
783 | * regardless of its current state. | |
784 | * | |
785 | * Optionally, a |buffer| of |len| random bytes can be passed, | |
786 | * which is assumed to contain at least |entropy| bits of entropy. | |
787 | * | |
788 | * If |entropy| > 0, the buffer content is used as entropy input. | |
789 | * | |
790 | * If |entropy| == 0, the buffer content is used as additional input | |
791 | * | |
792 | * Returns 1 on success, 0 on failure. | |
793 | * | |
794 | * This function is used internally only. | |
714a1bb3 | 795 | */ |
f000e828 | 796 | static int rand_drbg_restart(PROV_DRBG *drbg) |
714a1bb3 | 797 | { |
f000e828 P |
798 | if (drbg->seed_pool != NULL) { |
799 | drbg->state = EVP_RAND_STATE_ERROR; | |
800 | rand_pool_free(drbg->seed_pool); | |
801 | drbg->seed_pool = NULL; | |
802 | RANDerr(0, ERR_R_INTERNAL_ERROR); | |
803 | return 0; | |
714a1bb3 P |
804 | } |
805 | ||
f000e828 P |
806 | /* repair error state */ |
807 | if (drbg->state == EVP_RAND_STATE_ERROR) | |
808 | drbg->uninstantiate(drbg); | |
809 | ||
810 | /* repair uninitialized state */ | |
811 | if (drbg->state == EVP_RAND_STATE_UNINITIALISED) | |
812 | /* reinstantiate drbg */ | |
813 | PROV_DRBG_instantiate(drbg, drbg->strength, 0, NULL, 0); | |
714a1bb3 | 814 | |
f000e828 P |
815 | rand_pool_free(drbg->seed_pool); |
816 | drbg->seed_pool = NULL; | |
817 | return drbg->state == EVP_RAND_STATE_READY; | |
714a1bb3 | 818 | } |
714a1bb3 P |
819 | |
820 | /* Provider support from here down */ | |
821 | static const OSSL_DISPATCH *find_call(const OSSL_DISPATCH *dispatch, | |
822 | int function) | |
823 | { | |
824 | if (dispatch != NULL) | |
f000e828 | 825 | while (dispatch->function_id != 0) { |
714a1bb3 P |
826 | if (dispatch->function_id == function) |
827 | return dispatch; | |
f000e828 P |
828 | dispatch++; |
829 | } | |
714a1bb3 P |
830 | return NULL; |
831 | } | |
832 | ||
833 | int drbg_enable_locking(void *vctx) | |
834 | { | |
835 | PROV_DRBG *drbg = vctx; | |
714a1bb3 | 836 | |
f000e828 P |
837 | if (drbg != NULL && drbg->lock == NULL) { |
838 | if (drbg->parent_enable_locking != NULL) | |
839 | if (!drbg->parent_enable_locking(drbg->parent)) { | |
840 | ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED); | |
714a1bb3 P |
841 | return 0; |
842 | } | |
843 | drbg->lock = CRYPTO_THREAD_lock_new(); | |
844 | if (drbg->lock == NULL) { | |
f000e828 | 845 | ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK); |
714a1bb3 P |
846 | return 0; |
847 | } | |
848 | } | |
849 | return 1; | |
850 | } | |
851 | ||
852 | /* | |
853 | * Allocate memory and initialize a new DRBG. The DRBG is allocated on | |
854 | * the secure heap if |secure| is nonzero and the secure heap is enabled. | |
855 | * The |parent|, if not NULL, will be used as random source for reseeding. | |
856 | * This also requires the parent's provider context and the parent's lock. | |
857 | * | |
858 | * Returns a pointer to the new DRBG instance on success, NULL on failure. | |
859 | */ | |
f000e828 P |
860 | PROV_DRBG *prov_rand_drbg_new |
861 | (void *provctx, void *parent, const OSSL_DISPATCH *p_dispatch, | |
862 | int (*dnew)(PROV_DRBG *ctx), | |
863 | int (*instantiate)(PROV_DRBG *drbg, | |
864 | const unsigned char *entropy, size_t entropylen, | |
865 | const unsigned char *nonce, size_t noncelen, | |
866 | const unsigned char *pers, size_t perslen), | |
867 | int (*uninstantiate)(PROV_DRBG *ctx), | |
868 | int (*reseed)(PROV_DRBG *drbg, const unsigned char *ent, size_t ent_len, | |
869 | const unsigned char *adin, size_t adin_len), | |
870 | int (*generate)(PROV_DRBG *, unsigned char *out, size_t outlen, | |
871 | const unsigned char *adin, size_t adin_len)) | |
714a1bb3 P |
872 | { |
873 | PROV_DRBG *drbg = OPENSSL_zalloc(sizeof(*drbg)); | |
f000e828 P |
874 | unsigned int p_str; |
875 | const OSSL_DISPATCH *pfunc; | |
714a1bb3 P |
876 | |
877 | if (drbg == NULL) { | |
878 | ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); | |
879 | return NULL; | |
880 | } | |
881 | ||
f000e828 P |
882 | drbg->provctx = provctx; |
883 | drbg->instantiate = instantiate; | |
884 | drbg->uninstantiate = uninstantiate; | |
885 | drbg->reseed = reseed; | |
886 | drbg->generate = generate; | |
887 | drbg->fork_id = openssl_get_fork_id(); | |
888 | ||
889 | /* Extract parent's functions */ | |
714a1bb3 | 890 | drbg->parent = parent; |
f000e828 | 891 | if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_ENABLE_LOCKING)) != NULL) |
363b1e5d | 892 | drbg->parent_enable_locking = OSSL_FUNC_rand_enable_locking(pfunc); |
f000e828 | 893 | if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_LOCK)) != NULL) |
363b1e5d | 894 | drbg->parent_lock = OSSL_FUNC_rand_lock(pfunc); |
f000e828 | 895 | if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_UNLOCK)) != NULL) |
363b1e5d | 896 | drbg->parent_unlock = OSSL_FUNC_rand_unlock(pfunc); |
f000e828 | 897 | if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GET_CTX_PARAMS)) != NULL) |
363b1e5d | 898 | drbg->parent_get_ctx_params = OSSL_FUNC_rand_get_ctx_params(pfunc); |
f000e828 | 899 | if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GENERATE)) != NULL) |
363b1e5d | 900 | drbg->parent_generate = OSSL_FUNC_rand_generate(pfunc); |
f000e828 | 901 | if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_NONCE)) != NULL) |
363b1e5d | 902 | drbg->parent_nonce = OSSL_FUNC_rand_nonce(pfunc); |
714a1bb3 P |
903 | |
904 | /* Set some default maximums up */ | |
905 | drbg->max_entropylen = DRBG_MAX_LENGTH; | |
906 | drbg->max_noncelen = DRBG_MAX_LENGTH; | |
907 | drbg->max_perslen = DRBG_MAX_LENGTH; | |
908 | drbg->max_adinlen = DRBG_MAX_LENGTH; | |
909 | drbg->reseed_gen_counter = 1; | |
f000e828 P |
910 | drbg->reseed_counter = 1; |
911 | drbg->reseed_interval = RESEED_INTERVAL; | |
912 | drbg->reseed_time_interval = TIME_INTERVAL; | |
714a1bb3 | 913 | |
f000e828 | 914 | if (!dnew(drbg)) |
714a1bb3 P |
915 | goto err; |
916 | ||
917 | if (parent != NULL) { | |
918 | if (!get_parent_strength(drbg, &p_str)) | |
919 | goto err; | |
920 | if (drbg->strength > p_str) { | |
921 | /* | |
922 | * We currently don't support the algorithm from NIST SP 800-90C | |
923 | * 10.1.2 to use a weaker DRBG as source | |
924 | */ | |
f000e828 | 925 | ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_STRENGTH_TOO_WEAK); |
714a1bb3 P |
926 | goto err; |
927 | } | |
928 | } | |
929 | return drbg; | |
930 | ||
931 | err: | |
932 | prov_rand_drbg_free(drbg); | |
933 | return NULL; | |
934 | } | |
935 | ||
936 | void prov_rand_drbg_free(PROV_DRBG *drbg) | |
937 | { | |
938 | if (drbg == NULL) | |
939 | return; | |
940 | ||
941 | rand_pool_free(drbg->adin_pool); | |
942 | CRYPTO_THREAD_lock_free(drbg->lock); | |
f000e828 | 943 | OPENSSL_free(drbg); |
714a1bb3 P |
944 | } |
945 | ||
946 | int drbg_get_ctx_params(PROV_DRBG *drbg, OSSL_PARAM params[]) | |
947 | { | |
948 | OSSL_PARAM *p; | |
949 | ||
f000e828 | 950 | p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE); |
714a1bb3 P |
951 | if (p != NULL && !OSSL_PARAM_set_int(p, drbg->state)) |
952 | return 0; | |
953 | ||
954 | p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STRENGTH); | |
955 | if (p != NULL && !OSSL_PARAM_set_int(p, drbg->strength)) | |
956 | return 0; | |
957 | ||
f000e828 | 958 | p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_REQUEST); |
714a1bb3 P |
959 | if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_request)) |
960 | return 0; | |
961 | ||
f000e828 | 962 | p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MIN_ENTROPYLEN); |
714a1bb3 P |
963 | if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->min_entropylen)) |
964 | return 0; | |
965 | ||
f000e828 | 966 | p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_ENTROPYLEN); |
714a1bb3 P |
967 | if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_entropylen)) |
968 | return 0; | |
969 | ||
f000e828 | 970 | p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MIN_NONCELEN); |
714a1bb3 P |
971 | if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->min_noncelen)) |
972 | return 0; | |
973 | ||
f000e828 | 974 | p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_NONCELEN); |
714a1bb3 P |
975 | if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_noncelen)) |
976 | return 0; | |
977 | ||
f000e828 | 978 | p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_PERSLEN); |
714a1bb3 P |
979 | if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_perslen)) |
980 | return 0; | |
981 | ||
f000e828 | 982 | p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_ADINLEN); |
714a1bb3 P |
983 | if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_adinlen)) |
984 | return 0; | |
985 | ||
f000e828 P |
986 | p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_REQUESTS); |
987 | if (p != NULL && !OSSL_PARAM_set_uint(p, drbg->reseed_interval)) | |
714a1bb3 P |
988 | return 0; |
989 | ||
f000e828 P |
990 | p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_TIME); |
991 | if (p != NULL && !OSSL_PARAM_set_time_t(p, drbg->reseed_time)) | |
714a1bb3 P |
992 | return 0; |
993 | ||
f000e828 | 994 | p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL); |
714a1bb3 P |
995 | if (p != NULL && !OSSL_PARAM_set_time_t(p, drbg->reseed_time_interval)) |
996 | return 0; | |
997 | ||
f000e828 | 998 | p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_CTR); |
714a1bb3 | 999 | if (p != NULL |
f000e828 | 1000 | && !OSSL_PARAM_set_uint(p, tsan_load(&drbg->reseed_counter))) |
714a1bb3 P |
1001 | return 0; |
1002 | return 1; | |
1003 | } | |
1004 | ||
1005 | int drbg_set_ctx_params(PROV_DRBG *drbg, const OSSL_PARAM params[]) | |
1006 | { | |
1007 | const OSSL_PARAM *p; | |
1008 | ||
f000e828 | 1009 | p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RESEED_REQUESTS); |
714a1bb3 P |
1010 | if (p != NULL && !OSSL_PARAM_get_uint(p, &drbg->reseed_interval)) |
1011 | return 0; | |
1012 | ||
f000e828 | 1013 | p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL); |
714a1bb3 P |
1014 | if (p != NULL && !OSSL_PARAM_get_time_t(p, &drbg->reseed_time_interval)) |
1015 | return 0; | |
1016 | return 1; | |
1017 | } | |
f000e828 P |
1018 | |
1019 | int drbg_set_callbacks(void *vctx, OSSL_INOUT_CALLBACK *get_entropy_fn, | |
1020 | OSSL_CALLBACK *cleanup_entropy_fn, | |
1021 | OSSL_INOUT_CALLBACK *get_nonce_fn, | |
1022 | OSSL_CALLBACK *cleanup_nonce_fn, void *arg) | |
1023 | { | |
1024 | PROV_DRBG *drbg = vctx; | |
1025 | ||
1026 | if (drbg->state != EVP_RAND_STATE_UNINITIALISED | |
1027 | || drbg->parent != NULL) | |
1028 | return 0; | |
1029 | ||
1030 | drbg->get_entropy_fn = get_entropy_fn; | |
1031 | drbg->cleanup_entropy_fn = cleanup_entropy_fn; | |
1032 | drbg->get_nonce_fn = get_nonce_fn; | |
1033 | drbg->cleanup_nonce_fn = cleanup_nonce_fn; | |
1034 | drbg->callback_arg = arg; | |
1035 | return 1; | |
1036 | } |