diff --git a/crypto/fipsmodule/curve25519/curve25519.c b/crypto/fipsmodule/curve25519/curve25519.c index 1bbf164ddf..5717984a61 100644 --- a/crypto/fipsmodule/curve25519/curve25519.c +++ b/crypto/fipsmodule/curve25519/curve25519.c @@ -112,6 +112,8 @@ void ED25519_keypair(uint8_t out_public_key[ED25519_PUBLIC_KEY_LEN], // description why this is useful. ED25519_keypair_from_seed(out_public_key, out_private_key, seed); OPENSSL_cleanse(seed, ED25519_SEED_LEN); + + FIPS_service_indicator_update_state(); } int ED25519_sign(uint8_t out_sig[ED25519_SIGNATURE_LEN], @@ -155,6 +157,8 @@ int ED25519_sign(uint8_t out_sig[ED25519_SIGNATURE_LEN], // The signature is computed from the private key, but is public. CONSTTIME_DECLASSIFY(out_sig, 64); + + FIPS_service_indicator_update_state(); return 1; } @@ -212,8 +216,12 @@ int ED25519_verify(const uint8_t *message, size_t message_len, #endif // Comparison [S]B - [k]A' =? R_expected. Short-circuits if decoding failed. - return (res == 1) && - CRYPTO_memcmp(R_computed_encoded, R_expected, sizeof(R_computed_encoded)) == 0; + res = (res == 1) && CRYPTO_memcmp(R_computed_encoded, R_expected, + sizeof(R_computed_encoded)) == 0; + if(res) { + FIPS_service_indicator_update_state(); + } + return res; } diff --git a/crypto/fipsmodule/service_indicator/service_indicator.c b/crypto/fipsmodule/service_indicator/service_indicator.c index e642e9626f..df18dc657e 100644 --- a/crypto/fipsmodule/service_indicator/service_indicator.c +++ b/crypto/fipsmodule/service_indicator/service_indicator.c @@ -222,7 +222,14 @@ static void evp_md_ctx_verify_service_indicator(const EVP_MD_CTX *ctx, int (*md_ok)(int md_type, int pkey_type)) { if (EVP_MD_CTX_md(ctx) == NULL) { - // Signature schemes without a prehash are currently never FIPS approved. + if(ctx->pctx->pkey->type == EVP_PKEY_ED25519) { + // FIPS 186-5: + //. 7.6 EdDSA Signature Generation + // 7.7 EdDSA Signature Verification + FIPS_service_indicator_update_state(); + return; + } + // All other signature schemes without a prehash are currently never FIPS approved. goto err; } @@ -330,6 +337,8 @@ void EVP_PKEY_keygen_verify_service_indicator(const EVP_PKEY *pkey) { default: break; } + } else if (pkey->type == EVP_PKEY_ED25519) { + FIPS_service_indicator_update_state(); } } diff --git a/crypto/fipsmodule/service_indicator/service_indicator_test.cc b/crypto/fipsmodule/service_indicator/service_indicator_test.cc index e25587506e..ccb017d7c8 100644 --- a/crypto/fipsmodule/service_indicator/service_indicator_test.cc +++ b/crypto/fipsmodule/service_indicator/service_indicator_test.cc @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -4622,6 +4623,72 @@ TEST(ServiceIndicatorTest, ML_KEM) { } } +TEST(ServiceIndicatorTest, ED25519KeyGen) { + FIPSStatus approved = AWSLC_NOT_APPROVED; + uint8_t private_key[ED25519_PRIVATE_KEY_LEN] = {0}; + uint8_t public_key[ED25519_PUBLIC_KEY_LEN] = {0}; + CALL_SERVICE_AND_CHECK_APPROVED(approved, + ED25519_keypair(public_key, private_key)); + ASSERT_EQ(AWSLC_APPROVED, approved); + + approved = AWSLC_NOT_APPROVED; + + bssl::UniquePtr ctx( + EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, nullptr)); + EVP_PKEY *raw = nullptr; + bssl::UniquePtr pkey(raw); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); + CALL_SERVICE_AND_CHECK_APPROVED( + approved, ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw))); + ASSERT_EQ(AWSLC_APPROVED, approved); + pkey.reset(raw); +} + +TEST(ServiceIndicatorTest, ED25519SigGenVerify) { + const uint8_t MESSAGE[15] = {'E', 'D', '2', '5', '5', '1', '9', ' ', + 'M', 'E', 'S', 'S', 'A', 'G', 'E'}; + uint8_t private_key[ED25519_PRIVATE_KEY_LEN] = {0}; + uint8_t public_key[ED25519_PUBLIC_KEY_LEN] = {0}; + uint8_t signature[ED25519_SIGNATURE_LEN] = {0}; + ED25519_keypair(public_key, private_key); + + FIPSStatus approved = AWSLC_NOT_APPROVED; + CALL_SERVICE_AND_CHECK_APPROVED( + approved, ASSERT_TRUE(ED25519_sign(&signature[0], &MESSAGE[0], + sizeof(MESSAGE), private_key))); + ASSERT_EQ(AWSLC_APPROVED, approved); + + approved = AWSLC_NOT_APPROVED; + CALL_SERVICE_AND_CHECK_APPROVED( + approved, ASSERT_TRUE(ED25519_verify(&MESSAGE[0], sizeof(MESSAGE), + signature, public_key))); + ASSERT_EQ(AWSLC_APPROVED, approved); + + bssl::UniquePtr pkey(EVP_PKEY_new_raw_private_key( + EVP_PKEY_ED25519, NULL, &private_key[0], ED25519_PRIVATE_KEY_SEED_LEN)); + + bssl::UniquePtr mdctx(EVP_MD_CTX_new()); + CALL_SERVICE_AND_CHECK_APPROVED( + approved, EVP_DigestSignInit(mdctx.get(), NULL, NULL, NULL, pkey.get())); + ASSERT_EQ(AWSLC_NOT_APPROVED, approved); + size_t sig_out_len = sizeof(signature); + CALL_SERVICE_AND_CHECK_APPROVED( + approved, + ASSERT_TRUE(EVP_DigestSign(mdctx.get(), &signature[0], &sig_out_len, + &MESSAGE[0], sizeof(MESSAGE)))); + ASSERT_EQ(AWSLC_APPROVED, approved); + ASSERT_EQ(sizeof(signature), sig_out_len); + + mdctx.reset(EVP_MD_CTX_new()); + ASSERT_TRUE(EVP_DigestVerifyInit(mdctx.get(), NULL, NULL, NULL, pkey.get())); + approved = AWSLC_NOT_APPROVED; + CALL_SERVICE_AND_CHECK_APPROVED( + approved, ASSERT_TRUE(EVP_DigestVerify(mdctx.get(), &signature[0], + sizeof(signature), &MESSAGE[0], + sizeof(MESSAGE)))); + ASSERT_EQ(AWSLC_APPROVED, approved); +} + // Verifies that the awslc_version_string is as expected. // Since this is running in FIPS mode it should end in FIPS // Update this when the AWS-LC version number is modified