Some changes to support VxWorks in the validted module.
[oweals/openssl.git] / fips / rand / fips_rand.c
1 /* ====================================================================
2  * Copyright (c) 2007 The OpenSSL Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer. 
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by the OpenSSL Project
19  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
20  *
21  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For written permission, please contact
24  *    openssl-core@openssl.org.
25  *
26  * 5. Products derived from this software may not be called "OpenSSL"
27  *    nor may "OpenSSL" appear in their names without prior written
28  *    permission of the OpenSSL Project.
29  *
30  * 6. Redistributions of any form whatsoever must retain the following
31  *    acknowledgment:
32  *    "This product includes software developed by the OpenSSL Project
33  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46  * OF THE POSSIBILITY OF SUCH DAMAGE.
47  *
48  */
49
50 #define OPENSSL_FIPSAPI
51
52 /*
53  * This is a FIPS approved AES PRNG based on ANSI X9.31 A.2.4.
54  */
55 #include <openssl/crypto.h>
56 #include "e_os.h"
57
58 /* If we don't define _XOPEN_SOURCE_EXTENDED, struct timeval won't
59    be defined and gettimeofday() won't be declared with strict compilers
60    like DEC C in ANSI C mode.  */
61 #ifndef _XOPEN_SOURCE_EXTENDED
62 #define _XOPEN_SOURCE_EXTENDED 1
63 #endif
64
65 #include <openssl/rand.h>
66 #include <openssl/aes.h>
67 #include <openssl/err.h>
68 #include <openssl/fips_rand.h>
69 #if !(defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VXWORKS))
70 # include <sys/time.h>
71 #endif
72 #if defined(OPENSSL_SYS_VXWORKS)
73 # include <time.h>
74 #endif
75 #include <assert.h>
76 #ifndef OPENSSL_SYS_WIN32
77 # ifdef OPENSSL_UNISTD
78 #  include OPENSSL_UNISTD
79 # else
80 #  include <unistd.h>
81 # endif
82 #endif
83 #include <string.h>
84 #include <openssl/fips.h>
85 #include "fips_locl.h"
86
87 #ifdef OPENSSL_FIPS
88
89 void *OPENSSL_stderr(void);
90
91 #define AES_BLOCK_LENGTH        16
92
93
94 /* AES FIPS PRNG implementation */
95
96 typedef struct 
97         {
98         int seeded;
99         int keyed;
100         int test_mode;
101         int second;
102         int error;
103         unsigned long counter;
104         AES_KEY ks;
105         int vpos;
106         /* Temporary storage for key if it equals seed length */
107         unsigned char tmp_key[AES_BLOCK_LENGTH];
108         unsigned char V[AES_BLOCK_LENGTH];
109         unsigned char DT[AES_BLOCK_LENGTH];
110         unsigned char last[AES_BLOCK_LENGTH];
111         } FIPS_PRNG_CTX;
112
113 static FIPS_PRNG_CTX sctx;
114
115 static int fips_prng_fail = 0;
116
117 void FIPS_x931_stick(void)
118         {
119         fips_prng_fail = 1;
120         }
121
122 static void fips_rand_prng_reset(FIPS_PRNG_CTX *ctx)
123         {
124         ctx->seeded = 0;
125         ctx->keyed = 0;
126         ctx->test_mode = 0;
127         ctx->counter = 0;
128         ctx->second = 0;
129         ctx->error = 0;
130         ctx->vpos = 0;
131         OPENSSL_cleanse(ctx->V, AES_BLOCK_LENGTH);
132         OPENSSL_cleanse(&ctx->ks, sizeof(AES_KEY));
133         }
134         
135
136 static int fips_set_prng_key(FIPS_PRNG_CTX *ctx,
137                         const unsigned char *key, unsigned int keylen)
138         {
139         FIPS_selftest_check();
140         if (keylen != 16 && keylen != 24 && keylen != 32)
141                 {
142                 /* error: invalid key size */
143                 return 0;
144                 }
145         AES_set_encrypt_key(key, keylen << 3, &ctx->ks);
146         if (keylen == 16)
147                 {
148                 memcpy(ctx->tmp_key, key, 16);
149                 ctx->keyed = 2;
150                 }
151         else
152                 ctx->keyed = 1;
153         ctx->seeded = 0;
154         ctx->second = 0;
155         return 1;
156         }
157
158 static int fips_set_prng_seed(FIPS_PRNG_CTX *ctx,
159                         const unsigned char *seed, unsigned int seedlen)
160         {
161         unsigned int i;
162         if (!ctx->keyed)
163                 return 0;
164         /* In test mode seed is just supplied data */
165         if (ctx->test_mode)
166                 {
167                 if (seedlen != AES_BLOCK_LENGTH)
168                         return 0;
169                 memcpy(ctx->V, seed, AES_BLOCK_LENGTH);
170                 ctx->seeded = 1;
171                 return 1;
172                 }
173         /* Outside test mode XOR supplied data with existing seed */
174         for (i = 0; i < seedlen; i++)
175                 {
176                 ctx->V[ctx->vpos++] ^= seed[i];
177                 if (ctx->vpos == AES_BLOCK_LENGTH)
178                         {
179                         ctx->vpos = 0;
180                         /* Special case if first seed and key length equals
181                          * block size check key and seed do not match.
182                          */ 
183                         if (ctx->keyed == 2)
184                                 {
185                                 if (!memcmp(ctx->tmp_key, ctx->V, 16))
186                                         {
187                                         RANDerr(RAND_F_FIPS_SET_PRNG_SEED,
188                                                 RAND_R_PRNG_SEED_MUST_NOT_MATCH_KEY);
189                                         return 0;
190                                         }
191                                 OPENSSL_cleanse(ctx->tmp_key, 16);
192                                 ctx->keyed = 1;
193                                 }
194                         ctx->seeded = 1;
195                         }
196                 }
197         return 1;
198         }
199
200 static int fips_set_test_mode(FIPS_PRNG_CTX *ctx)
201         {
202         if (ctx->keyed)
203                 {
204                 RANDerr(RAND_F_FIPS_SET_TEST_MODE,RAND_R_PRNG_KEYED);
205                 return 0;
206                 }
207         ctx->test_mode = 1;
208         return 1;
209         }
210
211 int FIPS_x931_test_mode(void)
212         {
213         return fips_set_test_mode(&sctx);
214         }
215
216 int FIPS_x931_set_dt(unsigned char *dt)
217         {
218         if (!sctx.test_mode)
219                 {
220                 RANDerr(RAND_F_FIPS_X931_SET_DT,RAND_R_NOT_IN_TEST_MODE);
221                 return 0;
222                 }
223         memcpy(sctx.DT, dt, AES_BLOCK_LENGTH);
224         return 1;
225         }
226
227 void FIPS_get_timevec(unsigned char *buf, unsigned long *pctr)
228         {
229 #ifdef OPENSSL_SYS_WIN32
230         FILETIME ft;
231 #elif defined(OPENSSL_SYS_VXWORKS)
232         struct timespec ts;
233 #else
234         struct timeval tv;
235 #endif
236
237 #ifndef GETPID_IS_MEANINGLESS
238         unsigned long pid;
239 #endif
240
241 #ifdef OPENSSL_SYS_WIN32
242         GetSystemTimeAsFileTime(&ft);
243         buf[0] = (unsigned char) (ft.dwHighDateTime & 0xff);
244         buf[1] = (unsigned char) ((ft.dwHighDateTime >> 8) & 0xff);
245         buf[2] = (unsigned char) ((ft.dwHighDateTime >> 16) & 0xff);
246         buf[3] = (unsigned char) ((ft.dwHighDateTime >> 24) & 0xff);
247         buf[4] = (unsigned char) (ft.dwLowDateTime & 0xff);
248         buf[5] = (unsigned char) ((ft.dwLowDateTime >> 8) & 0xff);
249         buf[6] = (unsigned char) ((ft.dwLowDateTime >> 16) & 0xff);
250         buf[7] = (unsigned char) ((ft.dwLowDateTime >> 24) & 0xff);
251 #elif defined(OPENSSL_SYS_VXWORKS)
252         clock_gettime(CLOCK_REALTIME, &ts);
253         buf[0] = (unsigned char) (ts.tv_sec & 0xff);
254         buf[1] = (unsigned char) ((ts.tv_sec >> 8) & 0xff);
255         buf[2] = (unsigned char) ((ts.tv_sec >> 16) & 0xff);
256         buf[3] = (unsigned char) ((ts.tv_sec >> 24) & 0xff);
257         buf[4] = (unsigned char) (ts.tv_nsec & 0xff);
258         buf[5] = (unsigned char) ((ts.tv_nsec >> 8) & 0xff);
259         buf[6] = (unsigned char) ((ts.tv_nsec >> 16) & 0xff);
260         buf[7] = (unsigned char) ((ts.tv_nsec >> 24) & 0xff);
261 #else
262         gettimeofday(&tv,NULL);
263         buf[0] = (unsigned char) (tv.tv_sec & 0xff);
264         buf[1] = (unsigned char) ((tv.tv_sec >> 8) & 0xff);
265         buf[2] = (unsigned char) ((tv.tv_sec >> 16) & 0xff);
266         buf[3] = (unsigned char) ((tv.tv_sec >> 24) & 0xff);
267         buf[4] = (unsigned char) (tv.tv_usec & 0xff);
268         buf[5] = (unsigned char) ((tv.tv_usec >> 8) & 0xff);
269         buf[6] = (unsigned char) ((tv.tv_usec >> 16) & 0xff);
270         buf[7] = (unsigned char) ((tv.tv_usec >> 24) & 0xff);
271 #endif
272         buf[8] = (unsigned char) (*pctr & 0xff);
273         buf[9] = (unsigned char) ((*pctr >> 8) & 0xff);
274         buf[10] = (unsigned char) ((*pctr >> 16) & 0xff);
275         buf[11] = (unsigned char) ((*pctr >> 24) & 0xff);
276
277         (*pctr)++;
278
279
280 #ifndef GETPID_IS_MEANINGLESS
281         pid=(unsigned long)getpid();
282         buf[12] = (unsigned char) (pid & 0xff);
283         buf[13] = (unsigned char) ((pid >> 8) & 0xff);
284         buf[14] = (unsigned char) ((pid >> 16) & 0xff);
285         buf[15] = (unsigned char) ((pid >> 24) & 0xff);
286 #endif
287     }
288
289 static int fips_rand(FIPS_PRNG_CTX *ctx,
290                         unsigned char *out, unsigned int outlen)
291         {
292         unsigned char R[AES_BLOCK_LENGTH], I[AES_BLOCK_LENGTH];
293         unsigned char tmp[AES_BLOCK_LENGTH];
294         int i;
295         if (ctx->error)
296                 {
297                 RANDerr(RAND_F_FIPS_RAND,RAND_R_PRNG_ERROR);
298                 return 0;
299                 }
300         if (!ctx->keyed)
301                 {
302                 RANDerr(RAND_F_FIPS_RAND,RAND_R_NO_KEY_SET);
303                 return 0;
304                 }
305         if (!ctx->seeded)
306                 {
307                 RANDerr(RAND_F_FIPS_RAND,RAND_R_PRNG_NOT_SEEDED);
308                 return 0;
309                 }
310         for (;;)
311                 {
312                 if (!ctx->test_mode)
313                         FIPS_get_timevec(ctx->DT, &ctx->counter);
314                 AES_encrypt(ctx->DT, I, &ctx->ks);
315                 for (i = 0; i < AES_BLOCK_LENGTH; i++)
316                         tmp[i] = I[i] ^ ctx->V[i];
317                 AES_encrypt(tmp, R, &ctx->ks);
318                 for (i = 0; i < AES_BLOCK_LENGTH; i++)
319                         tmp[i] = R[i] ^ I[i];
320                 AES_encrypt(tmp, ctx->V, &ctx->ks);
321                 /* Continuous PRNG test */
322                 if (ctx->second)
323                         {
324                         if (fips_prng_fail)
325                                 memcpy(ctx->last, R, AES_BLOCK_LENGTH);
326                         if (!memcmp(R, ctx->last, AES_BLOCK_LENGTH))
327                                 {
328                                 RANDerr(RAND_F_FIPS_RAND,RAND_R_PRNG_STUCK);
329                                 ctx->error = 1;
330                                 fips_set_selftest_fail();
331                                 return 0;
332                                 }
333                         }
334                 memcpy(ctx->last, R, AES_BLOCK_LENGTH);
335                 if (!ctx->second)
336                         {
337                         ctx->second = 1;
338                         if (!ctx->test_mode)
339                                 continue;
340                         }
341
342                 if (outlen <= AES_BLOCK_LENGTH)
343                         {
344                         memcpy(out, R, outlen);
345                         break;
346                         }
347
348                 memcpy(out, R, AES_BLOCK_LENGTH);
349                 out += AES_BLOCK_LENGTH;
350                 outlen -= AES_BLOCK_LENGTH;
351                 }
352         return 1;
353         }
354
355
356 int FIPS_x931_set_key(const unsigned char *key, int keylen)
357         {
358         int ret;
359         CRYPTO_w_lock(CRYPTO_LOCK_RAND);
360         ret = fips_set_prng_key(&sctx, key, keylen);
361         CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
362         return ret;
363         }
364
365 int FIPS_x931_seed(const void *seed, int seedlen)
366         {
367         int ret;
368         CRYPTO_w_lock(CRYPTO_LOCK_RAND);
369         ret = fips_set_prng_seed(&sctx, seed, seedlen);
370         CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
371         return ret;
372         }
373
374
375 int FIPS_x931_bytes(unsigned char *out, int count)
376         {
377         int ret;
378         CRYPTO_w_lock(CRYPTO_LOCK_RAND);
379         ret = fips_rand(&sctx, out, count);
380         CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
381         return ret;
382         }
383
384 int FIPS_x931_status(void)
385         {
386         int ret;
387         CRYPTO_r_lock(CRYPTO_LOCK_RAND);
388         ret = sctx.seeded;
389         CRYPTO_r_unlock(CRYPTO_LOCK_RAND);
390         return ret;
391         }
392
393 void FIPS_x931_reset(void)
394         {
395         CRYPTO_w_lock(CRYPTO_LOCK_RAND);
396         fips_rand_prng_reset(&sctx);
397         CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
398         }
399
400 static int fips_do_rand_seed(const void *seed, int seedlen)
401         {
402         FIPS_x931_seed(seed, seedlen);
403         return 1;
404         }
405
406 static int fips_do_rand_add(const void *seed, int seedlen,
407                                         double add_entropy)
408         {
409         FIPS_x931_seed(seed, seedlen);
410         return 1;
411         }
412
413 static const RAND_METHOD rand_x931_meth=
414     {
415     fips_do_rand_seed,
416     FIPS_x931_bytes,
417     FIPS_x931_reset,
418     fips_do_rand_add,
419     FIPS_x931_bytes,
420     FIPS_x931_status
421     };
422
423 const RAND_METHOD *FIPS_x931_method(void)
424 {
425   return &rand_x931_meth;
426 }
427
428 #endif