summaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2011-04-23 19:55:55 +0000
committerDr. Stephen Henson <steve@openssl.org>2011-04-23 19:55:55 +0000
commitcac4fb58e02d8cf799d75212179f56c69e652ec7 (patch)
treed96dd01b03818cc88755fee7fe19d28d3ed9b43e /crypto
parent9e5fe439b4e8fb4198f241f2ba16a029a480d5f5 (diff)
downloadopenssl-new-cac4fb58e02d8cf799d75212179f56c69e652ec7.tar.gz
Add PRNG security strength checking.
Diffstat (limited to 'crypto')
-rw-r--r--crypto/dsa/dsa.h1
-rw-r--r--crypto/dsa/dsa_gen.c68
-rw-r--r--crypto/dsa/dsa_key.c5
-rw-r--r--crypto/dsa/dsa_ossl.c5
-rw-r--r--crypto/ec/ec.h10
-rw-r--r--crypto/ec/ec_key.c64
-rw-r--r--crypto/ec/ec_lcl.h1
-rw-r--r--crypto/ecdsa/ecs_ossl.c10
-rw-r--r--crypto/fips_err.h5
-rw-r--r--crypto/rsa/rsa.h4
-rw-r--r--crypto/rsa/rsa_gen.c46
-rw-r--r--crypto/rsa/rsa_x931g.c5
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();