fips.c revision 296465
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
68static int fips_selftest_fail;
69static int fips_mode;
70static const void *fips_rand_check;
71
72static 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
85static 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
98int 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
113const 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
128int 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
149void FIPS_selftest_check(void)
150{
151    if (fips_selftest_fail) {
152        OpenSSLDie(__FILE__, __LINE__, "FATAL FIPS SELFTEST FAILURE");
153    }
154}
155
156void fips_set_selftest_fail(void)
157{
158    fips_selftest_fail = 1;
159}
160
161int 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
172extern const void *FIPS_text_start(), *FIPS_text_end();
173extern const unsigned char FIPS_rodata_start[], FIPS_rodata_end[];
174unsigned char FIPS_signature[20] = { 0 };
175
176static const char FIPS_hmac_key[] = "etaonrishdlcupfm";
177
178unsigned 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
213int 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
253int 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
339void fips_w_lock(void)
340{
341    CRYPTO_w_lock(CRYPTO_LOCK_FIPS);
342}
343
344void fips_w_unlock(void)
345{
346    CRYPTO_w_unlock(CRYPTO_LOCK_FIPS);
347}
348
349void fips_r_lock(void)
350{
351    CRYPTO_r_lock(CRYPTO_LOCK_FIPS);
352}
353
354void fips_r_unlock(void)
355{
356    CRYPTO_r_unlock(CRYPTO_LOCK_FIPS);
357}
358
359static int fips_started = 0;
360static unsigned long fips_thread = 0;
361
362void fips_set_started(void)
363{
364    fips_started = 1;
365}
366
367int fips_is_started(void)
368{
369    return fips_started;
370}
371
372int 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
385int 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
400int 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
415unsigned 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
429int 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
490int 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 */
517void hash_final(void)
518{
519    FIPSerr(FIPS_F_HASH_FINAL, FIPS_R_NON_FIPS_METHOD);
520}
521# endif
522
523#endif
524