From 625ae848d80d4cc2b3964bd31aab6712730f0caa Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 13 Feb 2025 03:41:41 -0800 Subject: [PATCH] ML-KEM: Move FIPS-abort upon PCT failure to top-level API If AWSLC_FIPS is set, ML-KEM includes a PCT check after key generation, in compliance with the FIPS-203 IG https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf If the PCT fails, AWS_LC_FIPS_failure is called to abort operation. This commit hoists the call to AWS_LC_FIPS_failure one level up, into the toplevel ML-KEM API of crypto/fipsmodule/ml_kem/ml_kem.h: When the PCT fails, the lower-level key generation API that invokes the PCT returns -1, which is caught by the top-level ML-KEM API and converted into a call to AWS_LC_FIPS_failure. There is no other failure condition during key generation. When the PCT fails in the randomized key generation API, the coins are still cleansed before propagating the PCT error. It could be considered whether the PK and SK should be cleansed in this case, too, but this commit does not change behvaiour in this regard. The change facilitates replacing the ML-KEM reference implementation, since only the return-value behaviour needs to be maintained, but an alternative implementation need not be aware of the abort macro AWS_LC_FIPS_failure. Signed-off-by: Hanno Becker --- crypto/fipsmodule/ml_kem/ml_kem.c | 72 +++++++++++++++++++++-- crypto/fipsmodule/ml_kem/ml_kem_ref/kem.c | 12 ++-- 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/crypto/fipsmodule/ml_kem/ml_kem.c b/crypto/fipsmodule/ml_kem/ml_kem.c index 1da7350e4b..ab3a543e40 100644 --- a/crypto/fipsmodule/ml_kem/ml_kem.c +++ b/crypto/fipsmodule/ml_kem/ml_kem.c @@ -34,16 +34,36 @@ int ml_kem_512_keypair_deterministic_no_self_test(uint8_t *public_key /* OUT */ uint8_t *secret_key /* OUT */, const uint8_t *seed /* IN */) { ml_kem_params params; + int res; ml_kem_512_params_init(¶ms); - return ml_kem_keypair_derand_ref(¶ms, public_key, secret_key, seed); + res = ml_kem_keypair_derand_ref(¶ms, public_key, secret_key, seed); +#if defined(AWSLC_FIPS) + /* PCT failure is the only failure condition for key generation. */ + if (res != 0) { + AWS_LC_FIPS_failure("ML-KEM keygen PCT failed"); + } +#else + assert(res == 0); +#endif + return 0; } int ml_kem_512_keypair(uint8_t *public_key /* OUT */, uint8_t *secret_key /* OUT */) { boringssl_ensure_ml_kem_self_test(); + int res; ml_kem_params params; ml_kem_512_params_init(¶ms); - return ml_kem_keypair_ref(¶ms, public_key, secret_key); + res = ml_kem_keypair_ref(¶ms, public_key, secret_key); +#if defined(AWSLC_FIPS) + /* PCT failure is the only failure condition for key generation. */ + if (res != 0) { + AWS_LC_FIPS_failure("ML-KEM keygen PCT failed"); + } +#else + assert(res == 0); +#endif + return 0; } int ml_kem_512_encapsulate_deterministic(uint8_t *ciphertext /* OUT */, @@ -94,16 +114,36 @@ int ml_kem_768_keypair_deterministic(uint8_t *public_key /* OUT */, const uint8_t *seed /* IN */) { boringssl_ensure_ml_kem_self_test(); ml_kem_params params; + int res; ml_kem_768_params_init(¶ms); - return ml_kem_keypair_derand_ref(¶ms, public_key, secret_key, seed); + res = ml_kem_keypair_derand_ref(¶ms, public_key, secret_key, seed); +#if defined(AWSLC_FIPS) + /* PCT failure is the only failure condition for key generation. */ + if (res != 0) { + AWS_LC_FIPS_failure("ML-KEM keygen PCT failed"); + } +#else + assert(res == 0); +#endif + return 0; } int ml_kem_768_keypair(uint8_t *public_key /* OUT */, uint8_t *secret_key /* OUT */) { boringssl_ensure_ml_kem_self_test(); ml_kem_params params; + int res; ml_kem_768_params_init(¶ms); - return ml_kem_keypair_ref(¶ms, public_key, secret_key); + res = ml_kem_keypair_ref(¶ms, public_key, secret_key); +#if defined(AWSLC_FIPS) + /* PCT failure is the only failure condition for key generation. */ + if (res != 0) { + AWS_LC_FIPS_failure("ML-KEM keygen PCT failed"); + } +#else + assert(res == 0); +#endif + return 0; } int ml_kem_768_encapsulate_deterministic(uint8_t *ciphertext /* OUT */, @@ -139,16 +179,36 @@ int ml_kem_1024_keypair_deterministic(uint8_t *public_key /* OUT */, const uint8_t *seed /* IN */) { boringssl_ensure_ml_kem_self_test(); ml_kem_params params; + int res; ml_kem_1024_params_init(¶ms); - return ml_kem_keypair_derand_ref(¶ms, public_key, secret_key, seed); + res = ml_kem_keypair_derand_ref(¶ms, public_key, secret_key, seed); +#if defined(AWSLC_FIPS) + /* PCT failure is the only failure condition for key generation. */ + if (res != 0) { + AWS_LC_FIPS_failure("ML-KEM keygen PCT failed"); + } +#else + assert(res == 0); +#endif + return 0; } int ml_kem_1024_keypair(uint8_t *public_key /* OUT */, uint8_t *secret_key /* OUT */) { boringssl_ensure_ml_kem_self_test(); ml_kem_params params; + int res; ml_kem_1024_params_init(¶ms); - return ml_kem_keypair_ref(¶ms, public_key, secret_key); + res = ml_kem_keypair_ref(¶ms, public_key, secret_key); +#if defined(AWSLC_FIPS) + /* PCT failure is the only failure condition for key generation. */ + if (res != 0) { + AWS_LC_FIPS_failure("ML-KEM keygen PCT failed"); + } +#else + assert(res == 0); +#endif + return 0; } int ml_kem_1024_encapsulate_deterministic(uint8_t *ciphertext /* OUT */, diff --git a/crypto/fipsmodule/ml_kem/ml_kem_ref/kem.c b/crypto/fipsmodule/ml_kem/ml_kem_ref/kem.c index b2b28d201c..8a6f5395b7 100644 --- a/crypto/fipsmodule/ml_kem/ml_kem_ref/kem.c +++ b/crypto/fipsmodule/ml_kem/ml_kem_ref/kem.c @@ -7,7 +7,6 @@ #include "./verify.h" #include "./reduce.h" #include "./symmetric.h" -#include "../../../internal.h" #include "openssl/rand.h" @@ -40,8 +39,9 @@ static int keygen_pct(ml_kem_params *params, const uint8_t *ek, const uint8_t *d * (an already allocated array of KYBER_SECRETKEYBYTES bytes) * - uint8_t *coins: pointer to input randomness * (an already allocated array filled with 2*KYBER_SYMBYTES random bytes) -** -* Returns 0 on success, aborts on failure. +* +* Returns: - 0 on success +* - -1 upon PCT failure (if AWSLC_FIPS is set) **************************************************/ int crypto_kem_keypair_derand(ml_kem_params *params, uint8_t *pk, @@ -57,7 +57,7 @@ int crypto_kem_keypair_derand(ml_kem_params *params, #if defined(AWSLC_FIPS) // Abort in case of PCT failure. if (keygen_pct(params, pk, sk)) { - AWS_LC_FIPS_failure("ML-KEM keygen PCT failed"); + return -1; } #endif return 0; @@ -74,7 +74,8 @@ int crypto_kem_keypair_derand(ml_kem_params *params, * - uint8_t *sk: pointer to output private key * (an already allocated array of KYBER_SECRETKEYBYTES bytes) * -* Returns 0 on success, aborts on failure. +* Returns: - 0 on success +* - -1 upon PCT failure (if AWSLC_FIPS is set) **************************************************/ int crypto_kem_keypair(ml_kem_params *params, uint8_t *pk, @@ -83,7 +84,6 @@ int crypto_kem_keypair(ml_kem_params *params, uint8_t coins[2*KYBER_SYMBYTES]; RAND_bytes(coins, 2*KYBER_SYMBYTES); int res = crypto_kem_keypair_derand(params, pk, sk, coins); - assert(res == 0); // FIPS 203. Section 3.3 Destruction of intermediate values. OPENSSL_cleanse(coins, sizeof(coins));