diff options
author | Dr. Stephen Henson <steve@openssl.org> | 2011-04-23 19:55:55 +0000 |
---|---|---|
committer | Dr. Stephen Henson <steve@openssl.org> | 2011-04-23 19:55:55 +0000 |
commit | cac4fb58e02d8cf799d75212179f56c69e652ec7 (patch) | |
tree | d96dd01b03818cc88755fee7fe19d28d3ed9b43e /crypto | |
parent | 9e5fe439b4e8fb4198f241f2ba16a029a480d5f5 (diff) | |
download | openssl-new-cac4fb58e02d8cf799d75212179f56c69e652ec7.tar.gz |
Add PRNG security strength checking.
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/dsa/dsa.h | 1 | ||||
-rw-r--r-- | crypto/dsa/dsa_gen.c | 68 | ||||
-rw-r--r-- | crypto/dsa/dsa_key.c | 5 | ||||
-rw-r--r-- | crypto/dsa/dsa_ossl.c | 5 | ||||
-rw-r--r-- | crypto/ec/ec.h | 10 | ||||
-rw-r--r-- | crypto/ec/ec_key.c | 64 | ||||
-rw-r--r-- | crypto/ec/ec_lcl.h | 1 | ||||
-rw-r--r-- | crypto/ecdsa/ecs_ossl.c | 10 | ||||
-rw-r--r-- | crypto/fips_err.h | 5 | ||||
-rw-r--r-- | crypto/rsa/rsa.h | 4 | ||||
-rw-r--r-- | crypto/rsa/rsa_gen.c | 46 | ||||
-rw-r--r-- | crypto/rsa/rsa_x931g.c | 5 |
12 files changed, 212 insertions, 12 deletions
diff --git a/crypto/dsa/dsa.h b/crypto/dsa/dsa.h index b68fbce169..86766dacb4 100644 --- a/crypto/dsa/dsa.h +++ b/crypto/dsa/dsa.h @@ -113,6 +113,7 @@ */ #define DSA_FLAG_NON_FIPS_ALLOW 0x0400 +#define DSA_FLAG_FIPS_CHECKED 0x0800 #ifdef __cplusplus extern "C" { diff --git a/crypto/dsa/dsa_gen.c b/crypto/dsa/dsa_gen.c index 6517b1592d..4d6bbc0d05 100644 --- a/crypto/dsa/dsa_gen.c +++ b/crypto/dsa/dsa_gen.c @@ -83,6 +83,7 @@ #include <openssl/sha.h> #ifdef OPENSSL_FIPS #include <openssl/fips.h> +#include <openssl/fips_rand.h> #endif #include "dsa_locl.h" @@ -140,7 +141,8 @@ int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits, goto err; } - if (FIPS_mode() && (bits < OPENSSL_DSA_FIPS_MIN_MODULUS_BITS)) + if (FIPS_mode() && !(ret->flags & DSA_FLAG_NON_FIPS_ALLOW) + && (bits < OPENSSL_DSA_FIPS_MIN_MODULUS_BITS)) { DSAerr(DSA_F_DSA_BUILTIN_PARAMGEN, DSA_R_KEY_SIZE_TOO_SMALL); goto err; @@ -375,7 +377,24 @@ err: */ -static int dsa2_security_strength(size_t L, size_t N) +static int fips_ffc_strength(size_t L, size_t N) + { + if (L >= 15360 && N >= 512) + return 256; + if (L >= 7680 && N >= 384) + return 192; + if (L >= 3072 && N >= 256) + return 128; + if (L >= 2048 && N >= 224) + return 112; + if (L >= 1024 && N >= 160) + return 80; + return 0; + } + +/* Valid DSA2 parameters from FIPS 186-3 */ + +static int dsa2_valid_parameters(size_t L, size_t N) { if (L == 1024 && N == 160) return 80; @@ -388,6 +407,42 @@ static int dsa2_security_strength(size_t L, size_t N) return 0; } +int fips_check_dsa_prng(DSA *dsa, size_t L, size_t N) + { + int strength; + if (!FIPS_mode()) + return 1; + + if (dsa->flags & (DSA_FLAG_NON_FIPS_ALLOW|DSA_FLAG_FIPS_CHECKED)) + return 1; + + if (!L || !N) + { + L = BN_num_bits(dsa->p); + N = BN_num_bits(dsa->q); + } + if (!dsa2_valid_parameters(L, N)) + { + FIPSerr(FIPS_F_FIPS_CHECK_DSA_PRNG, FIPS_R_INVALID_PARAMETERS); + return 0; + } + + strength = fips_ffc_strength(L, N); + + if (!strength) + { + FIPSerr(FIPS_F_FIPS_CHECK_DSA_PRNG,FIPS_R_KEY_TOO_SHORT); + return 0; + } + + if (FIPS_rand_strength() >= strength) + return 1; + + FIPSerr(FIPS_F_FIPS_CHECK_DSA_PRNG,FIPS_R_PRNG_STRENGTH_TOO_LOW); + return 0; + + } + /* This is a parameter generation algorithm for the DSA2 algorithm as * described in FIPS 186-3. */ @@ -417,13 +472,10 @@ int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N, FIPS_R_FIPS_SELFTEST_FAILED); goto err; } -#endif - if (!dsa2_security_strength(L, N)) - { - DSAerr(DSA_F_DSA_BUILTIN_PARAMGEN2, DSA_R_INVALID_PARAMETERS); - ok = 0; + + if (!fips_check_dsa_prng(ret, L, N)) goto err; - } +#endif if (evpmd == NULL) { diff --git a/crypto/dsa/dsa_key.c b/crypto/dsa/dsa_key.c index 942000e3a5..3df9a6c6a9 100644 --- a/crypto/dsa/dsa_key.c +++ b/crypto/dsa/dsa_key.c @@ -106,11 +106,14 @@ static int dsa_builtin_keygen(DSA *dsa) BIGNUM *pub_key=NULL,*priv_key=NULL; #ifdef OPENSSL_FIPS - if (FIPS_mode() && (BN_num_bits(dsa->p) < OPENSSL_DSA_FIPS_MIN_MODULUS_BITS)) + if (FIPS_mode() && !(dsa->flags & DSA_FLAG_NON_FIPS_ALLOW) + && (BN_num_bits(dsa->p) < OPENSSL_DSA_FIPS_MIN_MODULUS_BITS)) { DSAerr(DSA_F_DSA_BUILTIN_KEYGEN, DSA_R_KEY_SIZE_TOO_SMALL); goto err; } + if (!fips_check_dsa_prng(dsa, 0, 0)) + goto err; #endif if ((ctx=BN_CTX_new()) == NULL) goto err; diff --git a/crypto/dsa/dsa_ossl.c b/crypto/dsa/dsa_ossl.c index f1512a40dd..acf7af95c4 100644 --- a/crypto/dsa/dsa_ossl.c +++ b/crypto/dsa/dsa_ossl.c @@ -150,11 +150,14 @@ static DSA_SIG *dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa) return NULL; } - if (FIPS_mode() && (BN_num_bits(dsa->p) < OPENSSL_DSA_FIPS_MIN_MODULUS_BITS)) + if (FIPS_mode() && !(dsa->flags & DSA_FLAG_NON_FIPS_ALLOW) + && (BN_num_bits(dsa->p) < OPENSSL_DSA_FIPS_MIN_MODULUS_BITS)) { DSAerr(DSA_F_DSA_DO_SIGN, DSA_R_KEY_SIZE_TOO_SMALL); return NULL; } + if (!fips_check_dsa_prng(dsa, 0, 0)) + goto err; #endif BN_init(&m); diff --git a/crypto/ec/ec.h b/crypto/ec/ec.h index 69d78642cc..acf9df1aab 100644 --- a/crypto/ec/ec.h +++ b/crypto/ec/ec.h @@ -703,11 +703,21 @@ typedef struct ec_key_st EC_KEY; #define EC_PKEY_NO_PARAMETERS 0x001 #define EC_PKEY_NO_PUBKEY 0x002 +/* some values for the flags field */ +#define EC_FLAG_NON_FIPS_ALLOW 0x1 +#define EC_FLAG_FIPS_CHECKED 0x2 + /** Creates a new EC_KEY object. * \return EC_KEY object or NULL if an error occurred. */ EC_KEY *EC_KEY_new(void); +int EC_KEY_get_flags(const EC_KEY *key); + +void EC_KEY_set_flags(EC_KEY *key, int flags); + +void EC_KEY_clear_flags(EC_KEY *key, int flags); + /** Creates a new EC_KEY object using a named curve as underlying * EC_GROUP object. * \param nid NID of the named curve. diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c index ad3022f868..4583d02f27 100644 --- a/crypto/ec/ec_key.c +++ b/crypto/ec/ec_key.c @@ -80,6 +80,7 @@ EC_KEY *EC_KEY_new(void) } ret->version = 1; + ret->flags = 0; ret->group = NULL; ret->pub_key = NULL; ret->priv_key= NULL; @@ -199,6 +200,7 @@ EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) dest->enc_flag = src->enc_flag; dest->conv_form = src->conv_form; dest->version = src->version; + dest->flags = src->flags; return dest; } @@ -235,6 +237,8 @@ int EC_KEY_up_ref(EC_KEY *r) #ifdef OPENSSL_FIPS #include <openssl/evp.h> +#include <openssl/fips.h> +#include <openssl/fips_rand.h> static int fips_check_ec(EC_KEY *key) { @@ -253,6 +257,46 @@ static int fips_check_ec(EC_KEY *key) return 1; } +int fips_check_ec_prng(EC_KEY *ec) + { + int bits, strength; + if (!FIPS_mode()) + return 1; + + if (ec->flags & (EC_FLAG_NON_FIPS_ALLOW|EC_FLAG_FIPS_CHECKED)) + return 1; + + if (!ec->group) + return 1; + + bits = BN_num_bits(&ec->group->order); + + if (bits < 160) + { + FIPSerr(FIPS_F_FIPS_CHECK_DSA_PRNG,FIPS_R_KEY_TOO_SHORT); + return 0; + } + /* Comparable algorithm strengths: from SP800-57 table 2 */ + if (bits >= 512) + strength = 256; + else if (bits >= 384) + strength = 192; + else if (bits >= 256) + strength = 128; + else if (bits >= 224) + strength = 112; + else + strength = 80; + + + if (FIPS_rand_strength() >= strength) + return 1; + + FIPSerr(FIPS_F_FIPS_CHECK_EC_PRNG,FIPS_R_PRNG_STRENGTH_TOO_LOW); + return 0; + + } + #endif int EC_KEY_generate_key(EC_KEY *eckey) @@ -283,6 +327,11 @@ int EC_KEY_generate_key(EC_KEY *eckey) if (!EC_GROUP_get_order(eckey->group, order, ctx)) goto err; +#ifdef OPENSSL_FIPS + if (!fips_check_ec_prng(eckey)) + goto err; +#endif + do if (!BN_rand_range(priv_key, order)) goto err; @@ -571,3 +620,18 @@ int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx) return 0; return EC_GROUP_precompute_mult(key->group, ctx); } + +int EC_KEY_get_flags(const EC_KEY *key) + { + return key->flags; + } + +void EC_KEY_set_flags(EC_KEY *key, int flags) + { + key->flags |= flags; + } + +void EC_KEY_clear_flags(EC_KEY *key, int flags) + { + key->flags &= ~flags; + } diff --git a/crypto/ec/ec_lcl.h b/crypto/ec/ec_lcl.h index 2e978181b9..afa1efa4bc 100644 --- a/crypto/ec/ec_lcl.h +++ b/crypto/ec/ec_lcl.h @@ -249,6 +249,7 @@ struct ec_key_st { point_conversion_form_t conv_form; int references; + int flags; EC_EXTRA_DATA *method_data; } /* EC_KEY */; diff --git a/crypto/ecdsa/ecs_ossl.c b/crypto/ecdsa/ecs_ossl.c index 4ed29d1889..3518bb02e1 100644 --- a/crypto/ecdsa/ecs_ossl.c +++ b/crypto/ecdsa/ecs_ossl.c @@ -133,6 +133,11 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } + +#ifdef OPENSSL_FIPS + if (!fips_check_ec_prng(eckey)) + goto err; +#endif do { @@ -235,6 +240,11 @@ static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len, return NULL; } +#ifdef OPENSSL_FIPS + if (!fips_check_ec_prng(eckey)) + return NULL; +#endif + ret = ECDSA_SIG_new(); if (!ret) { diff --git a/crypto/fips_err.h b/crypto/fips_err.h index 041bc1567a..5555f2d50b 100644 --- a/crypto/fips_err.h +++ b/crypto/fips_err.h @@ -77,9 +77,12 @@ static ERR_STRING_DATA FIPS_str_functs[]= {ERR_FUNC(FIPS_F_DSA_DO_SIGN), "DSA_do_sign"}, {ERR_FUNC(FIPS_F_DSA_DO_VERIFY), "DSA_do_verify"}, {ERR_FUNC(FIPS_F_FIPS_CHECK_DSA), "FIPS_CHECK_DSA"}, +{ERR_FUNC(FIPS_F_FIPS_CHECK_DSA_PRNG), "fips_check_dsa_prng"}, {ERR_FUNC(FIPS_F_FIPS_CHECK_EC), "FIPS_CHECK_EC"}, +{ERR_FUNC(FIPS_F_FIPS_CHECK_EC_PRNG), "fips_check_ec_prng"}, {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_CHECK_RSA_PRNG), "fips_check_rsa_prng"}, {ERR_FUNC(FIPS_F_FIPS_CIPHERINIT), "FIPS_CIPHERINIT"}, {ERR_FUNC(FIPS_F_FIPS_DIGESTINIT), "FIPS_DIGESTINIT"}, {ERR_FUNC(FIPS_F_FIPS_DRBG_BYTES), "FIPS_DRBG_BYTES"}, @@ -149,6 +152,7 @@ static ERR_STRING_DATA FIPS_str_reasons[]= {ERR_REASON(FIPS_R_INSUFFICIENT_SECURITY_STRENGTH),"insufficient security strength"}, {ERR_REASON(FIPS_R_INTERNAL_ERROR) ,"internal error"}, {ERR_REASON(FIPS_R_INVALID_KEY_LENGTH) ,"invalid key length"}, +{ERR_REASON(FIPS_R_INVALID_PARAMETERS) ,"invalid parameters"}, {ERR_REASON(FIPS_R_IN_ERROR_STATE) ,"in error state"}, {ERR_REASON(FIPS_R_KEY_TOO_SHORT) ,"key too short"}, {ERR_REASON(FIPS_R_NON_FIPS_METHOD) ,"non fips method"}, @@ -156,6 +160,7 @@ static ERR_STRING_DATA FIPS_str_reasons[]= {ERR_REASON(FIPS_R_PAIRWISE_TEST_FAILED) ,"pairwise test failed"}, {ERR_REASON(FIPS_R_PERSONALISATION_ERROR_UNDETECTED),"personalisation error undetected"}, {ERR_REASON(FIPS_R_PERSONALISATION_STRING_TOO_LONG),"personalisation string too long"}, +{ERR_REASON(FIPS_R_PRNG_STRENGTH_TOO_LOW),"prng strength too low"}, {ERR_REASON(FIPS_R_REQUEST_LENGTH_ERROR_UNDETECTED),"request length error undetected"}, {ERR_REASON(FIPS_R_REQUEST_TOO_LARGE_FOR_DRBG),"request too large for drbg"}, {ERR_REASON(FIPS_R_RESEED_COUNTER_ERROR) ,"reseed counter error"}, diff --git a/crypto/rsa/rsa.h b/crypto/rsa/rsa.h index b91501a8d0..7174f9cee8 100644 --- a/crypto/rsa/rsa.h +++ b/crypto/rsa/rsa.h @@ -470,6 +470,10 @@ RSA *RSAPrivateKey_dup(RSA *rsa); */ #define RSA_FLAG_NON_FIPS_ALLOW 0x0400 +/* Application has decided PRNG is good enough to generate a key: don't + * check. + */ +#define RSA_FLAG_CHECKED 0x0800 /* BEGIN ERROR CODES */ /* The following lines are auto generated by the script mkerr.pl. Any changes diff --git a/crypto/rsa/rsa_gen.c b/crypto/rsa/rsa_gen.c index 484468da05..24f9eaf4d6 100644 --- a/crypto/rsa/rsa_gen.c +++ b/crypto/rsa/rsa_gen.c @@ -74,8 +74,49 @@ #include <openssl/fips.h> +#include <openssl/fips_rand.h> #include <openssl/evp.h> +/* Check PRNG has sufficient security level to handle an RSA operation */ + +int fips_check_rsa_prng(RSA *rsa, int bits) + { + int strength; + if (!FIPS_mode()) + return 1; + + if (rsa->flags & (RSA_FLAG_NON_FIPS_ALLOW|RSA_FLAG_CHECKED)) + return 1; + + if (bits == 0) + bits = BN_num_bits(rsa->n); + + /* Should never happen */ + if (bits < 1024) + { + FIPSerr(FIPS_F_FIPS_CHECK_RSA_PRNG,FIPS_R_KEY_TOO_SHORT); + return 0; + } + /* From SP800-57 */ + if (bits < 2048) + strength = 80; + else if (bits < 3072) + strength = 112; + else if (bits < 7680) + strength = 128; + else if (bits < 15360) + strength = 192; + else + strength = 256; + + if (FIPS_rand_strength() >= strength) + return 1; + + FIPSerr(FIPS_F_FIPS_CHECK_RSA_PRNG,FIPS_R_PRNG_STRENGTH_TOO_LOW); + return 0; + } + + int fips_check_rsa(RSA *rsa) { const unsigned char tbs[] = "RSA Pairwise Check Data"; @@ -164,11 +205,14 @@ static int rsa_builtin_keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) return 0; } - if (FIPS_mode() && (bits < OPENSSL_RSA_FIPS_MIN_MODULUS_BITS)) + if (FIPS_mode() && !(rsa->flags & RSA_FLAG_NON_FIPS_ALLOW) + && (bits < OPENSSL_RSA_FIPS_MIN_MODULUS_BITS)) { FIPSerr(FIPS_F_RSA_BUILTIN_KEYGEN,FIPS_R_KEY_TOO_SHORT); return 0; } + if (!fips_check_rsa_prng(rsa, bits)) + return 0; #endif ctx=BN_CTX_new(); diff --git a/crypto/rsa/rsa_x931g.c b/crypto/rsa/rsa_x931g.c index 1ccd0a1969..819a728954 100644 --- a/crypto/rsa/rsa_x931g.c +++ b/crypto/rsa/rsa_x931g.c @@ -210,7 +210,8 @@ int RSA_X931_generate_key_ex(RSA *rsa, int bits, const BIGNUM *e, BN_GENCB *cb) BN_CTX *ctx = NULL; #ifdef OPENSSL_FIPS - if (bits < OPENSSL_RSA_FIPS_MIN_MODULUS_BITS) + if (FIPS_mode() && !(rsa->flags & RSA_FLAG_NON_FIPS_ALLOW) && + (bits < OPENSSL_RSA_FIPS_MIN_MODULUS_BITS)) { FIPSerr(FIPS_F_RSA_X931_GENERATE_KEY_EX,FIPS_R_KEY_TOO_SHORT); return 0; @@ -227,6 +228,8 @@ int RSA_X931_generate_key_ex(RSA *rsa, int bits, const BIGNUM *e, BN_GENCB *cb) FIPSerr(FIPS_F_RSA_X931_GENERATE_KEY_EX,FIPS_R_FIPS_SELFTEST_FAILED); return 0; } + if (!fips_check_rsa_prng(rsa, bits)) + return 0; #endif ctx = BN_CTX_new(); |