Add PRNG security strength checking.
authorDr. Stephen Henson <steve@openssl.org>
Sat, 23 Apr 2011 19:55:55 +0000 (19:55 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Sat, 23 Apr 2011 19:55:55 +0000 (19:55 +0000)
14 files changed:
CHANGES
crypto/dsa/dsa.h
crypto/dsa/dsa_gen.c
crypto/dsa/dsa_key.c
crypto/dsa/dsa_ossl.c
crypto/ec/ec.h
crypto/ec/ec_key.c
crypto/ec/ec_lcl.h
crypto/ecdsa/ecs_ossl.c
crypto/fips_err.h
crypto/rsa/rsa.h
crypto/rsa/rsa_gen.c
crypto/rsa/rsa_x931g.c
fips/fips.h

diff --git a/CHANGES b/CHANGES
index 29ac9dc..6e54214 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,10 @@
 
  Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]
 
+  *) Add PRNG security strength checks to RSA, DSA and ECDSA using 
+     information in FIPS186-3, SP800-57 and SP800-131A.
+     [Steve Henson]
+
   *) CCM support via EVP. Interface is very similar to GCM case except we
      must supply all data in one chunk (i.e. no update, final) and the
      message length must be supplied if AAD is used. Add algorithm test
index b68fbce..86766da 100644 (file)
  */
 
 #define DSA_FLAG_NON_FIPS_ALLOW                        0x0400
+#define DSA_FLAG_FIPS_CHECKED                  0x0800
 
 #ifdef  __cplusplus
 extern "C" {
index 6517b15..4d6bbc0 100644 (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)
                {
index 942000e..3df9a6c 100644 (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;
index f1512a4..acf7af9 100644 (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);
index 69d7864..acf9df1 100644 (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.
index ad3022f..4583d02 100644 (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;
+       }
index 2e97818..afa1efa 100644 (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 */;
index 4ed29d1..3518bb0 100644 (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)
        {
index 041bc15..5555f2d 100644 (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"},
index b91501a..7174f9c 100644 (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
index 484468d..24f9eaf 100644 (file)
 
 
 #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();
index 1ccd0a1..819a728 100644 (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();
index 60cc097..e07a795 100644 (file)
@@ -60,6 +60,7 @@ extern "C" {
 #endif
 
 struct dsa_st;
+struct ec_key_st;
 struct rsa_st;
 struct evp_pkey_st;
 struct env_md_st;
@@ -94,6 +95,9 @@ int FIPS_check_incore_fingerprint(void);
 
 void fips_set_selftest_fail(void);
 int fips_check_rsa(struct rsa_st *rsa);
+int fips_check_rsa_prng(struct rsa_st *rsa, int bits);
+int fips_check_dsa_prng(struct dsa_st *dsa, size_t L, size_t N);
+int fips_check_ec_prng(struct ec_key_st *ec);
 
 void FIPS_set_locking_callbacks(void (*func)(int mode, int type,
                                const char *file,int line),
@@ -239,9 +243,12 @@ void ERR_load_FIPS_strings(void);
 #define FIPS_F_DSA_DO_SIGN                              103
 #define FIPS_F_DSA_DO_VERIFY                            104
 #define FIPS_F_FIPS_CHECK_DSA                           105
+#define FIPS_F_FIPS_CHECK_DSA_PRNG                      151
 #define FIPS_F_FIPS_CHECK_EC                            106
+#define FIPS_F_FIPS_CHECK_EC_PRNG                       152
 #define FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT            107
 #define FIPS_F_FIPS_CHECK_RSA                           108
+#define FIPS_F_FIPS_CHECK_RSA_PRNG                      150
 #define FIPS_F_FIPS_CIPHERINIT                          109
 #define FIPS_F_FIPS_DIGESTINIT                          110
 #define FIPS_F_FIPS_DRBG_BYTES                          111
@@ -308,6 +315,7 @@ void ERR_load_FIPS_strings(void);
 #define FIPS_R_INSUFFICIENT_SECURITY_STRENGTH           120
 #define FIPS_R_INTERNAL_ERROR                           121
 #define FIPS_R_INVALID_KEY_LENGTH                       122
+#define FIPS_R_INVALID_PARAMETERS                       144
 #define FIPS_R_IN_ERROR_STATE                           123
 #define FIPS_R_KEY_TOO_SHORT                            124
 #define FIPS_R_NON_FIPS_METHOD                          125
@@ -315,6 +323,7 @@ void ERR_load_FIPS_strings(void);
 #define FIPS_R_PAIRWISE_TEST_FAILED                     127
 #define FIPS_R_PERSONALISATION_ERROR_UNDETECTED                 128
 #define FIPS_R_PERSONALISATION_STRING_TOO_LONG          129
+#define FIPS_R_PRNG_STRENGTH_TOO_LOW                    143
 #define FIPS_R_REQUEST_LENGTH_ERROR_UNDETECTED          130
 #define FIPS_R_REQUEST_TOO_LARGE_FOR_DRBG               131
 #define FIPS_R_RESEED_COUNTER_ERROR                     132