1 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4 /* ====================================================================
5 * Copyright (c) 2011 The OpenSSL Project. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * 3. All advertising materials mentioning features or use of this
20 * software must display the following acknowledgment:
21 * "This product includes software developed by the OpenSSL Project
22 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25 * endorse or promote products derived from this software without
26 * prior written permission. For written permission, please contact
27 * licensing@OpenSSL.org.
29 * 5. Products derived from this software may not be called "OpenSSL"
30 * nor may "OpenSSL" appear in their names without prior written
31 * permission of the OpenSSL Project.
33 * 6. Redistributions of any form whatsoever must retain the following
35 * "This product includes software developed by the OpenSSL Project
36 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
42 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49 * OF THE POSSIBILITY OF SUCH DAMAGE.
50 * ====================================================================
53 #define OPENSSL_FIPSAPI
56 #include <openssl/crypto.h>
57 #include <openssl/err.h>
58 #include <openssl/fips_rand.h>
59 #include "fips_rand_lcl.h"
61 /* Support framework for SP800-90 DRBGs */
63 int FIPS_drbg_init(DRBG_CTX
*dctx
, int type
, unsigned int flags
)
66 memset(dctx
, 0, sizeof(DRBG_CTX
));
67 dctx
->status
= DRBG_STATUS_UNINITIALISED
;
72 dctx
->entropy_blocklen
= 0;
73 dctx
->health_check_cnt
= 0;
74 dctx
->health_check_interval
= DRBG_HEALTH_INTERVAL
;
76 rv
= fips_drbg_hash_init(dctx
);
79 rv
= fips_drbg_ctr_init(dctx
);
81 rv
= fips_drbg_hmac_init(dctx
);
83 rv
= fips_drbg_ec_init(dctx
);
88 FIPSerr(FIPS_F_FIPS_DRBG_INIT
, FIPS_R_UNSUPPORTED_DRBG_TYPE
);
90 FIPSerr(FIPS_F_FIPS_DRBG_INIT
, FIPS_R_ERROR_INITIALISING_DRBG
);
93 /* If not in test mode run selftests on DRBG of the same type */
95 if (!(dctx
->xflags
& DRBG_FLAG_TEST
))
97 if (!FIPS_drbg_health_check(dctx
))
99 FIPSerr(FIPS_F_FIPS_DRBG_INIT
, FIPS_R_SELFTEST_FAILURE
);
107 DRBG_CTX
*FIPS_drbg_new(int type
, unsigned int flags
)
110 dctx
= OPENSSL_malloc(sizeof(DRBG_CTX
));
113 FIPSerr(FIPS_F_FIPS_DRBG_NEW
, ERR_R_MALLOC_FAILURE
);
119 memset(dctx
, 0, sizeof(DRBG_CTX
));
121 dctx
->status
= DRBG_STATUS_UNINITIALISED
;
125 if (FIPS_drbg_init(dctx
, type
, flags
) <= 0)
134 void FIPS_drbg_free(DRBG_CTX
*dctx
)
136 if (dctx
->uninstantiate
)
137 dctx
->uninstantiate(dctx
);
138 OPENSSL_cleanse(&dctx
->d
, sizeof(dctx
->d
));
142 static size_t fips_get_entropy(DRBG_CTX
*dctx
, unsigned char **pout
,
143 int entropy
, size_t min_len
, size_t max_len
)
145 unsigned char *tout
, *p
;
146 size_t bl
= dctx
->entropy_blocklen
, rv
;
147 if (dctx
->xflags
& DRBG_FLAG_TEST
|| !bl
)
148 return dctx
->get_entropy(dctx
, pout
, entropy
, min_len
, max_len
);
149 rv
= dctx
->get_entropy(dctx
, &tout
, entropy
+ bl
,
150 min_len
+ bl
, max_len
+ bl
);
152 if (rv
< (min_len
+ bl
) || (rv
% bl
))
154 /* Compare consecutive blocks for continuous PRNG test */
155 for (p
= tout
; p
< tout
+ rv
- bl
; p
+= bl
)
157 if (!memcmp(p
, p
+ bl
, bl
))
159 FIPSerr(FIPS_F_FIPS_GET_ENTROPY
, FIPS_R_ENTROPY_SOURCE_STUCK
);
169 static void fips_cleanup_entropy(DRBG_CTX
*dctx
,
170 unsigned char *out
, size_t olen
)
173 if (dctx
->xflags
& DRBG_FLAG_TEST
)
176 bl
= dctx
->entropy_blocklen
;
177 /* Call cleanup with original arguments */
178 dctx
->cleanup_entropy(dctx
, out
- bl
, olen
+ bl
);
182 int FIPS_drbg_instantiate(DRBG_CTX
*dctx
,
183 const unsigned char *pers
, size_t perslen
)
185 size_t entlen
= 0, noncelen
= 0;
186 unsigned char *nonce
= NULL
, *entropy
= NULL
;
189 /* Put here so error script picks them up */
190 FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE
,
191 FIPS_R_PERSONALISATION_STRING_TOO_LONG
);
192 FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE
, FIPS_R_IN_ERROR_STATE
);
193 FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE
, FIPS_R_ALREADY_INSTANTIATED
);
194 FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE
, FIPS_R_ERROR_RETRIEVING_ENTROPY
);
195 FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE
, FIPS_R_ERROR_RETRIEVING_NONCE
);
196 FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE
, FIPS_R_INSTANTIATE_ERROR
);
201 if (perslen
> dctx
->max_pers
)
203 r
= FIPS_R_PERSONALISATION_STRING_TOO_LONG
;
207 if (dctx
->status
!= DRBG_STATUS_UNINITIALISED
)
209 if (dctx
->status
== DRBG_STATUS_ERROR
)
210 r
= FIPS_R_IN_ERROR_STATE
;
212 r
= FIPS_R_ALREADY_INSTANTIATED
;
216 dctx
->status
= DRBG_STATUS_ERROR
;
218 entlen
= fips_get_entropy(dctx
, &entropy
, dctx
->strength
,
219 dctx
->min_entropy
, dctx
->max_entropy
);
221 if (entlen
< dctx
->min_entropy
|| entlen
> dctx
->max_entropy
)
223 r
= FIPS_R_ERROR_RETRIEVING_ENTROPY
;
227 if (dctx
->max_nonce
> 0)
229 noncelen
= dctx
->get_nonce(dctx
, &nonce
,
231 dctx
->min_nonce
, dctx
->max_nonce
);
233 if (noncelen
< dctx
->min_nonce
|| noncelen
> dctx
->max_nonce
)
235 r
= FIPS_R_ERROR_RETRIEVING_NONCE
;
241 if (!dctx
->instantiate(dctx
,
246 r
= FIPS_R_ERROR_INSTANTIATING_DRBG
;
251 dctx
->status
= DRBG_STATUS_READY
;
252 if (!(dctx
->iflags
& DRBG_CUSTOM_RESEED
))
253 dctx
->reseed_counter
= 1;
257 if (entropy
&& dctx
->cleanup_entropy
)
258 fips_cleanup_entropy(dctx
, entropy
, entlen
);
260 if (nonce
&& dctx
->cleanup_nonce
)
261 dctx
->cleanup_nonce(dctx
, nonce
, noncelen
);
263 if (dctx
->status
== DRBG_STATUS_READY
)
266 if (r
&& !(dctx
->iflags
& DRBG_FLAG_NOERR
))
267 FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE
, r
);
273 static int drbg_reseed(DRBG_CTX
*dctx
,
274 const unsigned char *adin
, size_t adinlen
, int hcheck
)
276 unsigned char *entropy
= NULL
;
281 FIPSerr(FIPS_F_FIPS_DRBG_RESEED
, FIPS_R_NOT_INSTANTIATED
);
282 FIPSerr(FIPS_F_FIPS_DRBG_RESEED
, FIPS_R_ADDITIONAL_INPUT_TOO_LONG
);
284 if (dctx
->status
!= DRBG_STATUS_READY
285 && dctx
->status
!= DRBG_STATUS_RESEED
)
287 if (dctx
->status
== DRBG_STATUS_ERROR
)
288 r
= FIPS_R_IN_ERROR_STATE
;
289 else if(dctx
->status
== DRBG_STATUS_UNINITIALISED
)
290 r
= FIPS_R_NOT_INSTANTIATED
;
296 else if (adinlen
> dctx
->max_adin
)
298 r
= FIPS_R_ADDITIONAL_INPUT_TOO_LONG
;
302 dctx
->status
= DRBG_STATUS_ERROR
;
303 /* Peform health check on all reseed operations if not a prediction
304 * resistance request and not in test mode.
306 if (hcheck
&& !(dctx
->xflags
& DRBG_FLAG_TEST
))
308 if (!FIPS_drbg_health_check(dctx
))
310 r
= FIPS_R_SELFTEST_FAILURE
;
315 entlen
= fips_get_entropy(dctx
, &entropy
, dctx
->strength
,
316 dctx
->min_entropy
, dctx
->max_entropy
);
318 if (entlen
< dctx
->min_entropy
|| entlen
> dctx
->max_entropy
)
320 r
= FIPS_R_ERROR_RETRIEVING_ENTROPY
;
324 if (!dctx
->reseed(dctx
, entropy
, entlen
, adin
, adinlen
))
327 dctx
->status
= DRBG_STATUS_READY
;
328 if (!(dctx
->iflags
& DRBG_CUSTOM_RESEED
))
329 dctx
->reseed_counter
= 1;
332 if (entropy
&& dctx
->cleanup_entropy
)
333 fips_cleanup_entropy(dctx
, entropy
, entlen
);
335 if (dctx
->status
== DRBG_STATUS_READY
)
338 if (r
&& !(dctx
->iflags
& DRBG_FLAG_NOERR
))
339 FIPSerr(FIPS_F_FIPS_DRBG_RESEED
, r
);
344 int FIPS_drbg_reseed(DRBG_CTX
*dctx
,
345 const unsigned char *adin
, size_t adinlen
)
347 return drbg_reseed(dctx
, adin
, adinlen
, 1);
350 static int fips_drbg_check(DRBG_CTX
*dctx
)
352 if (dctx
->xflags
& DRBG_FLAG_TEST
)
354 dctx
->health_check_cnt
++;
355 if (dctx
->health_check_cnt
>= dctx
->health_check_interval
)
357 if (!FIPS_drbg_health_check(dctx
))
359 FIPSerr(FIPS_F_FIPS_DRBG_CHECK
, FIPS_R_SELFTEST_FAILURE
);
366 int FIPS_drbg_generate(DRBG_CTX
*dctx
, unsigned char *out
, size_t outlen
,
367 int prediction_resistance
,
368 const unsigned char *adin
, size_t adinlen
)
372 if (!fips_drbg_check(dctx
))
375 if (dctx
->status
!= DRBG_STATUS_READY
376 && dctx
->status
!= DRBG_STATUS_RESEED
)
378 if (dctx
->status
== DRBG_STATUS_ERROR
)
379 r
= FIPS_R_IN_ERROR_STATE
;
380 else if(dctx
->status
== DRBG_STATUS_UNINITIALISED
)
381 r
= FIPS_R_NOT_INSTANTIATED
;
385 if (outlen
> dctx
->max_request
)
387 r
= FIPS_R_REQUEST_TOO_LARGE_FOR_DRBG
;
391 if (adinlen
> dctx
->max_adin
)
393 r
= FIPS_R_ADDITIONAL_INPUT_TOO_LONG
;
397 if (dctx
->iflags
& DRBG_CUSTOM_RESEED
)
398 dctx
->generate(dctx
, NULL
, outlen
, NULL
, 0);
399 else if (dctx
->reseed_counter
>= dctx
->reseed_interval
)
400 dctx
->status
= DRBG_STATUS_RESEED
;
402 if (dctx
->status
== DRBG_STATUS_RESEED
|| prediction_resistance
)
404 /* If prediction resistance request don't do health check */
405 int hcheck
= prediction_resistance
? 0 : 1;
407 if (!drbg_reseed(dctx
, adin
, adinlen
, hcheck
))
409 r
= FIPS_R_RESEED_ERROR
;
416 if (!dctx
->generate(dctx
, out
, outlen
, adin
, adinlen
))
418 r
= FIPS_R_GENERATE_ERROR
;
419 dctx
->status
= DRBG_STATUS_ERROR
;
422 if (!(dctx
->iflags
& DRBG_CUSTOM_RESEED
))
424 if (dctx
->reseed_counter
>= dctx
->reseed_interval
)
425 dctx
->status
= DRBG_STATUS_RESEED
;
427 dctx
->reseed_counter
++;
433 if (!(dctx
->iflags
& DRBG_FLAG_NOERR
))
434 FIPSerr(FIPS_F_FIPS_DRBG_GENERATE
, r
);
441 int FIPS_drbg_uninstantiate(DRBG_CTX
*dctx
)
444 if (!dctx
->uninstantiate
)
447 rv
= dctx
->uninstantiate(dctx
);
448 /* Although we'd like to cleanse here we can't because we have to
449 * test the uninstantiate really zeroes the data.
451 memset(&dctx
->d
, 0, sizeof(dctx
->d
));
452 dctx
->status
= DRBG_STATUS_UNINITIALISED
;
453 /* If method has problems uninstantiating, return error */
457 int FIPS_drbg_set_callbacks(DRBG_CTX
*dctx
,
458 size_t (*get_entropy
)(DRBG_CTX
*ctx
, unsigned char **pout
,
459 int entropy
, size_t min_len
, size_t max_len
),
460 void (*cleanup_entropy
)(DRBG_CTX
*ctx
, unsigned char *out
, size_t olen
),
461 size_t entropy_blocklen
,
462 size_t (*get_nonce
)(DRBG_CTX
*ctx
, unsigned char **pout
,
463 int entropy
, size_t min_len
, size_t max_len
),
464 void (*cleanup_nonce
)(DRBG_CTX
*ctx
, unsigned char *out
, size_t olen
))
466 if (dctx
->status
!= DRBG_STATUS_UNINITIALISED
)
468 dctx
->entropy_blocklen
= entropy_blocklen
;
469 dctx
->get_entropy
= get_entropy
;
470 dctx
->cleanup_entropy
= cleanup_entropy
;
471 dctx
->get_nonce
= get_nonce
;
472 dctx
->cleanup_nonce
= cleanup_nonce
;
476 int FIPS_drbg_set_rand_callbacks(DRBG_CTX
*dctx
,
477 size_t (*get_adin
)(DRBG_CTX
*ctx
, unsigned char **pout
),
478 void (*cleanup_adin
)(DRBG_CTX
*ctx
, unsigned char *out
, size_t olen
),
479 int (*rand_seed_cb
)(DRBG_CTX
*ctx
, const void *buf
, int num
),
480 int (*rand_add_cb
)(DRBG_CTX
*ctx
,
481 const void *buf
, int num
, double entropy
))
483 if (dctx
->status
!= DRBG_STATUS_UNINITIALISED
)
485 dctx
->get_adin
= get_adin
;
486 dctx
->cleanup_adin
= cleanup_adin
;
487 dctx
->rand_seed_cb
= rand_seed_cb
;
488 dctx
->rand_add_cb
= rand_add_cb
;
492 void *FIPS_drbg_get_app_data(DRBG_CTX
*dctx
)
494 return dctx
->app_data
;
497 void FIPS_drbg_set_app_data(DRBG_CTX
*dctx
, void *app_data
)
499 dctx
->app_data
= app_data
;
502 size_t FIPS_drbg_get_blocklength(DRBG_CTX
*dctx
)
504 return dctx
->blocklength
;
507 int FIPS_drbg_get_strength(DRBG_CTX
*dctx
)
509 return dctx
->strength
;
512 void FIPS_drbg_set_check_interval(DRBG_CTX
*dctx
, int interval
)
514 dctx
->health_check_interval
= interval
;
517 void FIPS_drbg_set_reseed_interval(DRBG_CTX
*dctx
, int interval
)
519 dctx
->reseed_interval
= interval
;
522 static int drbg_stick
= 0;
524 void FIPS_drbg_stick(void)
529 /* Continuous DRBG utility function */
530 int fips_drbg_cprng_test(DRBG_CTX
*dctx
, const unsigned char *out
)
532 /* No CPRNG in test mode */
533 if (dctx
->xflags
& DRBG_FLAG_TEST
)
535 /* Check block is valid: should never happen */
536 if (dctx
->lb_valid
== 0)
538 FIPSerr(FIPS_F_FIPS_DRBG_CPRNG_TEST
, FIPS_R_INTERNAL_ERROR
);
539 fips_set_selftest_fail();
543 memcpy(dctx
->lb
, out
, dctx
->blocklength
);
544 /* Check against last block: fail if match */
545 if (!memcmp(dctx
->lb
, out
, dctx
->blocklength
))
547 FIPSerr(FIPS_F_FIPS_DRBG_CPRNG_TEST
, FIPS_R_DRBG_STUCK
);
548 fips_set_selftest_fail();
551 /* Save last block for next comparison */
552 memcpy(dctx
->lb
, out
, dctx
->blocklength
);