Fix CPRNG test for Hash DRBG.
[openssl.git] / fips / rand / fips_drbg_hash.c
1 /* fips/rand/fips_drbg_hash.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 <stdlib.h>
57 #include <string.h>
58 #include <openssl/crypto.h>
59 #include <openssl/evp.h>
60 #include <openssl/aes.h>
61 #include <openssl/fips.h>
62 #include <openssl/fips_rand.h>
63 #include "fips_rand_lcl.h"
64
65 /* This is Hash_df from SP 800-90 10.4.1 */
66
67 static int hash_df(DRBG_CTX *dctx, unsigned char *out,
68                         const unsigned char *in1, size_t in1len,
69                         const unsigned char *in2, size_t in2len,
70                         const unsigned char *in3, size_t in3len,
71                         const unsigned char *in4, size_t in4len)
72         {
73         EVP_MD_CTX *mctx = &dctx->d.hash.mctx;
74         unsigned char *vtmp = dctx->d.hash.vtmp;
75         unsigned char tmp[6];
76         /* Standard only ever needs seedlen bytes which is always less than
77          * maximum permitted so no need to check length.
78          */
79         size_t outlen = dctx->seedlen;
80         tmp[0] = 1;
81         tmp[1] = ((outlen * 8) >> 24) & 0xff;
82         tmp[2] = ((outlen * 8) >> 16) & 0xff;
83         tmp[3] = ((outlen * 8) >> 8) & 0xff;
84         tmp[4] = (outlen * 8) & 0xff;
85         if (!in1)
86                 {
87                 tmp[5] = (unsigned char)in1len;
88                 in1 = tmp + 5;
89                 in1len = 1;
90                 }
91         for (;;)
92                 {
93                 if (!FIPS_digestinit(mctx, dctx->d.hash.md))
94                         return 0;
95                 if (!FIPS_digestupdate(mctx, tmp, 5))
96                         return 0;
97                 if (in1 && !FIPS_digestupdate(mctx, in1, in1len))
98                         return 0;
99                 if (in2 && !FIPS_digestupdate(mctx, in2, in2len))
100                         return 0;
101                 if (in3 && !FIPS_digestupdate(mctx, in3, in3len))
102                         return 0;
103                 if (in4 && !FIPS_digestupdate(mctx, in4, in4len))
104                         return 0;
105                 if (outlen < dctx->blocklength)
106                         {
107                         if (!FIPS_digestfinal(mctx, vtmp, NULL))
108                                 return 0;
109                         memcpy(out, vtmp, outlen);
110                         OPENSSL_cleanse(vtmp, dctx->blocklength);
111                         return 1;
112                         }
113                 else if(!FIPS_digestfinal(mctx, out, NULL))
114                         return 0;
115
116                 outlen -= dctx->blocklength;
117                 if (outlen == 0)
118                         return 1;
119                 tmp[0]++;
120                 out += dctx->blocklength;
121                 }
122         }
123
124
125 /* Add an unsigned buffer to the buf value, storing the result in buf. For
126  * this algorithm the length of input never exceeds the seed length.
127  */
128
129 static void ctx_add_buf(DRBG_CTX *dctx, unsigned char *buf,
130                                 unsigned char *in, size_t inlen)
131         {
132         size_t i = inlen;
133         const unsigned char *q;
134         unsigned char c, *p;
135         p = buf + dctx->seedlen;
136         q = in + inlen;
137
138         OPENSSL_assert(i <= dctx->seedlen);
139
140         /* Special case: zero length, just increment buffer */
141         if (i)
142                 c = 0;
143         else 
144                 c = 1;
145
146         while (i)
147                 {
148                 int r;
149                 p--;
150                 q--;
151                 r = *p + *q + c;
152                 /* Carry */
153                 if (r > 0xff)
154                         c = 1;
155                 else
156                         c = 0;
157                 *p = r & 0xff;
158                 i--;
159                 }
160
161         i = dctx->seedlen - inlen;
162
163         /* If not adding whole buffer handle final carries */
164         if (c && i)
165                 {
166                 do
167                         {
168                         p--;
169                         c = *p;
170                         c++;
171                         *p = c;
172                         if(c)
173                                 return;
174                         } while(i--);
175                 }
176         }
177
178 /* Finalise and add hash to V */
179         
180 static int ctx_add_md(DRBG_CTX *dctx)
181         {
182         if (!FIPS_digestfinal(&dctx->d.hash.mctx, dctx->d.hash.vtmp, NULL))
183                         return 0;
184         ctx_add_buf(dctx, dctx->d.hash.V, dctx->d.hash.vtmp, dctx->blocklength);
185         return 1;
186         }
187
188 static int hash_gen(DRBG_CTX *dctx, unsigned char *out, size_t outlen)
189         {
190         DRBG_HASH_CTX *hctx = &dctx->d.hash;
191         if (outlen == 0)
192                 return 1;
193         memcpy(hctx->vtmp, hctx->V, dctx->seedlen);
194         for(;;)
195                 {
196                 FIPS_digestinit(&hctx->mctx, hctx->md);
197                 FIPS_digestupdate(&hctx->mctx, hctx->vtmp, dctx->seedlen);
198                 if (!(dctx->flags & DRBG_FLAG_TEST) && !dctx->lb_valid)
199                         {
200                         FIPS_digestfinal(&hctx->mctx, dctx->lb, NULL);
201                         dctx->lb_valid = 1;
202                         }
203                 else if (outlen < dctx->blocklength)
204                         {
205                         FIPS_digestfinal(&hctx->mctx, hctx->vtmp, NULL);
206                         if (!fips_drbg_cprng_test(dctx, hctx->vtmp))
207                                 return 0;
208                         memcpy(out, hctx->vtmp, outlen);
209                         return 1;
210                         }
211                 else
212                         {
213                         FIPS_digestfinal(&hctx->mctx, out, NULL);
214                         if (!fips_drbg_cprng_test(dctx, out))
215                                 return 0;
216                         outlen -= dctx->blocklength;
217                         if (outlen == 0)
218                                 return 1;
219                         out += dctx->blocklength;
220                         }
221                 ctx_add_buf(dctx, hctx->vtmp, NULL, 0);
222                 }
223         }
224
225 static int drbg_hash_instantiate(DRBG_CTX *dctx,
226                                 const unsigned char *ent, size_t ent_len,
227                                 const unsigned char *nonce, size_t nonce_len,
228                                 const unsigned char *pstr, size_t pstr_len)
229         {
230         DRBG_HASH_CTX *hctx = &dctx->d.hash;
231         if (!hash_df(dctx, hctx->V, 
232                         ent, ent_len, nonce, nonce_len, pstr, pstr_len,
233                         NULL, 0))
234                 return 0;
235         if (!hash_df(dctx, hctx->C, 
236                         NULL, 0, hctx->V, dctx->seedlen,
237                         NULL, 0, NULL, 0))
238                 return 0;
239
240 #ifdef HASH_DRBG_TRACE
241         fprintf(stderr, "V+C after instantiate:\n");
242         hexprint(stderr, hctx->V, dctx->seedlen);
243         hexprint(stderr, hctx->C, dctx->seedlen);
244 #endif
245         return 1;
246         }
247
248         
249 static int drbg_hash_reseed(DRBG_CTX *dctx,
250                                 const unsigned char *ent, size_t ent_len,
251                                 const unsigned char *adin, size_t adin_len)
252         {
253         DRBG_HASH_CTX *hctx = &dctx->d.hash;
254         /* V about to be updated so use C as output instead */
255         if (!hash_df(dctx, hctx->C,
256                         NULL, 1, hctx->V, dctx->seedlen,
257                         ent, ent_len, adin, adin_len))
258                 return 0;
259         memcpy(hctx->V, hctx->C, dctx->seedlen);
260         if (!hash_df(dctx, hctx->C, NULL, 0,
261                         hctx->V, dctx->seedlen, NULL, 0, NULL, 0))
262                 return 0;
263 #ifdef HASH_DRBG_TRACE
264         fprintf(stderr, "V+C after reseed:\n");
265         hexprint(stderr, hctx->V, dctx->seedlen);
266         hexprint(stderr, hctx->C, dctx->seedlen);
267 #endif
268         return 1;
269         }
270
271 static int drbg_hash_generate(DRBG_CTX *dctx,
272                                 unsigned char *out, size_t outlen,
273                                 const unsigned char *adin, size_t adin_len)
274         {
275         DRBG_HASH_CTX *hctx = &dctx->d.hash;
276         EVP_MD_CTX *mctx = &hctx->mctx;
277         unsigned char tmp[4];
278         if (adin && adin_len)
279                 {
280                 tmp[0] = 2;
281                 if (!FIPS_digestinit(mctx, hctx->md))
282                         return 0;
283                 if (!EVP_DigestUpdate(mctx, tmp, 1))
284                         return 0;
285                 if (!EVP_DigestUpdate(mctx, hctx->V, dctx->seedlen))
286                         return 0;
287                 if (!EVP_DigestUpdate(mctx, adin, adin_len))
288                         return 0;
289                 if (!ctx_add_md(dctx))
290                         return 0;
291                 }
292         if (!hash_gen(dctx, out, outlen))
293                 return 0;
294
295         tmp[0] = 3;
296         if (!FIPS_digestinit(mctx, hctx->md))
297                 return 0;
298         if (!EVP_DigestUpdate(mctx, tmp, 1))
299                 return 0;
300         if (!EVP_DigestUpdate(mctx, hctx->V, dctx->seedlen))
301                 return 0;
302
303         if (!ctx_add_md(dctx))
304                 return 0;
305
306         ctx_add_buf(dctx, hctx->V, hctx->C, dctx->seedlen);
307
308         tmp[0] = (dctx->reseed_counter >> 24) & 0xff;
309         tmp[1] = (dctx->reseed_counter >> 16) & 0xff;
310         tmp[2] = (dctx->reseed_counter >> 8) & 0xff;
311         tmp[3] = dctx->reseed_counter & 0xff;
312         ctx_add_buf(dctx, hctx->V, tmp, 4);
313 #ifdef HASH_DRBG_TRACE
314         fprintf(stderr, "V+C after generate:\n");
315         hexprint(stderr, hctx->V, dctx->seedlen);
316         hexprint(stderr, hctx->C, dctx->seedlen);
317 #endif
318         return 1;
319         }
320
321 static int drbg_hash_uninstantiate(DRBG_CTX *dctx)
322         {
323         EVP_MD_CTX_cleanup(&dctx->d.hash.mctx);
324         OPENSSL_cleanse(&dctx->d.hash, sizeof(DRBG_HASH_CTX));
325         return 1;
326         }
327
328 int fips_drbg_hash_init(DRBG_CTX *dctx)
329         {
330         const EVP_MD *md;
331         DRBG_HASH_CTX *hctx = &dctx->d.hash;
332         md = FIPS_get_digestbynid(dctx->type);
333         if (!md)
334                 return -2;
335         switch (dctx->type)
336                 {
337                 case NID_sha1:
338                 md = EVP_sha1();
339                 dctx->strength = 128;
340                 break;
341
342                 case NID_sha224:
343                 md = EVP_sha224();
344                 dctx->strength = 192;
345                 break;
346
347                 default:
348                 dctx->strength = 256;
349                 break;
350                 }
351
352         dctx->instantiate = drbg_hash_instantiate;
353         dctx->reseed = drbg_hash_reseed;
354         dctx->generate = drbg_hash_generate;
355         dctx->uninstantiate = drbg_hash_uninstantiate;
356
357         dctx->d.hash.md = md;
358         EVP_MD_CTX_init(&hctx->mctx);
359
360         /* These are taken from SP 800-90 10.1 table 2 */
361
362         dctx->blocklength = M_EVP_MD_size(md);
363         if (dctx->blocklength > 32)
364                 dctx->seedlen = 111;
365         else
366                 dctx->seedlen = 55;
367
368
369         dctx->min_entropy = dctx->strength / 8;
370         dctx->max_entropy = DRBG_MAX_LENGTH;
371
372         dctx->min_nonce = dctx->min_entropy / 2;
373         dctx->max_nonce = DRBG_MAX_LENGTH;
374
375         dctx->max_pers = DRBG_MAX_LENGTH;
376         dctx->max_adin = DRBG_MAX_LENGTH;
377
378         dctx->max_request = 1<<19;
379         dctx->reseed_interval = 1<<24;
380
381         return 1;
382         }