From 9ddb51cea79ab2046d5c1cee105dda230a91f48e Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Thu, 22 Aug 2024 21:03:48 +0000 Subject: [PATCH] Add KDA OneStep (SSKDF_digest and SSKDF_hmac) to FIPS indicator --- crypto/fipsmodule/kdf/sskdf.c | 18 +++ .../fipsmodule/service_indicator/internal.h | 8 + .../service_indicator/service_indicator.c | 36 +++++ .../service_indicator_test.cc | 141 ++++++++++++++++++ 4 files changed, 203 insertions(+) diff --git a/crypto/fipsmodule/kdf/sskdf.c b/crypto/fipsmodule/kdf/sskdf.c index 6009614e83b..40efbf203c5 100644 --- a/crypto/fipsmodule/kdf/sskdf.c +++ b/crypto/fipsmodule/kdf/sskdf.c @@ -289,10 +289,15 @@ static int SSKDF(const sskdf_variant *variant, sskdf_variant_ctx *ctx, int SSKDF_digest(uint8_t *out_key, size_t out_len, const EVP_MD *digest, const uint8_t *secret, size_t secret_len, const uint8_t *info, size_t info_len) { + // We have to avoid the underlying |EVP_DigestFinal| services updating + // the indicator state, so we lock the state here. + FIPS_service_indicator_lock_state(); + sskdf_variant_ctx ctx = {0}; int ret = 0; if (!sskdf_variant_digest_ctx_init(&ctx, digest)) { + FIPS_service_indicator_unlock_state(); return 0; } @@ -305,16 +310,25 @@ int SSKDF_digest(uint8_t *out_key, size_t out_len, const EVP_MD *digest, end: sskdf_variant_digest_ctx_cleanup(&ctx); + FIPS_service_indicator_unlock_state(); + if (ret) { + SSKDF_digest_verify_service_indicator(digest); + } return ret; } int SSKDF_hmac(uint8_t *out_key, size_t out_len, const EVP_MD *digest, const uint8_t *secret, size_t secret_len, const uint8_t *info, size_t info_len, const uint8_t *salt, size_t salt_len) { + // We have to avoid the underlying |HMAC_Final| services updating + // the indicator state, so we lock the state here. + FIPS_service_indicator_lock_state(); + sskdf_variant_ctx ctx = {0}; int ret = 0; if (!sskdf_variant_hmac_ctx_init(&ctx, digest, salt, salt_len)) { + FIPS_service_indicator_unlock_state(); return 0; } @@ -327,5 +341,9 @@ int SSKDF_hmac(uint8_t *out_key, size_t out_len, const EVP_MD *digest, end: sskdf_variant_hmac_ctx_cleanup(&ctx); + FIPS_service_indicator_unlock_state(); + if(ret) { + SSKDF_hmac_verify_service_indicator(digest); + } return ret; } diff --git a/crypto/fipsmodule/service_indicator/internal.h b/crypto/fipsmodule/service_indicator/internal.h index e05c4d6201d..d6e9dfd2424 100644 --- a/crypto/fipsmodule/service_indicator/internal.h +++ b/crypto/fipsmodule/service_indicator/internal.h @@ -53,6 +53,8 @@ void PBKDF2_verify_service_indicator(const EVP_MD *evp_md, size_t password_len, void SSHKDF_verify_service_indicator(const EVP_MD *evp_md); void TLSKDF_verify_service_indicator(const EVP_MD *dgst, const char *label, size_t label_len); +void SSKDF_digest_verify_service_indicator(const EVP_MD *dgst); +void SSKDF_hmac_verify_service_indicator(const EVP_MD *dgst); #else @@ -116,6 +118,12 @@ OPENSSL_INLINE void TLSKDF_verify_service_indicator( OPENSSL_UNUSED const char *label, OPENSSL_UNUSED size_t label_len) {} +OPENSSL_INLINE void SSKDF_digest_verify_service_indicator( + OPENSSL_UNUSED const EVP_MD *dgst) {} + +OPENSSL_INLINE void SSKDF_hmac_verify_service_indicator( + OPENSSL_UNUSED const EVP_MD *dgst) {} + #endif // AWSLC_FIPS // is_fips_build is similar to |FIPS_mode| but returns 1 including in the case diff --git a/crypto/fipsmodule/service_indicator/service_indicator.c b/crypto/fipsmodule/service_indicator/service_indicator.c index 72d213808c0..f921722bee3 100644 --- a/crypto/fipsmodule/service_indicator/service_indicator.c +++ b/crypto/fipsmodule/service_indicator/service_indicator.c @@ -487,6 +487,42 @@ void TLSKDF_verify_service_indicator(const EVP_MD *dgst, const char *label, } } +void SSKDF_digest_verify_service_indicator(const EVP_MD *dgst) { + switch (dgst->type) { + case NID_sha1: + case NID_sha224: + case NID_sha256: + case NID_sha384: + case NID_sha512: + case NID_sha512_224: + case NID_sha512_256: + case NID_sha3_224: + case NID_sha3_256: + case NID_sha3_384: + case NID_sha3_512: + FIPS_service_indicator_update_state(); + break; + default: + break; + } +} + +void SSKDF_hmac_verify_service_indicator(const EVP_MD *dgst) { + switch (dgst->type) { + case NID_sha1: + case NID_sha224: + case NID_sha256: + case NID_sha384: + case NID_sha512: + case NID_sha512_224: + case NID_sha512_256: + FIPS_service_indicator_update_state(); + break; + default: + break; + } +} + #else uint64_t FIPS_service_indicator_before_call(void) { return 0; } diff --git a/crypto/fipsmodule/service_indicator/service_indicator_test.cc b/crypto/fipsmodule/service_indicator/service_indicator_test.cc index f600b8fc0d5..c3caf4fa072 100644 --- a/crypto/fipsmodule/service_indicator/service_indicator_test.cc +++ b/crypto/fipsmodule/service_indicator/service_indicator_test.cc @@ -4317,6 +4317,147 @@ TEST(ServiceIndicatorTest, DRBG) { EXPECT_EQ(approved, AWSLC_APPROVED); } +static const struct SSKDFDigestTestVector { + const EVP_MD *(*md)(); + const FIPSStatus expectation; +} kSSKDFDigestTestVectors[] = {{ + &EVP_sha1, + AWSLC_APPROVED, + }, + { + &EVP_sha224, + AWSLC_APPROVED, + }, + { + &EVP_sha256, + AWSLC_APPROVED, + }, + { + &EVP_sha384, + AWSLC_APPROVED, + }, + { + &EVP_sha512, + AWSLC_APPROVED, + }, + { + &EVP_sha512_224, + AWSLC_APPROVED, + }, + { + &EVP_sha512_256, + AWSLC_APPROVED, + }, + { + &EVP_sha3_224, + AWSLC_APPROVED, + }, + { + &EVP_sha3_256, + AWSLC_APPROVED, + }, + { + &EVP_sha3_384, + AWSLC_APPROVED, + }, + { + &EVP_sha3_512, + AWSLC_APPROVED, + }, + { + &EVP_md5, + AWSLC_NOT_APPROVED, + }}; + +class SSKDFDigestIndicatorTest : public TestWithNoErrors {}; + +INSTANTIATE_TEST_SUITE_P(All, SSKDFDigestIndicatorTest, + testing::ValuesIn(kSSKDFDigestTestVectors)); + + +TEST_P(SSKDFDigestIndicatorTest, SSKDF) { + const SSKDFDigestTestVector &vector = GetParam(); + + const uint8_t secret[23] = {'A', 'W', 'S', '-', 'L', 'C', ' ', 'S', + 'S', 'K', 'D', 'F', '-', 'D', 'I', 'G', + 'E', 'S', 'T', ' ', 'K', 'E', 'Y'}; + const uint8_t info[19] = {'A', 'W', 'S', '-', 'L', 'C', ' ', 'S', 'S', 'K', + 'D', 'F', '-', 'D', 'I', 'G', 'E', 'S', 'T'}; + uint8_t output[16] = {0}; + + FIPSStatus approved = AWSLC_NOT_APPROVED; + + CALL_SERVICE_AND_CHECK_APPROVED( + approved, ASSERT_TRUE(SSKDF_digest( + &output[0], sizeof(output), vector.md(), &secret[0], + sizeof(secret), &info[0], sizeof(info)))); + ASSERT_EQ(vector.expectation, approved); +} + +static const struct SSKDFHmacTestVector { + const EVP_MD *(*md)(); + const FIPSStatus expectation; +} kSSKDFHmacTestVectors[] = {{ + &EVP_sha1, + AWSLC_APPROVED, + }, + { + &EVP_sha224, + AWSLC_APPROVED, + }, + { + &EVP_sha256, + AWSLC_APPROVED, + }, + { + &EVP_sha384, + AWSLC_APPROVED, + }, + { + &EVP_sha512, + AWSLC_APPROVED, + }, + { + &EVP_sha512_224, + AWSLC_APPROVED, + }, + { + &EVP_sha512_256, + AWSLC_APPROVED, + }, + { + &EVP_md5, + AWSLC_NOT_APPROVED, + }}; + +class SSKDFHmacIndicatorTest : public TestWithNoErrors {}; + +INSTANTIATE_TEST_SUITE_P(All, SSKDFHmacIndicatorTest, + testing::ValuesIn(kSSKDFHmacTestVectors)); + + +TEST_P(SSKDFHmacIndicatorTest, SSKDF) { + const SSKDFHmacTestVector &vector = GetParam(); + + const uint8_t secret[21] = {'A', 'W', 'S', '-', 'L', 'C', ' ', + 'S', 'S', 'K', 'D', 'F', '-', 'H', + 'M', 'A', 'C', ' ', 'K', 'E', 'Y'}; + const uint8_t info[17] = {'A', 'W', 'S', '-', 'L', 'C', ' ', 'S', 'S', 'K', + 'D', 'F', '-', 'H', 'M', 'A', 'C'}; + const uint8_t salt[22] = {'A', 'W', 'S', '-', 'L', 'C', ' ', 'S', + 'S', 'K', 'D', 'F', '-', 'H', 'M', 'A', + 'C', ' ', 'S', 'A', 'L', 'T'}; + uint8_t output[16] = {0}; + + FIPSStatus approved = AWSLC_NOT_APPROVED; + + CALL_SERVICE_AND_CHECK_APPROVED( + approved, ASSERT_TRUE(SSKDF_hmac(&output[0], sizeof(output), vector.md(), + &secret[0], sizeof(secret), &info[0], + sizeof(info), &salt[0], sizeof(salt)))); + ASSERT_EQ(vector.expectation, 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