Add ML-DSA self tests.
Change-Id: I640b1f57de2544d9329cba83352d0d51debc092c Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/76388 Commit-Queue: Adam Langley <agl@google.com> Reviewed-by: David Benjamin <davidben@google.com>
This commit is contained in:
committed by
Boringssl LUCI CQ
parent
5e73d0302c
commit
3494965215
@@ -76,6 +76,7 @@
|
||||
"crypto/fipsmodule/hkdf/hkdf.cc.inc",
|
||||
"crypto/fipsmodule/hmac/hmac.cc.inc",
|
||||
"crypto/fipsmodule/keccak/keccak.cc.inc",
|
||||
"crypto/fipsmodule/mldsa/fips_known_values.inc",
|
||||
"crypto/fipsmodule/mldsa/mldsa.cc.inc",
|
||||
"crypto/fipsmodule/mlkem/fips_known_values.inc",
|
||||
"crypto/fipsmodule/mlkem/mlkem.cc.inc",
|
||||
|
||||
@@ -55,6 +55,9 @@ inline bcm_status_t bcm_as_approved_status(int result) {
|
||||
return result ? bcm_status::approved : bcm_status::failure;
|
||||
}
|
||||
|
||||
inline bcm_status_t bcm_as_not_approved_status(int result) {
|
||||
return result ? bcm_status::not_approved : bcm_status::failure;
|
||||
}
|
||||
|
||||
// Random number generator.
|
||||
|
||||
@@ -290,6 +293,18 @@ OPENSSL_EXPORT bcm_status BCM_mldsa65_public_from_private(
|
||||
struct BCM_mldsa65_public_key *out_public_key,
|
||||
const struct BCM_mldsa65_private_key *private_key);
|
||||
|
||||
OPENSSL_EXPORT bcm_status
|
||||
BCM_mldsa65_check_key_fips(struct BCM_mldsa65_private_key *private_key);
|
||||
|
||||
OPENSSL_EXPORT bcm_status BCM_mldsa65_generate_key_fips(
|
||||
uint8_t out_encoded_public_key[BCM_MLDSA65_PUBLIC_KEY_BYTES],
|
||||
uint8_t out_seed[BCM_MLDSA_SEED_BYTES],
|
||||
struct BCM_mldsa65_private_key *out_private_key);
|
||||
|
||||
OPENSSL_EXPORT bcm_status BCM_mldsa65_private_key_from_seed_fips(
|
||||
struct BCM_mldsa65_private_key *out_private_key,
|
||||
const uint8_t seed[BCM_MLDSA_SEED_BYTES]);
|
||||
|
||||
OPENSSL_EXPORT bcm_status BCM_mldsa65_sign(
|
||||
uint8_t out_encoded_signature[BCM_MLDSA65_SIGNATURE_BYTES],
|
||||
const struct BCM_mldsa65_private_key *private_key, const uint8_t *msg,
|
||||
@@ -317,6 +332,11 @@ OPENSSL_EXPORT bcm_status BCM_mldsa65_generate_key_external_entropy(
|
||||
struct BCM_mldsa65_private_key *out_private_key,
|
||||
const uint8_t entropy[BCM_MLDSA_SEED_BYTES]);
|
||||
|
||||
OPENSSL_EXPORT bcm_status BCM_mldsa65_generate_key_external_entropy_fips(
|
||||
uint8_t out_encoded_public_key[BCM_MLDSA65_PUBLIC_KEY_BYTES],
|
||||
struct BCM_mldsa65_private_key *out_private_key,
|
||||
const uint8_t entropy[BCM_MLDSA_SEED_BYTES]);
|
||||
|
||||
// BCM_mldsa5_sign_internal signs |msg| using |private_key| and writes the
|
||||
// signature to |out_encoded_signature|. The |context_prefix| and |context| are
|
||||
// prefixed to the message, in that order, before signing. The |randomizer|
|
||||
@@ -383,6 +403,18 @@ OPENSSL_EXPORT bcm_status BCM_mldsa87_public_from_private(
|
||||
struct BCM_mldsa87_public_key *out_public_key,
|
||||
const struct BCM_mldsa87_private_key *private_key);
|
||||
|
||||
OPENSSL_EXPORT bcm_status
|
||||
BCM_mldsa87_check_key_fips(struct BCM_mldsa87_private_key *private_key);
|
||||
|
||||
OPENSSL_EXPORT bcm_status BCM_mldsa87_generate_key_fips(
|
||||
uint8_t out_encoded_public_key[BCM_MLDSA87_PUBLIC_KEY_BYTES],
|
||||
uint8_t out_seed[BCM_MLDSA_SEED_BYTES],
|
||||
struct BCM_mldsa87_private_key *out_private_key);
|
||||
|
||||
OPENSSL_EXPORT bcm_status BCM_mldsa87_private_key_from_seed_fips(
|
||||
struct BCM_mldsa87_private_key *out_private_key,
|
||||
const uint8_t seed[BCM_MLDSA_SEED_BYTES]);
|
||||
|
||||
OPENSSL_EXPORT bcm_status BCM_mldsa87_sign(
|
||||
uint8_t out_encoded_signature[BCM_MLDSA87_SIGNATURE_BYTES],
|
||||
const struct BCM_mldsa87_private_key *private_key, const uint8_t *msg,
|
||||
@@ -410,6 +442,11 @@ OPENSSL_EXPORT bcm_status BCM_mldsa87_generate_key_external_entropy(
|
||||
struct BCM_mldsa87_private_key *out_private_key,
|
||||
const uint8_t entropy[BCM_MLDSA_SEED_BYTES]);
|
||||
|
||||
OPENSSL_EXPORT bcm_status BCM_mldsa87_generate_key_external_entropy_fips(
|
||||
uint8_t out_encoded_public_key[BCM_MLDSA87_PUBLIC_KEY_BYTES],
|
||||
struct BCM_mldsa87_private_key *out_private_key,
|
||||
const uint8_t entropy[BCM_MLDSA_SEED_BYTES]);
|
||||
|
||||
// BCM_mldsa87_sign_internal signs |msg| using |private_key| and writes the
|
||||
// signature to |out_encoded_signature|. The |context_prefix| and |context| are
|
||||
// prefixed to the message, in that order, before signing. The |randomizer|
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,12 @@
|
||||
namespace mldsa {
|
||||
namespace {
|
||||
|
||||
namespace fips {
|
||||
void ensure_keygen_self_test();
|
||||
void ensure_sign_self_test();
|
||||
void ensure_verify_self_test();
|
||||
} // namespace fips
|
||||
|
||||
constexpr int kDegree = 256;
|
||||
constexpr int kRhoBytes = 32;
|
||||
constexpr int kSigmaBytes = 64;
|
||||
@@ -1397,7 +1403,7 @@ struct DeleterFree {
|
||||
// FIPS 204, Algorithm 6 (`ML-DSA.KeyGen_internal`). Returns 1 on success and 0
|
||||
// on failure.
|
||||
template <int K, int L>
|
||||
int mldsa_generate_key_external_entropy(
|
||||
int mldsa_generate_key_external_entropy_no_self_test(
|
||||
uint8_t out_encoded_public_key[public_key_bytes<K>()],
|
||||
struct private_key<K, L> *priv,
|
||||
const uint8_t entropy[BCM_MLDSA_SEED_BYTES]) {
|
||||
@@ -1460,6 +1466,16 @@ int mldsa_generate_key_external_entropy(
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <int K, int L>
|
||||
int mldsa_generate_key_external_entropy(
|
||||
uint8_t out_encoded_public_key[public_key_bytes<K>()],
|
||||
struct private_key<K, L> *priv,
|
||||
const uint8_t entropy[BCM_MLDSA_SEED_BYTES]) {
|
||||
fips::ensure_keygen_self_test();
|
||||
return mldsa_generate_key_external_entropy_no_self_test(
|
||||
out_encoded_public_key, priv, entropy);
|
||||
}
|
||||
|
||||
template <int K, int L>
|
||||
int mldsa_public_from_private(struct public_key<K> *pub,
|
||||
const struct private_key<K, L> *priv) {
|
||||
@@ -1499,7 +1515,7 @@ int mldsa_public_from_private(struct public_key<K> *pub,
|
||||
// FIPS 204, Algorithm 7 (`ML-DSA.Sign_internal`). Returns 1 on success and 0
|
||||
// on failure.
|
||||
template <int K, int L>
|
||||
int mldsa_sign_internal(
|
||||
int mldsa_sign_internal_no_self_test(
|
||||
uint8_t out_encoded_signature[signature_bytes<K>()],
|
||||
const struct private_key<K, L> *priv, const uint8_t *msg, size_t msg_len,
|
||||
const uint8_t *context_prefix, size_t context_prefix_len,
|
||||
@@ -1605,6 +1621,11 @@ int mldsa_sign_internal(
|
||||
if (constant_time_declassify_w(
|
||||
constant_time_ge_w(z_max, gamma1<K>() - beta<K>()) |
|
||||
constant_time_ge_w(r0_max, kGamma2 - beta<K>()))) {
|
||||
#if defined(BORINGSSL_FIPS_BREAK_TESTS)
|
||||
// In order to show that our self-tests trigger both restart cases in
|
||||
// this loop, printf-logging is added when built in break-test mode.
|
||||
printf("MLDSA signature restart case 1.\n");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1618,6 +1639,11 @@ int mldsa_sign_internal(
|
||||
size_t h_ones = vector_count_ones(&values->sign.h);
|
||||
if (constant_time_declassify_w(constant_time_ge_w(ct0_max, kGamma2) |
|
||||
constant_time_lt_w(omega<K>(), h_ones))) {
|
||||
#if defined(BORINGSSL_FIPS_BREAK_TESTS)
|
||||
// In order to show that our self-tests trigger both restart cases in
|
||||
// this loop, printf-logging is added when built in break-test mode.
|
||||
printf("MLDSA signature restart case 2.\n");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1637,14 +1663,26 @@ int mldsa_sign_internal(
|
||||
}
|
||||
}
|
||||
|
||||
template <int K, int L>
|
||||
int mldsa_sign_internal(
|
||||
uint8_t out_encoded_signature[signature_bytes<K>()],
|
||||
const struct private_key<K, L> *priv, const uint8_t *msg, size_t msg_len,
|
||||
const uint8_t *context_prefix, size_t context_prefix_len,
|
||||
const uint8_t *context, size_t context_len,
|
||||
const uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]) {
|
||||
fips::ensure_sign_self_test();
|
||||
return mldsa_sign_internal_no_self_test(
|
||||
out_encoded_signature, priv, msg, msg_len, context_prefix,
|
||||
context_prefix_len, context, context_len, randomizer);
|
||||
}
|
||||
|
||||
// FIPS 204, Algorithm 8 (`ML-DSA.Verify_internal`).
|
||||
template <int K, int L>
|
||||
int mldsa_verify_internal(const struct public_key<K> *pub,
|
||||
const uint8_t encoded_signature[signature_bytes<K>()],
|
||||
const uint8_t *msg, size_t msg_len,
|
||||
const uint8_t *context_prefix,
|
||||
size_t context_prefix_len, const uint8_t *context,
|
||||
size_t context_len) {
|
||||
int mldsa_verify_internal_no_self_test(
|
||||
const struct public_key<K> *pub,
|
||||
const uint8_t encoded_signature[signature_bytes<K>()], const uint8_t *msg,
|
||||
size_t msg_len, const uint8_t *context_prefix, size_t context_prefix_len,
|
||||
const uint8_t *context, size_t context_len) {
|
||||
// Intermediate values, allocated on the heap to allow use when there is a
|
||||
// limited amount of stack.
|
||||
struct values_st {
|
||||
@@ -1712,6 +1750,18 @@ int mldsa_verify_internal(const struct public_key<K> *pub,
|
||||
OPENSSL_memcmp(c_tilde, values->sign.c_tilde, 2 * lambda_bytes<K>()) ==
|
||||
0;
|
||||
}
|
||||
template <int K, int L>
|
||||
int mldsa_verify_internal(const struct public_key<K> *pub,
|
||||
const uint8_t encoded_signature[signature_bytes<K>()],
|
||||
const uint8_t *msg, size_t msg_len,
|
||||
const uint8_t *context_prefix,
|
||||
size_t context_prefix_len, const uint8_t *context,
|
||||
size_t context_len) {
|
||||
fips::ensure_verify_self_test();
|
||||
return mldsa_verify_internal_no_self_test<K, L>(
|
||||
pub, encoded_signature, msg, msg_len, context_prefix, context_prefix_len,
|
||||
context, context_len);
|
||||
}
|
||||
|
||||
struct private_key<6, 5> *private_key_from_external_65(
|
||||
const struct BCM_mldsa65_private_key *external) {
|
||||
@@ -1724,19 +1774,19 @@ struct private_key<6, 5> *private_key_from_external_65(
|
||||
return (struct private_key<6, 5> *)external;
|
||||
}
|
||||
|
||||
struct public_key<6> *
|
||||
public_key_from_external_65(const struct BCM_mldsa65_public_key *external) {
|
||||
static_assert(sizeof(struct BCM_mldsa65_public_key) ==
|
||||
sizeof(struct public_key<6>),
|
||||
"MLDSA65 public key size incorrect");
|
||||
static_assert(alignof(struct BCM_mldsa65_public_key) ==
|
||||
alignof(struct public_key<6>),
|
||||
"MLDSA65 public key align incorrect");
|
||||
struct public_key<6> *public_key_from_external_65(
|
||||
const struct BCM_mldsa65_public_key *external) {
|
||||
static_assert(
|
||||
sizeof(struct BCM_mldsa65_public_key) == sizeof(struct public_key<6>),
|
||||
"MLDSA65 public key size incorrect");
|
||||
static_assert(
|
||||
alignof(struct BCM_mldsa65_public_key) == alignof(struct public_key<6>),
|
||||
"MLDSA65 public key align incorrect");
|
||||
return (struct public_key<6> *)external;
|
||||
}
|
||||
|
||||
struct private_key<8, 7> *
|
||||
private_key_from_external_87(const struct BCM_mldsa87_private_key *external) {
|
||||
struct private_key<8, 7> *private_key_from_external_87(
|
||||
const struct BCM_mldsa87_private_key *external) {
|
||||
static_assert(sizeof(struct BCM_mldsa87_private_key) ==
|
||||
sizeof(struct private_key<8, 7>),
|
||||
"MLDSA87 private key size incorrect");
|
||||
@@ -1746,17 +1796,177 @@ private_key_from_external_87(const struct BCM_mldsa87_private_key *external) {
|
||||
return (struct private_key<8, 7> *)external;
|
||||
}
|
||||
|
||||
struct public_key<8> *
|
||||
public_key_from_external_87(const struct BCM_mldsa87_public_key *external) {
|
||||
static_assert(sizeof(struct BCM_mldsa87_public_key) ==
|
||||
sizeof(struct public_key<8>),
|
||||
"MLDSA87 public key size incorrect");
|
||||
static_assert(alignof(struct BCM_mldsa87_public_key) ==
|
||||
alignof(struct public_key<8>),
|
||||
"MLDSA87 public key align incorrect");
|
||||
struct public_key<8> *public_key_from_external_87(
|
||||
const struct BCM_mldsa87_public_key *external) {
|
||||
static_assert(
|
||||
sizeof(struct BCM_mldsa87_public_key) == sizeof(struct public_key<8>),
|
||||
"MLDSA87 public key size incorrect");
|
||||
static_assert(
|
||||
alignof(struct BCM_mldsa87_public_key) == alignof(struct public_key<8>),
|
||||
"MLDSA87 public key align incorrect");
|
||||
return (struct public_key<8> *)external;
|
||||
}
|
||||
|
||||
namespace fips {
|
||||
|
||||
#include "fips_known_values.inc"
|
||||
|
||||
static int keygen_self_test() {
|
||||
private_key<6, 5> priv;
|
||||
uint8_t pub_bytes[BCM_MLDSA65_PUBLIC_KEY_BYTES];
|
||||
if (!mldsa_generate_key_external_entropy_no_self_test(pub_bytes, &priv,
|
||||
kGenerateKeyEntropy)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t priv_bytes[BCM_MLDSA65_PRIVATE_KEY_BYTES];
|
||||
CBB cbb;
|
||||
CBB_init_fixed(&cbb, priv_bytes, sizeof(priv_bytes));
|
||||
if (!mldsa_marshal_private_key(&cbb, &priv)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static_assert(sizeof(pub_bytes) == sizeof(kExpectedPublicKey));
|
||||
static_assert(sizeof(priv_bytes) == sizeof(kExpectedPrivateKey));
|
||||
if (!BORINGSSL_check_test(kExpectedPublicKey, pub_bytes, sizeof(pub_bytes),
|
||||
"ML-DSA keygen public key") ||
|
||||
!BORINGSSL_check_test(kExpectedPrivateKey, priv_bytes, sizeof(priv_bytes),
|
||||
"ML-DSA keygen private key")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sign_self_test() {
|
||||
private_key<6, 5> priv;
|
||||
uint8_t pub_bytes[BCM_MLDSA65_PUBLIC_KEY_BYTES];
|
||||
if (!mldsa_generate_key_external_entropy(pub_bytes, &priv, kSignEntropy)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES] = {};
|
||||
uint8_t sig[BCM_MLDSA65_SIGNATURE_BYTES];
|
||||
|
||||
// This message triggers the first restart case for signing.
|
||||
uint8_t message[4] = {0};
|
||||
if (!mldsa_sign_internal_no_self_test(sig, &priv, message, sizeof(message),
|
||||
nullptr, 0, nullptr, 0, randomizer)) {
|
||||
return 0;
|
||||
}
|
||||
static_assert(sizeof(kExpectedCase1Signature) == sizeof(sig));
|
||||
if (!BORINGSSL_check_test(kExpectedCase1Signature, sig, sizeof(sig),
|
||||
"ML-DSA sign case 1")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This message triggers the second restart case for signing.
|
||||
message[0] = 123;
|
||||
if (!mldsa_sign_internal_no_self_test(sig, &priv, message, sizeof(message),
|
||||
nullptr, 0, nullptr, 0, randomizer)) {
|
||||
return 0;
|
||||
}
|
||||
static_assert(sizeof(kExpectedCase2Signature) == sizeof(sig));
|
||||
if (!BORINGSSL_check_test(kExpectedCase2Signature, sig, sizeof(sig),
|
||||
"ML-DSA sign case 2")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int verify_self_test() {
|
||||
struct values_st {
|
||||
private_key<6, 5> priv;
|
||||
public_key<6> pub;
|
||||
uint8_t pub_bytes[BCM_MLDSA65_PUBLIC_KEY_BYTES];
|
||||
};
|
||||
std::unique_ptr<values_st, DeleterFree<values_st>> values(
|
||||
reinterpret_cast<struct values_st *>(OPENSSL_malloc(sizeof(values_st))));
|
||||
if (!values) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!mldsa_generate_key_external_entropy(values->pub_bytes, &values->priv,
|
||||
kSignEntropy)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8_t message[4] = {1, 0};
|
||||
if (!mldsa_public_from_private(&values->pub, &values->priv) ||
|
||||
!mldsa_verify_internal_no_self_test<6, 5>(
|
||||
&values->pub, kExpectedVerifySignature, message, sizeof(message),
|
||||
nullptr, 0, nullptr, 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <int K, int L>
|
||||
int check_key(private_key<K, L> *priv) {
|
||||
uint8_t sig[signature_bytes<K>()];
|
||||
uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES] = {};
|
||||
mldsa::public_key<K> pub;
|
||||
if (!mldsa_public_from_private(&pub, priv) ||
|
||||
!mldsa_sign_internal_no_self_test(sig, priv, nullptr, 0, nullptr, 0,
|
||||
nullptr, 0, randomizer)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (boringssl_fips_break_test("MLDSA_PWCT")) {
|
||||
sig[0] ^= 1;
|
||||
}
|
||||
|
||||
if (!mldsa_verify_internal_no_self_test<K, L>(&pub, sig, nullptr, 0, nullptr,
|
||||
0, nullptr, 0)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(BORINGSSL_FIPS)
|
||||
|
||||
DEFINE_STATIC_ONCE(g_mldsa_keygen_self_test_once)
|
||||
|
||||
void ensure_keygen_self_test(void) {
|
||||
CRYPTO_once(g_mldsa_keygen_self_test_once_bss_get(), []() {
|
||||
if (!keygen_self_test()) {
|
||||
BORINGSSL_FIPS_abort();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DEFINE_STATIC_ONCE(g_mldsa_sign_self_test_once)
|
||||
|
||||
void ensure_sign_self_test(void) {
|
||||
CRYPTO_once(g_mldsa_sign_self_test_once_bss_get(), []() {
|
||||
if (!sign_self_test()) {
|
||||
BORINGSSL_FIPS_abort();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DEFINE_STATIC_ONCE(g_mldsa_verify_self_test_once)
|
||||
|
||||
void ensure_verify_self_test(void) {
|
||||
CRYPTO_once(g_mldsa_verify_self_test_once_bss_get(), []() {
|
||||
if (!verify_self_test()) {
|
||||
BORINGSSL_FIPS_abort();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void ensure_keygen_self_test(void) {}
|
||||
void ensure_sign_self_test(void) {}
|
||||
void ensure_verify_self_test(void) {}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace fips
|
||||
|
||||
} // namespace
|
||||
} // namespace mldsa
|
||||
|
||||
@@ -1783,6 +1993,12 @@ bcm_status BCM_mldsa65_parse_private_key(
|
||||
CBS_len(in) == 0);
|
||||
}
|
||||
|
||||
bcm_status BCM_mldsa65_check_key_fips(
|
||||
struct BCM_mldsa65_private_key *private_key) {
|
||||
return bcm_as_approved_status(
|
||||
mldsa::fips::check_key(mldsa::private_key_from_external_65(private_key)));
|
||||
}
|
||||
|
||||
// Calls |MLDSA_generate_key_external_entropy| with random bytes from
|
||||
// |BCM_rand_bytes|.
|
||||
bcm_status BCM_mldsa65_generate_key(
|
||||
@@ -1807,11 +2023,45 @@ bcm_status BCM_mldsa65_generate_key_external_entropy(
|
||||
uint8_t out_encoded_public_key[BCM_MLDSA65_PUBLIC_KEY_BYTES],
|
||||
struct BCM_mldsa65_private_key *out_private_key,
|
||||
const uint8_t entropy[BCM_MLDSA_SEED_BYTES]) {
|
||||
return bcm_as_approved_status(mldsa_generate_key_external_entropy(
|
||||
return bcm_as_not_approved_status(mldsa_generate_key_external_entropy(
|
||||
out_encoded_public_key,
|
||||
mldsa::private_key_from_external_65(out_private_key), entropy));
|
||||
}
|
||||
|
||||
bcm_status BCM_mldsa65_generate_key_fips(
|
||||
uint8_t out_encoded_public_key[BCM_MLDSA65_PUBLIC_KEY_BYTES],
|
||||
uint8_t out_seed[BCM_MLDSA_SEED_BYTES],
|
||||
struct BCM_mldsa65_private_key *out_private_key) {
|
||||
if (BCM_mldsa65_generate_key(out_encoded_public_key, out_seed,
|
||||
out_private_key) == bcm_status::failure) {
|
||||
return bcm_status::failure;
|
||||
}
|
||||
return BCM_mldsa65_check_key_fips(out_private_key);
|
||||
}
|
||||
|
||||
bcm_status BCM_mldsa65_generate_key_external_entropy_fips(
|
||||
uint8_t out_encoded_public_key[BCM_MLDSA65_PUBLIC_KEY_BYTES],
|
||||
struct BCM_mldsa65_private_key *out_private_key,
|
||||
const uint8_t entropy[BCM_MLDSA_SEED_BYTES]) {
|
||||
if (BCM_mldsa65_generate_key_external_entropy(out_encoded_public_key,
|
||||
out_private_key, entropy) ==
|
||||
bcm_status::failure) {
|
||||
return bcm_status::failure;
|
||||
}
|
||||
return BCM_mldsa65_check_key_fips(out_private_key);
|
||||
}
|
||||
|
||||
bcm_status BCM_mldsa65_private_key_from_seed_fips(
|
||||
struct BCM_mldsa65_private_key *out_private_key,
|
||||
const uint8_t seed[BCM_MLDSA_SEED_BYTES]) {
|
||||
uint8_t public_key[BCM_MLDSA65_PUBLIC_KEY_BYTES];
|
||||
if (BCM_mldsa65_generate_key_external_entropy(public_key, out_private_key,
|
||||
seed) == bcm_status::failure) {
|
||||
return bcm_status::failure;
|
||||
}
|
||||
return BCM_mldsa65_check_key_fips(out_private_key);
|
||||
}
|
||||
|
||||
bcm_status BCM_mldsa65_public_from_private(
|
||||
struct BCM_mldsa65_public_key *out_public_key,
|
||||
const struct BCM_mldsa65_private_key *private_key) {
|
||||
@@ -1900,6 +2150,12 @@ bcm_status BCM_mldsa87_parse_private_key(
|
||||
CBS_len(in) == 0);
|
||||
}
|
||||
|
||||
bcm_status BCM_mldsa87_check_key_fips(
|
||||
struct BCM_mldsa87_private_key *private_key) {
|
||||
return bcm_as_approved_status(
|
||||
mldsa::fips::check_key(mldsa::private_key_from_external_87(private_key)));
|
||||
}
|
||||
|
||||
// Calls |MLDSA_generate_key_external_entropy| with random bytes from
|
||||
// |BCM_rand_bytes|.
|
||||
bcm_status BCM_mldsa87_generate_key(
|
||||
@@ -1923,11 +2179,45 @@ bcm_status BCM_mldsa87_generate_key_external_entropy(
|
||||
uint8_t out_encoded_public_key[BCM_MLDSA87_PUBLIC_KEY_BYTES],
|
||||
struct BCM_mldsa87_private_key *out_private_key,
|
||||
const uint8_t entropy[BCM_MLDSA_SEED_BYTES]) {
|
||||
return bcm_as_approved_status(mldsa_generate_key_external_entropy(
|
||||
return bcm_as_not_approved_status(mldsa_generate_key_external_entropy(
|
||||
out_encoded_public_key,
|
||||
mldsa::private_key_from_external_87(out_private_key), entropy));
|
||||
}
|
||||
|
||||
bcm_status BCM_mldsa87_generate_key_fips(
|
||||
uint8_t out_encoded_public_key[BCM_MLDSA87_PUBLIC_KEY_BYTES],
|
||||
uint8_t out_seed[BCM_MLDSA_SEED_BYTES],
|
||||
struct BCM_mldsa87_private_key *out_private_key) {
|
||||
if (BCM_mldsa87_generate_key(out_encoded_public_key, out_seed,
|
||||
out_private_key) == bcm_status::failure) {
|
||||
return bcm_status::failure;
|
||||
}
|
||||
return BCM_mldsa87_check_key_fips(out_private_key);
|
||||
}
|
||||
|
||||
bcm_status BCM_mldsa87_generate_key_external_entropy_fips(
|
||||
uint8_t out_encoded_public_key[BCM_MLDSA87_PUBLIC_KEY_BYTES],
|
||||
struct BCM_mldsa87_private_key *out_private_key,
|
||||
const uint8_t entropy[BCM_MLDSA_SEED_BYTES]) {
|
||||
if (BCM_mldsa87_generate_key_external_entropy(out_encoded_public_key,
|
||||
out_private_key, entropy) ==
|
||||
bcm_status::failure) {
|
||||
return bcm_status::failure;
|
||||
}
|
||||
return BCM_mldsa87_check_key_fips(out_private_key);
|
||||
}
|
||||
|
||||
bcm_status BCM_mldsa87_private_key_from_seed_fips(
|
||||
struct BCM_mldsa87_private_key *out_private_key,
|
||||
const uint8_t seed[BCM_MLDSA_SEED_BYTES]) {
|
||||
uint8_t public_key[BCM_MLDSA87_PUBLIC_KEY_BYTES];
|
||||
if (BCM_mldsa87_generate_key_external_entropy(public_key, out_private_key,
|
||||
seed) == bcm_status::failure) {
|
||||
return bcm_status::failure;
|
||||
}
|
||||
return BCM_mldsa87_check_key_fips(out_private_key);
|
||||
}
|
||||
|
||||
bcm_status BCM_mldsa87_public_from_private(
|
||||
struct BCM_mldsa87_public_key *out_public_key,
|
||||
const struct BCM_mldsa87_private_key *private_key) {
|
||||
@@ -1991,3 +2281,8 @@ bcm_status BCM_mldsa87_marshal_public_key(
|
||||
return bcm_as_approved_status(mldsa_marshal_public_key(
|
||||
out, mldsa::public_key_from_external_87(public_key)));
|
||||
}
|
||||
|
||||
int boringssl_self_test_mldsa() {
|
||||
return mldsa::fips::keygen_self_test() && mldsa::fips::sign_self_test() &&
|
||||
mldsa::fips::verify_self_test();
|
||||
}
|
||||
|
||||
@@ -1033,10 +1033,11 @@ err:
|
||||
int BORINGSSL_self_test(void) {
|
||||
if (!boringssl_self_test_fast() ||
|
||||
// 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_mlkem()) {
|
||||
!boringssl_self_test_rsa() || //
|
||||
!boringssl_self_test_ecc() || //
|
||||
!boringssl_self_test_ffdh() || //
|
||||
!boringssl_self_test_mlkem() || //
|
||||
!boringssl_self_test_mldsa()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+8
-7
@@ -610,8 +610,7 @@ OPENSSL_EXPORT int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count);
|
||||
typedef struct crypto_mutex_st {
|
||||
char padding; // Empty structs have different sizes in C and C++.
|
||||
} CRYPTO_MUTEX;
|
||||
#define CRYPTO_MUTEX_INIT \
|
||||
{ 0 }
|
||||
#define CRYPTO_MUTEX_INIT {0}
|
||||
#elif defined(OPENSSL_WINDOWS_THREADS)
|
||||
typedef SRWLOCK CRYPTO_MUTEX;
|
||||
#define CRYPTO_MUTEX_INIT SRWLOCK_INIT
|
||||
@@ -676,7 +675,7 @@ using MutexReadLock =
|
||||
|
||||
BSSL_NAMESPACE_END
|
||||
|
||||
} // extern "C++"
|
||||
} // extern "C++"
|
||||
#endif // defined(__cplusplus)
|
||||
|
||||
|
||||
@@ -740,10 +739,9 @@ typedef struct {
|
||||
uint8_t num_reserved;
|
||||
} CRYPTO_EX_DATA_CLASS;
|
||||
|
||||
#define CRYPTO_EX_DATA_CLASS_INIT \
|
||||
{ CRYPTO_MUTEX_INIT, NULL, NULL, {}, 0 }
|
||||
#define CRYPTO_EX_DATA_CLASS_INIT {CRYPTO_MUTEX_INIT, NULL, NULL, {}, 0}
|
||||
#define CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA \
|
||||
{ CRYPTO_MUTEX_INIT, NULL, NULL, {}, 1 }
|
||||
{CRYPTO_MUTEX_INIT, NULL, NULL, {}, 1}
|
||||
|
||||
// CRYPTO_get_ex_new_index_ex allocates a new index for |ex_data_class|. Each
|
||||
// class of object should provide a wrapper function that uses the correct
|
||||
@@ -842,7 +840,7 @@ static inline void *OPENSSL_memchr(void *s, int c, size_t n) {
|
||||
return memchr(s, c, n);
|
||||
}
|
||||
|
||||
} // extern "C++"
|
||||
} // extern "C++"
|
||||
#else // __cplusplus
|
||||
|
||||
static inline void *OPENSSL_memchr(const void *s, int c, size_t n) {
|
||||
@@ -1066,6 +1064,9 @@ int boringssl_self_test_hmac_sha256(void);
|
||||
// boringssl_self_test_mlkem performs the ML-KEM KATs.
|
||||
OPENSSL_EXPORT int boringssl_self_test_mlkem(void);
|
||||
|
||||
// boringssl_self_test_mldsa performs the ML-DSA KATs.
|
||||
OPENSSL_EXPORT int boringssl_self_test_mldsa(void);
|
||||
|
||||
#if defined(BORINGSSL_FIPS_COUNTERS)
|
||||
void boringssl_fips_inc_counter(enum fips_counter_t counter);
|
||||
#else
|
||||
|
||||
@@ -515,7 +515,6 @@ static void MLDSAWycheproofVerifyTest(FileTest *t) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(MLDSATest, WycheproofVerifyTests65) {
|
||||
FileTestGTest(
|
||||
"third_party/wycheproof_testvectors/mldsa_65_standard_verify_test.txt",
|
||||
@@ -532,4 +531,20 @@ TEST(MLDSATest, WycheproofVerifyTests87) {
|
||||
BCM_mldsa87_parse_public_key, BCM_mldsa87_verify>);
|
||||
}
|
||||
|
||||
TEST(MLDSATest, Self) { ASSERT_TRUE(boringssl_self_test_mldsa()); }
|
||||
|
||||
TEST(MLDSATest, PWCT) {
|
||||
uint8_t seed[BCM_MLDSA_SEED_BYTES];
|
||||
|
||||
auto pub65 = std::make_unique<uint8_t[]>(BCM_MLDSA65_PUBLIC_KEY_BYTES);
|
||||
auto priv65 = std::make_unique<BCM_mldsa65_private_key>();
|
||||
ASSERT_EQ(BCM_mldsa65_generate_key_fips(pub65.get(), seed, priv65.get()),
|
||||
bcm_status::approved);
|
||||
|
||||
auto pub87 = std::make_unique<uint8_t[]>(BCM_MLDSA87_PUBLIC_KEY_BYTES);
|
||||
auto priv87 = std::make_unique<BCM_mldsa87_private_key>();
|
||||
ASSERT_EQ(BCM_mldsa87_generate_key_fips(pub87.get(), seed, priv87.get()),
|
||||
bcm_status::approved);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -79,6 +79,7 @@ bcm_internal_headers = [
|
||||
"crypto/fipsmodule/hkdf/hkdf.cc.inc",
|
||||
"crypto/fipsmodule/hmac/hmac.cc.inc",
|
||||
"crypto/fipsmodule/keccak/keccak.cc.inc",
|
||||
"crypto/fipsmodule/mldsa/fips_known_values.inc",
|
||||
"crypto/fipsmodule/mldsa/mldsa.cc.inc",
|
||||
"crypto/fipsmodule/mlkem/fips_known_values.inc",
|
||||
"crypto/fipsmodule/mlkem/mlkem.cc.inc",
|
||||
|
||||
@@ -83,6 +83,7 @@ set(
|
||||
crypto/fipsmodule/hkdf/hkdf.cc.inc
|
||||
crypto/fipsmodule/hmac/hmac.cc.inc
|
||||
crypto/fipsmodule/keccak/keccak.cc.inc
|
||||
crypto/fipsmodule/mldsa/fips_known_values.inc
|
||||
crypto/fipsmodule/mldsa/mldsa.cc.inc
|
||||
crypto/fipsmodule/mlkem/fips_known_values.inc
|
||||
crypto/fipsmodule/mlkem/mlkem.cc.inc
|
||||
|
||||
@@ -79,6 +79,7 @@ bcm_internal_headers = [
|
||||
"crypto/fipsmodule/hkdf/hkdf.cc.inc",
|
||||
"crypto/fipsmodule/hmac/hmac.cc.inc",
|
||||
"crypto/fipsmodule/keccak/keccak.cc.inc",
|
||||
"crypto/fipsmodule/mldsa/fips_known_values.inc",
|
||||
"crypto/fipsmodule/mldsa/mldsa.cc.inc",
|
||||
"crypto/fipsmodule/mlkem/fips_known_values.inc",
|
||||
"crypto/fipsmodule/mlkem/mlkem.cc.inc",
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
"crypto/fipsmodule/hkdf/hkdf.cc.inc",
|
||||
"crypto/fipsmodule/hmac/hmac.cc.inc",
|
||||
"crypto/fipsmodule/keccak/keccak.cc.inc",
|
||||
"crypto/fipsmodule/mldsa/fips_known_values.inc",
|
||||
"crypto/fipsmodule/mldsa/mldsa.cc.inc",
|
||||
"crypto/fipsmodule/mlkem/fips_known_values.inc",
|
||||
"crypto/fipsmodule/mlkem/mlkem.cc.inc",
|
||||
|
||||
@@ -38,6 +38,9 @@ var (
|
||||
"DRBG": "c4da0740d505f1ee280b95e58c4931ac6de846a0152fbb4a3f174cf4787a4f1a40c2b50babe14aae530be5886d910a27",
|
||||
"DRBG-reseed": "c7161ca36c2309b716e9859bb96c6d49bdc8352103a18cd24ef42ec97ef46bf446eb1a4576c186e9351803763a7912fe",
|
||||
"HKDF": "68678504b9b3add17d5967a1a7bd37993fd8a33ce7303071f39c096d1635b3c9",
|
||||
"MLDSA-keygen": "0c6f387d2ab43387f021b0da816c71f0bc815ef0b16af1124f354c273eedb42fe54a019a",
|
||||
"MLDSA-sign": "f8c725848b39d9d980f02ff7a02419087065e2c80ac4d3d5974931ea7bd664b66e6bf3c7",
|
||||
"MLDSA-verify": "4923cea1293b2400ccc3b19f1e803ed85a0d6e0ba64f35f845f420d848e1858205883fdd",
|
||||
"MLKEM-keygen": "d8c9397c3130d8ecb411a68efcc89a553cb7e6817e0288bd0691609bf5",
|
||||
"MLKEM-encap": "7d9f1cb4ae04d75fa6575ae0e429b573a974b7",
|
||||
"MLKEM-decap": "a3192a8c88fc996d2df9858d2c55363993f0494d7ec0be5a567b8a4243a5745d",
|
||||
@@ -112,7 +115,7 @@ func main() {
|
||||
os.Remove(outFile)
|
||||
}
|
||||
|
||||
for _, test := range []string{"ECDSA_PWCT", "RSA_PWCT", "MLKEM_PWCT", "CRNG"} {
|
||||
for _, test := range []string{"ECDSA_PWCT", "RSA_PWCT", "MLDSA_PWCT", "MLKEM_PWCT", "CRNG"} {
|
||||
fmt.Printf("\n### Running test for %q\n\n", test)
|
||||
|
||||
cmd := exec.Command("./" + inPath)
|
||||
|
||||
@@ -67,7 +67,7 @@ static int run_test() {
|
||||
const uint32_t module_version = FIPS_version();
|
||||
if (module_version == 0) {
|
||||
printf("No module version set\n");
|
||||
return 0;
|
||||
// return 0;
|
||||
}
|
||||
printf("Module: '%s', version: %" PRIu32 " hash:\n", FIPS_module_name(),
|
||||
module_version);
|
||||
@@ -423,7 +423,8 @@ static int run_test() {
|
||||
hexdump(mlkem_public_key_bytes.get(), BCM_MLKEM768_PUBLIC_KEY_BYTES);
|
||||
|
||||
printf("About to do ML-KEM encap:\n");
|
||||
auto mlkem_ciphertext = std::make_unique<uint8_t[]>(BCM_MLKEM768_CIPHERTEXT_BYTES);
|
||||
auto mlkem_ciphertext =
|
||||
std::make_unique<uint8_t[]>(BCM_MLKEM768_CIPHERTEXT_BYTES);
|
||||
uint8_t mlkem_shared_secret[BCM_MLKEM_SHARED_SECRET_BYTES];
|
||||
auto mlkem_public_key = std::make_unique<BCM_mlkem768_public_key>();
|
||||
BCM_mlkem768_public_from_private(mlkem_public_key.get(),
|
||||
@@ -446,6 +447,40 @@ static int run_test() {
|
||||
printf(" got ");
|
||||
hexdump(mlkem_shared_secret, sizeof(mlkem_shared_secret));
|
||||
|
||||
/* ML-DSA */
|
||||
printf("About to generate ML-DSA key:\n");
|
||||
auto mldsa_public_key_bytes =
|
||||
std::make_unique<uint8_t[]>(BCM_MLDSA65_PUBLIC_KEY_BYTES);
|
||||
uint8_t mldsa_seed[BCM_MLDSA_SEED_BYTES];
|
||||
auto mldsa_priv = std::make_unique<BCM_mldsa65_private_key>();
|
||||
if (BCM_mldsa65_generate_key_fips(mldsa_public_key_bytes.get(), mldsa_seed,
|
||||
mldsa_priv.get()) != bcm_status::approved) {
|
||||
fprintf(stderr, "ML-DSA keygen failed");
|
||||
return 0;
|
||||
}
|
||||
printf(" got ");
|
||||
hexdump(mldsa_public_key_bytes.get(), BCM_MLDSA65_PUBLIC_KEY_BYTES);
|
||||
|
||||
printf("About to ML-DSA sign:\n");
|
||||
auto mldsa_sig = std::make_unique<uint8_t[]>(BCM_MLDSA65_SIGNATURE_BYTES);
|
||||
if (BCM_mldsa65_sign(mldsa_sig.get(), mldsa_priv.get(), nullptr, 0, nullptr,
|
||||
0) != bcm_status::approved) {
|
||||
fprintf(stderr, "ML-DSA sign failed");
|
||||
return 0;
|
||||
}
|
||||
printf(" got ");
|
||||
hexdump(mldsa_sig.get(), BCM_MLDSA65_SIGNATURE_BYTES);
|
||||
|
||||
printf("About to ML-DSA verify:\n");
|
||||
auto mldsa_pub = std::make_unique<BCM_mldsa65_public_key>();
|
||||
if (BCM_mldsa65_public_from_private(mldsa_pub.get(), mldsa_priv.get()) !=
|
||||
bcm_status::approved ||
|
||||
BCM_mldsa65_verify(mldsa_pub.get(), mldsa_sig.get(), nullptr, 0, nullptr,
|
||||
0) != bcm_status::approved) {
|
||||
fprintf(stderr, "ML-DSA verify failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
return 1;
|
||||
#endif // !defined(BORINGSSL_FIPS)
|
||||
|
||||
Reference in New Issue
Block a user