Skip to content

Commit

Permalink
ED25519 Service Indicator
Browse files Browse the repository at this point in the history
  • Loading branch information
skmcgrail committed Sep 5, 2024
1 parent 0f5d9c9 commit 3b33a00
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 3 deletions.
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 @@ -319,6 +326,8 @@ void EVP_PKEY_keygen_verify_service_indicator(const EVP_PKEY *pkey) {
if (is_ec_fips_approved(curve_nid)) {
FIPS_service_indicator_update_state();
}
} else if (pkey->type == EVP_PKEY_ED25519) {
FIPS_service_indicator_update_state();
}
}

Expand Down
64 changes: 64 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 @@ -4557,6 +4558,69 @@ TEST_P(KBKDFCtrHmacIndicatorTest, KBKDF) {
ASSERT_EQ(vector.expectation, approved);
}

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());
ASSERT_TRUE(EVP_DigestSignInit(mdctx.get(), NULL, NULL, NULL, pkey.get()));
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()));
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

0 comments on commit 3b33a00

Please sign in to comment.