0bf30f031488938be92a83681b25a3f1ac766d91
[openssl.git] / fips / rand / fips_drbg_lib.c
1 /* fips/rand/fips_drbg_lib.c */
2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3  * project.
4  */
5 /* ====================================================================
6  * Copyright (c) 2011 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer. 
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  */
53
54 #define OPENSSL_FIPSAPI
55
56 #include <string.h>
57 #include <openssl/crypto.h>
58 #include <openssl/evp.h>
59 #include <openssl/aes.h>
60 #include <openssl/fips_rand.h>
61 #include "fips_rand_lcl.h"
62
63 /* Support framework for SP800-90 DRBGs */
64
65 static int fips_drbg_init(DRBG_CTX *dctx, int type, unsigned int flags)
66         {
67         int rv;
68         memset(dctx, 0, sizeof(DRBG_CTX));
69         dctx->status = DRBG_STATUS_UNINITIALISED;
70         dctx->flags = flags;
71         dctx->type = type;
72
73         rv = fips_drbg_hash_init(dctx);
74
75         if (rv == -2)
76                 rv = fips_drbg_ctr_init(dctx);
77
78         return rv;
79         }
80
81 DRBG_CTX *FIPS_drbg_new(int type, unsigned int flags)
82         {
83         DRBG_CTX *dctx;
84         dctx = OPENSSL_malloc(sizeof(DRBG_CTX));
85         if (!dctx)
86                 return NULL;
87         if (fips_drbg_init(dctx, type, flags) <= 0)
88                 {
89                 OPENSSL_free(dctx);
90                 return NULL;
91                 }
92         return dctx;
93         }
94
95 void FIPS_drbg_free(DRBG_CTX *dctx)
96         {
97         dctx->uninstantiate(dctx);
98         OPENSSL_cleanse(dctx, sizeof(DRBG_CTX));
99         OPENSSL_free(dctx);
100         }
101
102 int FIPS_drbg_instantiate(DRBG_CTX *dctx,
103                                 int strength,
104                                 const unsigned char *pers, size_t perslen)
105         {
106         size_t entlen, noncelen;
107
108         if (perslen > dctx->max_pers)
109                 return 0;
110
111         if (dctx->status != DRBG_STATUS_UNINITIALISED)
112                 {
113                 /* error */
114                 return 0;
115                 }
116
117         dctx->status = DRBG_STATUS_ERROR;
118
119         entlen = dctx->get_entropy(dctx, dctx->entropy, dctx->strength,
120                                 dctx->min_entropy, dctx->max_entropy);
121
122         if (entlen < dctx->min_entropy || entlen > dctx->max_entropy)
123                 goto end;
124
125         if (dctx->max_nonce > 0)
126                 {
127
128                 noncelen = dctx->get_nonce(dctx, dctx->nonce,
129                                         dctx->strength / 2,
130                                         dctx->min_nonce, dctx->max_nonce);
131
132                 if (noncelen < dctx->min_nonce || noncelen > dctx->max_nonce)
133                         goto end;
134
135                 }
136         else
137                 noncelen = 0;
138
139         if (!dctx->instantiate(dctx, 
140                                 dctx->entropy, entlen,
141                                 dctx->nonce, noncelen,
142                                 pers, perslen))
143                 goto end;
144
145
146         dctx->status = DRBG_STATUS_READY;
147         dctx->reseed_counter = 1;
148         /* Initial test value for reseed interval */
149         dctx->reseed_interval = 1<<24;
150
151         end:
152
153         OPENSSL_cleanse(dctx->entropy, sizeof(dctx->entropy));
154         OPENSSL_cleanse(dctx->nonce, sizeof(dctx->nonce));
155
156         if (dctx->status == DRBG_STATUS_READY)
157                 return 1;
158
159         return 0;
160
161         }
162
163 int FIPS_drbg_reseed(DRBG_CTX *dctx,
164                         const unsigned char *adin, size_t adinlen)
165         {
166         size_t entlen;
167         if (dctx->status != DRBG_STATUS_READY
168                 && dctx->status != DRBG_STATUS_RESEED)
169                 {
170                 /* error */
171                 return 0;
172                 }
173
174         if (!adin)
175                 adinlen = 0;
176         else if (adinlen > dctx->max_adin)
177                 {
178                 /* error */
179                 return 0;
180                 }
181
182         dctx->status = DRBG_STATUS_ERROR;
183
184         entlen = dctx->get_entropy(dctx, dctx->entropy, dctx->strength,
185                                 dctx->min_entropy, dctx->max_entropy);
186
187         if (entlen < dctx->min_entropy || entlen > dctx->max_entropy)
188                 goto end;
189
190         if (!dctx->reseed(dctx, dctx->entropy, entlen, adin, adinlen))
191                 goto end;
192
193         dctx->status = DRBG_STATUS_READY;
194         dctx->reseed_counter = 1;
195         end:
196         OPENSSL_cleanse(dctx->entropy, sizeof(dctx->entropy));
197         if (dctx->status == DRBG_STATUS_READY)
198                 return 1;
199         return 0;
200         }
201         
202
203 int FIPS_drbg_generate(DRBG_CTX *dctx, unsigned char *out, size_t outlen,
204                         int prediction_resistance,
205                         const unsigned char *adin, size_t adinlen)
206         {
207         if (outlen > dctx->max_request)
208                 {
209                 /* Too large */
210                 return 0;
211                 }
212         if (dctx->status == DRBG_STATUS_RESEED || prediction_resistance)
213                 {
214                 if (!FIPS_drbg_reseed(dctx, adin, adinlen))
215                         return 0;
216                 adin = NULL;
217                 adinlen = 0;
218                 }
219         if (dctx->status != DRBG_STATUS_READY)
220                 {
221                 /* Bad error */
222                 return 0;
223                 }
224         if (!dctx->generate(dctx, out, outlen, adin, adinlen))
225                 {
226                 /* Bad error */
227                 dctx->status = DRBG_STATUS_ERROR;
228                 return 0;
229                 }
230         if (dctx->reseed_counter > dctx->reseed_interval)
231                 dctx->status = DRBG_STATUS_RESEED;
232         else
233                 dctx->reseed_counter++;
234
235         return 1;
236         }
237
238 int FIPS_drbg_uninstantiate(DRBG_CTX *dctx)
239         {
240         int save_type, save_flags, rv;
241         save_type = dctx->type;
242         save_flags = dctx->flags;
243         rv = dctx->uninstantiate(dctx);
244         OPENSSL_cleanse(dctx, sizeof(DRBG_CTX));
245         /* If method has problems uninstantiating, return error */
246         if (rv <= 0)
247                 return rv;
248         return fips_drbg_init(dctx, save_type, save_flags);
249         }
250
251 int FIPS_drbg_set_test_mode(DRBG_CTX *dctx,
252         size_t (*get_entropy)(DRBG_CTX *ctx, unsigned char *out,
253                                 int entropy, size_t min_len, size_t max_len),
254         size_t (*get_nonce)(DRBG_CTX *ctx, unsigned char *out,
255                                 int entropy, size_t min_len, size_t max_len))
256         {
257         if (dctx->status != DRBG_STATUS_UNINITIALISED)
258                 return 0;
259         dctx->flags |= DRBG_FLAG_TEST;
260         dctx->get_entropy = get_entropy;
261         dctx->get_nonce = get_nonce;
262         return 1;
263         }
264
265 void *FIPS_drbg_get_app_data(DRBG_CTX *dctx)
266         {
267         return dctx->app_data;
268         }
269
270 void FIPS_drbg_set_app_data(DRBG_CTX *dctx, void *app_data)
271         {
272         dctx->app_data = app_data;
273         }
274
275 size_t FIPS_drbg_get_blocklength(DRBG_CTX *dctx)
276         {
277         return dctx->blocklength;
278         }