32e4b83c5e9f7cdcb83fbc44436b3412dd7e0633
[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->xflags & DRBG_FLAG_TEST || !bl)
158                 return dctx->get_entropy(dctx, pout, entropy, min_len, max_len);
159         rv = dctx->get_entropy(dctx, &tout, entropy + bl,
160                                 min_len + bl, max_len + bl);
161         *pout = tout + bl;
162         if (rv < (min_len + bl) || (rv % bl))
163                 return 0;
164         /* Compare consecutive blocks for continuous PRNG test */
165         for (p = tout; p < tout + rv - bl; p += bl)
166                 {
167                 if (!memcmp(p, p + bl, bl))
168                         {
169                         FIPSerr(FIPS_F_FIPS_GET_ENTROPY, FIPS_R_ENTROPY_SOURCE_STUCK);
170                         return 0;
171                         }
172                 }
173         rv -= bl;
174         if (rv > max_len)
175                 return max_len;
176         return rv;
177         }
178
179 static void fips_cleanup_entropy(DRBG_CTX *dctx,
180                                         unsigned char *out, size_t olen)
181         {
182         size_t bl;
183         if (dctx->xflags & DRBG_FLAG_TEST)
184                 bl = 0;
185         else
186                 bl = dctx->entropy_blocklen;
187         /* Call cleanup with original arguments */
188         dctx->cleanup_entropy(dctx, out - bl, olen + bl);
189         }
190
191
192 int FIPS_drbg_instantiate(DRBG_CTX *dctx,
193                                 const unsigned char *pers, size_t perslen)
194         {
195         size_t entlen = 0, noncelen = 0;
196         unsigned char *nonce = NULL, *entropy = NULL;
197
198 #if 0
199         /* Put here so error script picks them up */
200         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE,
201                                 FIPS_R_PERSONALISATION_STRING_TOO_LONG);
202         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, FIPS_R_IN_ERROR_STATE);
203         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, FIPS_R_ALREADY_INSTANTIATED);
204         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, FIPS_R_ERROR_RETRIEVING_ENTROPY);
205         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, FIPS_R_ERROR_RETRIEVING_NONCE);
206         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, FIPS_R_INSTANTIATE_ERROR);
207         FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, FIPS_R_DRBG_NOT_INITIALISED);
208 #endif
209
210         int r = 0;
211
212         if (perslen > dctx->max_pers)
213                 {
214                 r = FIPS_R_PERSONALISATION_STRING_TOO_LONG;
215                 goto end;
216                 }
217
218         if (!dctx->instantiate)
219                 {
220                 r = FIPS_R_DRBG_NOT_INITIALISED;
221                 goto end;
222                 }
223
224         if (dctx->status != DRBG_STATUS_UNINITIALISED)
225                 {
226                 if (dctx->status == DRBG_STATUS_ERROR)
227                         r = FIPS_R_IN_ERROR_STATE;
228                 else
229                         r = FIPS_R_ALREADY_INSTANTIATED;
230                 goto end;
231                 }
232
233         dctx->status = DRBG_STATUS_ERROR;
234
235         entlen = fips_get_entropy(dctx, &entropy, dctx->strength,
236                                 dctx->min_entropy, dctx->max_entropy);
237
238         if (entlen < dctx->min_entropy || entlen > dctx->max_entropy)
239                 {
240                 r = FIPS_R_ERROR_RETRIEVING_ENTROPY;
241                 goto end;
242                 }
243
244         if (dctx->max_nonce > 0)
245                 {
246                 noncelen = dctx->get_nonce(dctx, &nonce,
247                                         dctx->strength / 2,
248                                         dctx->min_nonce, dctx->max_nonce);
249
250                 if (noncelen < dctx->min_nonce || noncelen > dctx->max_nonce)
251                         {
252                         r = FIPS_R_ERROR_RETRIEVING_NONCE;
253                         goto end;
254                         }
255
256                 }
257
258         if (!dctx->instantiate(dctx, 
259                                 entropy, entlen,
260                                 nonce, noncelen,
261                                 pers, perslen))
262                 {
263                 r = FIPS_R_ERROR_INSTANTIATING_DRBG;
264                 goto end;
265                 }
266
267
268         dctx->status = DRBG_STATUS_READY;
269         if (!(dctx->iflags & DRBG_CUSTOM_RESEED))
270                 dctx->reseed_counter = 1;
271
272         end:
273
274         if (entropy && dctx->cleanup_entropy)
275                 fips_cleanup_entropy(dctx, entropy, entlen);
276
277         if (nonce && dctx->cleanup_nonce)
278                 dctx->cleanup_nonce(dctx, nonce, noncelen);
279
280         if (dctx->status == DRBG_STATUS_READY)
281                 return 1;
282
283         if (r && !(dctx->iflags & DRBG_FLAG_NOERR))
284                 FIPSerr(FIPS_F_FIPS_DRBG_INSTANTIATE, r);
285
286         return 0;
287
288         }
289
290 static int drbg_reseed(DRBG_CTX *dctx,
291                         const unsigned char *adin, size_t adinlen, int hcheck)
292         {
293         unsigned char *entropy = NULL;
294         size_t entlen = 0;
295         int r = 0;
296
297 #if 0
298         FIPSerr(FIPS_F_DRBG_RESEED, FIPS_R_NOT_INSTANTIATED);
299         FIPSerr(FIPS_F_DRBG_RESEED, FIPS_R_ADDITIONAL_INPUT_TOO_LONG);
300 #endif
301         if (dctx->status != DRBG_STATUS_READY
302                 && dctx->status != DRBG_STATUS_RESEED)
303                 {
304                 if (dctx->status == DRBG_STATUS_ERROR)
305                         r = FIPS_R_IN_ERROR_STATE;
306                 else if(dctx->status == DRBG_STATUS_UNINITIALISED)
307                         r = FIPS_R_NOT_INSTANTIATED;
308                 goto end;
309                 }
310
311         if (!adin)
312                 adinlen = 0;
313         else if (adinlen > dctx->max_adin)
314                 {
315                 r = FIPS_R_ADDITIONAL_INPUT_TOO_LONG;
316                 goto end;
317                 }
318
319         dctx->status = DRBG_STATUS_ERROR;
320         /* Peform health check on all reseed operations if not a prediction
321          * resistance request and not in test mode.
322          */
323         if (hcheck && !(dctx->xflags & DRBG_FLAG_TEST))
324                 {
325                 if (!FIPS_drbg_health_check(dctx))
326                         {
327                         r = FIPS_R_SELFTEST_FAILURE;
328                         goto end;
329                         }
330                 }
331
332         entlen = fips_get_entropy(dctx, &entropy, dctx->strength,
333                                 dctx->min_entropy, dctx->max_entropy);
334
335         if (entlen < dctx->min_entropy || entlen > dctx->max_entropy)
336                 {
337                 r = FIPS_R_ERROR_RETRIEVING_ENTROPY;
338                 goto end;
339                 }
340
341         if (!dctx->reseed(dctx, entropy, entlen, adin, adinlen))
342                 goto end;
343
344         dctx->status = DRBG_STATUS_READY;
345         if (!(dctx->iflags & DRBG_CUSTOM_RESEED))
346                 dctx->reseed_counter = 1;
347         end:
348
349         if (entropy && dctx->cleanup_entropy)
350                 fips_cleanup_entropy(dctx, entropy, entlen);
351
352         if (dctx->status == DRBG_STATUS_READY)
353                 return 1;
354
355         if (r && !(dctx->iflags & DRBG_FLAG_NOERR))
356                 FIPSerr(FIPS_F_DRBG_RESEED, r);
357
358         return 0;
359         }
360
361 int FIPS_drbg_reseed(DRBG_CTX *dctx,
362                         const unsigned char *adin, size_t adinlen)
363         {
364         return drbg_reseed(dctx, adin, adinlen, 1);
365         }
366
367 static int fips_drbg_check(DRBG_CTX *dctx)
368         {
369         if (dctx->xflags & DRBG_FLAG_TEST)
370                 return 1;
371         dctx->health_check_cnt++;
372         if (dctx->health_check_cnt >= dctx->health_check_interval)
373                 {
374                 if (!FIPS_drbg_health_check(dctx))
375                         {
376                         FIPSerr(FIPS_F_FIPS_DRBG_CHECK, FIPS_R_SELFTEST_FAILURE);
377                         return 0;
378                         }
379                 }
380         return 1;
381         }
382
383 int FIPS_drbg_generate(DRBG_CTX *dctx, unsigned char *out, size_t outlen,
384                         int prediction_resistance,
385                         const unsigned char *adin, size_t adinlen)
386         {
387         int r = 0;
388
389         if (!fips_drbg_check(dctx))
390                 return 0;
391
392         if (dctx->status != DRBG_STATUS_READY
393                 && dctx->status != DRBG_STATUS_RESEED)
394                 {
395                 if (dctx->status == DRBG_STATUS_ERROR)
396                         r = FIPS_R_IN_ERROR_STATE;
397                 else if(dctx->status == DRBG_STATUS_UNINITIALISED)
398                         r = FIPS_R_NOT_INSTANTIATED;
399                 goto end;
400                 }
401
402         if (outlen > dctx->max_request)
403                 {
404                 r = FIPS_R_REQUEST_TOO_LARGE_FOR_DRBG;
405                 return 0;
406                 }
407
408         if (adinlen > dctx->max_adin)
409                 {
410                 r = FIPS_R_ADDITIONAL_INPUT_TOO_LONG;
411                 goto end;
412                 }
413
414         if (dctx->iflags & DRBG_CUSTOM_RESEED)
415                 dctx->generate(dctx, NULL, outlen, NULL, 0);
416         else if (dctx->reseed_counter >= dctx->reseed_interval)
417                 dctx->status = DRBG_STATUS_RESEED;
418
419         if (dctx->status == DRBG_STATUS_RESEED || prediction_resistance)
420                 {
421                 /* If prediction resistance request don't do health check */
422                 int hcheck = prediction_resistance ? 0 : 1;
423                 
424                 if (!drbg_reseed(dctx, adin, adinlen, hcheck))
425                         {
426                         r = FIPS_R_RESEED_ERROR;
427                         goto end;
428                         }
429                 adin = NULL;
430                 adinlen = 0;
431                 }
432
433         if (!dctx->generate(dctx, out, outlen, adin, adinlen))
434                 {
435                 r = FIPS_R_GENERATE_ERROR;
436                 dctx->status = DRBG_STATUS_ERROR;
437                 goto end;
438                 }
439         if (!(dctx->iflags & DRBG_CUSTOM_RESEED))
440                 {
441                 if (dctx->reseed_counter >= dctx->reseed_interval)
442                         dctx->status = DRBG_STATUS_RESEED;
443                 else
444                         dctx->reseed_counter++;
445                 }
446
447         end:
448         if (r)
449                 {
450                 if (!(dctx->iflags & DRBG_FLAG_NOERR))
451                         FIPSerr(FIPS_F_FIPS_DRBG_GENERATE, r);
452                 return 0;
453                 }
454
455         return 1;
456         }
457
458 int FIPS_drbg_uninstantiate(DRBG_CTX *dctx)
459         {
460         int rv;
461         if (!dctx->uninstantiate)
462                 rv = 1;
463         else
464                 rv = dctx->uninstantiate(dctx);
465         /* Although we'd like to cleanse here we can't because we have to
466          * test the uninstantiate really zeroes the data.
467          */
468         memset(&dctx->d, 0, sizeof(dctx->d));
469         dctx->status = DRBG_STATUS_UNINITIALISED;
470         /* If method has problems uninstantiating, return error */
471         return rv;
472         }
473
474 int FIPS_drbg_set_callbacks(DRBG_CTX *dctx,
475         size_t (*get_entropy)(DRBG_CTX *ctx, unsigned char **pout,
476                                 int entropy, size_t min_len, size_t max_len),
477         void (*cleanup_entropy)(DRBG_CTX *ctx, unsigned char *out, size_t olen),
478         size_t entropy_blocklen,
479         size_t (*get_nonce)(DRBG_CTX *ctx, unsigned char **pout,
480                                 int entropy, size_t min_len, size_t max_len),
481         void (*cleanup_nonce)(DRBG_CTX *ctx, unsigned char *out, size_t olen))
482         {
483         if (dctx->status != DRBG_STATUS_UNINITIALISED)
484                 return 0;
485         dctx->entropy_blocklen = entropy_blocklen;
486         dctx->get_entropy = get_entropy;
487         dctx->cleanup_entropy = cleanup_entropy;
488         dctx->get_nonce = get_nonce;
489         dctx->cleanup_nonce = cleanup_nonce;
490         return 1;
491         }
492
493 int FIPS_drbg_set_rand_callbacks(DRBG_CTX *dctx,
494         size_t (*get_adin)(DRBG_CTX *ctx, unsigned char **pout),
495         void (*cleanup_adin)(DRBG_CTX *ctx, unsigned char *out, size_t olen),
496         int (*rand_seed_cb)(DRBG_CTX *ctx, const void *buf, int num),
497         int (*rand_add_cb)(DRBG_CTX *ctx,
498                                 const void *buf, int num, double entropy))
499         {
500         if (dctx->status != DRBG_STATUS_UNINITIALISED)
501                 return 0;
502         dctx->get_adin = get_adin;
503         dctx->cleanup_adin = cleanup_adin;
504         dctx->rand_seed_cb = rand_seed_cb;
505         dctx->rand_add_cb = rand_add_cb;
506         return 1;
507         }
508
509 void *FIPS_drbg_get_app_data(DRBG_CTX *dctx)
510         {
511         return dctx->app_data;
512         }
513
514 void FIPS_drbg_set_app_data(DRBG_CTX *dctx, void *app_data)
515         {
516         dctx->app_data = app_data;
517         }
518
519 size_t FIPS_drbg_get_blocklength(DRBG_CTX *dctx)
520         {
521         return dctx->blocklength;
522         }
523
524 int FIPS_drbg_get_strength(DRBG_CTX *dctx)
525         {
526         return dctx->strength;
527         }
528
529 void FIPS_drbg_set_check_interval(DRBG_CTX *dctx, int interval)
530         {
531         dctx->health_check_interval = interval;
532         }
533
534 void FIPS_drbg_set_reseed_interval(DRBG_CTX *dctx, int interval)
535         {
536         dctx->reseed_interval = interval;
537         }
538
539 static int drbg_stick = 0;
540
541 void FIPS_drbg_stick(void)
542         {
543         drbg_stick = 1;
544         }
545
546 /* Continuous DRBG utility function */
547 int fips_drbg_cprng_test(DRBG_CTX *dctx, const unsigned char *out)
548         {
549         /* No CPRNG in test mode */
550         if (dctx->xflags & DRBG_FLAG_TEST)
551                 return 1;
552         /* Check block is valid: should never happen */
553         if (dctx->lb_valid == 0)
554                 {
555                 FIPSerr(FIPS_F_FIPS_DRBG_CPRNG_TEST, FIPS_R_INTERNAL_ERROR);
556                 fips_set_selftest_fail();
557                 return 0;
558                 }
559         if (drbg_stick)
560                 memcpy(dctx->lb, out, dctx->blocklength);
561         /* Check against last block: fail if match */
562         if (!memcmp(dctx->lb, out, dctx->blocklength))
563                 {
564                 FIPSerr(FIPS_F_FIPS_DRBG_CPRNG_TEST, FIPS_R_DRBG_STUCK);
565                 fips_set_selftest_fail();
566                 return 0;
567                 }
568         /* Save last block for next comparison */
569         memcpy(dctx->lb, out, dctx->blocklength);
570         return 1;
571         }