From 25c6542944821afc0693ca7027c769cc8775e90d Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Tue, 15 Feb 2011 16:03:47 +0000 Subject: [PATCH] Add non-FIPS algorithm blocking and selftest checking. --- CHANGES | 7 +++-- crypto/evp/evp.h | 1 + crypto/evp/evp_err.c | 1 + crypto/fips_err.h | 2 ++ fips/des/fips_des_selftest.c | 8 ------ fips/dsa/fips_dsa_sign.c | 2 ++ fips/fips.h | 5 ++++ fips/rsa/fips_rsa_sign.c | 4 +++ fips/utl/fips_enc.c | 54 ++++++++++++++++++++++++++++++++++++ fips/utl/fips_md.c | 45 ++++++++++++++++++++++++++++++ 10 files changed, 119 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index 315bf8e302..237234db9e 100644 --- a/CHANGES +++ b/CHANGES @@ -4,10 +4,13 @@ Changes between 1.0.1 and 1.1.0 [xx XXX xxxx] + *) Add selftest checks and algorithm block of non-fips algorithms in + FIPS mode. Remove DES2 from selftests. + [Steve Henson] + *) Add ECDSA code to fips module. Add tiny fips_ecdsa_check to just return internal method without any ENGINE dependencies. Add new - tiny fips sign and verify functions. Initial incomplete algorithm - test program. + tiny fips sign and verify functions. [Steve Henson] *) New build option no-ec2m to disable characteristic 2 code. diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h index 042dc1c577..240d9d5d69 100644 --- a/crypto/evp/evp.h +++ b/crypto/evp/evp.h @@ -1319,6 +1319,7 @@ void ERR_load_EVP_strings(void); #define EVP_R_DECODE_ERROR 114 #define EVP_R_DIFFERENT_KEY_TYPES 101 #define EVP_R_DIFFERENT_PARAMETERS 153 +#define EVP_R_DISABLED_FOR_FIPS 163 #define EVP_R_ENCODE_ERROR 115 #define EVP_R_EVP_PBE_CIPHERINIT_ERROR 119 #define EVP_R_EXPECTING_AN_RSA_KEY 127 diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c index 92e0493d3e..a9e26562c6 100644 --- a/crypto/evp/evp_err.c +++ b/crypto/evp/evp_err.c @@ -162,6 +162,7 @@ static ERR_STRING_DATA EVP_str_reasons[]= {ERR_REASON(EVP_R_DECODE_ERROR) ,"decode error"}, {ERR_REASON(EVP_R_DIFFERENT_KEY_TYPES) ,"different key types"}, {ERR_REASON(EVP_R_DIFFERENT_PARAMETERS) ,"different parameters"}, +{ERR_REASON(EVP_R_DISABLED_FOR_FIPS) ,"disabled for fips"}, {ERR_REASON(EVP_R_ENCODE_ERROR) ,"encode error"}, {ERR_REASON(EVP_R_EVP_PBE_CIPHERINIT_ERROR),"evp pbe cipherinit error"}, {ERR_REASON(EVP_R_EXPECTING_AN_RSA_KEY) ,"expecting an rsa key"}, diff --git a/crypto/fips_err.h b/crypto/fips_err.h index d2d9eb0d30..4ea18399f1 100644 --- a/crypto/fips_err.h +++ b/crypto/fips_err.h @@ -80,6 +80,8 @@ static ERR_STRING_DATA FIPS_str_functs[]= {ERR_FUNC(FIPS_F_FIPS_CHECK_DSA), "FIPS_CHECK_DSA"}, {ERR_FUNC(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT), "FIPS_check_incore_fingerprint"}, {ERR_FUNC(FIPS_F_FIPS_CHECK_RSA), "fips_check_rsa"}, +{ERR_FUNC(FIPS_F_FIPS_CIPHERINIT), "FIPS_CIPHERINIT"}, +{ERR_FUNC(FIPS_F_FIPS_DIGESTINIT), "FIPS_DIGESTINIT"}, {ERR_FUNC(FIPS_F_FIPS_DSA_CHECK), "FIPS_DSA_CHECK"}, {ERR_FUNC(FIPS_F_FIPS_MODE_SET), "FIPS_mode_set"}, {ERR_FUNC(FIPS_F_FIPS_PKEY_SIGNATURE_TEST), "fips_pkey_signature_test"}, diff --git a/fips/des/fips_des_selftest.c b/fips/des/fips_des_selftest.c index 7b7543b645..6ce556e2bd 100644 --- a/fips/des/fips_des_selftest.c +++ b/fips/des/fips_des_selftest.c @@ -111,14 +111,6 @@ int FIPS_selftest_des() int n, ret = 0; EVP_CIPHER_CTX ctx; FIPS_cipher_ctx_init(&ctx); - /* Encrypt/decrypt with 2-key 3DES and compare to known answers */ - for(n=0 ; n < 2 ; ++n) - { - if (!fips_cipher_test(&ctx, EVP_des_ede_ecb(), - tests2[n].key, NULL, - tests2[n].plaintext, tests2[n].ciphertext, 8)) - goto err; - } /* Encrypt/decrypt with 3DES and compare to known answers */ for(n=0 ; n < 2 ; ++n) diff --git a/fips/dsa/fips_dsa_sign.c b/fips/dsa/fips_dsa_sign.c index ab28cdf7d1..16689309b9 100644 --- a/fips/dsa/fips_dsa_sign.c +++ b/fips/dsa/fips_dsa_sign.c @@ -84,6 +84,7 @@ DSA_SIG * FIPS_dsa_sign_ctx(DSA *dsa, EVP_MD_CTX *ctx) DSA_SIG * FIPS_dsa_sign_digest(DSA *dsa, const unsigned char *dig, int dlen) { + FIPS_selftest_check(); return dsa->meth->dsa_do_sign(dig, dlen, dsa); } @@ -101,6 +102,7 @@ int FIPS_dsa_verify_ctx(DSA *dsa, EVP_MD_CTX *ctx, DSA_SIG *s) int FIPS_dsa_verify_digest(DSA *dsa, const unsigned char *dig, int dlen, DSA_SIG *s) { + FIPS_selftest_check(); return dsa->meth->dsa_do_verify(dig,dlen,s,dsa); } diff --git a/fips/fips.h b/fips/fips.h index 38a27bbcfe..64115da2d6 100644 --- a/fips/fips.h +++ b/fips/fips.h @@ -114,6 +114,9 @@ void FIPS_set_locking_callbacks(void (*func)(int mode, int type, int (*add_cb)(int *pointer, int amount, int type, const char *file, int line)); +#define FIPS_ERROR_IGNORED(alg) OpenSSLDie(__FILE__, __LINE__, \ + alg " previous FIPS forbidden algorithm error ignored"); + /* Where necessary redirect standard OpenSSL APIs to FIPS versions */ #if defined(OPENSSL_FIPSCANISTER) && defined(OPENSSL_FIPSAPI) @@ -179,6 +182,8 @@ void ERR_load_FIPS_strings(void); #define FIPS_F_FIPS_CHECK_DSA 104 #define FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT 105 #define FIPS_F_FIPS_CHECK_RSA 106 +#define FIPS_F_FIPS_CIPHERINIT 128 +#define FIPS_F_FIPS_DIGESTINIT 127 #define FIPS_F_FIPS_DSA_CHECK 107 #define FIPS_F_FIPS_MODE_SET 108 #define FIPS_F_FIPS_PKEY_SIGNATURE_TEST 109 diff --git a/fips/rsa/fips_rsa_sign.c b/fips/rsa/fips_rsa_sign.c index f54d890e73..46d0d4061a 100644 --- a/fips/rsa/fips_rsa_sign.c +++ b/fips/rsa/fips_rsa_sign.c @@ -219,6 +219,8 @@ int FIPS_rsa_sign_digest(RSA *rsa, const unsigned char *md, int md_len, /* Largest DigestInfo: 19 (max encoding) + max MD */ unsigned char tmpdinfo[19 + EVP_MAX_MD_SIZE]; + FIPS_selftest_check(); + md_type = M_EVP_MD_type(mhash); if (rsa_pad_mode == RSA_X931_PADDING) @@ -326,6 +328,8 @@ int FIPS_rsa_verify_digest(RSA *rsa, const unsigned char *dig, int diglen, return(0); } + FIPS_selftest_check(); + md_type = M_EVP_MD_type(mhash); s= OPENSSL_malloc((unsigned int)siglen); diff --git a/fips/utl/fips_enc.c b/fips/utl/fips_enc.c index d7f32611f3..b3db931fe9 100644 --- a/fips/utl/fips_enc.c +++ b/fips/utl/fips_enc.c @@ -78,9 +78,53 @@ EVP_CIPHER_CTX *FIPS_cipher_ctx_new(void) return ctx; } +/* The purpose of these is to trap programs that attempt to use non FIPS + * algorithms in FIPS mode and ignore the errors. + */ + +static int bad_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) + { FIPS_ERROR_IGNORED("Cipher init"); return 0;} + +static int bad_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) + { FIPS_ERROR_IGNORED("Cipher update"); return 0;} + +/* NB: no cleanup because it is allowed after failed init */ + +static int bad_set_asn1(EVP_CIPHER_CTX *ctx, ASN1_TYPE *typ) + { FIPS_ERROR_IGNORED("Cipher set_asn1"); return 0;} +static int bad_get_asn1(EVP_CIPHER_CTX *ctx, ASN1_TYPE *typ) + { FIPS_ERROR_IGNORED("Cipher get_asn1"); return 0;} +static int bad_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) + { FIPS_ERROR_IGNORED("Cipher ctrl"); return 0;} + +static const EVP_CIPHER bad_cipher = + { + 0, + 0, + 0, + 0, + 0, + bad_init, + bad_do_cipher, + NULL, + 0, + bad_set_asn1, + bad_get_asn1, + bad_ctrl, + NULL + }; + int FIPS_cipherinit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv, int enc) { + if(FIPS_selftest_failed()) + { + FIPSerr(FIPS_F_FIPS_CIPHERINIT,FIPS_R_FIPS_SELFTEST_FAILED); + ctx->cipher = &bad_cipher; + return 0; + } if (enc == -1) enc = ctx->encrypt; else @@ -91,6 +135,14 @@ int FIPS_cipherinit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, } if (cipher) { + /* Only FIPS ciphers allowed */ + if (FIPS_mode() && !(cipher->flags & EVP_CIPH_FLAG_FIPS) && + !(ctx->flags & EVP_CIPH_FLAG_NON_FIPS_ALLOW)) + { + EVPerr(EVP_F_FIPS_CIPHERINIT, EVP_R_DISABLED_FOR_FIPS); + ctx->cipher = &bad_cipher; + return 0; + } /* Ensure a context left lying around from last time is cleared * (the previous check attempted to avoid this if the same * ENGINE and EVP_CIPHER could be used). */ @@ -208,6 +260,7 @@ int FIPS_cipher_ctx_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) EVPerr(EVP_F_FIPS_CIPHER_CTX_CTRL, EVP_R_NO_CIPHER_SET); return 0; } + FIPS_selftest_check(); if(!ctx->cipher->ctrl) { EVPerr(EVP_F_FIPS_CIPHER_CTX_CTRL, EVP_R_CTRL_NOT_IMPLEMENTED); @@ -226,5 +279,6 @@ int FIPS_cipher_ctx_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) int FIPS_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl) { + FIPS_selftest_check(); return ctx->cipher->do_cipher(ctx,out,in,inl); } diff --git a/fips/utl/fips_md.c b/fips/utl/fips_md.c index 19595dd390..37149506f3 100644 --- a/fips/utl/fips_md.c +++ b/fips/utl/fips_md.c @@ -135,9 +135,51 @@ EVP_MD_CTX *FIPS_md_ctx_create(void) return ctx; } +/* The purpose of these is to trap programs that attempt to use non FIPS + * algorithms in FIPS mode and ignore the errors. + */ + +static int bad_init(EVP_MD_CTX *ctx) + { FIPS_ERROR_IGNORED("Digest init"); return 0;} + +static int bad_update(EVP_MD_CTX *ctx,const void *data,size_t count) + { FIPS_ERROR_IGNORED("Digest update"); return 0;} + +static int bad_final(EVP_MD_CTX *ctx,unsigned char *md) + { FIPS_ERROR_IGNORED("Digest Final"); return 0;} + +static const EVP_MD bad_md = + { + 0, + 0, + 0, + 0, + bad_init, + bad_update, + bad_final, + NULL, + NULL, + NULL, + 0, + {0,0,0,0}, + }; + int FIPS_digestinit(EVP_MD_CTX *ctx, const EVP_MD *type) { M_EVP_MD_CTX_clear_flags(ctx,EVP_MD_CTX_FLAG_CLEANED); + if(FIPS_selftest_failed()) + { + FIPSerr(FIPS_F_FIPS_DIGESTINIT,FIPS_R_FIPS_SELFTEST_FAILED); + ctx->digest = &bad_md; + return 0; + } + if(FIPS_mode() && !(type->flags & EVP_MD_FLAG_FIPS) && + !(ctx->flags & EVP_MD_CTX_FLAG_NON_FIPS_ALLOW)) + { + EVPerr(EVP_F_FIPS_DIGESTINIT, EVP_R_DISABLED_FOR_FIPS); + ctx->digest = &bad_md; + return 0; + } if (ctx->digest != type) { if (ctx->digest && ctx->digest->ctx_size) @@ -162,6 +204,7 @@ int FIPS_digestinit(EVP_MD_CTX *ctx, const EVP_MD *type) int FIPS_digestupdate(EVP_MD_CTX *ctx, const void *data, size_t count) { + FIPS_selftest_check(); return ctx->update(ctx,data,count); } @@ -170,6 +213,8 @@ int FIPS_digestfinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size) { int ret; + FIPS_selftest_check(); + OPENSSL_assert(ctx->digest->md_size <= EVP_MAX_MD_SIZE); ret=ctx->digest->final(ctx,md); if (size != NULL) -- 2.34.1