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

ED25519 Service Indicator #1829

Merged
merged 2 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
12 changes: 10 additions & 2 deletions crypto/fipsmodule/curve25519/curve25519.c
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}


Expand Down
11 changes: 10 additions & 1 deletion crypto/fipsmodule/service_indicator/service_indicator.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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();
}
}

Expand Down
67 changes: 67 additions & 0 deletions crypto/fipsmodule/service_indicator/service_indicator_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <openssl/cmac.h>
#include <openssl/crypto.h>
#include <openssl/ctrdrbg.h>
#include <openssl/curve25519.h>
#include <openssl/dh.h>
#include <openssl/digest.h>
#include <openssl/ec.h>
Expand Down Expand Up @@ -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<EVP_PKEY_CTX> ctx(
EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, nullptr));
EVP_PKEY *raw = nullptr;
bssl::UniquePtr<EVP_PKEY> 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<EVP_PKEY> pkey(EVP_PKEY_new_raw_private_key(
EVP_PKEY_ED25519, NULL, &private_key[0], ED25519_PRIVATE_KEY_SEED_LEN));

bssl::UniquePtr<EVP_MD_CTX> 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
Expand Down
Loading