Add PRNG security strength checking.

This commit is contained in:
Dr. Stephen Henson
2011-04-23 19:55:55 +00:00
parent 9e5fe439b4
commit cac4fb58e0
14 changed files with 225 additions and 12 deletions

View File

@@ -113,6 +113,7 @@
*/
#define DSA_FLAG_NON_FIPS_ALLOW 0x0400
#define DSA_FLAG_FIPS_CHECKED 0x0800
#ifdef __cplusplus
extern "C" {

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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);

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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 */;

View File

@@ -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)
{

View File

@@ -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"},

View File

@@ -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

View File

@@ -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();

View File

@@ -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();