Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Allowed RSA KeySize Generation to FIPS 186-5 specification #1823

Merged
merged 4 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions crypto/fipsmodule/rsa/rsa_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1269,11 +1269,12 @@ int RSA_generate_key_ex(RSA *rsa, int bits, const BIGNUM *e_value,
}

int RSA_generate_key_fips(RSA *rsa, int bits, BN_GENCB *cb) {
// FIPS 186-4 allows 2048-bit and 3072-bit RSA keys (1024-bit and 1536-bit
// primes, respectively) with the prime generation method we use.
// Subsequently, IG A.14 stated that larger modulus sizes can be used and ACVP
// testing supports 4096 bits.
if (bits != 2048 && bits != 3072 && bits != 4096) {
// FIPS 186-5 Section 5.1:
// This standard specifies the use of a modulus whose bit length is an even
// integer and greater than or equal to 2048 bits. Furthermore, this standard
// specifies that p and q be of the same bit length – namely, half the bit
// length of n
if (bits < 2048 || bits % 128 != 0) {
OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_RSA_PARAMETERS);
return 0;
}
Expand Down
26 changes: 9 additions & 17 deletions crypto/fipsmodule/service_indicator/service_indicator.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,14 +260,12 @@ static void evp_md_ctx_verify_service_indicator(const EVP_MD_CTX *ctx,
}
}

// The approved RSA key sizes for signing are 2048, 3072 and 4096 bits.
// Note: |EVP_PKEY_size| returns the size in bytes.
size_t pkey_size = EVP_PKEY_size(ctx->pctx->pkey);
// The approved RSA key sizes for signing are key sizes >= 2048 bits and bits % 2 == 0.
size_t n_bits = RSA_bits(ctx->pctx->pkey->pkey.rsa);

// Check if the MD type and the RSA key size are approved.
if (md_ok(md_type, pkey_type) &&
((rsa_1024_ok && pkey_size == 128) || pkey_size == 256 ||
pkey_size == 384 || pkey_size == 512)) {
((rsa_1024_ok && n_bits == 1024) || (n_bits >= 2048 && n_bits % 2 == 0))) {
skmcgrail marked this conversation as resolved.
Show resolved Hide resolved
FIPS_service_indicator_update_state();
}
} else if (pkey_type == EVP_PKEY_EC) {
Expand Down Expand Up @@ -299,18 +297,12 @@ void ECDH_verify_service_indicator(const EC_KEY *ec_key) {

void EVP_PKEY_keygen_verify_service_indicator(const EVP_PKEY *pkey) {
if (pkey->type == EVP_PKEY_RSA || pkey->type == EVP_PKEY_RSA_PSS) {
// 2048, 3072 and 4096 bit keys are approved for RSA key generation.
// EVP_PKEY_size returns the size of the key in bytes.
// Note: |EVP_PKEY_size| returns the length in bytes.
size_t key_size = EVP_PKEY_size(pkey);
switch (key_size) {
case 256:
case 384:
case 512:
FIPS_service_indicator_update_state();
break;
default:
break;
// The approved RSA key sizes for signing are key sizes >= 2048 bits and
// bits % 2 == 0, though we check bits % 128 == 0 for consistency with
// our RSA key generation.
size_t n_bits = RSA_bits(pkey->pkey.rsa);
if (n_bits >= 2048 && n_bits % 128 == 0) {
FIPS_service_indicator_update_state();
}
} else if (pkey->type == EVP_PKEY_EC) {
// Note: even though the function is called |EC_GROUP_get_curve_name|
Expand Down
92 changes: 67 additions & 25 deletions crypto/fipsmodule/service_indicator/service_indicator_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2012,9 +2012,8 @@ TEST(ServiceIndicatorTest, RSAKeyGen) {
bssl::UniquePtr<RSA> rsa(RSA_new());
ASSERT_TRUE(rsa);

// |RSA_generate_key_fips| may only be used for 2048-, 3072-, and 4096-bit
// keys.
for (const size_t bits : {512, 1024, 3071, 4095}) {
// |RSA_generate_key_fips| may only be used for bits >= 2048 && bits % 128 == 0
for (const size_t bits : {512, 1024, 2520, 3071}) {
SCOPED_TRACE(bits);

rsa.reset(RSA_new());
Expand All @@ -2023,8 +2022,9 @@ TEST(ServiceIndicatorTest, RSAKeyGen) {
EXPECT_EQ(approved, AWSLC_NOT_APPROVED);
}

// Test that we can generate keys of the supported lengths:
for (const size_t bits : {2048, 3072, 4096}) {
// Test that we can generate keys with supported lengths,
// larger key sizes are supported but are omitted for time.
for (const size_t bits : {2048, 3072, 4096, 6144, 8192}) {
SCOPED_TRACE(bits);

rsa.reset(RSA_new());
Expand All @@ -2044,7 +2044,7 @@ TEST(ServiceIndicatorTest, RSAKeyGen) {
ASSERT_TRUE(ctx);

if (kEVPKeyGenShouldCallFIPSFunctions) {
// Test unapproved key sizes of RSA.
// Test various unapproved key sizes of RSA.
for (const size_t bits : {512, 1024, 3071, 4095}) {
skmcgrail marked this conversation as resolved.
Show resolved Hide resolved
SCOPED_TRACE(bits);
CALL_SERVICE_AND_CHECK_APPROVED(
Expand All @@ -2058,8 +2058,8 @@ TEST(ServiceIndicatorTest, RSAKeyGen) {
raw = nullptr;
}

// Test approved key sizes of RSA.
for (const size_t bits : {2048, 3072, 4096}) {
// Test various approved key sizes of RSA.
for (const size_t bits : {2048, 3072, 4096, 6144, 8192}) {
SCOPED_TRACE(bits);
CALL_SERVICE_AND_CHECK_APPROVED(
approved, ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())));
Expand Down Expand Up @@ -2094,9 +2094,6 @@ struct RSATestVector kRSATestVectors[] = {
{ 1536, &EVP_sha256, false, AWSLC_NOT_APPROVED, AWSLC_NOT_APPROVED },
{ 1536, &EVP_sha512, true, AWSLC_NOT_APPROVED, AWSLC_NOT_APPROVED },
{ 2048, &EVP_md5, false, AWSLC_NOT_APPROVED, AWSLC_NOT_APPROVED },
{ 3071, &EVP_md5, true, AWSLC_NOT_APPROVED, AWSLC_NOT_APPROVED },
{ 3071, &EVP_sha256, false, AWSLC_NOT_APPROVED, AWSLC_NOT_APPROVED },
{ 3071, &EVP_sha512, true, AWSLC_NOT_APPROVED, AWSLC_NOT_APPROVED },
{ 4096, &EVP_md5, false, AWSLC_NOT_APPROVED, AWSLC_NOT_APPROVED },

// RSA test cases that are approved.
Expand Down Expand Up @@ -2194,6 +2191,54 @@ struct RSATestVector kRSATestVectors[] = {
{ 4096, &EVP_sha3_256, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 4096, &EVP_sha3_384, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 4096, &EVP_sha3_512, true, AWSLC_APPROVED, AWSLC_APPROVED },

{ 6144, &EVP_sha1, false, AWSLC_NOT_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha224, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha256, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha384, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha512, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha512_224, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha512_256, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha3_224, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha3_256, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha3_384, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha3_512, false, AWSLC_APPROVED, AWSLC_APPROVED },

{ 6144, &EVP_sha1, true, AWSLC_NOT_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha224, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha256, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha384, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha512, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha512_224, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha512_256, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha3_224, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha3_256, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha3_384, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 6144, &EVP_sha3_512, true, AWSLC_APPROVED, AWSLC_APPROVED },

{ 8192, &EVP_sha1, false, AWSLC_NOT_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha224, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha256, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha384, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha512, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha512_224, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha512_256, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha3_224, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha3_256, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha3_384, false, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha3_512, false, AWSLC_APPROVED, AWSLC_APPROVED },

{ 8192, &EVP_sha1, true, AWSLC_NOT_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha224, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha256, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha384, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha512, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha512_224, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha512_256, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha3_224, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha3_256, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha3_384, true, AWSLC_APPROVED, AWSLC_APPROVED },
{ 8192, &EVP_sha3_512, true, AWSLC_APPROVED, AWSLC_APPROVED },
};

class RSAServiceIndicatorTest : public TestWithNoErrors<RSATestVector> {};
Expand Down Expand Up @@ -2228,20 +2273,20 @@ static RSA *GetRSAKey(unsigned bits) {
return ret;
}

// When using |EVP_PKEY_assign| to assign |RSA| to |EVP_PKEY|, the pointer will
// get assigned to |EVP_PKEY| and get freed along with it.
static RSA *GetRSAPSSKey(unsigned bits) {
bssl::UniquePtr<BIGNUM> e(BN_new());
if (!e || !BN_set_word(e.get(), RSA_F4)) {
static void AssignRSAPSSKey(EVP_PKEY *pkey, unsigned bits) {
RSA *rsa = GetRSAKey(bits);
if (rsa == NULL || pkey == NULL) {
abort();
}

RSA *key = RSA_new();
if (!key || !RSA_generate_key_ex(key, bits, e.get(), nullptr)) {
// When using |EVP_PKEY_assign| to assign |RSA| to |EVP_PKEY|, the pointer
// will get assigned to |EVP_PKEY| and get freed along with it. This will not
// up the reference to RSA unlike |EVP_PKEY_assign_RSA|! So we do that after.
if (!EVP_PKEY_assign(pkey, EVP_PKEY_RSA_PSS, rsa)) {
abort();
}

return key;
RSA_up_ref(rsa);
}

TEST_P(RSAServiceIndicatorTest, RSASigGen) {
Expand All @@ -2252,8 +2297,7 @@ TEST_P(RSAServiceIndicatorTest, RSASigGen) {
ASSERT_TRUE(pkey);
RSA *rsa = nullptr;
if(test.use_pss) {
rsa = GetRSAPSSKey(test.key_size);
ASSERT_TRUE(EVP_PKEY_assign(pkey.get(), EVP_PKEY_RSA_PSS, rsa));
AssignRSAPSSKey(pkey.get(), test.key_size);
} else {
rsa = GetRSAKey(test.key_size);
ASSERT_TRUE(EVP_PKEY_set1_RSA(pkey.get(), rsa));
Expand Down Expand Up @@ -2350,8 +2394,7 @@ TEST_P(RSAServiceIndicatorTest, RSASigVer) {

RSA *rsa = nullptr;
if(test.use_pss) {
rsa = GetRSAPSSKey(test.key_size);
ASSERT_TRUE(EVP_PKEY_assign(pkey.get(), EVP_PKEY_RSA_PSS, rsa));
AssignRSAPSSKey(pkey.get(), test.key_size);
} else {
rsa = GetRSAKey(test.key_size);
ASSERT_TRUE(EVP_PKEY_set1_RSA(pkey.get(), rsa));
Expand Down Expand Up @@ -2432,8 +2475,7 @@ TEST_P(RSAServiceIndicatorTest, ManualRSASignVerify) {

RSA *rsa = nullptr;
if(test.use_pss) {
rsa = GetRSAPSSKey(test.key_size);
ASSERT_TRUE(EVP_PKEY_assign(pkey.get(), EVP_PKEY_RSA_PSS, rsa));
AssignRSAPSSKey(pkey.get(), test.key_size);
} else {
rsa = GetRSAKey(test.key_size);
ASSERT_TRUE(EVP_PKEY_set1_RSA(pkey.get(), rsa));
Expand Down
5 changes: 5 additions & 0 deletions include/openssl/rsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,11 @@ OPENSSL_EXPORT int RSA_meth_set_sign(RSA_METHOD *meth,
// is called with event=2 when the n'th prime is rejected as unsuitable and
// with event=3 when a suitable value for |p| is found.
//
// Note: |bits| is expected to be divisible by 128, and if not will be rounded
// down to the nearest valid value. For example, requesting 3071 bits will
// provide a key that is 2944 bits. |RSA_bits| can be used to verify the
// RSA modulus size of the returned key.
//
// It returns one on success or zero on error.
OPENSSL_EXPORT int RSA_generate_key_ex(RSA *rsa, int bits, const BIGNUM *e,
BN_GENCB *cb);
Expand Down
Binary file modified util/fipstools/acvp/acvptool/test/expected/RSA.bz2
Binary file not shown.
1 change: 1 addition & 0 deletions util/fipstools/acvp/acvptool/test/tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
{"Wrapper": "modulewrapper", "In": "vectors/kdf-components.bz2", "Out": "expected/kdf-components.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/RSA.bz2", "Out": "expected/RSA.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/RSA-SigGen.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/RSA-KeyGen.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/TLS-1.2-KDF.bz2", "Out": "expected/TLS-1.2-KDF.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/PBKDF.bz2", "Out": "expected/PBKDF.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/KDA-HKDF.bz2", "Out": "expected/KDA-HKDF.bz2"},
Expand Down
Binary file not shown.
Binary file modified util/fipstools/acvp/acvptool/test/vectors/RSA-SigGen.bz2
Binary file not shown.
Binary file modified util/fipstools/acvp/acvptool/test/vectors/RSA.bz2
Binary file not shown.
Loading
Loading