diff --git a/crypto/fipsmodule/evp/digestsign.c b/crypto/fipsmodule/evp/digestsign.c index e2bedf0c42..39914db92a 100644 --- a/crypto/fipsmodule/evp/digestsign.c +++ b/crypto/fipsmodule/evp/digestsign.c @@ -292,7 +292,9 @@ int EVP_DigestSign(EVP_MD_CTX *ctx, uint8_t *out_sig, size_t *out_sig_len, data_len); end: FIPS_service_indicator_unlock_state(); - if (ret > 0) { + if (ret > 0 && out_sig != NULL) { + // Indicator should only be set if we performed crypto, don't set if we only + // performed a size check. EVP_DigestSign_verify_service_indicator(ctx); } return ret; diff --git a/crypto/fipsmodule/evp/evp_ctx.c b/crypto/fipsmodule/evp/evp_ctx.c index e659e317dc..e827c39caf 100644 --- a/crypto/fipsmodule/evp/evp_ctx.c +++ b/crypto/fipsmodule/evp/evp_ctx.c @@ -591,30 +591,56 @@ int EVP_PKEY_encapsulate_deterministic(EVP_PKEY_CTX *ctx, seed, seed_len); } -int EVP_PKEY_encapsulate(EVP_PKEY_CTX *ctx, - uint8_t *ciphertext, size_t *ciphertext_len, - uint8_t *shared_secret, size_t *shared_secret_len) { +int EVP_PKEY_encapsulate(EVP_PKEY_CTX *ctx, uint8_t *ciphertext, + size_t *ciphertext_len, uint8_t *shared_secret, + size_t *shared_secret_len) { + // We have to avoid potential underlying services updating the indicator + // state, so we lock the state here. + FIPS_service_indicator_lock_state(); SET_DIT_AUTO_DISABLE; + int ret = 0; if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->encapsulate == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); - return 0; + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + goto end; } - return ctx->pmeth->encapsulate(ctx, ciphertext, ciphertext_len, - shared_secret, shared_secret_len); + if (!ctx->pmeth->encapsulate(ctx, ciphertext, ciphertext_len, shared_secret, + shared_secret_len)) { + goto end; + } + ret = 1; +end: + FIPS_service_indicator_unlock_state(); + if (ret && ciphertext != NULL && shared_secret != NULL) { + EVP_PKEY_encapsulate_verify_service_indicator(ctx); + } + return ret; } -int EVP_PKEY_decapsulate(EVP_PKEY_CTX *ctx, - uint8_t *shared_secret, size_t *shared_secret_len, - const uint8_t *ciphertext, size_t ciphertext_len) { +int EVP_PKEY_decapsulate(EVP_PKEY_CTX *ctx, uint8_t *shared_secret, + size_t *shared_secret_len, const uint8_t *ciphertext, + size_t ciphertext_len) { + // We have to avoid potential underlying services updating the indicator + // state, so we lock the state here. + FIPS_service_indicator_lock_state(); SET_DIT_AUTO_DISABLE; + int ret = 0; if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->decapsulate == NULL) { - OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); - return 0; + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + goto end; } - return ctx->pmeth->decapsulate(ctx, shared_secret, shared_secret_len, - ciphertext, ciphertext_len); + if (!ctx->pmeth->decapsulate(ctx, shared_secret, shared_secret_len, + ciphertext, ciphertext_len)) { + goto end; + } + ret = 1; +end: + FIPS_service_indicator_unlock_state(); + if (ret && shared_secret != NULL) { + EVP_PKEY_decapsulate_verify_service_indicator(ctx); + } + return ret; } // Deprecated keygen NO-OP functions diff --git a/crypto/fipsmodule/evp/p_kem.c b/crypto/fipsmodule/evp/p_kem.c index c5c310e122..64a96693fd 100644 --- a/crypto/fipsmodule/evp/p_kem.c +++ b/crypto/fipsmodule/evp/p_kem.c @@ -95,10 +95,11 @@ static int pkey_kem_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { if (key == NULL || !KEM_KEY_init(key, kem) || !kem->method->keygen(key->public_key, key->secret_key) || - !EVP_PKEY_assign(pkey, EVP_PKEY_KEM, key)) { + !EVP_PKEY_set_type(pkey, EVP_PKEY_KEM)) { KEM_KEY_free(key); return 0; } + pkey->pkey.kem_key = key; return 1; } diff --git a/crypto/fipsmodule/service_indicator/internal.h b/crypto/fipsmodule/service_indicator/internal.h index b051ff62af..0f8881132b 100644 --- a/crypto/fipsmodule/service_indicator/internal.h +++ b/crypto/fipsmodule/service_indicator/internal.h @@ -56,6 +56,8 @@ void TLSKDF_verify_service_indicator(const EVP_MD *dgst, const char *label, void SSKDF_digest_verify_service_indicator(const EVP_MD *dgst); void SSKDF_hmac_verify_service_indicator(const EVP_MD *dgst); void KBKDF_ctr_hmac_verify_service_indicator(const EVP_MD *dgst); +void EVP_PKEY_encapsulate_verify_service_indicator(const EVP_PKEY_CTX* ctx); +void EVP_PKEY_decapsulate_verify_service_indicator(const EVP_PKEY_CTX* ctx); #else @@ -127,6 +129,10 @@ OPENSSL_INLINE void SSKDF_hmac_verify_service_indicator( OPENSSL_INLINE void KBKDF_ctr_hmac_verify_service_indicator(OPENSSL_UNUSED const EVP_MD *dgst) {} +OPENSSL_INLINE void EVP_PKEY_encapsulate_verify_service_indicator(OPENSSL_UNUSED const EVP_PKEY_CTX* ctx) {} + +OPENSSL_INLINE void EVP_PKEY_decapsulate_verify_service_indicator(OPENSSL_UNUSED const EVP_PKEY_CTX* ctx) {} + #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 791038e071..e642e9626f 100644 --- a/crypto/fipsmodule/service_indicator/service_indicator.c +++ b/crypto/fipsmodule/service_indicator/service_indicator.c @@ -319,6 +319,17 @@ 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_KEM) { + const KEM *kem = KEM_KEY_get0_kem(pkey->pkey.kem_key); + switch (kem->nid) { + case NID_MLKEM512: + case NID_MLKEM768: + case NID_MLKEM1024: + FIPS_service_indicator_update_state(); + break; + default: + break; + } } } @@ -571,6 +582,36 @@ void KBKDF_ctr_hmac_verify_service_indicator(const EVP_MD *dgst) { } } +void EVP_PKEY_encapsulate_verify_service_indicator(const EVP_PKEY_CTX* ctx) { + if (ctx->pkey->type == EVP_PKEY_KEM) { + const KEM *kem = KEM_KEY_get0_kem(ctx->pkey->pkey.kem_key); + switch (kem->nid) { + case NID_MLKEM512: + case NID_MLKEM768: + case NID_MLKEM1024: + FIPS_service_indicator_update_state(); + break; + default: + break; + } + } +} + +void EVP_PKEY_decapsulate_verify_service_indicator(const EVP_PKEY_CTX* ctx) { + if (ctx->pkey->type == EVP_PKEY_KEM) { + const KEM *kem = KEM_KEY_get0_kem(ctx->pkey->pkey.kem_key); + switch (kem->nid) { + case NID_MLKEM512: + case NID_MLKEM768: + case NID_MLKEM1024: + 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 6495aa795f..e25587506e 100644 --- a/crypto/fipsmodule/service_indicator/service_indicator_test.cc +++ b/crypto/fipsmodule/service_indicator/service_indicator_test.cc @@ -2297,21 +2297,31 @@ TEST_P(RSAServiceIndicatorTest, RSASigGen) { &sig_len))); EXPECT_EQ(approved, test.sig_gen_expect_approved); - // Test using the one-shot |EVP_DigestSign| function for approval. md_ctx.Reset(); std::vector oneshot_output(sig_len); CALL_SERVICE_AND_CHECK_APPROVED( approved, ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pctx, test.func(), nullptr, pkey.get()))); EXPECT_EQ(approved, AWSLC_NOT_APPROVED); + if (test.use_pss) { - CALL_SERVICE_AND_CHECK_APPROVED(approved, - ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING))); + CALL_SERVICE_AND_CHECK_APPROVED( + approved, + ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING))); EXPECT_EQ(approved, AWSLC_NOT_APPROVED); CALL_SERVICE_AND_CHECK_APPROVED( approved, ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1))); EXPECT_EQ(approved, AWSLC_NOT_APPROVED); } + + // Test the one-shot |EVP_DigestSign| function to determine size. + // This should not set the indicator. + CALL_SERVICE_AND_CHECK_APPROVED( + approved, + ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), nullptr, &sig_len, nullptr, 0))); + EXPECT_EQ(approved, AWSLC_NOT_APPROVED); + + // Now test using the one-shot |EVP_DigestSign| function for approval. CALL_SERVICE_AND_CHECK_APPROVED(approved, ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), oneshot_output.data(), &sig_len, kPlaintext, sizeof(kPlaintext)))); @@ -4557,6 +4567,61 @@ TEST_P(KBKDFCtrHmacIndicatorTest, KBKDF) { ASSERT_EQ(vector.expectation, approved); } +TEST(ServiceIndicatorTest, ML_KEM) { + for (int nid : {NID_MLKEM512, NID_MLKEM768, NID_MLKEM1024}) { + bssl::UniquePtr ctx( + EVP_PKEY_CTX_new_id(EVP_PKEY_KEM, nullptr)); + ASSERT_TRUE(EVP_PKEY_CTX_kem_set_params(ctx.get(), nid)); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); + + FIPSStatus approved = AWSLC_NOT_APPROVED; + EVP_PKEY *raw = nullptr; + // keygen for ML-KEM algorithms should be approved + CALL_SERVICE_AND_CHECK_APPROVED(approved, EVP_PKEY_keygen(ctx.get(), &raw)); + bssl::UniquePtr pkey(raw); + ASSERT_EQ(approved, AWSLC_APPROVED); + + size_t ciphertext_len = 0; + size_t shared_secret_len = 0; + + ctx.reset(EVP_PKEY_CTX_new(pkey.get(), nullptr)); + + approved = AWSLC_NOT_APPROVED; + // encapsulate size check should not set indicator + CALL_SERVICE_AND_CHECK_APPROVED( + approved, EVP_PKEY_encapsulate(ctx.get(), nullptr, &ciphertext_len, + nullptr, &shared_secret_len)); + ASSERT_EQ(approved, AWSLC_NOT_APPROVED); + + std::vector ciphertext(ciphertext_len); + std::vector encap_shared_secret(shared_secret_len); + + // encapsulate should set indicator + CALL_SERVICE_AND_CHECK_APPROVED( + approved, + EVP_PKEY_encapsulate(ctx.get(), ciphertext.data(), &ciphertext_len, + encap_shared_secret.data(), &shared_secret_len)); + ASSERT_EQ(approved, AWSLC_APPROVED); + + shared_secret_len = 0; + approved = AWSLC_NOT_APPROVED; + // decapsulate size check should not set indicator + CALL_SERVICE_AND_CHECK_APPROVED( + approved, EVP_PKEY_decapsulate(ctx.get(), nullptr, &shared_secret_len, + ciphertext.data(), ciphertext.size())); + ASSERT_EQ(approved, AWSLC_NOT_APPROVED); + + std::vector decap_shared_secret(shared_secret_len); + // decapsulate should set indicator + CALL_SERVICE_AND_CHECK_APPROVED( + approved, EVP_PKEY_decapsulate(ctx.get(), decap_shared_secret.data(), + &shared_secret_len, ciphertext.data(), + ciphertext.size())); + ASSERT_EQ(approved, AWSLC_APPROVED); + ASSERT_EQ(encap_shared_secret, decap_shared_secret); + } +} + // 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