ee162d05eb0281d42548ec0365262ae79631943b
[openssl.git] / fips / rand / fips_drbg_lib.c
1 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
2  * project.
3  */
4 /* ====================================================================
5  * Copyright (c) 2011 The OpenSSL Project.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer. 
13  *
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
17  *    distribution.
18  *
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/)"
23  *
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.
28  *
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.
32  *
33  * 6. Redistributions of any form whatsoever must retain the following
34  *    acknowledgment:
35  *    "This product includes software developed by the OpenSSL Project
36  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
37  *
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  * ====================================================================
51  */
52
53 #define OPENSSL_FIPSAPI
54
55 #include <string.h>
56 #include <openssl/crypto.h>
57 #include <openssl/err.h>
58 #include <openssl/fips_rand.h>
59 #include "fips_rand_lcl.h"
60
61 /* Support framework for SP800-90 DRBGs */
62
63 int FIPS_drbg_init(DRBG_CTX *dctx, int type, unsigned int flags)
64         {
65         int rv;
66         memset(dctx, 0, sizeof(DRBG_CTX));
67         dctx->status = DRBG_STATUS_UNINITIALISED;
68         dctx->xflags = flags;
69         dctx->type = type;
70
71         dctx->iflags = 0;
72         dctx->entropy_blocklen = 0;
73         dctx->health_check_cnt = 0;
74         dctx->health_check_interval = DRBG_HEALTH_INTERVAL;
75
76         rv = fips_drbg_hash_init(dctx);
77
78         if (rv == -2)
79                 rv = fips_drbg_ctr_init(dctx);
80         if (rv == -2)
81                 rv = fips_drbg_hmac_init(dctx);
82         if (rv == -2)
83                 rv = fips_drbg_ec_init(dctx);
84
85         if (rv <= 0)
86                 {
87                 if (rv == -2)
88                         FIPSerr(FIPS_F_FIPS_DRBG_INIT, FIPS_R_UNSUPPORTED_DRBG_TYPE);
89                 else
90                         FIPSerr(FIPS_F_FIPS_DRBG_INIT, FIPS_R_ERROR_INITIALISING_DRBG);
91                 }
92
93         /* If not in test mode run selftests on DRBG of the same type */
94
95         if (!(dctx->xflags & DRBG_FLAG_TEST))
96                 {
97                 if (!FIPS_drbg_health_check(dctx))
98                         {
99                         FIPSerr(FIPS_F_FIPS_DRBG_INIT, FIPS_R_SELFTEST_FAILURE);
100                         return 0;
101                         }
102                 }
103
104         return rv;
105         }
106
107 DRBG_CTX *FIPS_drbg_new(int type, unsigned int flags)
108         {
109         DRBG_CTX *dctx;
110         dctx = OPENSSL_malloc(sizeof(DRBG_CTX));
111         if (!dctx)
112                 {
113                 FIPSerr(FIPS_F_FIPS_DRBG_NEW, ERR_R_MALLOC_FAILURE);
114                 return NULL;
115                 }
116
117         if (type == 0)
118                 {
119                 memset(dctx, 0, sizeof(DRBG_CTX));
120                 dctx->type = 0;
121                 dctx->status = DRBG_STATUS_UNINITIALISED;
122                 return dctx;
123                 }
124
125         if (FIPS_drbg_init(dctx, type, flags) <= 0)
126                 {
127                 OPENSSL_free(dctx);
128                 return NULL;
129                 }
130                 
131         return dctx;
132         }
133
134 void FIPS_drbg_free(DRBG_CTX *dctx)
135         {
136         if (dctx->uninstantiate)
137                 dctx->uninstantiate(dctx);
138         /* Don't free up default DRBG */
139         if (dctx == FIPS_get_default_drbg())
140                 {
141                 memset(dctx, 0, sizeof(DRBG_CTX));
142                 dctx->type = 0;
143                 dctx->status = DRBG_STATUS_UNINITIALISED;
144                 }
145         else
146                 {
147                 OPENSSL_cleanse(&dctx->d, sizeof(dctx->d));
148                 OPENSSL_free(dctx);
149                 }
150         }
151
152 static size_t fips_get_entropy(DRBG_CTX *dctx, unsigned char **pout,
153                                 int entropy, size_t min_len, size_t max_len)
154         {
155         unsigned char *tout, *p;
156         size_t bl = dctx->entropy_blocklen, rv;
157         if (!dctx->get_entropy)
158                 return 0;
159         if (dctx->xflags & DRBG_FLAG_TEST || !bl)
160                 return dctx->get_entropy(dctx, pout, entropy, min_len, max_len);
161         rv = dctx->get_entropy(dctx, &tout, entropy + bl,
162                                 min_len + bl, max_len + bl);
163         *pout = tout + bl;
164         if (rv < (min_len + bl) || (rv % bl))
165                 return 0;
166         /* Compare consecutive blocks for continuous PRNG test */
167         for (p = tout; p < tout + rv - bl; p += bl)
168                 {
169                 if (!memcmp(p, p + bl, bl))
170                         {
171                         FIPSerr(FIPS_F_FIPS_GET_ENTROPY, FIPS_R_ENTROPY_SOURCE_STUCK);
172                         return 0;
173                         }
174                 }
175         rv -= bl;
176         if (rv > max_len)
177                 return max_len;
178         return rv;
179         }
180
181 static void fips_cleanup_entropy(DRBG_CTX *dctx,
182                                         unsigned char *out, size_t olen)
183         {
184         size_t bl;
185         if (dctx->xflags & DRBG_FLAG_TEST)
186                 bl = 0;
187         else
188                 bl = dctx->entropy_blocklen;
189         /* Call cleanup with original arguments */
190         dctx->cleanup_entropy(dctx, out - bl, olen + bl);
191         }
192
193
194 int FIPS_drbg_instantiate(DRBG_CTX *dctx,
195                                 const unsigned char *pers, size_t perslen)
196         {
197         size_t entlen = 0, noncelen = 0;
198         unsigned char *nonce = NULL, *entropy = NULL;
199
200 #if 0
201         /* Put here so error script picks them up */
202         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE,
203                                 FIPS_R_PERSONALISATION_STRING_TOO_LONG);
204         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, FIPS_R_IN_ERROR_STATE);
205         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, FIPS_R_ALREADY_INSTANTIATED);
206         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, FIPS_R_ERROR_RETRIEVING_ENTROPY);
207         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, FIPS_R_ERROR_RETRIEVING_NONCE);
208         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, FIPS_R_INSTANTIATE_ERROR);
209         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, FIPS_R_DRBG_NOT_INITIALISED);
210 #endif
211
212         int r = 0;
213
214         if (perslen > dctx->max_pers)
215                 {
216                 r = FIPS_R_PERSONALISATION_STRING_TOO_LONG;
217                 goto end;
218                 }
219
220         if (!dctx->instantiate)
221                 {
222                 r = FIPS_R_DRBG_NOT_INITIALISED;
223                 goto end;
224                 }
225
226         if (dctx->status != DRBG_STATUS_UNINITIALISED)
227                 {
228                 if (dctx->status == DRBG_STATUS_ERROR)
229                         r = FIPS_R_IN_ERROR_STATE;
230                 else
231                         r = FIPS_R_ALREADY_INSTANTIATED;
232                 goto end;
233                 }
234
235         dctx->status = DRBG_STATUS_ERROR;
236
237         entlen = fips_get_entropy(dctx, &entropy, dctx->strength,
238                                 dctx->min_entropy, dctx->max_entropy);
239
240         if (entlen < dctx->min_entropy || entlen > dctx->max_entropy)
241                 {
242                 r = FIPS_R_ERROR_RETRIEVING_ENTROPY;
243                 goto end;
244                 }
245
246         if (dctx->max_nonce > 0 && dctx->get_nonce)
247                 {
248                 noncelen = dctx->get_nonce(dctx, &nonce,
249                                         dctx->strength / 2,
250                                         dctx->min_nonce, dctx->max_nonce);
251
252                 if (noncelen < dctx->min_nonce || noncelen > dctx->max_nonce)
253                         {
254                         r = FIPS_R_ERROR_RETRIEVING_NONCE;
255                         goto end;
256                         }
257
258                 }
259
260         if (!dctx->instantiate(dctx, 
261                                 entropy, entlen,
262                                 nonce, noncelen,
263                                 pers, perslen))
264                 {
265                 r = FIPS_R_ERROR_INSTANTIATING_DRBG;
266                 goto end;
267                 }
268
269
270         dctx->status = DRBG_STATUS_READY;
271         if (!(dctx->iflags & DRBG_CUSTOM_RESEED))
272                 dctx->reseed_counter = 1;
273
274         end:
275
276         if (entropy && dctx->cleanup_entropy)
277                 fips_cleanup_entropy(dctx, entropy, entlen);
278
279         if (nonce && dctx->cleanup_nonce)
280                 dctx->cleanup_nonce(dctx, nonce, noncelen);
281
282         if (dctx->status == DRBG_STATUS_READY)
283                 return 1;
284
285         if (r && !(dctx->iflags & DRBG_FLAG_NOERR))
286                 FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, r);
287
288         return 0;
289
290         }
291
292 static int drbg_reseed(DRBG_CTX *dctx,
293                         const unsigned char *adin, size_t adinlen, int hcheck)
294         {
295         unsigned char *entropy = NULL;
296         size_t entlen = 0;
297         int r = 0;
298
299 #if 0
300         FIPSerr(FIPS_F_DRBG_RESEED, FIPS_R_NOT_INSTANTIATED);
301         FIPSerr(FIPS_F_DRBG_RESEED, FIPS_R_ADDITIONAL_INPUT_TOO_LONG);
302 #endif
303         if (dctx->status != DRBG_STATUS_READY
304                 && dctx->status != DRBG_STATUS_RESEED)
305                 {
306                 if (dctx->status == DRBG_STATUS_ERROR)
307                         r = FIPS_R_IN_ERROR_STATE;
308                 else if(dctx->status == DRBG_STATUS_UNINITIALISED)
309                         r = FIPS_R_NOT_INSTANTIATED;
310                 goto end;
311                 }
312
313         if (!adin)
314                 adinlen = 0;
315         else if (adinlen > dctx->max_adin)
316                 {
317                 r = FIPS_R_ADDITIONAL_INPUT_TOO_LONG;
318                 goto end;
319                 }
320
321         dctx->status = DRBG_STATUS_ERROR;
322         /* Peform health check on all reseed operations if not a prediction
323          * resistance request and not in test mode.
324          */
325         if (hcheck && !(dctx->xflags & DRBG_FLAG_TEST))
326                 {
327                 if (!FIPS_drbg_health_check(dctx))
328                         {
329                         r = FIPS_R_SELFTEST_FAILURE;
330                         goto end;
331                         }
332                 }
333
334         entlen = fips_get_entropy(dctx, &entropy, dctx->strength,
335                                 dctx->min_entropy, dctx->max_entropy);
336
337         if (entlen < dctx->min_entropy || entlen > dctx->max_entropy)
338                 {
339                 r = FIPS_R_ERROR_RETRIEVING_ENTROPY;
340                 goto end;
341                 }
342
343         if (!dctx->reseed(dctx, entropy, entlen, adin, adinlen))
344                 goto end;
345
346         dctx->status = DRBG_STATUS_READY;
347         if (!(dctx->iflags & DRBG_CUSTOM_RESEED))
348                 dctx->reseed_counter = 1;
349         end:
350
351         if (entropy && dctx->cleanup_entropy)
352                 fips_cleanup_entropy(dctx, entropy, entlen);
353
354         if (dctx->status == DRBG_STATUS_READY)
355                 return 1;
356
357         if (r && !(dctx->iflags & DRBG_FLAG_NOERR))
358                 FIPSerr(FIPS_F_DRBG_RESEED, r);
359
360         return 0;
361         }
362
363 int FIPS_drbg_reseed(DRBG_CTX *dctx,
364                         const unsigned char *adin, size_t adinlen)
365         {
366         return drbg_reseed(dctx, adin, adinlen, 1);
367         }
368
369 static int fips_drbg_check(DRBG_CTX *dctx)
370         {
371         if (dctx->xflags & DRBG_FLAG_TEST)
372                 return 1;
373         dctx->health_check_cnt++;
374         if (dctx->health_check_cnt >= dctx->health_check_interval)
375                 {
376                 if (!FIPS_drbg_health_check(dctx))
377                         {
378                         FIPSerr(FIPS_F_FIPS_DRBG_CHECK, FIPS_R_SELFTEST_FAILURE);
379                         return 0;
380                         }
381                 }
382         return 1;
383         }
384
385 int FIPS_drbg_generate(DRBG_CTX *dctx, unsigned char *out, size_t outlen,
386                         int prediction_resistance,
387                         const unsigned char *adin, size_t adinlen)
388         {
389         int r = 0;
390
391         if (FIPS_selftest_failed())
392                 {
393                 FIPSerr(FIPS_F_FIPS_DRBG_GENERATE, FIPS_R_SELFTEST_FAILED);
394                 return 0;
395                 }
396
397         if (!fips_drbg_check(dctx))
398                 return 0;
399
400         if (dctx->status != DRBG_STATUS_READY
401                 && dctx->status != DRBG_STATUS_RESEED)
402                 {
403                 if (dctx->status == DRBG_STATUS_ERROR)
404                         r = FIPS_R_IN_ERROR_STATE;
405                 else if(dctx->status == DRBG_STATUS_UNINITIALISED)
406                         r = FIPS_R_NOT_INSTANTIATED;
407                 goto end;
408                 }
409
410         if (outlen > dctx->max_request)
411                 {
412                 r = FIPS_R_REQUEST_TOO_LARGE_FOR_DRBG;
413                 return 0;
414                 }
415
416         if (adinlen > dctx->max_adin)
417                 {
418                 r = FIPS_R_ADDITIONAL_INPUT_TOO_LONG;
419                 goto end;
420                 }
421
422         if (dctx->iflags & DRBG_CUSTOM_RESEED)
423                 dctx->generate(dctx, NULL, outlen, NULL, 0);
424         else if (dctx->reseed_counter >= dctx->reseed_interval)
425                 dctx->status = DRBG_STATUS_RESEED;
426
427         if (dctx->status == DRBG_STATUS_RESEED || prediction_resistance)
428                 {
429                 /* If prediction resistance request don't do health check */
430                 int hcheck = prediction_resistance ? 0 : 1;
431                 
432                 if (!drbg_reseed(dctx, adin, adinlen, hcheck))
433                         {
434                         r = FIPS_R_RESEED_ERROR;
435                         goto end;
436                         }
437                 adin = NULL;
438                 adinlen = 0;
439                 }
440
441         if (!dctx->generate(dctx, out, outlen, adin, adinlen))
442                 {
443                 r = FIPS_R_GENERATE_ERROR;
444                 dctx->status = DRBG_STATUS_ERROR;
445                 goto end;
446                 }
447         if (!(dctx->iflags & DRBG_CUSTOM_RESEED))
448                 {
449                 if (dctx->reseed_counter >= dctx->reseed_interval)
450                         dctx->status = DRBG_STATUS_RESEED;
451                 else
452                         dctx->reseed_counter++;
453                 }
454
455         end:
456         if (r)
457                 {
458                 if (!(dctx->iflags & DRBG_FLAG_NOERR))
459                         FIPSerr(FIPS_F_FIPS_DRBG_GENERATE, r);
460                 return 0;
461                 }
462
463         return 1;
464         }
465
466 int FIPS_drbg_uninstantiate(DRBG_CTX *dctx)
467         {
468         int rv;
469         if (!dctx->uninstantiate)
470                 rv = 1;
471         else
472                 rv = dctx->uninstantiate(dctx);
473         /* Although we'd like to cleanse here we can't because we have to
474          * test the uninstantiate really zeroes the data.
475          */
476         memset(&dctx->d, 0, sizeof(dctx->d));
477         dctx->status = DRBG_STATUS_UNINITIALISED;
478         /* If method has problems uninstantiating, return error */
479         return rv;
480         }
481
482 int FIPS_drbg_set_callbacks(DRBG_CTX *dctx,
483         size_t (*get_entropy)(DRBG_CTX *ctx, unsigned char **pout,
484                                 int entropy, size_t min_len, size_t max_len),
485         void (*cleanup_entropy)(DRBG_CTX *ctx, unsigned char *out, size_t olen),
486         size_t entropy_blocklen,
487         size_t (*get_nonce)(DRBG_CTX *ctx, unsigned char **pout,
488                                 int entropy, size_t min_len, size_t max_len),
489         void (*cleanup_nonce)(DRBG_CTX *ctx, unsigned char *out, size_t olen))
490         {
491         if (dctx->status != DRBG_STATUS_UNINITIALISED)
492                 return 0;
493         dctx->entropy_blocklen = entropy_blocklen;
494         dctx->get_entropy = get_entropy;
495         dctx->cleanup_entropy = cleanup_entropy;
496         dctx->get_nonce = get_nonce;
497         dctx->cleanup_nonce = cleanup_nonce;
498         return 1;
499         }
500
501 int FIPS_drbg_set_rand_callbacks(DRBG_CTX *dctx,
502         size_t (*get_adin)(DRBG_CTX *ctx, unsigned char **pout),
503         void (*cleanup_adin)(DRBG_CTX *ctx, unsigned char *out, size_t olen),
504         int (*rand_seed_cb)(DRBG_CTX *ctx, const void *buf, int num),
505         int (*rand_add_cb)(DRBG_CTX *ctx,
506                                 const void *buf, int num, double entropy))
507         {
508         if (dctx->status != DRBG_STATUS_UNINITIALISED)
509                 return 0;
510         dctx->get_adin = get_adin;
511         dctx->cleanup_adin = cleanup_adin;
512         dctx->rand_seed_cb = rand_seed_cb;
513         dctx->rand_add_cb = rand_add_cb;
514         return 1;
515         }
516
517 void *FIPS_drbg_get_app_data(DRBG_CTX *dctx)
518         {
519         return dctx->app_data;
520         }
521
522 void FIPS_drbg_set_app_data(DRBG_CTX *dctx, void *app_data)
523         {
524         dctx->app_data = app_data;
525         }
526
527 size_t FIPS_drbg_get_blocklength(DRBG_CTX *dctx)
528         {
529         return dctx->blocklength;
530         }
531
532 int FIPS_drbg_get_strength(DRBG_CTX *dctx)
533         {
534         return dctx->strength;
535         }
536
537 void FIPS_drbg_set_check_interval(DRBG_CTX *dctx, int interval)
538         {
539         dctx->health_check_interval = interval;
540         }
541
542 void FIPS_drbg_set_reseed_interval(DRBG_CTX *dctx, int interval)
543         {
544         dctx->reseed_interval = interval;
545         }
546
547 static int drbg_stick = 0;
548
549 void FIPS_drbg_stick(int onoff)
550         {
551         drbg_stick = onoff;
552         }
553
554 /* Continuous DRBG utility function */
555 int fips_drbg_cprng_test(DRBG_CTX *dctx, const unsigned char *out)
556         {
557         /* No CPRNG in test mode */
558         if (dctx->xflags & DRBG_FLAG_TEST)
559                 return 1;
560         /* Check block is valid: should never happen */
561         if (dctx->lb_valid == 0)
562                 {
563                 FIPSerr(FIPS_F_FIPS_DRBG_CPRNG_TEST, FIPS_R_INTERNAL_ERROR);
564                 fips_set_selftest_fail();
565                 return 0;
566                 }
567         if (drbg_stick)
568                 memcpy(dctx->lb, out, dctx->blocklength);
569         /* Check against last block: fail if match */
570         if (!memcmp(dctx->lb, out, dctx->blocklength))
571                 {
572                 FIPSerr(FIPS_F_FIPS_DRBG_CPRNG_TEST, FIPS_R_DRBG_STUCK);
573                 fips_set_selftest_fail();
574                 return 0;
575                 }
576         /* Save last block for next comparison */
577         memcpy(dctx->lb, out, dctx->blocklength);
578         return 1;
579         }