]>
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 RS |
66 | RAND_DRBG *drbg = OPENSSL_zalloc(sizeof(*drbg)); |
67 | unsigned char *ucp = OPENSSL_zalloc(RANDOMNESS_NEEDED); | |
12fb8c3d | 68 | |
75e2c877 | 69 | if (drbg == NULL || ucp == NULL) { |
12fb8c3d | 70 | RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE); |
75e2c877 | 71 | goto err; |
12fb8c3d | 72 | } |
75e2c877 RS |
73 | drbg->size = RANDOMNESS_NEEDED; |
74 | drbg->randomness = ucp; | |
75 | ||
76 | drbg->parent = parent; | |
77 | if (RAND_DRBG_set(drbg, type, flags) < 0) | |
78 | goto err; | |
79 | ||
80 | if (parent != NULL) { | |
ae3947de RS |
81 | if (parent->state == DRBG_UNINITIALISED |
82 | && RAND_DRBG_instantiate(parent, NULL, 0) == 0) | |
83 | goto err; | |
75e2c877 RS |
84 | if (!RAND_DRBG_set_callbacks(drbg, drbg_entropy_from_parent, |
85 | drbg_release_entropy, | |
86 | NULL, NULL) | |
87 | /* | |
88 | * Add in our address. Note we are adding the pointer | |
89 | * itself, not its contents! | |
90 | */ | |
91 | || !RAND_DRBG_instantiate(drbg, | |
92 | (unsigned char*)&drbg, sizeof(drbg))) | |
93 | goto err; | |
12fb8c3d | 94 | } |
75e2c877 RS |
95 | |
96 | return drbg; | |
97 | ||
98 | err: | |
99 | OPENSSL_free(ucp); | |
100 | OPENSSL_free(drbg); | |
101 | return NULL; | |
12fb8c3d RS |
102 | } |
103 | ||
ae3947de RS |
104 | RAND_DRBG *RAND_DRBG_get0_global(void) |
105 | { | |
106 | return &rand_drbg; | |
107 | } | |
108 | ||
12fb8c3d | 109 | /* |
75e2c877 | 110 | * Uninstantiate |drbg| and free all memory. |
12fb8c3d | 111 | */ |
75e2c877 | 112 | void RAND_DRBG_free(RAND_DRBG *drbg) |
12fb8c3d | 113 | { |
75e2c877 RS |
114 | /* The global DRBG is free'd by rand_cleanup_int() */ |
115 | if (drbg == NULL || drbg == &rand_drbg) | |
12fb8c3d RS |
116 | return; |
117 | ||
75e2c877 RS |
118 | ctr_uninstantiate(drbg); |
119 | OPENSSL_cleanse(drbg->randomness, drbg->size); | |
120 | OPENSSL_free(drbg->randomness); | |
121 | CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DRBG, drbg, &drbg->ex_data); | |
122 | OPENSSL_clear_free(drbg, sizeof(*drbg)); | |
12fb8c3d RS |
123 | } |
124 | ||
125 | /* | |
75e2c877 | 126 | * Instantiate |drbg|, after it has been initialized. Use |pers| and |
12fb8c3d RS |
127 | * |perslen| as prediction-resistance input. |
128 | */ | |
75e2c877 | 129 | int RAND_DRBG_instantiate(RAND_DRBG *drbg, |
12fb8c3d RS |
130 | const unsigned char *pers, size_t perslen) |
131 | { | |
12fb8c3d | 132 | unsigned char *nonce = NULL, *entropy = NULL; |
75e2c877 | 133 | size_t noncelen = 0, entlen = 0; |
12fb8c3d | 134 | |
75e2c877 RS |
135 | if (perslen > drbg->max_pers) { |
136 | RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, | |
137 | RAND_R_PERSONALISATION_STRING_TOO_LONG); | |
12fb8c3d RS |
138 | goto end; |
139 | } | |
75e2c877 RS |
140 | if (drbg->state != DRBG_UNINITIALISED) { |
141 | RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, | |
142 | drbg->state == DRBG_ERROR ? RAND_R_IN_ERROR_STATE | |
143 | : RAND_R_ALREADY_INSTANTIATED); | |
12fb8c3d RS |
144 | goto end; |
145 | } | |
146 | ||
75e2c877 RS |
147 | drbg->state = DRBG_ERROR; |
148 | if (drbg->get_entropy != NULL) | |
149 | entlen = drbg->get_entropy(drbg, &entropy, drbg->strength, | |
150 | drbg->min_entropy, drbg->max_entropy); | |
151 | if (entlen < drbg->min_entropy || entlen > drbg->max_entropy) { | |
152 | RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_ENTROPY); | |
12fb8c3d RS |
153 | goto end; |
154 | } | |
155 | ||
75e2c877 RS |
156 | if (drbg->max_nonce > 0 && drbg->get_nonce != NULL) { |
157 | noncelen = drbg->get_nonce(drbg, &nonce, drbg->strength / 2, | |
158 | drbg->min_nonce, drbg->max_nonce); | |
159 | if (noncelen < drbg->min_nonce || noncelen > drbg->max_nonce) { | |
160 | RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_NONCE); | |
12fb8c3d RS |
161 | goto end; |
162 | } | |
163 | } | |
164 | ||
75e2c877 | 165 | if (!ctr_instantiate(drbg, entropy, entlen, |
12fb8c3d | 166 | nonce, noncelen, pers, perslen)) { |
75e2c877 | 167 | RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_INSTANTIATING_DRBG); |
12fb8c3d RS |
168 | goto end; |
169 | } | |
170 | ||
75e2c877 RS |
171 | drbg->state = DRBG_READY; |
172 | drbg->reseed_counter = 1; | |
12fb8c3d RS |
173 | |
174 | end: | |
75e2c877 RS |
175 | if (entropy != NULL && drbg->cleanup_entropy != NULL) |
176 | drbg->cleanup_entropy(drbg, entropy); | |
177 | if (nonce != NULL && drbg->cleanup_nonce!= NULL ) | |
178 | drbg->cleanup_nonce(drbg, nonce); | |
179 | if (drbg->state == DRBG_READY) | |
12fb8c3d | 180 | return 1; |
12fb8c3d RS |
181 | return 0; |
182 | } | |
183 | ||
184 | /* | |
75e2c877 | 185 | * Uninstantiate |drbg|. Must be instantiated before it can be used. |
12fb8c3d | 186 | */ |
75e2c877 | 187 | int RAND_DRBG_uninstantiate(RAND_DRBG *drbg) |
12fb8c3d | 188 | { |
75e2c877 | 189 | int ret = ctr_uninstantiate(drbg); |
12fb8c3d | 190 | |
75e2c877 RS |
191 | OPENSSL_cleanse(&drbg->ctr, sizeof(drbg->ctr)); |
192 | drbg->state = DRBG_UNINITIALISED; | |
12fb8c3d RS |
193 | return ret; |
194 | } | |
195 | ||
196 | /* | |
75e2c877 | 197 | * Mix in the specified data to reseed |drbg|. |
12fb8c3d | 198 | */ |
75e2c877 | 199 | int RAND_DRBG_reseed(RAND_DRBG *drbg, |
12fb8c3d RS |
200 | const unsigned char *adin, size_t adinlen) |
201 | { | |
202 | unsigned char *entropy = NULL; | |
203 | size_t entlen = 0; | |
75e2c877 RS |
204 | |
205 | if (drbg->state == DRBG_ERROR) { | |
206 | RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_IN_ERROR_STATE); | |
207 | return 0; | |
208 | } | |
209 | if (drbg->state == DRBG_UNINITIALISED) { | |
210 | RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_NOT_INSTANTIATED); | |
211 | return 0; | |
12fb8c3d RS |
212 | } |
213 | ||
214 | if (adin == NULL) | |
215 | adinlen = 0; | |
75e2c877 RS |
216 | else if (adinlen > drbg->max_adin) { |
217 | RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ADDITIONAL_INPUT_TOO_LONG); | |
218 | return 0; | |
12fb8c3d RS |
219 | } |
220 | ||
75e2c877 RS |
221 | drbg->state = DRBG_ERROR; |
222 | if (drbg->get_entropy != NULL) | |
223 | entlen = drbg->get_entropy(drbg, &entropy, drbg->strength, | |
224 | drbg->min_entropy, drbg->max_entropy); | |
225 | if (entlen < drbg->min_entropy || entlen > drbg->max_entropy) { | |
226 | RANDerr(RAND_F_RAND_DRBG_RESEED, RAND_R_ERROR_RETRIEVING_ENTROPY); | |
12fb8c3d RS |
227 | goto end; |
228 | } | |
229 | ||
75e2c877 | 230 | if (!ctr_reseed(drbg, entropy, entlen, adin, adinlen)) |
12fb8c3d | 231 | goto end; |
75e2c877 RS |
232 | drbg->state = DRBG_READY; |
233 | drbg->reseed_counter = 1; | |
12fb8c3d RS |
234 | |
235 | end: | |
75e2c877 RS |
236 | if (entropy != NULL && drbg->cleanup_entropy != NULL) |
237 | drbg->cleanup_entropy(drbg, entropy); | |
238 | if (drbg->state == DRBG_READY) | |
12fb8c3d | 239 | return 1; |
12fb8c3d RS |
240 | return 0; |
241 | } | |
242 | ||
243 | /* | |
244 | * Generate |outlen| bytes into the buffer at |out|. Reseed if we need | |
245 | * to or if |prediction_resistance| is set. Additional input can be | |
246 | * sent in |adin| and |adinlen|. | |
247 | */ | |
75e2c877 | 248 | int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen, |
12fb8c3d RS |
249 | int prediction_resistance, |
250 | const unsigned char *adin, size_t adinlen) | |
251 | { | |
75e2c877 RS |
252 | if (drbg->state == DRBG_ERROR) { |
253 | RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_IN_ERROR_STATE); | |
254 | return 0; | |
12fb8c3d | 255 | } |
75e2c877 RS |
256 | if (drbg->state == DRBG_UNINITIALISED) { |
257 | RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_NOT_INSTANTIATED); | |
12fb8c3d RS |
258 | return 0; |
259 | } | |
75e2c877 RS |
260 | if (outlen > drbg->max_request) { |
261 | RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG); | |
262 | return 0; | |
263 | } | |
264 | if (adinlen > drbg->max_adin) { | |
265 | RANDerr(RAND_F_RAND_DRBG_GENERATE, RAND_R_ADDITIONAL_INPUT_TOO_LONG); | |
266 | return 0; | |
12fb8c3d RS |
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); | |
401 | ret = rand_drbg.state == DRBG_READY ? 1 : 0; | |
402 | CRYPTO_THREAD_unlock(rand_drbg.lock); | |
403 | return ret; | |
12fb8c3d RS |
404 | } |
405 | ||
75e2c877 | 406 | RAND_DRBG rand_drbg; /* The default global DRBG. */ |
ddc6a5c8 | 407 | RAND_DRBG priv_drbg; /* The global private-key DRBG. */ |
75e2c877 RS |
408 | |
409 | RAND_METHOD rand_meth = { | |
410 | drbg_seed, | |
411 | drbg_bytes, | |
ddc6a5c8 | 412 | NULL, |
75e2c877 RS |
413 | drbg_add, |
414 | drbg_bytes, | |
415 | drbg_status | |
416 | }; | |
417 | ||
418 | RAND_METHOD *RAND_OpenSSL(void) | |
12fb8c3d | 419 | { |
75e2c877 | 420 | return &rand_meth; |
12fb8c3d | 421 | } |