e0e1d750916b8cf5badcb625653799a3a56a83c4
[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_selftest_failed())
390                 {
391                 FIPSerr(FIPS_F_FIPS_DRBG_GENERATE, FIPS_R_SELFTEST_FAILED);
392                 return 0;
393                 }
394
395         if (!fips_drbg_check(dctx))
396                 return 0;
397
398         if (dctx->status != DRBG_STATUS_READY
399                 && dctx->status != DRBG_STATUS_RESEED)
400                 {
401                 if (dctx->status == DRBG_STATUS_ERROR)
402                         r = FIPS_R_IN_ERROR_STATE;
403                 else if(dctx->status == DRBG_STATUS_UNINITIALISED)
404                         r = FIPS_R_NOT_INSTANTIATED;
405                 goto end;
406                 }
407
408         if (outlen > dctx->max_request)
409                 {
410                 r = FIPS_R_REQUEST_TOO_LARGE_FOR_DRBG;
411                 return 0;
412                 }
413
414         if (adinlen > dctx->max_adin)
415                 {
416                 r = FIPS_R_ADDITIONAL_INPUT_TOO_LONG;
417                 goto end;
418                 }
419
420         if (dctx->iflags & DRBG_CUSTOM_RESEED)
421                 dctx->generate(dctx, NULL, outlen, NULL, 0);
422         else if (dctx->reseed_counter >= dctx->reseed_interval)
423                 dctx->status = DRBG_STATUS_RESEED;
424
425         if (dctx->status == DRBG_STATUS_RESEED || prediction_resistance)
426                 {
427                 /* If prediction resistance request don't do health check */
428                 int hcheck = prediction_resistance ? 0 : 1;
429                 
430                 if (!drbg_reseed(dctx, adin, adinlen, hcheck))
431                         {
432                         r = FIPS_R_RESEED_ERROR;
433                         goto end;
434                         }
435                 adin = NULL;
436                 adinlen = 0;
437                 }
438
439         if (!dctx->generate(dctx, out, outlen, adin, adinlen))
440                 {
441                 r = FIPS_R_GENERATE_ERROR;
442                 dctx->status = DRBG_STATUS_ERROR;
443                 goto end;
444                 }
445         if (!(dctx->iflags & DRBG_CUSTOM_RESEED))
446                 {
447                 if (dctx->reseed_counter >= dctx->reseed_interval)
448                         dctx->status = DRBG_STATUS_RESEED;
449                 else
450                         dctx->reseed_counter++;
451                 }
452
453         end:
454         if (r)
455                 {
456                 if (!(dctx->iflags & DRBG_FLAG_NOERR))
457                         FIPSerr(FIPS_F_FIPS_DRBG_GENERATE, r);
458                 return 0;
459                 }
460
461         return 1;
462         }
463
464 int FIPS_drbg_uninstantiate(DRBG_CTX *dctx)
465         {
466         int rv;
467         if (!dctx->uninstantiate)
468                 rv = 1;
469         else
470                 rv = dctx->uninstantiate(dctx);
471         /* Although we'd like to cleanse here we can't because we have to
472          * test the uninstantiate really zeroes the data.
473          */
474         memset(&dctx->d, 0, sizeof(dctx->d));
475         dctx->status = DRBG_STATUS_UNINITIALISED;
476         /* If method has problems uninstantiating, return error */
477         return rv;
478         }
479
480 int FIPS_drbg_set_callbacks(DRBG_CTX *dctx,
481         size_t (*get_entropy)(DRBG_CTX *ctx, unsigned char **pout,
482                                 int entropy, size_t min_len, size_t max_len),
483         void (*cleanup_entropy)(DRBG_CTX *ctx, unsigned char *out, size_t olen),
484         size_t entropy_blocklen,
485         size_t (*get_nonce)(DRBG_CTX *ctx, unsigned char **pout,
486                                 int entropy, size_t min_len, size_t max_len),
487         void (*cleanup_nonce)(DRBG_CTX *ctx, unsigned char *out, size_t olen))
488         {
489         if (dctx->status != DRBG_STATUS_UNINITIALISED)
490                 return 0;
491         dctx->entropy_blocklen = entropy_blocklen;
492         dctx->get_entropy = get_entropy;
493         dctx->cleanup_entropy = cleanup_entropy;
494         dctx->get_nonce = get_nonce;
495         dctx->cleanup_nonce = cleanup_nonce;
496         return 1;
497         }
498
499 int FIPS_drbg_set_rand_callbacks(DRBG_CTX *dctx,
500         size_t (*get_adin)(DRBG_CTX *ctx, unsigned char **pout),
501         void (*cleanup_adin)(DRBG_CTX *ctx, unsigned char *out, size_t olen),
502         int (*rand_seed_cb)(DRBG_CTX *ctx, const void *buf, int num),
503         int (*rand_add_cb)(DRBG_CTX *ctx,
504                                 const void *buf, int num, double entropy))
505         {
506         if (dctx->status != DRBG_STATUS_UNINITIALISED)
507                 return 0;
508         dctx->get_adin = get_adin;
509         dctx->cleanup_adin = cleanup_adin;
510         dctx->rand_seed_cb = rand_seed_cb;
511         dctx->rand_add_cb = rand_add_cb;
512         return 1;
513         }
514
515 void *FIPS_drbg_get_app_data(DRBG_CTX *dctx)
516         {
517         return dctx->app_data;
518         }
519
520 void FIPS_drbg_set_app_data(DRBG_CTX *dctx, void *app_data)
521         {
522         dctx->app_data = app_data;
523         }
524
525 size_t FIPS_drbg_get_blocklength(DRBG_CTX *dctx)
526         {
527         return dctx->blocklength;
528         }
529
530 int FIPS_drbg_get_strength(DRBG_CTX *dctx)
531         {
532         return dctx->strength;
533         }
534
535 void FIPS_drbg_set_check_interval(DRBG_CTX *dctx, int interval)
536         {
537         dctx->health_check_interval = interval;
538         }
539
540 void FIPS_drbg_set_reseed_interval(DRBG_CTX *dctx, int interval)
541         {
542         dctx->reseed_interval = interval;
543         }
544
545 static int drbg_stick = 0;
546
547 void FIPS_drbg_stick(int onoff)
548         {
549         drbg_stick = onoff;
550         }
551
552 /* Continuous DRBG utility function */
553 int fips_drbg_cprng_test(DRBG_CTX *dctx, const unsigned char *out)
554         {
555         /* No CPRNG in test mode */
556         if (dctx->xflags & DRBG_FLAG_TEST)
557                 return 1;
558         /* Check block is valid: should never happen */
559         if (dctx->lb_valid == 0)
560                 {
561                 FIPSerr(FIPS_F_FIPS_DRBG_CPRNG_TEST, FIPS_R_INTERNAL_ERROR);
562                 fips_set_selftest_fail();
563                 return 0;
564                 }
565         if (drbg_stick)
566                 memcpy(dctx->lb, out, dctx->blocklength);
567         /* Check against last block: fail if match */
568         if (!memcmp(dctx->lb, out, dctx->blocklength))
569                 {
570                 FIPSerr(FIPS_F_FIPS_DRBG_CPRNG_TEST, FIPS_R_DRBG_STUCK);
571                 fips_set_selftest_fail();
572                 return 0;
573                 }
574         /* Save last block for next comparison */
575         memcpy(dctx->lb, out, dctx->blocklength);
576         return 1;
577         }