]>
Commit | Line | Data |
---|---|---|
12fb8c3d RS |
1 | /* |
2 | * Copyright 2011-2017 The OpenSSL Project Authors. All Rights Reserved. | |
3 | * | |
4 | * Licensed under the OpenSSL license (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> | |
14 | #include "rand_lcl.h" | |
15 | ||
16 | /* | |
17 | * Support framework for NIST SP 800-90A DRBG, AES-CTR mode. | |
75e2c877 RS |
18 | * The RAND_DRBG is OpenSSL's pointer to an instance of the DRBG. |
19 | * | |
12fb8c3d RS |
20 | * The OpenSSL model is to have new and free functions, and that new |
21 | * does all initialization. That is not the NIST model, which has | |
22 | * instantiation and un-instantiate, and re-use within a new/free | |
23 | * lifecycle. (No doubt this comes from the desire to support hardware | |
24 | * DRBG, where allocation of resources on something like an HSM is | |
25 | * a much bigger deal than just re-setting an allocated resource.) | |
12fb8c3d RS |
26 | */ |
27 | ||
28 | /* | |
75e2c877 | 29 | * Set/initialize |drbg| to be of type |nid|, with optional |flags|. |
12fb8c3d RS |
30 | * Return -2 if the type is not supported, 1 on success and -1 on |
31 | * failure. | |
32 | */ | |
75e2c877 | 33 | int RAND_DRBG_set(RAND_DRBG *drbg, int nid, unsigned int flags) |
12fb8c3d RS |
34 | { |
35 | int ret = 1; | |
36 | ||
75e2c877 RS |
37 | drbg->state = DRBG_UNINITIALISED; |
38 | drbg->flags = flags; | |
39 | drbg->nid = nid; | |
12fb8c3d RS |
40 | |
41 | switch (nid) { | |
42 | default: | |
43 | RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_UNSUPPORTED_DRBG_TYPE); | |
44 | return -2; | |
45 | case 0: | |
46 | /* Uninitialized; that's okay. */ | |
47 | return 1; | |
48 | case NID_aes_128_ctr: | |
49 | case NID_aes_192_ctr: | |
50 | case NID_aes_256_ctr: | |
75e2c877 | 51 | ret = ctr_init(drbg); |
12fb8c3d RS |
52 | break; |
53 | } | |
54 | ||
55 | if (ret < 0) | |
56 | RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_ERROR_INITIALISING_DRBG); | |
57 | return ret; | |
58 | } | |
59 | ||
60 | /* | |
61 | * Allocate memory and initialize a new DRBG. The |parent|, if not | |
75e2c877 | 62 | * NULL, will be used to auto-seed this RAND_DRBG as needed. |
12fb8c3d | 63 | */ |
75e2c877 | 64 | RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent) |
12fb8c3d | 65 | { |
75e2c877 | 66 | RAND_DRBG *drbg = OPENSSL_zalloc(sizeof(*drbg)); |
12fb8c3d | 67 | |
9d951a78 | 68 | if (drbg == NULL) { |
12fb8c3d | 69 | RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE); |
75e2c877 | 70 | goto err; |
12fb8c3d | 71 | } |
75e2c877 | 72 | drbg->size = RANDOMNESS_NEEDED; |
a35f607c | 73 | drbg->fork_count = rand_fork_count; |
75e2c877 RS |
74 | drbg->parent = parent; |
75 | if (RAND_DRBG_set(drbg, type, flags) < 0) | |
76 | goto err; | |
77 | ||
78 | if (parent != NULL) { | |
ae3947de RS |
79 | if (parent->state == DRBG_UNINITIALISED |
80 | && RAND_DRBG_instantiate(parent, NULL, 0) == 0) | |
81 | goto err; | |
75e2c877 RS |
82 | if (!RAND_DRBG_set_callbacks(drbg, drbg_entropy_from_parent, |
83 | drbg_release_entropy, | |
84 | NULL, NULL) | |
85 | /* | |
86 | * Add in our address. Note we are adding the pointer | |
87 | * itself, not its contents! | |
88 | */ | |
89 | || !RAND_DRBG_instantiate(drbg, | |
90 | (unsigned char*)&drbg, sizeof(drbg))) | |
91 | goto err; | |
12fb8c3d | 92 | } |
75e2c877 RS |
93 | |
94 | return drbg; | |
95 | ||
96 | err: | |
75e2c877 RS |
97 | OPENSSL_free(drbg); |
98 | return NULL; | |
12fb8c3d RS |
99 | } |
100 | ||
ae3947de RS |
101 | RAND_DRBG *RAND_DRBG_get0_global(void) |
102 | { | |
103 | return &rand_drbg; | |
104 | } | |
105 | ||
12fb8c3d | 106 | /* |
75e2c877 | 107 | * Uninstantiate |drbg| and free all memory. |
12fb8c3d | 108 | */ |
75e2c877 | 109 | void RAND_DRBG_free(RAND_DRBG *drbg) |
12fb8c3d | 110 | { |
75e2c877 RS |
111 | /* The global DRBG is free'd by rand_cleanup_int() */ |
112 | if (drbg == NULL || drbg == &rand_drbg) | |
12fb8c3d RS |
113 | return; |
114 | ||
75e2c877 | 115 | ctr_uninstantiate(drbg); |
75e2c877 RS |
116 | CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DRBG, drbg, &drbg->ex_data); |
117 | OPENSSL_clear_free(drbg, sizeof(*drbg)); | |
12fb8c3d RS |
118 | } |
119 | ||
120 | /* | |
75e2c877 | 121 | * Instantiate |drbg|, after it has been initialized. Use |pers| and |
12fb8c3d RS |
122 | * |perslen| as prediction-resistance input. |
123 | */ | |
75e2c877 | 124 | int RAND_DRBG_instantiate(RAND_DRBG *drbg, |
12fb8c3d RS |
125 | const unsigned char *pers, size_t perslen) |
126 | { | |
12fb8c3d | 127 | unsigned char *nonce = NULL, *entropy = NULL; |
aa048aef | 128 | size_t noncelen = 0, entropylen = 0; |
12fb8c3d | 129 | |
aa048aef | 130 | if (perslen > drbg->max_perslen) { |
75e2c877 RS |
131 | RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, |
132 | RAND_R_PERSONALISATION_STRING_TOO_LONG); | |
12fb8c3d RS |
133 | goto end; |
134 | } | |
75e2c877 RS |
135 | if (drbg->state != DRBG_UNINITIALISED) { |
136 | RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, | |
137 | drbg->state == DRBG_ERROR ? RAND_R_IN_ERROR_STATE | |
138 | : RAND_R_ALREADY_INSTANTIATED); | |
12fb8c3d RS |
139 | goto end; |
140 | } | |
141 | ||
75e2c877 RS |
142 | drbg->state = DRBG_ERROR; |
143 | if (drbg->get_entropy != NULL) | |
aa048aef DMSP |
144 | entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength, |
145 | drbg->min_entropylen, drbg->max_entropylen); | |
146 | if (entropylen < drbg->min_entropylen || entropylen > drbg->max_entropylen) { | |
75e2c877 | 147 | RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_ENTROPY); |
12fb8c3d RS |
148 | goto end; |
149 | } | |
150 | ||
aa048aef | 151 | if (drbg->max_noncelen > 0 && drbg->get_nonce != NULL) { |
75e2c877 | 152 | noncelen = drbg->get_nonce(drbg, &nonce, drbg->strength / 2, |
aa048aef DMSP |
153 | drbg->min_noncelen, drbg->max_noncelen); |
154 | if (noncelen < drbg->min_noncelen || noncelen > drbg->max_noncelen) { | |
75e2c877 | 155 | RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_NONCE); |
12fb8c3d RS |
156 | goto end; |
157 | } | |
158 | } | |
159 | ||
aa048aef | 160 | if (!ctr_instantiate(drbg, entropy, entropylen, |
12fb8c3d | 161 | nonce, noncelen, pers, perslen)) { |
75e2c877 | 162 | RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_INSTANTIATING_DRBG); |
12fb8c3d RS |
163 | goto end; |
164 | } | |
165 | ||
75e2c877 RS |
166 | drbg->state = DRBG_READY; |
167 | drbg->reseed_counter = 1; | |
12fb8c3d RS |
168 | |
169 | end: | |
75e2c877 RS |
170 | if (entropy != NULL && drbg->cleanup_entropy != NULL) |
171 | drbg->cleanup_entropy(drbg, entropy); | |
172 | if (nonce != NULL && drbg->cleanup_nonce!= NULL ) | |
173 | drbg->cleanup_nonce(drbg, nonce); | |
174 | if (drbg->state == DRBG_READY) | |
12fb8c3d | 175 | return 1; |
12fb8c3d RS |
176 | return 0; |
177 | } | |
178 | ||
179 | /* | |
75e2c877 | 180 | * Uninstantiate |drbg|. Must be instantiated before it can be used. |
12fb8c3d | 181 | */ |
75e2c877 | 182 | int RAND_DRBG_uninstantiate(RAND_DRBG *drbg) |
12fb8c3d | 183 | { |
75e2c877 | 184 | int ret = ctr_uninstantiate(drbg); |
12fb8c3d | 185 | |
75e2c877 RS |
186 | OPENSSL_cleanse(&drbg->ctr, sizeof(drbg->ctr)); |
187 | drbg->state = DRBG_UNINITIALISED; | |
12fb8c3d RS |
188 | return ret; |
189 | } | |
190 | ||
191 | /* | |
75e2c877 | 192 | * Mix in the specified data to reseed |drbg|. |
12fb8c3d | 193 | */ |
75e2c877 | 194 | int RAND_DRBG_reseed(RAND_DRBG *drbg, |
12fb8c3d RS |
195 | const unsigned char *adin, size_t adinlen) |
196 | { | |
197 | unsigned char *entropy = NULL; | |
aa048aef | 198 | size_t entropylen = 0; |
75e2c877 RS |
199 | |
200 | if (drbg->state == DRBG_ERROR) { | |
201 | RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_IN_ERROR_STATE); | |
202 | return 0; | |
203 | } | |
204 | if (drbg->state == DRBG_UNINITIALISED) { | |
205 | RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_NOT_INSTANTIATED); | |
206 | return 0; | |
12fb8c3d RS |
207 | } |
208 | ||
209 | if (adin == NULL) | |
210 | adinlen = 0; | |
aa048aef | 211 | else if (adinlen > drbg->max_adinlen) { |
75e2c877 RS |
212 | RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ADDITIONAL_INPUT_TOO_LONG); |
213 | return 0; | |
12fb8c3d RS |
214 | } |
215 | ||
75e2c877 RS |
216 | drbg->state = DRBG_ERROR; |
217 | if (drbg->get_entropy != NULL) | |
aa048aef DMSP |
218 | entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength, |
219 | drbg->min_entropylen, drbg->max_entropylen); | |
220 | if (entropylen < drbg->min_entropylen || entropylen > drbg->max_entropylen) { | |
75e2c877 | 221 | RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ERROR_RETRIEVING_ENTROPY); |
12fb8c3d RS |
222 | goto end; |
223 | } | |
224 | ||
aa048aef | 225 | if (!ctr_reseed(drbg, entropy, entropylen, adin, adinlen)) |
12fb8c3d | 226 | goto end; |
75e2c877 RS |
227 | drbg->state = DRBG_READY; |
228 | drbg->reseed_counter = 1; | |
12fb8c3d RS |
229 | |
230 | end: | |
75e2c877 RS |
231 | if (entropy != NULL && drbg->cleanup_entropy != NULL) |
232 | drbg->cleanup_entropy(drbg, entropy); | |
233 | if (drbg->state == DRBG_READY) | |
12fb8c3d | 234 | return 1; |
12fb8c3d RS |
235 | return 0; |
236 | } | |
237 | ||
238 | /* | |
239 | * Generate |outlen| bytes into the buffer at |out|. Reseed if we need | |
240 | * to or if |prediction_resistance| is set. Additional input can be | |
241 | * sent in |adin| and |adinlen|. | |
242 | */ | |
75e2c877 | 243 | int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen, |
12fb8c3d RS |
244 | int prediction_resistance, |
245 | const unsigned char *adin, size_t adinlen) | |
246 | { | |
75e2c877 RS |
247 | if (drbg->state == DRBG_ERROR) { |
248 | RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_IN_ERROR_STATE); | |
249 | return 0; | |
12fb8c3d | 250 | } |
75e2c877 RS |
251 | if (drbg->state == DRBG_UNINITIALISED) { |
252 | RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_NOT_INSTANTIATED); | |
12fb8c3d RS |
253 | return 0; |
254 | } | |
75e2c877 RS |
255 | if (outlen > drbg->max_request) { |
256 | RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG); | |
257 | return 0; | |
258 | } | |
aa048aef | 259 | if (adinlen > drbg->max_adinlen) { |
75e2c877 RS |
260 | RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_ADDITIONAL_INPUT_TOO_LONG); |
261 | return 0; | |
12fb8c3d RS |
262 | } |
263 | ||
a35f607c RS |
264 | if (drbg->fork_count != rand_fork_count) { |
265 | drbg->fork_count = rand_fork_count; | |
266 | drbg->state = DRBG_RESEED; | |
267 | } | |
268 | ||
75e2c877 RS |
269 | if (drbg->reseed_counter >= drbg->reseed_interval) |
270 | drbg->state = DRBG_RESEED; | |
12fb8c3d | 271 | |
75e2c877 RS |
272 | if (drbg->state == DRBG_RESEED || prediction_resistance) { |
273 | if (!RAND_DRBG_reseed(drbg, adin, adinlen)) { | |
274 | RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_RESEED_ERROR); | |
275 | return 0; | |
12fb8c3d RS |
276 | } |
277 | adin = NULL; | |
278 | adinlen = 0; | |
279 | } | |
280 | ||
75e2c877 RS |
281 | if (!ctr_generate(drbg, out, outlen, adin, adinlen)) { |
282 | drbg->state = DRBG_ERROR; | |
283 | RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_GENERATE_ERROR); | |
284 | return 0; | |
12fb8c3d | 285 | } |
75e2c877 RS |
286 | |
287 | if (drbg->reseed_counter >= drbg->reseed_interval) | |
288 | drbg->state = DRBG_RESEED; | |
12fb8c3d | 289 | else |
75e2c877 | 290 | drbg->reseed_counter++; |
12fb8c3d | 291 | return 1; |
12fb8c3d RS |
292 | } |
293 | ||
294 | /* | |
75e2c877 RS |
295 | * Set the callbacks for entropy and nonce. We currently don't use |
296 | * the nonce; that's mainly for the KATs | |
12fb8c3d | 297 | */ |
75e2c877 RS |
298 | int RAND_DRBG_set_callbacks(RAND_DRBG *drbg, |
299 | RAND_DRBG_get_entropy_fn cb_get_entropy, | |
300 | RAND_DRBG_cleanup_entropy_fn cb_cleanup_entropy, | |
301 | RAND_DRBG_get_nonce_fn cb_get_nonce, | |
302 | RAND_DRBG_cleanup_nonce_fn cb_cleanup_nonce) | |
12fb8c3d | 303 | { |
75e2c877 | 304 | if (drbg->state != DRBG_UNINITIALISED) |
12fb8c3d | 305 | return 0; |
75e2c877 RS |
306 | drbg->get_entropy = cb_get_entropy; |
307 | drbg->cleanup_entropy = cb_cleanup_entropy; | |
308 | drbg->get_nonce = cb_get_nonce; | |
309 | drbg->cleanup_nonce = cb_cleanup_nonce; | |
12fb8c3d RS |
310 | return 1; |
311 | } | |
312 | ||
313 | /* | |
75e2c877 | 314 | * Set the reseed interval. |
12fb8c3d | 315 | */ |
75e2c877 | 316 | int RAND_DRBG_set_reseed_interval(RAND_DRBG *drbg, int interval) |
12fb8c3d | 317 | { |
4c75ee85 RS |
318 | if (interval < 0 || interval > MAX_RESEED) |
319 | return 0; | |
75e2c877 | 320 | drbg->reseed_interval = interval; |
4c75ee85 | 321 | return 1; |
12fb8c3d RS |
322 | } |
323 | ||
324 | /* | |
325 | * Get and set the EXDATA | |
326 | */ | |
75e2c877 RS |
327 | int RAND_DRBG_set_ex_data(RAND_DRBG *drbg, int idx, void *arg) |
328 | { | |
329 | return CRYPTO_set_ex_data(&drbg->ex_data, idx, arg); | |
330 | } | |
331 | ||
332 | void *RAND_DRBG_get_ex_data(const RAND_DRBG *drbg, int idx) | |
333 | { | |
334 | return CRYPTO_get_ex_data(&drbg->ex_data, idx); | |
335 | } | |
336 | ||
337 | ||
338 | /* | |
339 | * The following functions provide a RAND_METHOD that works on the | |
340 | * global DRBG. They lock. | |
341 | */ | |
342 | ||
343 | static int drbg_bytes(unsigned char *out, int count) | |
344 | { | |
345 | int ret = 0; | |
346 | size_t chunk; | |
347 | ||
348 | CRYPTO_THREAD_write_lock(rand_drbg.lock); | |
349 | if (rand_drbg.state == DRBG_UNINITIALISED | |
350 | && RAND_DRBG_instantiate(&rand_drbg, NULL, 0) == 0) | |
351 | goto err; | |
352 | ||
353 | for ( ; count > 0; count -= chunk, out += chunk) { | |
354 | chunk = count; | |
355 | if (chunk > rand_drbg.max_request) | |
356 | chunk = rand_drbg.max_request; | |
357 | ret = RAND_DRBG_generate(&rand_drbg, out, chunk, 0, NULL, 0); | |
358 | if (!ret) | |
359 | goto err; | |
360 | } | |
361 | ret = 1; | |
362 | ||
363 | err: | |
364 | CRYPTO_THREAD_unlock(rand_drbg.lock); | |
365 | return ret; | |
366 | } | |
367 | ||
75e2c877 RS |
368 | static int drbg_add(const void *buf, int num, double randomness) |
369 | { | |
370 | unsigned char *in = (unsigned char *)buf; | |
371 | unsigned char *out, *end; | |
372 | ||
373 | CRYPTO_THREAD_write_lock(rand_bytes.lock); | |
374 | out = &rand_bytes.buff[rand_bytes.curr]; | |
375 | end = &rand_bytes.buff[rand_bytes.size]; | |
376 | ||
377 | /* Copy whatever fits into the end of the buffer. */ | |
378 | for ( ; --num >= 0 && out < end; rand_bytes.curr++) | |
379 | *out++ = *in++; | |
380 | ||
381 | /* XOR any the leftover. */ | |
382 | while (num > 0) { | |
383 | for (out = rand_bytes.buff; --num >= 0 && out < end; ) | |
384 | *out++ ^= *in++; | |
385 | } | |
386 | ||
387 | CRYPTO_THREAD_unlock(rand_bytes.lock); | |
388 | return 1; | |
389 | } | |
390 | ||
391 | static int drbg_seed(const void *buf, int num) | |
392 | { | |
393 | return drbg_add(buf, num, num); | |
394 | } | |
395 | ||
396 | static int drbg_status(void) | |
12fb8c3d | 397 | { |
75e2c877 RS |
398 | int ret; |
399 | ||
400 | CRYPTO_THREAD_write_lock(rand_drbg.lock); | |
bc5145e3 RS |
401 | if (rand_drbg.state == DRBG_UNINITIALISED) |
402 | RAND_DRBG_instantiate(&rand_drbg, NULL, 0); | |
75e2c877 RS |
403 | ret = rand_drbg.state == DRBG_READY ? 1 : 0; |
404 | CRYPTO_THREAD_unlock(rand_drbg.lock); | |
405 | return ret; | |
12fb8c3d RS |
406 | } |
407 | ||
75e2c877 | 408 | RAND_DRBG rand_drbg; /* The default global DRBG. */ |
ddc6a5c8 | 409 | RAND_DRBG priv_drbg; /* The global private-key DRBG. */ |
75e2c877 RS |
410 | |
411 | RAND_METHOD rand_meth = { | |
412 | drbg_seed, | |
413 | drbg_bytes, | |
ddc6a5c8 | 414 | NULL, |
75e2c877 RS |
415 | drbg_add, |
416 | drbg_bytes, | |
417 | drbg_status | |
418 | }; | |
419 | ||
420 | RAND_METHOD *RAND_OpenSSL(void) | |
12fb8c3d | 421 | { |
75e2c877 | 422 | return &rand_meth; |
12fb8c3d | 423 | } |