Skip to content

Commit 1be4999

Browse files
committed
Add runtime options to break the pairwise consistency test for Ed, ML-KEM, and ML-DSA
1 parent 028cd9f commit 1be4999

7 files changed

Lines changed: 97 additions & 12 deletions

File tree

crypto/fipsmodule/FIPS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ Some FIPS tests cannot be broken by replacing a known string in the binary. For
4545

4646
1. `RSA_PWCT`
4747
2. `ECDSA_PWCT`
48+
3. `EDDSA_PWCT`
49+
4. `MLKEM_PWCT`
50+
5. `MLDSA_PWCT`
4851

4952
## Running ACVP tests
5053

crypto/fipsmodule/curve25519/curve25519.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,15 @@ static void ed25519_keypair_pct(uint8_t public_key[ED25519_PUBLIC_KEY_LEN],
117117
#if defined(AWSLC_FIPS)
118118
uint8_t msg[16] = {16};
119119
uint8_t out_sig[ED25519_SIGNATURE_LEN];
120-
if (ED25519_sign_no_self_test(out_sig, msg, 16, private_key) != 1 ||
121-
ED25519_verify_no_self_test(msg, 16, out_sig, public_key) != 1) {
120+
if (ED25519_sign_no_self_test(out_sig, msg, 16, private_key) != 1) {
121+
// This should never happen and static analysis will say that ED25519_sign_no_self_test
122+
// always returns 1
123+
AWS_LC_FIPS_failure("Ed25519 keygen PCT failed");
124+
}
125+
if (boringssl_fips_break_test("EDDSA_PWCT")) {
126+
msg[0] = ~msg[0];
127+
}
128+
if (ED25519_verify_no_self_test(msg, 16, out_sig, public_key) != 1) {
122129
AWS_LC_FIPS_failure("Ed25519 keygen PCT failed");
123130
}
124131
#endif

crypto/fipsmodule/ml_kem/ml_kem_ref/kem.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ static int keygen_pct(ml_kem_params *params, const uint8_t *ek, const uint8_t *d
2424
crypto_kem_enc(params, ct, ss_enc, ek);
2525
crypto_kem_dec(params, ss_dec, ct, dk);
2626

27+
if (boringssl_fips_break_test("MLKEM_PWCT")) {
28+
ss_enc[0] = ~ss_enc[0];
29+
}
30+
2731
return verify(ss_enc, ss_dec, KYBER_SSBYTES);
2832
}
2933
#endif

crypto/ml_dsa/ml_dsa_ref/sign.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,15 @@
2525
static int ml_dsa_keypair_pct(ml_dsa_params *params,
2626
uint8_t *pk,
2727
uint8_t *sk) {
28+
uint8_t message[16] = {0};
2829
uint8_t signature[MLDSA87_SIGNATURE_BYTES];
29-
ml_dsa_sign(params, signature, &params->bytes, NULL, 0, NULL, 0, sk);
30-
return ml_dsa_verify(params, signature, params->bytes, NULL, 0, NULL, 0, pk) == 0;
30+
ml_dsa_sign(params, signature, &params->bytes, message, sizeof(message), NULL, 0, sk);
31+
32+
if (boringssl_fips_break_test("MLDSA_PWCT")) {
33+
message[0] = ~message[0];
34+
}
35+
36+
return ml_dsa_verify(params, signature, params->bytes, message, sizeof(message), NULL, 0, pk) == 0;
3137
}
3238
#endif
3339

tests/ci/run_fips_tests.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ if static_linux_supported || static_openbsd_supported; then
3434
echo "Testing AWS-LC static breakable release build"
3535
run_build -DFIPS=1 -DCMAKE_C_FLAGS="-DBORINGSSL_FIPS_BREAK_TESTS"
3636
./util/fipstools/test-break-kat.sh
37+
./util/fipstools/test-runtime-pwct.sh
3738
export BORINGSSL_FIPS_BREAK_TEST="RSA_PWCT"
3839
${BUILD_ROOT}/crypto/crypto_test --gtest_filter="RSADeathTest.KeygenFailAndDie"
3940
unset BORINGSSL_FIPS_BREAK_TEST
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0 OR ISC
3+
4+
# This script attempts to break each of the key generation pair wise consistency tests and checks that doing so
5+
# seems to work and at least mentions the correct KAT in the output.
6+
7+
set -x
8+
set -e
9+
10+
TEST_FIPS_BIN="test_build_dir/util/fipstools/test_fips"
11+
12+
if [ ! -f $TEST_FIPS_BIN ]; then
13+
echo "$TEST_FIPS_BIN is missing. Run this script from the top level of a"
14+
echo "BoringSSL checkout and ensure that ./build-fips-break-test-binaries.sh"
15+
echo "has been run first."
16+
exit 1
17+
fi
18+
19+
check_test_output() {
20+
local test_name="$1"
21+
local output="$2"
22+
case "$test_name" in
23+
"ECDSA_PWCT") expected="EC keygen checks failed" ;;
24+
"RSA_PWCT") expected="RSA keygen checks failed" ;;
25+
"MLKEM_PWCT") expected="ML-KEM keygen PCT failed" ;;
26+
"MLDSA_PWCT") expected="ML-DSA keygen PCT failed" ;;
27+
"EDDSA_PWCT") expected="Ed25519 keygen PCT failed" ;;
28+
*) echo "Unknown test: $test_name"; return 1 ;;
29+
esac
30+
31+
if ! echo "$output" | grep -q "$expected"; then
32+
echo "Failure for ${test_name} did not contain expected message: '${expected}'"
33+
echo "Actual output was: '${output}'"
34+
return 1
35+
fi
36+
return 0
37+
}
38+
39+
for runtime_test in ECDSA_PWCT RSA_PWCT EDDSA_PWCT MLKEM_PWCT MLDSA_PWCT; do
40+
output=$(2>&1 BORINGSSL_FIPS_BREAK_TEST=$runtime_test $TEST_FIPS_BIN 2>&1 >/dev/null || true)
41+
echo $output
42+
if ! check_test_output "$runtime_test" "$output"; then
43+
exit 1
44+
fi
45+
done
46+
47+
echo "All tests broken as expected"
48+

util/fipstools/test_fips.c

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
#include "../../crypto/fipsmodule/evp/internal.h"
3838
#include "../../crypto/fipsmodule/kem/internal.h"
39+
#include "../../crypto/fipsmodule/pqdsa/internal.h"
3940
#include "../../crypto/fipsmodule/rand/internal.h"
4041
#include "../../crypto/internal.h"
4142

@@ -431,18 +432,33 @@ int main(int argc, char **argv) {
431432

432433
/* ML-KEM */
433434
printf("About to Generate ML-KEM key\n");
434-
EVP_PKEY *raw = NULL;
435-
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_KEM, NULL);
436-
if (ctx == NULL || !EVP_PKEY_CTX_kem_set_params(ctx, NID_MLKEM512) ||
437-
!EVP_PKEY_keygen_init(ctx) ||
438-
!EVP_PKEY_keygen(ctx, &raw)) {
435+
EVP_PKEY *kem_raw = NULL;
436+
EVP_PKEY_CTX *kem_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_KEM, NULL);
437+
if (kem_ctx == NULL || !EVP_PKEY_CTX_kem_set_params(kem_ctx, NID_MLKEM512) ||
438+
!EVP_PKEY_keygen_init(kem_ctx) ||
439+
!EVP_PKEY_keygen(kem_ctx, &kem_raw)) {
439440
printf("ML-KEM keygen failed.\n");
440441
goto err;
441442
}
442443
printf("Generated public key: ");
443-
hexdump(raw->pkey.kem_key->public_key, raw->pkey.kem_key->kem->public_key_len);
444-
EVP_PKEY_free(raw);
445-
EVP_PKEY_CTX_free(ctx);
444+
hexdump(kem_raw->pkey.kem_key->public_key, kem_raw->pkey.kem_key->kem->public_key_len);
445+
EVP_PKEY_free(kem_raw);
446+
EVP_PKEY_CTX_free(kem_ctx);
447+
448+
/* ML-DSA */
449+
printf("About to Generate ML-DSA key\n");
450+
EVP_PKEY *dsa_raw = NULL;
451+
EVP_PKEY_CTX *dsa_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_PQDSA, NULL);
452+
if (dsa_ctx == NULL || !EVP_PKEY_CTX_pqdsa_set_params(dsa_ctx, NID_MLDSA44) ||
453+
!EVP_PKEY_keygen_init(dsa_ctx) ||
454+
!EVP_PKEY_keygen(dsa_ctx, &dsa_raw)) {
455+
printf("ML-DSA keygen failed.\n");
456+
goto err;
457+
}
458+
printf("Generated public key: ");
459+
hexdump(dsa_raw->pkey.pqdsa_key->public_key, dsa_raw->pkey.pqdsa_key->pqdsa->public_key_len);
460+
EVP_PKEY_free(dsa_raw);
461+
EVP_PKEY_CTX_free(dsa_ctx);
446462

447463
/* DBRG */
448464
CTR_DRBG_STATE drbg;

0 commit comments

Comments
 (0)