OLD | NEW |
| (Empty) |
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 /* | |
51 * This is a FIPS approved AES PRNG based on ANSI X9.31 A.2.4. | |
52 */ | |
53 | |
54 #include "e_os.h" | |
55 | |
56 /* If we don't define _XOPEN_SOURCE_EXTENDED, struct timeval won't | |
57 be defined and gettimeofday() won't be declared with strict compilers | |
58 like DEC C in ANSI C mode. */ | |
59 #ifndef _XOPEN_SOURCE_EXTENDED | |
60 #define _XOPEN_SOURCE_EXTENDED 1 | |
61 #endif | |
62 | |
63 #include <openssl/rand.h> | |
64 #include <openssl/aes.h> | |
65 #include <openssl/err.h> | |
66 #include <openssl/fips_rand.h> | |
67 #ifndef OPENSSL_SYS_WIN32 | |
68 #include <sys/time.h> | |
69 #endif | |
70 #include <assert.h> | |
71 #ifndef OPENSSL_SYS_WIN32 | |
72 # ifdef OPENSSL_UNISTD | |
73 # include OPENSSL_UNISTD | |
74 # else | |
75 # include <unistd.h> | |
76 # endif | |
77 #endif | |
78 #include <string.h> | |
79 #include <openssl/fips.h> | |
80 #include "fips_locl.h" | |
81 | |
82 #ifdef OPENSSL_FIPS | |
83 | |
84 void *OPENSSL_stderr(void); | |
85 | |
86 #define AES_BLOCK_LENGTH 16 | |
87 | |
88 | |
89 /* AES FIPS PRNG implementation */ | |
90 | |
91 typedef struct | |
92 { | |
93 int seeded; | |
94 int keyed; | |
95 int test_mode; | |
96 int second; | |
97 int error; | |
98 unsigned long counter; | |
99 AES_KEY ks; | |
100 int vpos; | |
101 /* Temporary storage for key if it equals seed length */ | |
102 unsigned char tmp_key[AES_BLOCK_LENGTH]; | |
103 unsigned char V[AES_BLOCK_LENGTH]; | |
104 unsigned char DT[AES_BLOCK_LENGTH]; | |
105 unsigned char last[AES_BLOCK_LENGTH]; | |
106 } FIPS_PRNG_CTX; | |
107 | |
108 static FIPS_PRNG_CTX sctx; | |
109 | |
110 static int fips_prng_fail = 0; | |
111 | |
112 void FIPS_rng_stick(void) | |
113 { | |
114 fips_prng_fail = 1; | |
115 } | |
116 | |
117 static void fips_rand_prng_reset(FIPS_PRNG_CTX *ctx) | |
118 { | |
119 ctx->seeded = 0; | |
120 ctx->keyed = 0; | |
121 ctx->test_mode = 0; | |
122 ctx->counter = 0; | |
123 ctx->second = 0; | |
124 ctx->error = 0; | |
125 ctx->vpos = 0; | |
126 OPENSSL_cleanse(ctx->V, AES_BLOCK_LENGTH); | |
127 OPENSSL_cleanse(&ctx->ks, sizeof(AES_KEY)); | |
128 } | |
129 | |
130 | |
131 static int fips_set_prng_key(FIPS_PRNG_CTX *ctx, | |
132 const unsigned char *key, FIPS_RAND_SIZE_T keylen) | |
133 { | |
134 FIPS_selftest_check(); | |
135 if (keylen != 16 && keylen != 24 && keylen != 32) | |
136 { | |
137 /* error: invalid key size */ | |
138 return 0; | |
139 } | |
140 AES_set_encrypt_key(key, keylen << 3, &ctx->ks); | |
141 if (keylen == 16) | |
142 { | |
143 memcpy(ctx->tmp_key, key, 16); | |
144 ctx->keyed = 2; | |
145 } | |
146 else | |
147 ctx->keyed = 1; | |
148 ctx->seeded = 0; | |
149 ctx->second = 0; | |
150 return 1; | |
151 } | |
152 | |
153 static int fips_set_prng_seed(FIPS_PRNG_CTX *ctx, | |
154 const unsigned char *seed, FIPS_RAND_SIZE_T seedlen) | |
155 { | |
156 int i; | |
157 if (!ctx->keyed) | |
158 return 0; | |
159 /* In test mode seed is just supplied data */ | |
160 if (ctx->test_mode) | |
161 { | |
162 if (seedlen != AES_BLOCK_LENGTH) | |
163 return 0; | |
164 memcpy(ctx->V, seed, AES_BLOCK_LENGTH); | |
165 ctx->seeded = 1; | |
166 return 1; | |
167 } | |
168 /* Outside test mode XOR supplied data with existing seed */ | |
169 for (i = 0; i < seedlen; i++) | |
170 { | |
171 ctx->V[ctx->vpos++] ^= seed[i]; | |
172 if (ctx->vpos == AES_BLOCK_LENGTH) | |
173 { | |
174 ctx->vpos = 0; | |
175 /* Special case if first seed and key length equals | |
176 * block size check key and seed do not match. | |
177 */ | |
178 if (ctx->keyed == 2) | |
179 { | |
180 if (!memcmp(ctx->tmp_key, ctx->V, 16)) | |
181 { | |
182 RANDerr(RAND_F_FIPS_SET_PRNG_SEED, | |
183 RAND_R_PRNG_SEED_MUST_NOT_MATCH_
KEY); | |
184 return 0; | |
185 } | |
186 OPENSSL_cleanse(ctx->tmp_key, 16); | |
187 ctx->keyed = 1; | |
188 } | |
189 ctx->seeded = 1; | |
190 } | |
191 } | |
192 return 1; | |
193 } | |
194 | |
195 static int fips_set_test_mode(FIPS_PRNG_CTX *ctx) | |
196 { | |
197 if (ctx->keyed) | |
198 { | |
199 RANDerr(RAND_F_FIPS_SET_TEST_MODE,RAND_R_PRNG_KEYED); | |
200 return 0; | |
201 } | |
202 ctx->test_mode = 1; | |
203 return 1; | |
204 } | |
205 | |
206 int FIPS_rand_test_mode(void) | |
207 { | |
208 return fips_set_test_mode(&sctx); | |
209 } | |
210 | |
211 int FIPS_rand_set_dt(unsigned char *dt) | |
212 { | |
213 if (!sctx.test_mode) | |
214 { | |
215 RANDerr(RAND_F_FIPS_RAND_SET_DT,RAND_R_NOT_IN_TEST_MODE); | |
216 return 0; | |
217 } | |
218 memcpy(sctx.DT, dt, AES_BLOCK_LENGTH); | |
219 return 1; | |
220 } | |
221 | |
222 static void fips_get_dt(FIPS_PRNG_CTX *ctx) | |
223 { | |
224 #ifdef OPENSSL_SYS_WIN32 | |
225 FILETIME ft; | |
226 #else | |
227 struct timeval tv; | |
228 #endif | |
229 unsigned char *buf = ctx->DT; | |
230 | |
231 #ifndef GETPID_IS_MEANINGLESS | |
232 unsigned long pid; | |
233 #endif | |
234 | |
235 #ifdef OPENSSL_SYS_WIN32 | |
236 GetSystemTimeAsFileTime(&ft); | |
237 buf[0] = (unsigned char) (ft.dwHighDateTime & 0xff); | |
238 buf[1] = (unsigned char) ((ft.dwHighDateTime >> 8) & 0xff); | |
239 buf[2] = (unsigned char) ((ft.dwHighDateTime >> 16) & 0xff); | |
240 buf[3] = (unsigned char) ((ft.dwHighDateTime >> 24) & 0xff); | |
241 buf[4] = (unsigned char) (ft.dwLowDateTime & 0xff); | |
242 buf[5] = (unsigned char) ((ft.dwLowDateTime >> 8) & 0xff); | |
243 buf[6] = (unsigned char) ((ft.dwLowDateTime >> 16) & 0xff); | |
244 buf[7] = (unsigned char) ((ft.dwLowDateTime >> 24) & 0xff); | |
245 #else | |
246 gettimeofday(&tv,NULL); | |
247 buf[0] = (unsigned char) (tv.tv_sec & 0xff); | |
248 buf[1] = (unsigned char) ((tv.tv_sec >> 8) & 0xff); | |
249 buf[2] = (unsigned char) ((tv.tv_sec >> 16) & 0xff); | |
250 buf[3] = (unsigned char) ((tv.tv_sec >> 24) & 0xff); | |
251 buf[4] = (unsigned char) (tv.tv_usec & 0xff); | |
252 buf[5] = (unsigned char) ((tv.tv_usec >> 8) & 0xff); | |
253 buf[6] = (unsigned char) ((tv.tv_usec >> 16) & 0xff); | |
254 buf[7] = (unsigned char) ((tv.tv_usec >> 24) & 0xff); | |
255 #endif | |
256 buf[8] = (unsigned char) (ctx->counter & 0xff); | |
257 buf[9] = (unsigned char) ((ctx->counter >> 8) & 0xff); | |
258 buf[10] = (unsigned char) ((ctx->counter >> 16) & 0xff); | |
259 buf[11] = (unsigned char) ((ctx->counter >> 24) & 0xff); | |
260 | |
261 ctx->counter++; | |
262 | |
263 | |
264 #ifndef GETPID_IS_MEANINGLESS | |
265 pid=(unsigned long)getpid(); | |
266 buf[12] = (unsigned char) (pid & 0xff); | |
267 buf[13] = (unsigned char) ((pid >> 8) & 0xff); | |
268 buf[14] = (unsigned char) ((pid >> 16) & 0xff); | |
269 buf[15] = (unsigned char) ((pid >> 24) & 0xff); | |
270 #endif | |
271 } | |
272 | |
273 static int fips_rand(FIPS_PRNG_CTX *ctx, | |
274 unsigned char *out, FIPS_RAND_SIZE_T outlen) | |
275 { | |
276 unsigned char R[AES_BLOCK_LENGTH], I[AES_BLOCK_LENGTH]; | |
277 unsigned char tmp[AES_BLOCK_LENGTH]; | |
278 int i; | |
279 if (ctx->error) | |
280 { | |
281 RANDerr(RAND_F_FIPS_RAND,RAND_R_PRNG_ERROR); | |
282 return 0; | |
283 } | |
284 if (!ctx->keyed) | |
285 { | |
286 RANDerr(RAND_F_FIPS_RAND,RAND_R_NO_KEY_SET); | |
287 return 0; | |
288 } | |
289 if (!ctx->seeded) | |
290 { | |
291 RANDerr(RAND_F_FIPS_RAND,RAND_R_PRNG_NOT_SEEDED); | |
292 return 0; | |
293 } | |
294 for (;;) | |
295 { | |
296 if (!ctx->test_mode) | |
297 fips_get_dt(ctx); | |
298 AES_encrypt(ctx->DT, I, &ctx->ks); | |
299 for (i = 0; i < AES_BLOCK_LENGTH; i++) | |
300 tmp[i] = I[i] ^ ctx->V[i]; | |
301 AES_encrypt(tmp, R, &ctx->ks); | |
302 for (i = 0; i < AES_BLOCK_LENGTH; i++) | |
303 tmp[i] = R[i] ^ I[i]; | |
304 AES_encrypt(tmp, ctx->V, &ctx->ks); | |
305 /* Continuous PRNG test */ | |
306 if (ctx->second) | |
307 { | |
308 if (fips_prng_fail) | |
309 memcpy(ctx->last, R, AES_BLOCK_LENGTH); | |
310 if (!memcmp(R, ctx->last, AES_BLOCK_LENGTH)) | |
311 { | |
312 RANDerr(RAND_F_FIPS_RAND,RAND_R_PRNG_STUCK); | |
313 ctx->error = 1; | |
314 fips_set_selftest_fail(); | |
315 return 0; | |
316 } | |
317 } | |
318 memcpy(ctx->last, R, AES_BLOCK_LENGTH); | |
319 if (!ctx->second) | |
320 { | |
321 ctx->second = 1; | |
322 if (!ctx->test_mode) | |
323 continue; | |
324 } | |
325 | |
326 if (outlen <= AES_BLOCK_LENGTH) | |
327 { | |
328 memcpy(out, R, outlen); | |
329 break; | |
330 } | |
331 | |
332 memcpy(out, R, AES_BLOCK_LENGTH); | |
333 out += AES_BLOCK_LENGTH; | |
334 outlen -= AES_BLOCK_LENGTH; | |
335 } | |
336 return 1; | |
337 } | |
338 | |
339 | |
340 int FIPS_rand_set_key(const unsigned char *key, FIPS_RAND_SIZE_T keylen) | |
341 { | |
342 int ret; | |
343 CRYPTO_w_lock(CRYPTO_LOCK_RAND); | |
344 ret = fips_set_prng_key(&sctx, key, keylen); | |
345 CRYPTO_w_unlock(CRYPTO_LOCK_RAND); | |
346 return ret; | |
347 } | |
348 | |
349 int FIPS_rand_seed(const void *seed, FIPS_RAND_SIZE_T seedlen) | |
350 { | |
351 int ret; | |
352 CRYPTO_w_lock(CRYPTO_LOCK_RAND); | |
353 ret = fips_set_prng_seed(&sctx, seed, seedlen); | |
354 CRYPTO_w_unlock(CRYPTO_LOCK_RAND); | |
355 return ret; | |
356 } | |
357 | |
358 | |
359 int FIPS_rand_bytes(unsigned char *out, FIPS_RAND_SIZE_T count) | |
360 { | |
361 int ret; | |
362 CRYPTO_w_lock(CRYPTO_LOCK_RAND); | |
363 ret = fips_rand(&sctx, out, count); | |
364 CRYPTO_w_unlock(CRYPTO_LOCK_RAND); | |
365 return ret; | |
366 } | |
367 | |
368 int FIPS_rand_status(void) | |
369 { | |
370 int ret; | |
371 CRYPTO_r_lock(CRYPTO_LOCK_RAND); | |
372 ret = sctx.seeded; | |
373 CRYPTO_r_unlock(CRYPTO_LOCK_RAND); | |
374 return ret; | |
375 } | |
376 | |
377 void FIPS_rand_reset(void) | |
378 { | |
379 CRYPTO_w_lock(CRYPTO_LOCK_RAND); | |
380 fips_rand_prng_reset(&sctx); | |
381 CRYPTO_w_unlock(CRYPTO_LOCK_RAND); | |
382 } | |
383 | |
384 static void fips_do_rand_seed(const void *seed, FIPS_RAND_SIZE_T seedlen) | |
385 { | |
386 FIPS_rand_seed(seed, seedlen); | |
387 } | |
388 | |
389 static void fips_do_rand_add(const void *seed, FIPS_RAND_SIZE_T seedlen, | |
390 double add_entropy) | |
391 { | |
392 FIPS_rand_seed(seed, seedlen); | |
393 } | |
394 | |
395 static const RAND_METHOD rand_fips_meth= | |
396 { | |
397 fips_do_rand_seed, | |
398 FIPS_rand_bytes, | |
399 FIPS_rand_reset, | |
400 fips_do_rand_add, | |
401 FIPS_rand_bytes, | |
402 FIPS_rand_status | |
403 }; | |
404 | |
405 const RAND_METHOD *FIPS_rand_method(void) | |
406 { | |
407 return &rand_fips_meth; | |
408 } | |
409 | |
410 #endif | |
OLD | NEW |