From ac892b7aa6532e0345e430208335403ead5d2de1 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Thu, 14 Apr 2011 11:15:10 +0000 Subject: [PATCH] Initial incomplete POST overhaul: add support for POST callback to allow status of POST to be monitored and/or failures induced. --- CHANGES | 5 + crypto/dsa/dsa_key.c | 3 +- crypto/ec/ec_key.c | 3 +- crypto/evp/evp.h | 1 + crypto/rsa/rsa_gen.c | 6 +- fips/Makefile | 4 +- fips/aes/fips_aes_selftest.c | 2 +- fips/des/fips_des_selftest.c | 2 +- fips/dsa/fips_dsa_selftest.c | 2 +- fips/ecdsa/fips_ecdsa_selftest.c | 2 +- fips/fips.c | 206 ++--------------- fips/fips.h | 73 ++++-- fips/fips_locl.h | 8 + fips/fips_post.c | 379 +++++++++++++++++++++++++++++++ fips/fips_test_suite.c | 197 ++++++++++++++-- fips/rsa/fips_rsa_selftest.c | 3 +- fips/sha/fips_sha1_selftest.c | 31 ++- 17 files changed, 681 insertions(+), 246 deletions(-) create mode 100644 fips/fips_post.c diff --git a/CHANGES b/CHANGES index 877976c23a..70d2382e16 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,11 @@ Changes between 1.0.1 and 1.1.0 [xx XXX xxxx] + *) Initial version of POST overhaul. Add POST callback to allow the status + of POST to be monitored and/or failures induced. Modify fips_test_suite + to use callback. Always run all selftests even if one fails. + [Steve Henson] + *) Provisional XTS support. Note: this does increase the maximum key length from 32 to 64 bytes but there should be no binary compatibility issues as existing applications will never use XTS mode. diff --git a/crypto/dsa/dsa_key.c b/crypto/dsa/dsa_key.c index fa4fb09c31..39cf6b790d 100644 --- a/crypto/dsa/dsa_key.c +++ b/crypto/dsa/dsa_key.c @@ -85,7 +85,8 @@ static int fips_check_dsa(DSA *dsa) pk.type = EVP_PKEY_DSA; pk.pkey.dsa = dsa; - if (!fips_pkey_signature_test(&pk, tbs, -1, NULL, 0, NULL, 0, NULL)) + if (!fips_pkey_signature_test(FIPS_TEST_PAIRWISE, + &pk, tbs, -1, NULL, 0, NULL, 0, NULL)) { FIPSerr(FIPS_F_FIPS_CHECK_DSA,FIPS_R_PAIRWISE_TEST_FAILED); fips_set_selftest_fail(); diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c index 1615ec8a5a..1f048948e2 100644 --- a/crypto/ec/ec_key.c +++ b/crypto/ec/ec_key.c @@ -250,7 +250,8 @@ static int fips_check_ec(EC_KEY *key) pk.type = EVP_PKEY_EC; pk.pkey.ec = key; - if (!fips_pkey_signature_test(&pk, tbs, -1, NULL, 0, NULL, 0, NULL)) + if (!fips_pkey_signature_test(FIPS_TEST_PAIRWISE, + &pk, tbs, -1, NULL, 0, NULL, 0, NULL)) { FIPSerr(FIPS_F_FIPS_CHECK_EC,FIPS_R_PAIRWISE_TEST_FAILED); fips_set_selftest_fail(); diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h index d51e0d3403..b4c8675043 100644 --- a/crypto/evp/evp.h +++ b/crypto/evp/evp.h @@ -460,6 +460,7 @@ typedef int (EVP_PBE_KEYGEN)(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, #define M_EVP_MD_CTX_type(e) M_EVP_MD_type(M_EVP_MD_CTX_md(e)) #define M_EVP_MD_CTX_md(e) ((e)->digest) +#define M_EVP_CIPHER_nid(e) ((e)->nid) #define M_EVP_CIPHER_CTX_iv_length(e) ((e)->cipher->iv_len) #define M_EVP_CIPHER_CTX_flags(e) ((e)->cipher->flags) #define M_EVP_CIPHER_CTX_block_size(e) ((e)->cipher->block_size) diff --git a/crypto/rsa/rsa_gen.c b/crypto/rsa/rsa_gen.c index 7bef5dd6bf..977e461ef0 100644 --- a/crypto/rsa/rsa_gen.c +++ b/crypto/rsa/rsa_gen.c @@ -93,11 +93,11 @@ int fips_check_rsa(RSA *rsa) pk.pkey.rsa = rsa; /* Perform pairwise consistency signature test */ - if (!fips_pkey_signature_test(&pk, tbs, -1, + if (!fips_pkey_signature_test(FIPS_TEST_PAIRWISE, &pk, tbs, -1, NULL, 0, NULL, RSA_PKCS1_PADDING, NULL) - || !fips_pkey_signature_test(&pk, tbs, -1, + || !fips_pkey_signature_test(FIPS_TEST_PAIRWISE, &pk, tbs, -1, NULL, 0, NULL, RSA_X931_PADDING, NULL) - || !fips_pkey_signature_test(&pk, tbs, -1, + || !fips_pkey_signature_test(FIPS_TEST_PAIRWISE, &pk, tbs, -1, NULL, 0, NULL, RSA_PKCS1_PSS_PADDING, NULL)) goto err; /* Now perform pairwise consistency encrypt/decrypt test */ diff --git a/fips/Makefile b/fips/Makefile index 28df80cab8..e84a4fb044 100644 --- a/fips/Makefile +++ b/fips/Makefile @@ -41,8 +41,8 @@ GENERAL=Makefile README fips-lib.com install.com LIB= $(TOP)/libcrypto.a SHARED_LIB= $(FIPSCANLIB)$(SHLIB_EXT) -LIBSRC=fips.c -LIBOBJ=fips.o +LIBSRC=fips.c fips_post.c +LIBOBJ=fips.o fips_post.o FIPS_OBJ_LISTS=sha/lib hmac/lib rand/lib des/lib aes/lib dsa/lib rsa/lib \ dh/lib utl/lib ecdsa/lib cmac/lib diff --git a/fips/aes/fips_aes_selftest.c b/fips/aes/fips_aes_selftest.c index 05f18d1484..457dabda38 100644 --- a/fips/aes/fips_aes_selftest.c +++ b/fips/aes/fips_aes_selftest.c @@ -86,7 +86,7 @@ int FIPS_selftest_aes() for(n=0 ; n < 1 ; ++n) { - if (fips_cipher_test(&ctx, EVP_aes_128_ecb(), + if (fips_cipher_test(FIPS_TEST_CIPHER, &ctx, EVP_aes_128_ecb(), tests[n].key, NULL, tests[n].plaintext, tests[n].ciphertext, diff --git a/fips/des/fips_des_selftest.c b/fips/des/fips_des_selftest.c index 6ce556e2bd..9eea546560 100644 --- a/fips/des/fips_des_selftest.c +++ b/fips/des/fips_des_selftest.c @@ -115,7 +115,7 @@ int FIPS_selftest_des() /* Encrypt/decrypt with 3DES and compare to known answers */ for(n=0 ; n < 2 ; ++n) { - if (!fips_cipher_test(&ctx, EVP_des_ede3_ecb(), + if (!fips_cipher_test(FIPS_TEST_CIPHER, &ctx, EVP_des_ede3_ecb(), tests3[n].key, NULL, tests3[n].plaintext, tests3[n].ciphertext, 8)) goto err; diff --git a/fips/dsa/fips_dsa_selftest.c b/fips/dsa/fips_dsa_selftest.c index 9646ae93da..8d894256f6 100644 --- a/fips/dsa/fips_dsa_selftest.c +++ b/fips/dsa/fips_dsa_selftest.c @@ -169,7 +169,7 @@ int FIPS_selftest_dsa() pk.type = EVP_PKEY_DSA; pk.pkey.dsa = dsa; - if (!fips_pkey_signature_test(&pk, NULL, 0, + if (!fips_pkey_signature_test(FIPS_TEST_SIGNATURE, &pk, NULL, 0, NULL, 0, EVP_sha384(), 0, "DSA SHA384")) goto err; diff --git a/fips/ecdsa/fips_ecdsa_selftest.c b/fips/ecdsa/fips_ecdsa_selftest.c index c09f59d926..69494806d5 100644 --- a/fips/ecdsa/fips_ecdsa_selftest.c +++ b/fips/ecdsa/fips_ecdsa_selftest.c @@ -176,7 +176,7 @@ int FIPS_selftest_ecdsa() pk.type = EVP_PKEY_EC; pk.pkey.ec = ec; - if (!fips_pkey_signature_test(&pk, NULL, 0, + if (!fips_pkey_signature_test(FIPS_TEST_SIGNATURE, &pk, NULL, 0, NULL, 0, EVP_sha512(), 0, ecd->name)) goto err; diff --git a/fips/fips.c b/fips/fips.c index 9ad1761f0d..a18fd58f28 100644 --- a/fips/fips.c +++ b/fips/fips.c @@ -142,20 +142,6 @@ void fips_set_selftest_fail(void) fips_selftest_fail = 1; } -int FIPS_selftest(void) - { - - return FIPS_selftest_sha1() - && FIPS_selftest_hmac() - && FIPS_selftest_cmac() - && FIPS_selftest_aes() - && FIPS_selftest_aes_gcm() - && FIPS_selftest_des() - && FIPS_selftest_rsa() - && FIPS_selftest_ecdsa() - && FIPS_selftest_dsa(); - } - extern const void *FIPS_text_start(), *FIPS_text_end(); extern const unsigned char FIPS_rodata_start[], FIPS_rodata_end[]; unsigned char FIPS_signature [20] = { 0 }; @@ -192,6 +178,9 @@ unsigned int FIPS_incore_fingerprint(unsigned char *sig,unsigned int len) else HMAC_Update(&c,p3,(size_t)p4-(size_t)p3); + if (!fips_post_corrupt(FIPS_TEST_INTEGRITY, 0, NULL)) + HMAC_Update(&c, (unsigned char *)FIPS_hmac_key, 1); + HMAC_Final(&c,sig,&len); HMAC_CTX_cleanup(&c); @@ -202,19 +191,23 @@ int FIPS_check_incore_fingerprint(void) { unsigned char sig[EVP_MAX_MD_SIZE]; unsigned int len; + int rv = 0; #if defined(__sgi) && (defined(__mips) || defined(mips)) extern int __dso_displacement[]; #else extern int OPENSSL_NONPIC_relocated; #endif + if (!fips_post_started(FIPS_TEST_INTEGRITY, 0, NULL)) + return 1; + if (FIPS_text_start()==NULL) { FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_UNSUPPORTED_PLATFORM); - return 0; + goto err; } - len=FIPS_incore_fingerprint (sig,sizeof(sig)); + len=FIPS_incore_fingerprint(sig,sizeof(sig)); if (len!=sizeof(FIPS_signature) || memcmp(FIPS_signature,sig,sizeof(FIPS_signature))) @@ -230,12 +223,18 @@ int FIPS_check_incore_fingerprint(void) else FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_FINGERPRINT_DOES_NOT_MATCH); #ifdef OPENSSL_FIPS_DEBUGGER - return 1; -#else - return 0; + rv = 1; #endif + goto err; } - return 1; + rv = 1; + err: + if (rv == 0) + fips_post_failed(FIPS_TEST_INTEGRITY, 0, NULL); + else + if (!fips_post_success(FIPS_TEST_INTEGRITY, 0, NULL)) + return 0; + return rv; } int FIPS_mode_set(int onoff) @@ -281,28 +280,6 @@ int FIPS_mode_set(int onoff) goto end; } - if(!FIPS_check_incore_fingerprint()) - { - fips_selftest_fail = 1; - ret = 0; - goto end; - } - - if (!FIPS_selftest_drbg()) - { - fips_selftest_fail = 1; - ret = 0; - goto end; - } - - /* Perform RNG KAT before seeding */ - if (!FIPS_selftest_x931()) - { - fips_selftest_fail = 1; - ret = 0; - goto end; - } - if(FIPS_selftest()) fips_set_mode(1); else @@ -388,151 +365,6 @@ unsigned char *fips_signature_witness(void) return FIPS_signature; } -/* Generalized public key test routine. Signs and verifies the data - * supplied in tbs using mesage digest md and setting RSA padding mode - * pad_mode. If the 'kat' parameter is not NULL it will - * additionally check the signature matches it: a known answer test - * The string "fail_str" is used for identification purposes in case - * of failure. - */ - -int fips_pkey_signature_test(EVP_PKEY *pkey, - const unsigned char *tbs, size_t tbslen, - const unsigned char *kat, size_t katlen, - const EVP_MD *digest, int pad_mode, - const char *fail_str) - { - int ret = 0; - unsigned char *sig = NULL; - unsigned int siglen; - static const unsigned char str1[]="12345678901234567890"; - DSA_SIG *dsig = NULL; - ECDSA_SIG *esig = NULL; - EVP_MD_CTX mctx; - FIPS_md_ctx_init(&mctx); - - - if (tbs == NULL) - tbs = str1; - - if (pkey->type == EVP_PKEY_RSA) - { - sig = OPENSSL_malloc(RSA_size(pkey->pkey.rsa)); - if (!sig) - { - FIPSerr(FIPS_F_FIPS_PKEY_SIGNATURE_TEST,ERR_R_MALLOC_FAILURE); - return 0; - } - } - - if (tbslen == 0) - tbslen = strlen((char *)tbs); - - if (digest == NULL) - digest = EVP_sha256(); - - if (!FIPS_digestinit(&mctx, digest)) - goto error; - if (!FIPS_digestupdate(&mctx, tbs, tbslen)) - goto error; - if (pkey->type == EVP_PKEY_RSA) - { - if (!FIPS_rsa_sign_ctx(pkey->pkey.rsa, &mctx, - pad_mode, 0, NULL, sig, &siglen)) - goto error; - } - else if (pkey->type == EVP_PKEY_DSA) - { - dsig = FIPS_dsa_sign_ctx(pkey->pkey.dsa, &mctx); - if (!dsig) - goto error; - } - else if (pkey->type == EVP_PKEY_EC) - { - esig = FIPS_ecdsa_sign_ctx(pkey->pkey.ec, &mctx); - if (!esig) - goto error; - } - - if (kat && ((siglen != katlen) || memcmp(kat, sig, katlen))) - goto error; -#if 0 - { - /* Debug code to print out self test KAT discrepancies */ - unsigned int i; - fprintf(stderr, "%s=", fail_str); - for (i = 0; i < siglen; i++) - fprintf(stderr, "%02X", sig[i]); - fprintf(stderr, "\n"); - goto error; - } -#endif - if (!FIPS_digestinit(&mctx, digest)) - goto error; - if (!FIPS_digestupdate(&mctx, tbs, tbslen)) - goto error; - if (pkey->type == EVP_PKEY_RSA) - { - ret = FIPS_rsa_verify_ctx(pkey->pkey.rsa, &mctx, - pad_mode, 0, NULL, sig, siglen); - } - else if (pkey->type == EVP_PKEY_DSA) - { - ret = FIPS_dsa_verify_ctx(pkey->pkey.dsa, &mctx, dsig); - } - else if (pkey->type == EVP_PKEY_EC) - { - ret = FIPS_ecdsa_verify_ctx(pkey->pkey.ec, &mctx, esig); - } - - error: - if (dsig != NULL) - FIPS_dsa_sig_free(dsig); - if (esig != NULL) - FIPS_ecdsa_sig_free(esig); - if (sig) - OPENSSL_free(sig); - FIPS_md_ctx_cleanup(&mctx); - if (ret != 1) - { - FIPSerr(FIPS_F_FIPS_PKEY_SIGNATURE_TEST,FIPS_R_TEST_FAILURE); - if (fail_str) - FIPS_add_error_data(2, "Type=", fail_str); - return 0; - } - return 1; - } - -/* Generalized symmetric cipher test routine. Encrypt data, verify result - * against known answer, decrypt and compare with original plaintext. - */ - -int fips_cipher_test(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, - const unsigned char *key, - const unsigned char *iv, - const unsigned char *plaintext, - const unsigned char *ciphertext, - int len) - { - unsigned char pltmp[FIPS_MAX_CIPHER_TEST_SIZE]; - unsigned char citmp[FIPS_MAX_CIPHER_TEST_SIZE]; - OPENSSL_assert(len <= FIPS_MAX_CIPHER_TEST_SIZE); - memset(pltmp, 0, FIPS_MAX_CIPHER_TEST_SIZE); - memset(citmp, 0, FIPS_MAX_CIPHER_TEST_SIZE); - if (FIPS_cipherinit(ctx, cipher, key, iv, 1) <= 0) - return 0; - if (!FIPS_cipher(ctx, citmp, plaintext, len)) - return 0; - if (memcmp(citmp, ciphertext, len)) - return 0; - if (FIPS_cipherinit(ctx, cipher, key, iv, 0) <= 0) - return 0; - FIPS_cipher(ctx, pltmp, citmp, len); - if (memcmp(pltmp, plaintext, len)) - return 0; - return 1; - } - #if 0 /* The purpose of this is to ensure the error code exists and the function * name is to keep the error checking script quiet diff --git a/fips/fips.h b/fips/fips.h index e308ff44a1..4bc77f00d9 100644 --- a/fips/fips.h +++ b/fips/fips.h @@ -101,20 +101,6 @@ int FIPS_selftest_cmac(void); unsigned int FIPS_incore_fingerprint(unsigned char *sig,unsigned int len); int FIPS_check_incore_fingerprint(void); -int fips_pkey_signature_test(struct evp_pkey_st *pkey, - const unsigned char *tbs, size_t tbslen, - const unsigned char *kat, size_t katlen, - const struct env_md_st *digest, int pad_mode, - const char *fail_str); - -int fips_cipher_test(struct evp_cipher_ctx_st *ctx, - const struct evp_cipher_st *cipher, - const unsigned char *key, - const unsigned char *iv, - const unsigned char *plaintext, - const unsigned char *ciphertext, - int len); - void fips_set_selftest_fail(void); int fips_check_rsa(struct rsa_st *rsa); @@ -129,9 +115,68 @@ void FIPS_set_malloc_callbacks( void FIPS_get_timevec(unsigned char *buf, unsigned long *pctr); +/* POST callback operation value: */ +/* All tests started */ +#define FIPS_POST_BEGIN 1 +/* All tests end: result in id */ +#define FIPS_POST_END 2 +/* One individual test started */ +#define FIPS_POST_STARTED 3 +/* Individual test success */ +#define FIPS_POST_SUCCESS 4 +/* Individual test failure */ +#define FIPS_POST_FAIL 5 +/* Induce failure in test if zero return */ +#define FIPS_POST_CORRUPT 6 + +/* Test IDs */ +/* HMAC integrity test */ +#define FIPS_TEST_INTEGRITY 1 +/* Digest test */ +#define FIPS_TEST_DIGEST 2 +/* Symmetric cipher test */ +#define FIPS_TEST_CIPHER 3 +/* Public key signature test */ +#define FIPS_TEST_SIGNATURE 4 +/* HMAC test */ +#define FIPS_TEST_HMAC 5 +/* CMAC test */ +#define FIPS_TEST_CMAC 6 +/* GCM test */ +#define FIPS_TEST_GCM 7 +/* CCM test */ +#define FIPS_TEST_CCM 8 +/* XTS test */ +#define FIPS_TEST_XTS 9 +/* X9.31 PRNG */ +#define FIPS_TEST_X931 10 +/* DRNB */ +#define FIPS_TEST_DRBG 11 +/* Keygen pairwise consistency test */ +#define FIPS_TEST_PAIRWISE 12 +/* Continuous PRNG test */ +#define FIPS_TEST_CONTINUOUS 13 + +void FIPS_post_set_callback( + int (*post_cb)(int op, int id, int subid, void *ex)); + #define FIPS_ERROR_IGNORED(alg) OpenSSLDie(__FILE__, __LINE__, \ alg " previous FIPS forbidden algorithm error ignored"); +int fips_pkey_signature_test(int id, struct evp_pkey_st *pkey, + const unsigned char *tbs, size_t tbslen, + const unsigned char *kat, size_t katlen, + const struct env_md_st *digest, int pad_mode, + const char *fail_str); + +int fips_cipher_test(int id, struct evp_cipher_ctx_st *ctx, + const struct evp_cipher_st *cipher, + const unsigned char *key, + const unsigned char *iv, + const unsigned char *plaintext, + const unsigned char *ciphertext, + int len); + /* Where necessary redirect standard OpenSSL APIs to FIPS versions */ #if defined(OPENSSL_FIPSCANISTER) && defined(OPENSSL_FIPSAPI) diff --git a/fips/fips_locl.h b/fips/fips_locl.h index 3273ba6a83..fba8db8b63 100644 --- a/fips/fips_locl.h +++ b/fips/fips_locl.h @@ -59,6 +59,14 @@ extern "C" { if (!key->comp) \ goto err +int fips_post_begin(void); +void fips_post_end(void); +int fips_post_started(int id, int subid, void *ex); +int fips_post_success(int id, int subid, void *ex); +int fips_post_failed(int id, int subid, void *ex); +int fips_post_corrupt(int id, int subid, void *ex); +int fips_post_status(void); + #ifdef __cplusplus } #endif diff --git a/fips/fips_post.c b/fips/fips_post.c new file mode 100644 index 0000000000..1ab156fb3f --- /dev/null +++ b/fips/fips_post.c @@ -0,0 +1,379 @@ +/* ==================================================================== + * Copyright (c) 2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#define OPENSSL_FIPSAPI + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef OPENSSL_FIPS + +/* Power on self test (POST) support functions */ + +#include +#include "fips_locl.h" + +/* POST notification callback */ + +int (*fips_post_cb)(int op, int id, int subid, void *ex); + +void FIPS_post_set_callback( + int (*post_cb)(int op, int id, int subid, void *ex)) + { + fips_post_cb = post_cb; + } + +/* POST status: i.e. status of all tests */ +#define FIPS_POST_STATUS_NOT_STARTED 0 +#define FIPS_POST_STATUS_OK 1 +#define FIPS_POST_STATUS_RUNNING 2 +#define FIPS_POST_STATUS_FAILED -1 +static int post_status = 0; +/* Set to 1 if any test failed */ +static int post_failure = 0; + +/* All tests started */ + +int fips_post_begin(void) + { + post_failure = 0; + post_status = FIPS_POST_STATUS_NOT_STARTED; + if (fips_post_cb) + if (!fips_post_cb(FIPS_POST_BEGIN, 0, 0, NULL)) + return 0; + post_status = FIPS_POST_STATUS_RUNNING; + return 1; + } + +void fips_post_end(void) + { + if (post_failure) + { + post_status = FIPS_POST_STATUS_FAILED; + fips_post_cb(FIPS_POST_END, 0, 0, NULL); + } + else + { + post_status = FIPS_POST_STATUS_OK; + fips_post_cb(FIPS_POST_END, 1, 0, NULL); + } + } + +/* A self test started */ +int fips_post_started(int id, int subid, void *ex) + { + if (fips_post_cb) + return fips_post_cb(FIPS_POST_STARTED, id, subid, ex); + return 1; + } +/* A self test passed successfully */ +int fips_post_success(int id, int subid, void *ex) + { + if (fips_post_cb) + return fips_post_cb(FIPS_POST_SUCCESS, id, subid, ex); + return 1; + } +/* A self test failed */ +int fips_post_failed(int id, int subid, void *ex) + { + post_failure = 1; + if (fips_post_cb) + return fips_post_cb(FIPS_POST_FAIL, id, subid, ex); + return 1; + } +/* Indicate if a self test failure should be induced */ +int fips_post_corrupt(int id, int subid, void *ex) + { + if (fips_post_cb) + return fips_post_cb(FIPS_POST_CORRUPT, id, subid, ex); + return 1; + } +/* Note: if selftests running return status OK so their operation is + * not interrupted. This will only happen while selftests are actually + * running so will not interfere with normal operation. + */ +int fips_post_status(void) + { + return post_status > 0 ? 1 : 0; + } +/* Run all selftests */ +int FIPS_selftest(void) + { + int rv = 1; + fips_post_begin(); + if(!FIPS_check_incore_fingerprint()) + rv = 0; + if (!FIPS_selftest_drbg()) + rv = 0; + if (!FIPS_selftest_x931()) + rv = 0; + if (!FIPS_selftest_sha1()) + rv = 0; + if (!FIPS_selftest_hmac()) + rv = 0; + if (!FIPS_selftest_cmac()) + rv = 0; + if (!FIPS_selftest_aes()) + rv = 0; + if (!FIPS_selftest_aes_gcm()) + rv = 0; + if (!FIPS_selftest_des()) + rv = 0; + if (!FIPS_selftest_rsa()) + rv = 0; + if (!FIPS_selftest_ecdsa()) + rv = 0; + if (!FIPS_selftest_dsa()) + rv = 0; + fips_post_end(); + return rv; + } + +/* Generalized public key test routine. Signs and verifies the data + * supplied in tbs using mesage digest md and setting RSA padding mode + * pad_mode. If the 'kat' parameter is not NULL it will + * additionally check the signature matches it: a known answer test + * The string "fail_str" is used for identification purposes in case + * of failure. If "pkey" is NULL just perform a message digest check. + */ + +int fips_pkey_signature_test(int id, EVP_PKEY *pkey, + const unsigned char *tbs, size_t tbslen, + const unsigned char *kat, size_t katlen, + const EVP_MD *digest, int pad_mode, + const char *fail_str) + { + int subid; + void *ex = NULL; + int ret = 0; + unsigned char *sig = NULL; + unsigned int siglen; + static const unsigned char str1[]="12345678901234567890"; + DSA_SIG *dsig = NULL; + ECDSA_SIG *esig = NULL; + EVP_MD_CTX mctx; + FIPS_md_ctx_init(&mctx); + + if (tbs == NULL) + tbs = str1; + + if (tbslen == 0) + tbslen = strlen((char *)tbs); + + if (digest == NULL) + digest = EVP_sha256(); + + subid = M_EVP_MD_type(digest); + + + if (!fips_post_started(id, subid, pkey)) + return 1; + + if (!pkey || pkey->type == EVP_PKEY_RSA) + { + size_t sigsize; + if (!pkey) + sigsize = EVP_MAX_MD_SIZE; + else + sigsize = RSA_size(pkey->pkey.rsa); + + sig = OPENSSL_malloc(sigsize); + if (!sig) + { + FIPSerr(FIPS_F_FIPS_PKEY_SIGNATURE_TEST,ERR_R_MALLOC_FAILURE); + goto error; + } + } + + if (!FIPS_digestinit(&mctx, digest)) + goto error; + if (!FIPS_digestupdate(&mctx, tbs, tbslen)) + goto error; + + if (!fips_post_corrupt(id, subid, pkey)) + { + if (!FIPS_digestupdate(&mctx, tbs, 1)) + goto error; + } + + if (pkey == NULL) + { + if (!FIPS_digestfinal(&mctx, sig, &siglen)) + goto error; + } + else if (pkey->type == EVP_PKEY_RSA) + { + if (!FIPS_rsa_sign_ctx(pkey->pkey.rsa, &mctx, + pad_mode, 0, NULL, sig, &siglen)) + goto error; + } + else if (pkey->type == EVP_PKEY_DSA) + { + dsig = FIPS_dsa_sign_ctx(pkey->pkey.dsa, &mctx); + if (!dsig) + goto error; + } + else if (pkey->type == EVP_PKEY_EC) + { + esig = FIPS_ecdsa_sign_ctx(pkey->pkey.ec, &mctx); + if (!esig) + goto error; + } + + if (kat && ((siglen != katlen) || memcmp(kat, sig, katlen))) + goto error; +#if 0 + { + /* Debug code to print out self test KAT discrepancies */ + unsigned int i; + fprintf(stderr, "%s=", fail_str); + for (i = 0; i < siglen; i++) + fprintf(stderr, "%02X", sig[i]); + fprintf(stderr, "\n"); + goto error; + } +#endif + /* If just digest test we've finished */ + if (pkey == NULL) + { + ret = 1; + /* Well actually sucess as we've set ret to 1 */ + goto error; + } + if (!FIPS_digestinit(&mctx, digest)) + goto error; + if (!FIPS_digestupdate(&mctx, tbs, tbslen)) + goto error; + if (pkey->type == EVP_PKEY_RSA) + { + ret = FIPS_rsa_verify_ctx(pkey->pkey.rsa, &mctx, + pad_mode, 0, NULL, sig, siglen); + } + else if (pkey->type == EVP_PKEY_DSA) + { + ret = FIPS_dsa_verify_ctx(pkey->pkey.dsa, &mctx, dsig); + } + else if (pkey->type == EVP_PKEY_EC) + { + ret = FIPS_ecdsa_verify_ctx(pkey->pkey.ec, &mctx, esig); + } + + error: + if (dsig != NULL) + FIPS_dsa_sig_free(dsig); + if (esig != NULL) + FIPS_ecdsa_sig_free(esig); + if (sig) + OPENSSL_free(sig); + FIPS_md_ctx_cleanup(&mctx); + if (ret != 1) + { + FIPSerr(FIPS_F_FIPS_PKEY_SIGNATURE_TEST,FIPS_R_TEST_FAILURE); + if (fail_str) + FIPS_add_error_data(2, "Type=", fail_str); + fips_post_failed(id, subid, ex); + return 0; + } + return fips_post_success(id, subid, pkey); + } + +/* Generalized symmetric cipher test routine. Encrypt data, verify result + * against known answer, decrypt and compare with original plaintext. + */ + +int fips_cipher_test(int id, EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const unsigned char *key, + const unsigned char *iv, + const unsigned char *plaintext, + const unsigned char *ciphertext, + int len) + { + unsigned char pltmp[FIPS_MAX_CIPHER_TEST_SIZE]; + unsigned char citmp[FIPS_MAX_CIPHER_TEST_SIZE]; + int subid = M_EVP_CIPHER_nid(cipher); + int rv = 0; + OPENSSL_assert(len <= FIPS_MAX_CIPHER_TEST_SIZE); + memset(pltmp, 0, FIPS_MAX_CIPHER_TEST_SIZE); + memset(citmp, 0, FIPS_MAX_CIPHER_TEST_SIZE); + + if (!fips_post_started(id, subid, NULL)) + return 1; + if (FIPS_cipherinit(ctx, cipher, key, iv, 1) <= 0) + goto error; + if (!FIPS_cipher(ctx, citmp, plaintext, len)) + goto error; + if (memcmp(citmp, ciphertext, len)) + goto error; + if (!fips_post_corrupt(id, subid, NULL)) + citmp[0] ^= 0x1; + if (FIPS_cipherinit(ctx, cipher, key, iv, 0) <= 0) + goto error; + FIPS_cipher(ctx, pltmp, citmp, len); + if (memcmp(pltmp, plaintext, len)) + goto error; + rv = 1; + error: + if (rv == 0) + { + fips_post_failed(id, subid, NULL); + return 0; + } + return fips_post_success(id, subid, NULL); + } + +#endif diff --git a/fips/fips_test_suite.c b/fips/fips_test_suite.c index 2cfd5ef930..e71ab11599 100644 --- a/fips/fips_test_suite.c +++ b/fips/fips_test_suite.c @@ -665,6 +665,165 @@ static void test_msg(const char *msg, int result) printf("%s...%s\n", msg, result ? "successful" : Fail("Failed!")); } +static const char *post_get_sig(int id) + { + switch (id) + { + case EVP_PKEY_RSA: + return " (RSA)"; + + case EVP_PKEY_DSA: + return " (DSA)"; + + case EVP_PKEY_EC: + return " (ECDSA)"; + + default: + return " (UNKNOWN)"; + + } + } + +static const char *post_get_cipher(int id) + { + static char out[128]; + switch(id) + { + + case NID_aes_128_ecb: + return " (AES-128-ECB)"; + + case NID_des_ede3_ecb: + return " (DES-EDE3-ECB)"; + + default: + sprintf(out, " (NID=%d)", id); + return out; + + } + } + +static int fail_id = -1; +static int fail_sub = -1; +static int fail_key = -1; + +static int post_cb(int op, int id, int subid, void *ex) + { + const char *idstr, *exstr = ""; + int keytype = -1; + switch(id) + { + case FIPS_TEST_INTEGRITY: + idstr = "Integrity"; + break; + + case FIPS_TEST_DIGEST: + idstr = "Digest"; + if (subid == NID_sha1) + exstr = " (SHA1)"; + break; + + case FIPS_TEST_CIPHER: + exstr = post_get_cipher(subid); + idstr = "Cipher"; + break; + + case FIPS_TEST_SIGNATURE: + if (ex) + { + EVP_PKEY *pkey = ex; + keytype = pkey->type; + exstr = post_get_sig(keytype); + } + idstr = "Signature"; + break; + + case FIPS_TEST_HMAC: + idstr = "HMAC"; + break; + + case FIPS_TEST_CMAC: + idstr = "HMAC"; + break; + + case FIPS_TEST_GCM: + idstr = "HMAC"; + break; + + case FIPS_TEST_CCM: + idstr = "HMAC"; + break; + + case FIPS_TEST_XTS: + idstr = "HMAC"; + break; + + case FIPS_TEST_X931: + idstr = "X9.31 PRNG"; + break; + + case FIPS_TEST_DRBG: + idstr = "DRBG"; + break; + + case FIPS_TEST_PAIRWISE: + if (ex) + { + EVP_PKEY *pkey = ex; + keytype = pkey->type; + exstr = post_get_sig(keytype); + } + idstr = "Pairwise Consistency"; + break; + + case FIPS_TEST_CONTINUOUS: + idstr = "Continuous PRNG"; + break; + + default: + idstr = "Unknown"; + break; + + } + + switch(op) + { + case FIPS_POST_BEGIN: + printf("\tPOST started\n"); + break; + + case FIPS_POST_END: + printf("\tPOST %s\n", id ? "Success" : "Failed"); + break; + + case FIPS_POST_STARTED: + printf("\t\t%s%s test started\n", idstr, exstr); + break; + + case FIPS_POST_SUCCESS: + printf("\t\t%s%s test OK\n", idstr, exstr); + break; + + case FIPS_POST_FAIL: + printf("\t\t%s%s test FAILED!!\n", idstr, exstr); + break; + + case FIPS_POST_CORRUPT: + if (fail_id == id + && (fail_key == -1 || fail_key == keytype) + && (fail_sub == -1 || fail_sub == subid)) + { + printf("\t\t%s%s test failure induced\n", idstr, exstr); + return 0; + } + break; + + } + return 1; + } + + + int main(int argc,char **argv) { @@ -676,47 +835,51 @@ int main(int argc,char **argv) fips_algtest_init_nofips(); + FIPS_post_set_callback(post_cb); + printf("\tFIPS-mode test application\n\n"); if (argv[1]) { /* Corrupted KAT tests */ - if (!strcmp(argv[1], "aes")) { - FIPS_corrupt_aes(); - printf("AES encryption/decryption with corrupted KAT...\n"); + if (!strcmp(argv[1], "integrity")) { + fail_id = FIPS_TEST_INTEGRITY; + } else if (!strcmp(argv[1], "aes")) { + fail_id = FIPS_TEST_CIPHER; + fail_sub = NID_aes_128_ecb; } else if (!strcmp(argv[1], "aes-gcm")) { FIPS_corrupt_aes_gcm(); printf("AES-GCM encryption/decryption with corrupted KAT...\n"); } else if (!strcmp(argv[1], "des")) { - FIPS_corrupt_des(); - printf("DES3-ECB encryption/decryption with corrupted KAT...\n"); + fail_id = FIPS_TEST_CIPHER; + fail_sub = NID_des_ede3_ecb; } else if (!strcmp(argv[1], "dsa")) { - FIPS_corrupt_dsa(); - printf("DSA key generation and signature validation with corrupted KAT...\n"); + fail_id = FIPS_TEST_SIGNATURE; + fail_key = EVP_PKEY_DSA; } else if (!strcmp(argv[1], "ecdsa")) { - FIPS_corrupt_ecdsa(); - printf("ECDSA key generation and signature validation with corrupted KAT...\n"); + fail_id = FIPS_TEST_SIGNATURE; + fail_key = EVP_PKEY_EC; } else if (!strcmp(argv[1], "rsa")) { - FIPS_corrupt_rsa(); - printf("RSA key generation and signature validation with corrupted KAT...\n"); + fail_id = FIPS_TEST_SIGNATURE; + fail_key = EVP_PKEY_RSA; } else if (!strcmp(argv[1], "rsakey")) { printf("RSA key generation and signature validation with corrupted key...\n"); bad_rsa = 1; no_exit = 1; } else if (!strcmp(argv[1], "rsakeygen")) { - do_corrupt_rsa_keygen = 1; + fail_id = FIPS_TEST_PAIRWISE; + fail_key = EVP_PKEY_RSA; no_exit = 1; - printf("RSA key generation and signature validation with corrupted keygen...\n"); } else if (!strcmp(argv[1], "dsakey")) { printf("DSA key generation and signature validation with corrupted key...\n"); bad_dsa = 1; no_exit = 1; } else if (!strcmp(argv[1], "dsakeygen")) { - do_corrupt_dsa_keygen = 1; + fail_id = FIPS_TEST_PAIRWISE; + fail_key = EVP_PKEY_DSA; no_exit = 1; - printf("DSA key generation and signature validation with corrupted keygen...\n"); } else if (!strcmp(argv[1], "sha1")) { - FIPS_corrupt_sha1(); - printf("SHA-1 hash with corrupted KAT...\n"); + fail_id = FIPS_TEST_DIGEST; + fail_sub = NID_sha1; } else if (!strcmp(argv[1], "drbg")) { FIPS_corrupt_drbg(); } else if (!strcmp(argv[1], "rng")) { diff --git a/fips/rsa/fips_rsa_selftest.c b/fips/rsa/fips_rsa_selftest.c index d20b753a7d..0f6c5ff51a 100644 --- a/fips/rsa/fips_rsa_selftest.c +++ b/fips/rsa/fips_rsa_selftest.c @@ -239,7 +239,8 @@ int FIPS_selftest_rsa() pk.type = EVP_PKEY_RSA; pk.pkey.rsa = key; - if (!fips_pkey_signature_test(&pk, kat_tbs, sizeof(kat_tbs) - 1, + if (!fips_pkey_signature_test(FIPS_TEST_SIGNATURE, + &pk, kat_tbs, sizeof(kat_tbs) - 1, kat_RSA_PSS_SHA256, sizeof(kat_RSA_PSS_SHA256), EVP_sha256(), RSA_PKCS1_PSS_PADDING, "RSA SHA256 PSS")) diff --git a/fips/sha/fips_sha1_selftest.c b/fips/sha/fips_sha1_selftest.c index 3a4b4315c5..e0f0c12d9e 100644 --- a/fips/sha/fips_sha1_selftest.c +++ b/fips/sha/fips_sha1_selftest.c @@ -56,7 +56,7 @@ #include #ifdef OPENSSL_FIPS -static char test[][60]= +static unsigned char test[][60]= { "", "abc", @@ -79,21 +79,20 @@ void FIPS_corrupt_sha1() } int FIPS_selftest_sha1() - { - size_t n; - - for(n=0 ; n