OLD | NEW |
| (Empty) |
1 /* ==================================================================== | |
2 * Copyright (c) 2003 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 #include <openssl/rand.h> | |
52 #include <openssl/fips_rand.h> | |
53 #include <openssl/err.h> | |
54 #include <openssl/bio.h> | |
55 #include <openssl/hmac.h> | |
56 #include <openssl/rsa.h> | |
57 #include <string.h> | |
58 #include <limits.h> | |
59 #include "fips_locl.h" | |
60 | |
61 #ifdef OPENSSL_FIPS | |
62 | |
63 #include <openssl/fips.h> | |
64 | |
65 #ifndef PATH_MAX | |
66 #define PATH_MAX 1024 | |
67 #endif | |
68 | |
69 static int fips_selftest_fail; | |
70 static int fips_mode; | |
71 static const void *fips_rand_check; | |
72 | |
73 static void fips_set_mode(int onoff) | |
74 { | |
75 int owning_thread = fips_is_owning_thread(); | |
76 | |
77 if (fips_is_started()) | |
78 { | |
79 if (!owning_thread) fips_w_lock(); | |
80 fips_mode = onoff; | |
81 if (!owning_thread) fips_w_unlock(); | |
82 } | |
83 } | |
84 | |
85 static void fips_set_rand_check(const void *rand_check) | |
86 { | |
87 int owning_thread = fips_is_owning_thread(); | |
88 | |
89 if (fips_is_started()) | |
90 { | |
91 if (!owning_thread) fips_w_lock(); | |
92 fips_rand_check = rand_check; | |
93 if (!owning_thread) fips_w_unlock(); | |
94 } | |
95 } | |
96 | |
97 int FIPS_mode(void) | |
98 { | |
99 int ret = 0; | |
100 int owning_thread = fips_is_owning_thread(); | |
101 | |
102 if (fips_is_started()) | |
103 { | |
104 if (!owning_thread) fips_r_lock(); | |
105 ret = fips_mode; | |
106 if (!owning_thread) fips_r_unlock(); | |
107 } | |
108 return ret; | |
109 } | |
110 | |
111 const void *FIPS_rand_check(void) | |
112 { | |
113 const void *ret = 0; | |
114 int owning_thread = fips_is_owning_thread(); | |
115 | |
116 if (fips_is_started()) | |
117 { | |
118 if (!owning_thread) fips_r_lock(); | |
119 ret = fips_rand_check; | |
120 if (!owning_thread) fips_r_unlock(); | |
121 } | |
122 return ret; | |
123 } | |
124 | |
125 int FIPS_selftest_failed(void) | |
126 { | |
127 int ret = 0; | |
128 if (fips_is_started()) | |
129 { | |
130 int owning_thread = fips_is_owning_thread(); | |
131 | |
132 if (!owning_thread) fips_r_lock(); | |
133 ret = fips_selftest_fail; | |
134 if (!owning_thread) fips_r_unlock(); | |
135 } | |
136 return ret; | |
137 } | |
138 | |
139 /* Selftest failure fatal exit routine. This will be called | |
140 * during *any* cryptographic operation. It has the minimum | |
141 * overhead possible to avoid too big a performance hit. | |
142 */ | |
143 | |
144 void FIPS_selftest_check(void) | |
145 { | |
146 if (fips_selftest_fail) | |
147 { | |
148 OpenSSLDie(__FILE__,__LINE__, "FATAL FIPS SELFTEST FAILURE"); | |
149 } | |
150 } | |
151 | |
152 void fips_set_selftest_fail(void) | |
153 { | |
154 fips_selftest_fail = 1; | |
155 } | |
156 | |
157 int FIPS_selftest() | |
158 { | |
159 | |
160 return FIPS_selftest_sha1() | |
161 && FIPS_selftest_hmac() | |
162 && FIPS_selftest_aes() | |
163 && FIPS_selftest_des() | |
164 && FIPS_selftest_rsa() | |
165 && FIPS_selftest_dsa(); | |
166 } | |
167 | |
168 extern const void *FIPS_text_start(), *FIPS_text_end(); | |
169 extern const unsigned char FIPS_rodata_start[], FIPS_rodata_end[]; | |
170 unsigned char FIPS_signature [20] = { 0 }; | |
171 static const char FIPS_hmac_key[]="etaonrishdlcupfm"; | |
172 | |
173 unsigned int FIPS_incore_fingerprint(unsigned char *sig,unsigned int len) | |
174 { | |
175 const unsigned char *p1 = FIPS_text_start(); | |
176 const unsigned char *p2 = FIPS_text_end(); | |
177 const unsigned char *p3 = FIPS_rodata_start; | |
178 const unsigned char *p4 = FIPS_rodata_end; | |
179 HMAC_CTX c; | |
180 | |
181 HMAC_CTX_init(&c); | |
182 HMAC_Init(&c,FIPS_hmac_key,strlen(FIPS_hmac_key),EVP_sha1()); | |
183 | |
184 /* detect overlapping regions */ | |
185 if (p1<=p3 && p2>=p3) | |
186 p3=p1, p4=p2>p4?p2:p4, p1=NULL, p2=NULL; | |
187 else if (p3<=p1 && p4>=p1) | |
188 p3=p3, p4=p2>p4?p2:p4, p1=NULL, p2=NULL; | |
189 | |
190 if (p1) | |
191 HMAC_Update(&c,p1,(size_t)p2-(size_t)p1); | |
192 | |
193 if (FIPS_signature>=p3 && FIPS_signature<p4) | |
194 { | |
195 /* "punch" hole */ | |
196 HMAC_Update(&c,p3,(size_t)FIPS_signature-(size_t)p3); | |
197 p3 = FIPS_signature+sizeof(FIPS_signature); | |
198 if (p3<p4) | |
199 HMAC_Update(&c,p3,(size_t)p4-(size_t)p3); | |
200 } | |
201 else | |
202 HMAC_Update(&c,p3,(size_t)p4-(size_t)p3); | |
203 | |
204 HMAC_Final(&c,sig,&len); | |
205 HMAC_CTX_cleanup(&c); | |
206 | |
207 return len; | |
208 } | |
209 | |
210 int FIPS_check_incore_fingerprint(void) | |
211 { | |
212 unsigned char sig[EVP_MAX_MD_SIZE]; | |
213 unsigned int len; | |
214 #if defined(__sgi) && (defined(__mips) || defined(mips)) | |
215 extern int __dso_displacement[]; | |
216 #else | |
217 extern int OPENSSL_NONPIC_relocated; | |
218 #endif | |
219 | |
220 if (FIPS_text_start()==NULL) | |
221 { | |
222 FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_UNSUPPORTED_PLATFORM
); | |
223 return 0; | |
224 } | |
225 | |
226 len=FIPS_incore_fingerprint (sig,sizeof(sig)); | |
227 | |
228 if (len!=sizeof(FIPS_signature) || | |
229 memcmp(FIPS_signature,sig,sizeof(FIPS_signature))) | |
230 { | |
231 if (FIPS_signature>=FIPS_rodata_start && FIPS_signature<FIPS_rodata_end) | |
232 FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_FINGERPRINT_DOES
_NOT_MATCH_SEGMENT_ALIASING); | |
233 #if defined(__sgi) && (defined(__mips) || defined(mips)) | |
234 else if (__dso_displacement!=NULL) | |
235 #else | |
236 else if (OPENSSL_NONPIC_relocated) | |
237 #endif | |
238 FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_FINGERPRINT_DOES
_NOT_MATCH_NONPIC_RELOCATED); | |
239 else | |
240 FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_FINGERPRINT_DOES
_NOT_MATCH); | |
241 return 0; | |
242 } | |
243 | |
244 return 1; | |
245 } | |
246 | |
247 int FIPS_mode_set(int onoff) | |
248 { | |
249 int fips_set_owning_thread(); | |
250 int fips_clear_owning_thread(); | |
251 int ret = 0; | |
252 | |
253 fips_w_lock(); | |
254 fips_set_started(); | |
255 fips_set_owning_thread(); | |
256 | |
257 if(onoff) | |
258 { | |
259 unsigned char buf[48]; | |
260 | |
261 fips_selftest_fail = 0; | |
262 | |
263 /* Don't go into FIPS mode twice, just so we can do automagic | |
264 seeding */ | |
265 if(FIPS_mode()) | |
266 { | |
267 FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_FIPS_MODE_ALREADY_SET); | |
268 fips_selftest_fail = 1; | |
269 ret = 0; | |
270 goto end; | |
271 } | |
272 | |
273 #ifdef OPENSSL_IA32_SSE2 | |
274 if ((OPENSSL_ia32cap & (1<<25|1<<26)) != (1<<25|1<<26)) | |
275 { | |
276 FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_UNSUPPORTED_PLATFORM); | |
277 fips_selftest_fail = 1; | |
278 ret = 0; | |
279 goto end; | |
280 } | |
281 #endif | |
282 | |
283 if(fips_signature_witness() != FIPS_signature) | |
284 { | |
285 FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_CONTRADICTING_EVIDENCE); | |
286 fips_selftest_fail = 1; | |
287 ret = 0; | |
288 goto end; | |
289 } | |
290 | |
291 if(!FIPS_check_incore_fingerprint()) | |
292 { | |
293 fips_selftest_fail = 1; | |
294 ret = 0; | |
295 goto end; | |
296 } | |
297 | |
298 /* Perform RNG KAT before seeding */ | |
299 if (!FIPS_selftest_rng()) | |
300 { | |
301 fips_selftest_fail = 1; | |
302 ret = 0; | |
303 goto end; | |
304 } | |
305 | |
306 /* automagically seed PRNG if not already seeded */ | |
307 if(!FIPS_rand_status()) | |
308 { | |
309 if(RAND_bytes(buf,sizeof buf) <= 0) | |
310 { | |
311 fips_selftest_fail = 1; | |
312 ret = 0; | |
313 goto end; | |
314 } | |
315 FIPS_rand_set_key(buf,32); | |
316 FIPS_rand_seed(buf+32,16); | |
317 } | |
318 | |
319 /* now switch into FIPS mode */ | |
320 fips_set_rand_check(FIPS_rand_method()); | |
321 RAND_set_rand_method(FIPS_rand_method()); | |
322 if(FIPS_selftest()) | |
323 fips_set_mode(1); | |
324 else | |
325 { | |
326 fips_selftest_fail = 1; | |
327 ret = 0; | |
328 goto end; | |
329 } | |
330 ret = 1; | |
331 goto end; | |
332 } | |
333 fips_set_mode(0); | |
334 fips_selftest_fail = 0; | |
335 ret = 1; | |
336 end: | |
337 fips_clear_owning_thread(); | |
338 fips_w_unlock(); | |
339 return ret; | |
340 } | |
341 | |
342 void fips_w_lock(void) { CRYPTO_w_lock(CRYPTO_LOCK_FIPS); } | |
343 void fips_w_unlock(void) { CRYPTO_w_unlock(CRYPTO_LOCK_FIPS); } | |
344 void fips_r_lock(void) { CRYPTO_r_lock(CRYPTO_LOCK_FIPS); } | |
345 void fips_r_unlock(void) { CRYPTO_r_unlock(CRYPTO_LOCK_FIPS); } | |
346 | |
347 static int fips_started = 0; | |
348 static unsigned long fips_thread = 0; | |
349 | |
350 void fips_set_started(void) | |
351 { | |
352 fips_started = 1; | |
353 } | |
354 | |
355 int fips_is_started(void) | |
356 { | |
357 return fips_started; | |
358 } | |
359 | |
360 int fips_is_owning_thread(void) | |
361 { | |
362 int ret = 0; | |
363 | |
364 if (fips_is_started()) | |
365 { | |
366 CRYPTO_r_lock(CRYPTO_LOCK_FIPS2); | |
367 if (fips_thread != 0 && fips_thread == CRYPTO_thread_id()) | |
368 ret = 1; | |
369 CRYPTO_r_unlock(CRYPTO_LOCK_FIPS2); | |
370 } | |
371 return ret; | |
372 } | |
373 | |
374 int fips_set_owning_thread(void) | |
375 { | |
376 int ret = 0; | |
377 | |
378 if (fips_is_started()) | |
379 { | |
380 CRYPTO_w_lock(CRYPTO_LOCK_FIPS2); | |
381 if (fips_thread == 0) | |
382 { | |
383 fips_thread = CRYPTO_thread_id(); | |
384 ret = 1; | |
385 } | |
386 CRYPTO_w_unlock(CRYPTO_LOCK_FIPS2); | |
387 } | |
388 return ret; | |
389 } | |
390 | |
391 int fips_clear_owning_thread(void) | |
392 { | |
393 int ret = 0; | |
394 | |
395 if (fips_is_started()) | |
396 { | |
397 CRYPTO_w_lock(CRYPTO_LOCK_FIPS2); | |
398 if (fips_thread == CRYPTO_thread_id()) | |
399 { | |
400 fips_thread = 0; | |
401 ret = 1; | |
402 } | |
403 CRYPTO_w_unlock(CRYPTO_LOCK_FIPS2); | |
404 } | |
405 return ret; | |
406 } | |
407 | |
408 unsigned char *fips_signature_witness(void) | |
409 { | |
410 extern unsigned char FIPS_signature[]; | |
411 return FIPS_signature; | |
412 } | |
413 | |
414 /* Generalized public key test routine. Signs and verifies the data | |
415 * supplied in tbs using mesage digest md and setting option digest | |
416 * flags md_flags. If the 'kat' parameter is not NULL it will | |
417 * additionally check the signature matches it: a known answer test | |
418 * The string "fail_str" is used for identification purposes in case | |
419 * of failure. | |
420 */ | |
421 | |
422 int fips_pkey_signature_test(EVP_PKEY *pkey, | |
423 const unsigned char *tbs, int tbslen, | |
424 const unsigned char *kat, unsigned int katlen, | |
425 const EVP_MD *digest, unsigned int md_flags, | |
426 const char *fail_str) | |
427 { | |
428 int ret = 0; | |
429 unsigned char sigtmp[256], *sig = sigtmp; | |
430 unsigned int siglen; | |
431 EVP_MD_CTX mctx; | |
432 EVP_MD_CTX_init(&mctx); | |
433 | |
434 if ((pkey->type == EVP_PKEY_RSA) | |
435 && (RSA_size(pkey->pkey.rsa) > sizeof(sigtmp))) | |
436 { | |
437 sig = OPENSSL_malloc(RSA_size(pkey->pkey.rsa)); | |
438 if (!sig) | |
439 { | |
440 FIPSerr(FIPS_F_FIPS_PKEY_SIGNATURE_TEST,ERR_R_MALLOC_FAI
LURE); | |
441 return 0; | |
442 } | |
443 } | |
444 | |
445 if (tbslen == -1) | |
446 tbslen = strlen((char *)tbs); | |
447 | |
448 if (md_flags) | |
449 M_EVP_MD_CTX_set_flags(&mctx, md_flags); | |
450 | |
451 if (!EVP_SignInit_ex(&mctx, digest, NULL)) | |
452 goto error; | |
453 if (!EVP_SignUpdate(&mctx, tbs, tbslen)) | |
454 goto error; | |
455 if (!EVP_SignFinal(&mctx, sig, &siglen, pkey)) | |
456 goto error; | |
457 | |
458 if (kat && ((siglen != katlen) || memcmp(kat, sig, katlen))) | |
459 goto error; | |
460 | |
461 if (!EVP_VerifyInit_ex(&mctx, digest, NULL)) | |
462 goto error; | |
463 if (!EVP_VerifyUpdate(&mctx, tbs, tbslen)) | |
464 goto error; | |
465 ret = EVP_VerifyFinal(&mctx, sig, siglen, pkey); | |
466 | |
467 error: | |
468 if (sig != sigtmp) | |
469 OPENSSL_free(sig); | |
470 EVP_MD_CTX_cleanup(&mctx); | |
471 if (ret != 1) | |
472 { | |
473 FIPSerr(FIPS_F_FIPS_PKEY_SIGNATURE_TEST,FIPS_R_TEST_FAILURE); | |
474 if (fail_str) | |
475 ERR_add_error_data(2, "Type=", fail_str); | |
476 return 0; | |
477 } | |
478 return 1; | |
479 } | |
480 | |
481 /* Generalized symmetric cipher test routine. Encrypt data, verify result | |
482 * against known answer, decrypt and compare with original plaintext. | |
483 */ | |
484 | |
485 int fips_cipher_test(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, | |
486 const unsigned char *key, | |
487 const unsigned char *iv, | |
488 const unsigned char *plaintext, | |
489 const unsigned char *ciphertext, | |
490 int len) | |
491 { | |
492 unsigned char pltmp[FIPS_MAX_CIPHER_TEST_SIZE]; | |
493 unsigned char citmp[FIPS_MAX_CIPHER_TEST_SIZE]; | |
494 OPENSSL_assert(len <= FIPS_MAX_CIPHER_TEST_SIZE); | |
495 if (EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 1) <= 0) | |
496 return 0; | |
497 EVP_Cipher(ctx, citmp, plaintext, len); | |
498 if (memcmp(citmp, ciphertext, len)) | |
499 return 0; | |
500 if (EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 0) <= 0) | |
501 return 0; | |
502 EVP_Cipher(ctx, pltmp, citmp, len); | |
503 if (memcmp(pltmp, plaintext, len)) | |
504 return 0; | |
505 return 1; | |
506 } | |
507 | |
508 #if 0 | |
509 /* The purpose of this is to ensure the error code exists and the function | |
510 * name is to keep the error checking script quiet | |
511 */ | |
512 void hash_final(void) | |
513 { | |
514 FIPSerr(FIPS_F_HASH_FINAL,FIPS_R_NON_FIPS_METHOD); | |
515 } | |
516 #endif | |
517 | |
518 | |
519 #endif | |
OLD | NEW |