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
*/
#define DSA_FLAG_NON_FIPS_ALLOW 0x0400
+#define DSA_FLAG_FIPS_CHECKED 0x0800
#ifdef __cplusplus
extern "C" {
#include <openssl/sha.h>
#ifdef OPENSSL_FIPS
#include <openssl/fips.h>
+#include <openssl/fips_rand.h>
#endif
#include "dsa_locl.h"
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;
*/
-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;
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.
*/
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)
{
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;
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);
#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.
}
ret->version = 1;
+ ret->flags = 0;
ret->group = NULL;
ret->pub_key = NULL;
ret->priv_key= NULL;
dest->enc_flag = src->enc_flag;
dest->conv_form = src->conv_form;
dest->version = src->version;
+ dest->flags = src->flags;
return dest;
}
#ifdef OPENSSL_FIPS
#include <openssl/evp.h>
+#include <openssl/fips.h>
+#include <openssl/fips_rand.h>
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)
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;
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;
+ }
point_conversion_form_t conv_form;
int references;
+ int flags;
EC_EXTRA_DATA *method_data;
} /* EC_KEY */;
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
{
return NULL;
}
+#ifdef OPENSSL_FIPS
+ if (!fips_check_ec_prng(eckey))
+ return NULL;
+#endif
+
ret = ECDSA_SIG_new();
if (!ret)
{
{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"},
{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"},
{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"},
*/
#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
#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";
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();
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;
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();
#endif
struct dsa_st;
+struct ec_key_st;
struct rsa_st;
struct evp_pkey_st;
struct env_md_st;
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),
#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
#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
#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