diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c index 20dd505866..7f2015f81b 100644 --- a/crypto/fipsmodule/bcm.c +++ b/crypto/fipsmodule/bcm.c @@ -184,6 +184,12 @@ extern const uint8_t BORINGSSL_bcm_rodata_start[]; extern const uint8_t BORINGSSL_bcm_rodata_end[]; #endif +#define STRING_POINTER_LENGTH 18 +#define MAX_FUNCTION_NAME 32 +#define ASSERT_WITHIN_MSG "FIPS module doesn't span expected symbol (%s). Expected %p <= %p < %p\n" +#define MAX_WITHIN_MSG_LEN sizeof(ASSERT_WITHIN_MSG) + (3 * STRING_POINTER_LENGTH) + MAX_FUNCTION_NAME +#define ASSERT_OUTSIDE_MSG "FIPS module spans unexpected symbol (%s), expected %p < %p || %p > %p\n" +#define MAX_OUTSIDE_MSG_LEN sizeof(ASSERT_OUTSIDE_MSG) + (4 * STRING_POINTER_LENGTH) + MAX_FUNCTION_NAME // assert_within is used to sanity check that certain symbols are within the // bounds of the integrity check. It checks that start <= symbol < end and // aborts otherwise. @@ -197,11 +203,10 @@ static void assert_within(const void *start, const void *symbol, return; } - fprintf( - stderr, - "FIPS module doesn't span expected symbol (%s). Expected %p <= %p < %p\n", - symbol_name, start, symbol, end); - BORINGSSL_FIPS_abort(); + assert(sizeof(symbol_name) < MAX_FUNCTION_NAME); + char message[MAX_WITHIN_MSG_LEN] = {0}; + snprintf(message, sizeof(message), ASSERT_WITHIN_MSG, symbol_name, start, symbol, end); + AWS_LC_FIPS_failure(message); } static void assert_not_within(const void *start, const void *symbol, @@ -214,11 +219,10 @@ static void assert_not_within(const void *start, const void *symbol, return; } - fprintf( - stderr, - "FIPS module spans unexpected symbol (%s), expected %p < %p || %p > %p\n", - symbol_name, symbol, start, symbol, end); - BORINGSSL_FIPS_abort(); + assert(sizeof(symbol_name) < MAX_FUNCTION_NAME); + char message[MAX_WITHIN_MSG_LEN] = {0}; + snprintf(message, sizeof(message), ASSERT_OUTSIDE_MSG, symbol_name, symbol, start, symbol, end); + AWS_LC_FIPS_failure(message); } // TODO: Re-enable once all data has been moved out of .text segments CryptoAlg-2360 @@ -266,7 +270,7 @@ static void BORINGSSL_bcm_power_on_self_test(void) { #if defined(FIPS_ENTROPY_SOURCE_JITTER_CPU) if (jent_entropy_init()) { fprintf(stderr, "CPU Jitter entropy RNG initialization failed.\n"); - goto err; + AWS_LC_FIPS_failure("CPU Jitter failed to initilize"); } #endif @@ -274,18 +278,13 @@ static void BORINGSSL_bcm_power_on_self_test(void) { // Integrity tests cannot run under ASAN because it involves reading the full // .text section, which triggers the global-buffer overflow detection. if (!BORINGSSL_integrity_test()) { - goto err; + AWS_LC_FIPS_failure("Integrity test failed"); } #endif // OPENSSL_ASAN if (!boringssl_self_test_startup()) { - goto err; + AWS_LC_FIPS_failure("Power on self test failed"); } - - return; - -err: - BORINGSSL_FIPS_abort(); } #if !defined(OPENSSL_ASAN) @@ -333,8 +332,8 @@ int BORINGSSL_integrity_test(void) { uint8_t result[SHA256_DIGEST_LENGTH]; const EVP_MD *const kHashFunction = EVP_sha256(); - if (!boringssl_self_test_sha256() || - !boringssl_self_test_hmac_sha256()) { + if (!boringssl_self_test_sha256(true) || + !boringssl_self_test_hmac_sha256(true)) { return 0; } @@ -377,18 +376,22 @@ int BORINGSSL_integrity_test(void) { const uint8_t *expected = BORINGSSL_bcm_text_hash; - if (!check_test(expected, result, sizeof(result), "FIPS integrity test")) { -#if !defined(BORINGSSL_FIPS_BREAK_TESTS) - return 0; +#if defined(BORINGSSL_FIPS_BREAK_TESTS) + // Check the integrity but don't call AWS_LC_FIPS_failure or return 0 + check_test(expected, result, sizeof(result), "FIPS integrity test", false); +#else + // Check the integrity, call AWS_LC_FIPS_failure if it doesn't match which will + // result in an abort + check_test(expected, result, sizeof(result), "FIPS integrity test", true); #endif - } OPENSSL_cleanse(result, sizeof(result)); // FIPS 140-3, AS05.10. return 1; } #endif // OPENSSL_ASAN -void BORINGSSL_FIPS_abort(void) { +void AWS_LC_FIPS_failure(const char* message) { + fprintf(stderr, "AWS-LC FIPS failure caused by:\n%s\n", message); for (;;) { abort(); exit(1); diff --git a/crypto/fipsmodule/curve25519/curve25519.c b/crypto/fipsmodule/curve25519/curve25519.c index 16249bd1a2..aed3a8c4b9 100644 --- a/crypto/fipsmodule/curve25519/curve25519.c +++ b/crypto/fipsmodule/curve25519/curve25519.c @@ -119,7 +119,7 @@ static void ed25519_keypair_pct(uint8_t public_key[ED25519_PUBLIC_KEY_LEN], uint8_t out_sig[ED25519_SIGNATURE_LEN]; if (ED25519_sign_no_self_test(out_sig, msg, 16, private_key) != 1 || ED25519_verify_no_self_test(msg, 16, out_sig, public_key) != 1) { - BORINGSSL_FIPS_abort(); + AWS_LC_FIPS_failure("Ed25519 keygen PCT failed"); } #endif } diff --git a/crypto/fipsmodule/ec/ec_key.c b/crypto/fipsmodule/ec/ec_key.c index ccc3221029..19abe34ea5 100644 --- a/crypto/fipsmodule/ec/ec_key.c +++ b/crypto/fipsmodule/ec/ec_key.c @@ -549,7 +549,7 @@ int EC_KEY_generate_key_fips(EC_KEY *eckey) { eckey->priv_key = NULL; #if defined(AWSLC_FIPS) - BORINGSSL_FIPS_abort(); + AWS_LC_FIPS_failure("EC keygen checks failed"); #else return 0; #endif diff --git a/crypto/fipsmodule/ml_kem/ml_kem_ref/kem.c b/crypto/fipsmodule/ml_kem/ml_kem_ref/kem.c index 02faae7b0f..b2b28d201c 100644 --- a/crypto/fipsmodule/ml_kem/ml_kem_ref/kem.c +++ b/crypto/fipsmodule/ml_kem/ml_kem_ref/kem.c @@ -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)) { - BORINGSSL_FIPS_abort(); + AWS_LC_FIPS_failure("ML-KEM keygen PCT failed"); } #endif return 0; diff --git a/crypto/fipsmodule/rsa/rsa_impl.c b/crypto/fipsmodule/rsa/rsa_impl.c index f3e98fc4b8..b23aed760c 100644 --- a/crypto/fipsmodule/rsa/rsa_impl.c +++ b/crypto/fipsmodule/rsa/rsa_impl.c @@ -1231,7 +1231,7 @@ static int RSA_generate_key_ex_maybe_fips(RSA *rsa, int bits, if(check_fips && !RSA_check_fips(tmp)) { RSA_free(tmp); #if defined(AWSLC_FIPS) - BORINGSSL_FIPS_abort(); + AWS_LC_FIPS_failure("RSA keygen checks failed"); #endif return ret; } diff --git a/crypto/fipsmodule/self_check/self_check.c b/crypto/fipsmodule/self_check/self_check.c index 1ff3ba4921..0591955f4c 100644 --- a/crypto/fipsmodule/self_check/self_check.c +++ b/crypto/fipsmodule/self_check/self_check.c @@ -45,21 +45,46 @@ #include "../rsa/internal.h" #include "../../curve25519_extra/internal.h" -static void hexdump(const uint8_t *in, size_t len) { - for (size_t i = 0; i < len; i++) { - fprintf(stderr, "%02x", in[i]); - } +// This should track the biggest input/output used in self_check.c +#define MAX_HEXDUMP_SIZE (MLDSA44_PRIVATE_KEY_BYTES * 2) +#define ERROR_FORMAT "%s failed.\nExpected: %s\nCalculated: %s\n" +// The current max is "ML-KEM-encapsulate-shared-secret\0" +#define MAX_NAME 33 +#define MAX_ERROR_MSG_SIZE (( 2 * MAX_HEXDUMP_SIZE) + sizeof(ERROR_FORMAT) + MAX_NAME) + +static void hexdump(char buf[MAX_HEXDUMP_SIZE], const uint8_t *in, size_t in_len) { + assert(in_len * 2 < MAX_HEXDUMP_SIZE); + size_t pos = 0; + for (size_t i = 0; i < in_len; i++) { + pos += snprintf(buf + pos, MAX_HEXDUMP_SIZE - pos, "%02x", in[i]); + } } static int check_test(const void *expected, const void *actual, - size_t expected_len, const char *name) { + size_t expected_len, const char *name, + const bool call_aws_lc_fips_failure) { if (OPENSSL_memcmp(actual, expected, expected_len) != 0) { - fprintf(stderr, "%s failed.\nExpected: ", name); - hexdump(expected, expected_len); - fprintf(stderr, "\nCalculated: "); - hexdump(actual, expected_len); - fprintf(stderr, "\n"); + assert(sizeof(name) < MAX_NAME); + char expected_hex[MAX_HEXDUMP_SIZE] = {0}; + char actual_hex[MAX_HEXDUMP_SIZE] = {0}; + char error_msg[MAX_ERROR_MSG_SIZE] = {0}; + hexdump(expected_hex, expected, expected_len); + hexdump(actual_hex, actual, expected_len); + + snprintf(error_msg, sizeof(error_msg), + "%s failed.\nExpected: %s\nCalculated: %s\n", + name, expected_hex, actual_hex); +#if defined(BORINGSSL_FIPS) + if (call_aws_lc_fips_failure) { + AWS_LC_FIPS_failure(error_msg); + } else { + fprintf(stderr, "%s", error_msg); + fflush(stderr); + } +#else + fprintf(stderr, "%s", error_msg); fflush(stderr); +#endif return 0; } return 1; @@ -415,7 +440,7 @@ static DH *self_test_dh(void) { // actually exercised, in FIPS mode. (In non-FIPS mode these tests are only run // when requested by |BORINGSSL_self_test|.) -static int boringssl_self_test_rsa(void) { +static int boringssl_self_test_rsa(const bool call_aws_lc_fips_failure) { int ret = 0; uint8_t output[256]; @@ -464,8 +489,7 @@ static int boringssl_self_test_rsa(void) { if (!rsa_digestsign_no_self_test(EVP_sha256(), kRSASignPlaintext, sizeof(kRSASignPlaintext),output, &sig_len, rsa_key) || !check_test(kRSASignSignature, output, sizeof(kRSASignSignature), - "RSA-sign KAT")) { - fprintf(stderr, "RSA signing test failed.\n"); + "RSA-sign KAT", call_aws_lc_fips_failure)) { goto err; } @@ -515,7 +539,7 @@ static int boringssl_self_test_rsa(void) { return ret; } -static int boringssl_self_test_ecc(void) { +static int boringssl_self_test_ecc(const bool call_aws_lc_fips_failure) { int ret = 0; EC_KEY *ec_key = NULL; EC_POINT *ec_point_in = NULL; @@ -556,7 +580,7 @@ static int boringssl_self_test_ecc(void) { if (sig == NULL || !serialize_ecdsa_sig(ecdsa_sign_output, sizeof(ecdsa_sign_output), sig) || !check_test(kECDSASignSig, ecdsa_sign_output, sizeof(ecdsa_sign_output), - "ECDSA-sign signature")) { + "ECDSA-sign signature", call_aws_lc_fips_failure)) { fprintf(stderr, "ECDSA-sign KAT failed.\n"); goto err; } @@ -625,8 +649,7 @@ static int boringssl_self_test_ecc(void) { !EC_POINT_point2oct(ec_group, ec_point_out, POINT_CONVERSION_UNCOMPRESSED, z_comp_result, sizeof(z_comp_result), NULL) || !check_test(kP256PointResult, z_comp_result, sizeof(z_comp_result), - "Z Computation Result")) { - fprintf(stderr, "Z-computation KAT failed.\n"); + "Z-computation", call_aws_lc_fips_failure)) { goto err; } @@ -642,7 +665,7 @@ static int boringssl_self_test_ecc(void) { return ret; } -static int boringssl_self_test_ffdh(void) { +static int boringssl_self_test_ffdh(const bool call_aws_lc_fips_failure) { int ret = 0; DH *dh = NULL; DH *fb_dh = NULL; @@ -767,8 +790,7 @@ static int boringssl_self_test_ffdh(void) { if (dh == NULL || ffdhe2048_value == NULL || sizeof(dh_out) != DH_size(dh) || dh_compute_key_padded_no_self_test(dh_out, ffdhe2048_value, dh) != sizeof(dh_out) || - !check_test(kDHOutput, dh_out, sizeof(dh_out), "FFC DH")) { - fprintf(stderr, "FFDH failed.\n"); + !check_test(kDHOutput, dh_out, sizeof(dh_out), "FFC DH", call_aws_lc_fips_failure)) { goto err; } @@ -780,8 +802,7 @@ static int boringssl_self_test_ffdh(void) { sizeof(fb_dh_out) != DH_size(fb_dh) || dh_compute_key_padded_no_self_test(fb_dh_out, fb_peers_key, fb_dh) != sizeof(fb_dh_out) || - !check_test(kDH_fb_z, fb_dh_out, sizeof(fb_dh_out), "FFC DH FB")) { - fprintf(stderr, "FFDH FB failed.\n"); + !check_test(kDH_fb_z, fb_dh_out, sizeof(fb_dh_out), "FFC DH FB", call_aws_lc_fips_failure)) { goto err; } @@ -796,7 +817,7 @@ static int boringssl_self_test_ffdh(void) { return ret; } -static int boringssl_self_test_ml_kem(void) { +static int boringssl_self_test_ml_kem(const bool call_aws_lc_fips_failure) { int ret = 0; static const uint8_t kKeyGenEKSeed[MLKEM512_KEYGEN_SEED_LEN] = { @@ -881,7 +902,7 @@ static int boringssl_self_test_ml_kem(void) { if (ml_kem_512_keypair_deterministic_no_self_test( keygen_encaps, keygen_decaps, kKeyGenEKSeed) || !check_test(kKeyGenEK, keygen_encaps, sizeof(keygen_encaps), - "ML-KEM-keyGen-encaps")) { + "ML-KEM-keyGen-encaps", call_aws_lc_fips_failure)) { goto err; } @@ -1039,10 +1060,9 @@ static int boringssl_self_test_ml_kem(void) { if (ml_kem_512_keypair_deterministic_no_self_test( keygen_encaps, keygen_decaps, kKeyGenDKSeed) || !check_test(kKeyGenDK, keygen_decaps, sizeof(keygen_decaps), - "ML-KEM-keyGen-decaps") - ) { + "ML-KEM-keyGen-decaps", call_aws_lc_fips_failure)) { goto err; - } + } static const uint8_t kEncapEK[MLKEM512_PUBLIC_KEY_BYTES] = { 0x57, 0xc3, 0xba, 0x4c, 0xd7, 0x81, 0xd8, 0x69, 0x0b, 0x4c, 0x39, 0x0d, @@ -1192,9 +1212,9 @@ static int boringssl_self_test_ml_kem(void) { if (ml_kem_512_encapsulate_deterministic_no_self_test( ciphertext, shared_secret, kEncapEK, kEncapM) || !check_test(kEncapCiphertext, ciphertext, sizeof(kEncapCiphertext), - "ML-KEM-encapsulate-ciphertext") || + "ML-KEM-encapsulate-ciphertext", call_aws_lc_fips_failure) || !check_test(kEncapSharedSecret, shared_secret, sizeof(kEncapSharedSecret), - "ML-KEM-encapsulate-shared-secret")) { + "ML-KEM-encapsulate-shared-secret", call_aws_lc_fips_failure)) { goto err; } @@ -1477,12 +1497,12 @@ static int boringssl_self_test_ml_kem(void) { if (ml_kem_512_decapsulate_no_self_test(shared_secret, kDecapCiphertext, kDecapDK) || !check_test(kDecapSharedSecret, shared_secret, sizeof(kDecapSharedSecret), - "ML-KEM decapsulate non-rejection") || + "ML-KEM decapsulate non-rejection", call_aws_lc_fips_failure) || ml_kem_512_decapsulate_no_self_test( shared_secret, kDecapCiphertextRejection, kDecapDK) || !check_test(kDecapSharedSecretRejection, shared_secret, sizeof(kDecapSharedSecretRejection), - "ML-KEM decapsulate implicit rejection")) { + "ML-KEM decapsulate implicit rejection", call_aws_lc_fips_failure)) { goto err; } @@ -1491,7 +1511,7 @@ static int boringssl_self_test_ml_kem(void) { return ret; } -static int boringssl_self_test_ml_dsa(void) { +static int boringssl_self_test_ml_dsa(const bool call_aws_lc_fips_failure) { int ret = 0; // Examples kMLDSAKeyGenSeed, kMLDSAKeyGenPublicKey, kMLDSAKeyGenPrivateKey from @@ -2057,9 +2077,8 @@ static int boringssl_self_test_ml_dsa(void) { uint8_t private_key[MLDSA44_PRIVATE_KEY_BYTES] = {0}; if (!ml_dsa_44_keypair_internal_no_self_test(public_key, private_key, kMLDSAKeyGenSeed) || - !check_test(kMLDSAKeyGenPublicKey, public_key, sizeof(public_key), "ML-DSA keyGen public") || - !check_test(kMLDSAKeyGenPrivateKey, private_key, sizeof(private_key), "ML-DSA keyGen private")) { - fprintf(stderr, "ML-DSA-44 KeyGen failed.\n"); + !check_test(kMLDSAKeyGenPublicKey, public_key, sizeof(public_key), "ML-DSA keyGen public", call_aws_lc_fips_failure) || + !check_test(kMLDSAKeyGenPrivateKey, private_key, sizeof(private_key), "ML-DSA keyGen private", call_aws_lc_fips_failure)) { goto err; } @@ -2070,15 +2089,13 @@ static int boringssl_self_test_ml_dsa(void) { if (!ml_dsa_44_sign_internal_no_self_test(private_key, signature, &sig_len, kMLDSASignPlaintext, mlen_int, NULL, 0, kMLDSASigGenSeed) || - !check_test(kMLDSASignSignature, signature, sizeof(signature), "ML-DSA SigGen signature")) { - fprintf(stderr, "ML-DSA-44 sign failed.\n"); + !check_test(kMLDSASignSignature, signature, sizeof(signature), "ML-DSA SigGen signature", call_aws_lc_fips_failure)) { goto err; } // Verify if (!ml_dsa_44_verify_internal_no_self_test(public_key, kMLDSASignSignature, sig_len, kMLDSASignPlaintext, mlen_int, NULL, 0)) { - fprintf(stderr, "ML-DSA-44 verify failed.\n"); goto err; } @@ -2087,7 +2104,7 @@ static int boringssl_self_test_ml_dsa(void) { return ret; } -static int boringssl_self_test_eddsa(void) { +static int boringssl_self_test_eddsa(const bool call_aws_lc_fips_failure) { int ret = 0; static const uint8_t kEd25519PrivateKey[ED25519_PRIVATE_KEY_SEED_LEN] = { @@ -2123,7 +2140,7 @@ static int boringssl_self_test_eddsa(void) { sizeof(kEd25519SignMessage), ed25519_private_key) || !check_test(kEd25519SignSignature, ed25519_out_sig, - ED25519_SIGNATURE_LEN, "ED25519 sign")) { + ED25519_SIGNATURE_LEN, "ED25519-sign", call_aws_lc_fips_failure)) { fprintf(stderr, "ED25519-sign failed.\n"); goto err; } @@ -2150,7 +2167,7 @@ static int boringssl_self_test_eddsa(void) { return ret; } -static int boringssl_self_test_hasheddsa(void) { +static int boringssl_self_test_hasheddsa(const bool call_aws_lc_fips_failure) { int ret = 0; static const uint8_t kEd25519PrivateKey[ED25519_PRIVATE_KEY_SEED_LEN] = { @@ -2194,8 +2211,7 @@ static int boringssl_self_test_hasheddsa(void) { &ed25519_out_sig[0], kEd25519SignMessage, sizeof(kEd25519SignMessage), ed25519_private_key, kEd25519Context, sizeof(kEd25519Context)) || !check_test(kEd25519SignSignature, ed25519_out_sig, - ED25519_SIGNATURE_LEN, "ED25519 sign")) { - fprintf(stderr, "ED25519ph-sign failed.\n"); + ED25519_SIGNATURE_LEN, "ED25519ph-sign", call_aws_lc_fips_failure)) { goto err; } @@ -2226,8 +2242,8 @@ static int boringssl_self_test_hasheddsa(void) { #if defined(BORINGSSL_FIPS) static void run_self_test_rsa(void) { - if (!boringssl_self_test_rsa()) { - BORINGSSL_FIPS_abort(); + if (!boringssl_self_test_rsa(true)) { + AWS_LC_FIPS_failure("RSA self tests failed"); } } @@ -2238,8 +2254,8 @@ void boringssl_ensure_rsa_self_test(void) { } static void run_self_test_ecc(void) { - if (!boringssl_self_test_ecc()) { - BORINGSSL_FIPS_abort(); + if (!boringssl_self_test_ecc(true)) { + AWS_LC_FIPS_failure("ECC self tests failed"); } } @@ -2250,8 +2266,8 @@ void boringssl_ensure_ecc_self_test(void) { } static void run_self_test_ffdh(void) { - if (!boringssl_self_test_ffdh()) { - BORINGSSL_FIPS_abort(); + if (!boringssl_self_test_ffdh(true)) { + AWS_LC_FIPS_failure("FFDH self tests failed"); } } @@ -2262,8 +2278,8 @@ void boringssl_ensure_ffdh_self_test(void) { } static void run_self_test_ml_kem(void) { - if (!boringssl_self_test_ml_kem()) { - BORINGSSL_FIPS_abort(); + if (!boringssl_self_test_ml_kem(true)) { + AWS_LC_FIPS_failure("RSA self tests failed"); } } @@ -2274,8 +2290,8 @@ void boringssl_ensure_ml_kem_self_test(void) { } static void run_self_test_ml_dsa(void) { - if (!boringssl_self_test_ml_dsa()) { - BORINGSSL_FIPS_abort(); + if (!boringssl_self_test_ml_dsa(true)) { + AWS_LC_FIPS_failure("ML-DSA self tests failed"); } } @@ -2286,8 +2302,8 @@ void boringssl_ensure_ml_dsa_self_test(void) { } static void run_self_test_eddsa(void) { - if (!boringssl_self_test_eddsa()) { - BORINGSSL_FIPS_abort(); + if (!boringssl_self_test_eddsa(true)) { + AWS_LC_FIPS_failure("EdDSA self tests failed"); } } @@ -2298,8 +2314,8 @@ void boringssl_ensure_eddsa_self_test(void) { } static void run_self_test_hasheddsa(void) { - if (!boringssl_self_test_hasheddsa()) { - BORINGSSL_FIPS_abort(); + if (!boringssl_self_test_hasheddsa(true)) { + AWS_LC_FIPS_failure("EdDSA-ph self tests failed"); } } @@ -2317,7 +2333,7 @@ void boringssl_ensure_hasheddsa_self_test(void) { // These tests are run at process start when in FIPS mode. Note that the SHA256 // and HMAC-SHA256 tests are also used from bcm.c, so they can't be static. -int boringssl_self_test_sha256(void) { +int boringssl_self_test_sha256(const bool call_aws_lc_fips_failure) { static const uint8_t kInput[16] = { 0xff, 0x3b, 0x85, 0x7d, 0xa7, 0x23, 0x6a, 0x2b, 0xaa, 0x0f, 0x39, 0x6b, 0x51, 0x52, 0x22, 0x17, @@ -2332,10 +2348,10 @@ int boringssl_self_test_sha256(void) { // SHA-256 KAT SHA256(kInput, sizeof(kInput), output); return check_test(kPlaintextSHA256, output, sizeof(kPlaintextSHA256), - "SHA-256 KAT"); + "SHA-256 KAT", call_aws_lc_fips_failure); } -static int boringssl_self_test_sha512(void) { +static int boringssl_self_test_sha512(const bool call_aws_lc_fips_failure) { static const uint8_t kInput[16] = { 0x21, 0x25, 0x12, 0xf8, 0xd2, 0xad, 0x83, 0x22, 0x78, 0x1c, 0x6c, 0x4d, 0x69, 0xa9, 0xda, 0xa1, @@ -2353,10 +2369,10 @@ static int boringssl_self_test_sha512(void) { // SHA-512 KAT SHA512(kInput, sizeof(kInput), output); return check_test(kPlaintextSHA512, output, sizeof(kPlaintextSHA512), - "SHA-512 KAT"); + "SHA-512 KAT", call_aws_lc_fips_failure); } -int boringssl_self_test_hmac_sha256(void) { +int boringssl_self_test_hmac_sha256(const bool call_aws_lc_fips_failure) { static const uint8_t kInput[16] = { 0xda, 0xd9, 0x12, 0x93, 0xdf, 0xcf, 0x2a, 0x7c, 0x8e, 0xcd, 0x13, 0xfe, 0x35, 0x3f, 0xa7, 0x5b, @@ -2373,10 +2389,10 @@ int boringssl_self_test_hmac_sha256(void) { &output_len); return output_len == sizeof(kPlaintextHMACSHA256) && check_test(kPlaintextHMACSHA256, output, sizeof(kPlaintextHMACSHA256), - "HMAC-SHA-256 KAT"); + "HMAC-SHA-256 KAT", call_aws_lc_fips_failure); } -static int boringssl_self_test_hkdf_sha256(void) { +static int boringssl_self_test_hkdf_sha256(const bool call_aws_lc_fips_failure) { static const uint8_t kHKDF_ikm_tc1[] = { // RFC 5869 Test Case 1 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b @@ -2401,10 +2417,10 @@ static int boringssl_self_test_hkdf_sha256(void) { kHKDF_salt_tc1, sizeof(kHKDF_salt_tc1), kHKDF_info_tc1, sizeof(kHKDF_info_tc1)); return check_test(kHKDF_okm_tc1_sha256, output, sizeof(output), - "HKDF-SHA-256 KAT"); + "HKDF-SHA-256 KAT", call_aws_lc_fips_failure); } -static int boringssl_self_test_sha3_256(void) { +static int boringssl_self_test_sha3_256(const bool call_aws_lc_fips_failure) { // From: SHA3_256ShortMsg.txt // Len = 128 // Msg = d83c721ee51b060c5a41438a8221e040 @@ -2423,10 +2439,10 @@ static int boringssl_self_test_sha3_256(void) { // SHA3-256 KAT SHA3_256(kInput, sizeof(kInput), output); return check_test(kPlaintextSHA3_256, output, sizeof(kPlaintextSHA3_256), - "SHA3-256 KAT"); + "SHA3-256 KAT", call_aws_lc_fips_failure); } -static int boringssl_self_test_fast(void) { +static int boringssl_self_test_fast(const bool call_aws_lc_fips_failure) { static const uint8_t kAESKey[16] = {'B', 'o', 'r', 'i', 'n', 'g', 'C', 'r', 'y', 'p', 't', 'o', ' ', 'K', 'e', 'y'}; // Older versions of the gcc release build on ARM will optimize out the @@ -2468,7 +2484,7 @@ static int boringssl_self_test_fast(void) { AES_cbc_encrypt(kAESCBCEncPlaintext, output, sizeof(kAESCBCEncPlaintext), &aes_key, aes_iv, AES_ENCRYPT); if (!check_test(kAESCBCEncCiphertext, output, sizeof(kAESCBCEncCiphertext), - "AES-CBC-encrypt KAT")) { + "AES-CBC-encrypt KAT", call_aws_lc_fips_failure)) { goto err; } @@ -2491,7 +2507,7 @@ static int boringssl_self_test_fast(void) { AES_cbc_encrypt(kAESCBCDecCiphertext, output, sizeof(kAESCBCDecCiphertext), &aes_key, aes_iv, AES_DECRYPT); if (!check_test(kAESCBCDecPlaintext, output, sizeof(kAESCBCDecPlaintext), - "AES-CBC-decrypt KAT")) { + "AES-CBC-decrypt KAT", call_aws_lc_fips_failure)) { goto err; } @@ -2521,7 +2537,7 @@ static int boringssl_self_test_fast(void) { kAESGCMEncPlaintext, sizeof(kAESGCMEncPlaintext), NULL, 0) || !check_test(kAESGCMCiphertext, output, sizeof(kAESGCMCiphertext), - "AES-GCM-encrypt KAT")) { + "AES-GCM-encrypt KAT", call_aws_lc_fips_failure)) { fprintf(stderr, "EVP_AEAD_CTX_seal for AES-128-GCM failed.\n"); goto err; } @@ -2544,7 +2560,7 @@ static int boringssl_self_test_fast(void) { kAESGCMDecCiphertext, sizeof(kAESGCMDecCiphertext), NULL, 0) || !check_test(kAESGCMDecPlaintext, output, sizeof(kAESGCMDecPlaintext), - "AES-GCM-decrypt KAT")) { + "AES-GCM-decrypt KAT", call_aws_lc_fips_failure)) { fprintf(stderr, "AES-GCM-decrypt KAT failed because EVP_AEAD_CTX_open failed.\n"); goto err; @@ -2561,13 +2577,13 @@ static int boringssl_self_test_fast(void) { }; SHA1(kSHA1Input, sizeof(kSHA1Input), output); if (!check_test(kSHA1Digest, output, sizeof(kSHA1Digest), - "SHA-1 KAT")) { + "SHA-1 KAT", call_aws_lc_fips_failure)) { goto err; } - if (!boringssl_self_test_sha512() || - !boringssl_self_test_sha3_256() || - !boringssl_self_test_hkdf_sha256()) { + if (!boringssl_self_test_sha512(call_aws_lc_fips_failure) || + !boringssl_self_test_sha3_256(call_aws_lc_fips_failure) || + !boringssl_self_test_hkdf_sha256(call_aws_lc_fips_failure)) { goto err; } @@ -2611,12 +2627,12 @@ static int boringssl_self_test_fast(void) { !CTR_DRBG_generate(&drbg, output, sizeof(kDRBGOutput), kDRBGAD, sizeof(kDRBGAD)) || !check_test(kDRBGOutput, output, sizeof(kDRBGOutput), - "DRBG Generate KAT") || + "DRBG Generate KAT", call_aws_lc_fips_failure) || !CTR_DRBG_reseed(&drbg, kDRBGEntropy2, kDRBGAD, sizeof(kDRBGAD)) || !CTR_DRBG_generate(&drbg, output, sizeof(kDRBGReseedOutput), kDRBGAD, sizeof(kDRBGAD)) || !check_test(kDRBGReseedOutput, output, sizeof(kDRBGReseedOutput), - "DRBG-reseed KAT")) { + "DRBG-reseed KAT", call_aws_lc_fips_failure)) { fprintf(stderr, "CTR-DRBG failed.\n"); goto err; } @@ -2624,7 +2640,7 @@ static int boringssl_self_test_fast(void) { CTR_DRBG_STATE kZeroDRBG; memset(&kZeroDRBG, 0, sizeof(kZeroDRBG)); - if (!check_test(&kZeroDRBG, &drbg, sizeof(drbg), "DRBG Clear KAT")) { + if (!check_test(&kZeroDRBG, &drbg, sizeof(drbg), "DRBG Clear KAT", call_aws_lc_fips_failure)) { goto err; } @@ -2653,8 +2669,7 @@ static int boringssl_self_test_fast(void) { sizeof(kTLSSecret), kTLSLabel, sizeof(kTLSLabel), kTLSSeed1, sizeof(kTLSSeed1), kTLSSeed2, sizeof(kTLSSeed2)) || - !check_test(kTLSOutput, tls_output, sizeof(kTLSOutput), "TLS-KDF KAT")) { - fprintf(stderr, "TLS KDF failed.\n"); + !check_test(kTLSOutput, tls_output, sizeof(kTLSOutput), "TLS-KDF KAT", call_aws_lc_fips_failure)) { goto err; } @@ -2681,8 +2696,7 @@ static int boringssl_self_test_fast(void) { EVP_sha256(), sizeof(kPBKDF2DerivedKey), pbkdf2_output) || !check_test(kPBKDF2DerivedKey, pbkdf2_output, sizeof(kPBKDF2DerivedKey), - "PBKDF2 KAT")) { - fprintf(stderr, "PBKDF2 failed.\n"); + "PBKDF2 KAT", call_aws_lc_fips_failure)) { goto err; } @@ -2725,7 +2739,7 @@ static int boringssl_self_test_fast(void) { sizeof(kSSKDFDigestSharedSecret), &kSSKDFDigestInfo[0], sizeof(kSSKDFDigestInfo)) || !check_test(kSSKDFDigestDerivedKey, sskdf_digest_output, - sizeof(kSSKDFDigestDerivedKey), "SSKDF_digest KAT")) { + sizeof(kSSKDFDigestDerivedKey), "SSKDF_digest KAT", call_aws_lc_fips_failure)) { fprintf(stderr, "SSKDF_digest failed.\n"); goto err; } @@ -2755,8 +2769,7 @@ static int boringssl_self_test_fast(void) { kKBKDF_ctr_hmac_info, sizeof(kKBKDF_ctr_hmac_info)) || !check_test(kKBKDF_ctr_hmac_output, kbkdf_ctr_hmac_output, sizeof(kbkdf_ctr_hmac_output), - "KBKDF-CTR-HMAC-SHA-256 KAT")) { - fprintf(stderr, "KBKDF counter HMAC-SHA-256 failed.\n"); + "KBKDF-CTR-HMAC-SHA-256 KAT", call_aws_lc_fips_failure)) { goto err; } ret = 1; @@ -2767,16 +2780,17 @@ static int boringssl_self_test_fast(void) { return ret; } +// BORINGSSL_self_test does not abort if any tests fail int BORINGSSL_self_test(void) { - if (!boringssl_self_test_fast() || + if (!boringssl_self_test_fast(false) || // When requested to run self tests, also run the lazy tests. - !boringssl_self_test_rsa() || - !boringssl_self_test_ecc() || - !boringssl_self_test_ffdh() || - !boringssl_self_test_ml_kem() || - !boringssl_self_test_ml_dsa() || - !boringssl_self_test_eddsa() || - !boringssl_self_test_hasheddsa()) { + !boringssl_self_test_rsa(false) || + !boringssl_self_test_ecc(false) || + !boringssl_self_test_ffdh(false) || + !boringssl_self_test_ml_kem(false) || + !boringssl_self_test_ml_dsa(false) || + !boringssl_self_test_eddsa(false) || + !boringssl_self_test_hasheddsa(false)) { return 0; } @@ -2785,6 +2799,6 @@ int BORINGSSL_self_test(void) { #if defined(BORINGSSL_FIPS) int boringssl_self_test_startup(void) { - return boringssl_self_test_fast(); + return boringssl_self_test_fast(true); } #endif diff --git a/crypto/internal.h b/crypto/internal.h index a0c4818929..4e42bb5b5b 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -154,6 +154,8 @@ OPENSSL_MSVC_PRAGMA(warning(push, 3)) OPENSSL_MSVC_PRAGMA(warning(pop)) #endif +#include + #if defined(__cplusplus) extern "C" { #endif @@ -1267,13 +1269,13 @@ static inline uint64_t CRYPTO_subc_u64(uint64_t x, uint64_t y, uint64_t borrow, #if defined(BORINGSSL_FIPS) -// BORINGSSL_FIPS_abort is called when a FIPS power-on or continuous test +// AWS_LC_FIPS_failure is called when a FIPS power-on or continuous test // fails. It prevents any further cryptographic operations by the current // process. #if defined(_MSC_VER) -__declspec(noreturn) void BORINGSSL_FIPS_abort(void); +__declspec(noreturn) void AWS_LC_FIPS_failure(const char* message); #else -void BORINGSSL_FIPS_abort(void) __attribute__((noreturn)); +void AWS_LC_FIPS_failure(const char* message) __attribute__((noreturn)); #endif // boringssl_self_test_startup runs all startup self tests and returns one on @@ -1330,11 +1332,15 @@ OPENSSL_INLINE void boringssl_ensure_hasheddsa_self_test(void) {} #endif // FIPS -// boringssl_self_test_sha256 performs a SHA-256 KAT. -int boringssl_self_test_sha256(void); +// boringssl_self_test_sha256 performs a SHA-256 KAT, |call_aws_lc_fips_failure| +// determines if error messages should be printed to |stderr| call +// |AWS_LC_FIPS_failure| with the message. +int boringssl_self_test_sha256(const bool call_aws_lc_fips_failure); -// boringssl_self_test_hmac_sha256 performs an HMAC-SHA-256 KAT. -int boringssl_self_test_hmac_sha256(void); + // boringssl_self_test_hmac_sha256 performs an HMAC-SHA-256 KAT, + // |call_aws_lc_fips_failure| determines if error messages should be printed + // to |stderr| or call |AWS_LC_FIPS_failure| with the message. +int boringssl_self_test_hmac_sha256(const bool call_aws_lc_fips_failure); #if defined(BORINGSSL_FIPS_COUNTERS) void boringssl_fips_inc_counter(enum fips_counter_t counter); diff --git a/crypto/ml_dsa/ml_dsa_ref/sign.c b/crypto/ml_dsa/ml_dsa_ref/sign.c index 95073110e4..39243369f0 100644 --- a/crypto/ml_dsa/ml_dsa_ref/sign.c +++ b/crypto/ml_dsa/ml_dsa_ref/sign.c @@ -106,7 +106,7 @@ int ml_dsa_keypair_internal(ml_dsa_params *params, #if defined(AWSLC_FIPS) // Abort in case of PCT failure. if (!ml_dsa_keypair_pct(params, pk, sk)) { - BORINGSSL_FIPS_abort(); + AWS_LC_FIPS_failure("ML-DSA keygen PCT failed"); } #endif return 0; diff --git a/util/fipstools/capture_hash/capture_hash.go b/util/fipstools/capture_hash/capture_hash.go index f2eb0250b0..e8e558b2a8 100644 --- a/util/fipstools/capture_hash/capture_hash.go +++ b/util/fipstools/capture_hash/capture_hash.go @@ -16,10 +16,11 @@ import ( "strings" ) -const line0 = "FIPS integrity test failed." +const line0 = "AWS-LC FIPS failure caused by:" +const line1 = "FIPS integrity test failed." // This must match what is in crypto/fipsmodule/fips_shared_support.c -const line1 = "Expected: ae2cea2abda6f3ec977f9bf6949afc836827cba0a09f6b6fde52cde2cdff3180" +const line2 = "Expected: ae2cea2abda6f3ec977f9bf6949afc836827cba0a09f6b6fde52cde2cdff3180" const hash_len = 64 func main() { executable := flag.String("in-executable", "", "Path to the executable file") @@ -31,9 +32,9 @@ func main() { panic("Executable did not fail as expected") } lines := strings.Split(string(out), "\r\n") - if len(lines) != 4 { + if len(lines) != 6 { fmt.Fprintf(os.Stderr, string(out)) - panic(fmt.Sprintf("Expected 4 lines in output but got %d", len(lines))) + panic(fmt.Sprintf("Expected 6 lines in output but got %d", len(lines))) } if lines[0] != line0 { @@ -45,7 +46,11 @@ func main() { fmt.Fprintf(os.Stderr, string(out)) panic(fmt.Sprintf("Expected \"%s\" got \"%s\"", line1, lines[1])) } - hash := strings.Split(lines[2], " ")[1] + if lines[2] != line2 { + fmt.Fprintf(os.Stderr, string(out)) + panic(fmt.Sprintf("Expected \"%s\" got \"%s\"", line1, lines[1])) + } + hash := strings.Split(lines[3], " ")[1] if len(hash) != hash_len { fmt.Fprintf(os.Stderr, string(out)) diff --git a/util/fipstools/test-break-kat.sh b/util/fipstools/test-break-kat.sh index b586f8e9f0..e42cc517cd 100755 --- a/util/fipstools/test-break-kat.sh +++ b/util/fipstools/test-break-kat.sh @@ -34,7 +34,7 @@ for kat in $KATS; do chmod u+x ./break-kat-bin # Only capture stderr output=$(2>&1 ./break-kat-bin 2>&1 >/dev/null || true) - if ! echo "$output" | egrep -q "^${kat}[^a-zA-Z0-9]"; then + if ! echo "$output" | egrep -q "^${kat}"; then echo "Failure for $kat did not mention that name in the output" exit 1 fi