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