Handle nullptr arguments to FIPS key generation functions

FIPS needs these functions to handle nullptr arguments without crashing.

Change-Id: Ic3f2f4d988b80e621a990c28423e3323ea526241
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/77308
Reviewed-by: Bob Beck <bbe@google.com>
Auto-Submit: Adam Langley <agl@google.com>
Commit-Queue: Bob Beck <bbe@google.com>
diff --git a/crypto/fipsmodule/bcm_interface.h b/crypto/fipsmodule/bcm_interface.h
index c22ef77..2f53777 100644
--- a/crypto/fipsmodule/bcm_interface.h
+++ b/crypto/fipsmodule/bcm_interface.h
@@ -713,14 +713,22 @@
 // SLH-DSA-SHA2-128s signature.
 #define BCM_SLHDSA_SHA2_128S_SIGNATURE_BYTES 7856
 
-// SLHDSA_SHA2_128S_generate_key_from_seed generates an SLH-DSA-SHA2-128s key
-// pair from a 48-byte seed and writes the result to |out_public_key| and
+// BCM_slhdsa_sha2_128s_generate_key_from_seed generates an SLH-DSA-SHA2-128s
+// key pair from a 48-byte seed and writes the result to |out_public_key| and
 // |out_secret_key|.
 OPENSSL_EXPORT bcm_infallible BCM_slhdsa_sha2_128s_generate_key_from_seed(
     uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
     uint8_t out_secret_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES],
     const uint8_t seed[3 * BCM_SLHDSA_SHA2_128S_N]);
 
+// BCM_slhdsa_sha2_128s_generate_key_from_seed_fips does the same thing as
+// `BCM_slhdsa_sha2_128s_generate_key_from_seed` but implements the required
+// second check before generating a key by testing for nullptr arguments.
+OPENSSL_EXPORT bcm_status BCM_slhdsa_sha2_128s_generate_key_from_seed_fips(
+    uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
+    uint8_t out_secret_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES],
+    const uint8_t seed[3 * BCM_SLHDSA_SHA2_128S_N]);
+
 // BCM_slhdsa_sha2_128s_sign_internal acts like |SLHDSA_SHA2_128S_sign| but
 // accepts an explicit entropy input, which can be PK.seed (bytes 32..48 of
 // the private key) to generate deterministic signatures. It also takes the
@@ -748,6 +756,10 @@
     uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
     uint8_t out_private_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES]);
 
+OPENSSL_EXPORT bcm_status BCM_slhdsa_sha2_128s_generate_key_fips(
+    uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
+    uint8_t out_private_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES]);
+
 OPENSSL_EXPORT bcm_infallible BCM_slhdsa_sha2_128s_public_from_private(
     uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
     const uint8_t private_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES]);
diff --git a/crypto/fipsmodule/mldsa/mldsa.cc.inc b/crypto/fipsmodule/mldsa/mldsa.cc.inc
index 52f5836..e89d87c 100644
--- a/crypto/fipsmodule/mldsa/mldsa.cc.inc
+++ b/crypto/fipsmodule/mldsa/mldsa.cc.inc
@@ -2032,6 +2032,9 @@
     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 (out_encoded_public_key == nullptr || out_private_key == nullptr) {
+    return bcm_status::failure;
+  }
   if (BCM_mldsa65_generate_key(out_encoded_public_key, out_seed,
                                out_private_key) == bcm_status::failure) {
     return bcm_status::failure;
@@ -2043,6 +2046,9 @@
     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 (out_encoded_public_key == nullptr || out_private_key == nullptr) {
+    return bcm_status::failure;
+  }
   if (BCM_mldsa65_generate_key_external_entropy(out_encoded_public_key,
                                                 out_private_key, entropy) ==
       bcm_status::failure) {
@@ -2188,6 +2194,9 @@
     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 (out_encoded_public_key == nullptr || out_private_key == nullptr) {
+    return bcm_status::failure;
+  }
   if (BCM_mldsa87_generate_key(out_encoded_public_key, out_seed,
                                out_private_key) == bcm_status::failure) {
     return bcm_status::failure;
@@ -2199,6 +2208,9 @@
     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 (out_encoded_public_key == nullptr || out_private_key == nullptr) {
+    return bcm_status::failure;
+  }
   if (BCM_mldsa87_generate_key_external_entropy(out_encoded_public_key,
                                                 out_private_key, entropy) ==
       bcm_status::failure) {
diff --git a/crypto/fipsmodule/mlkem/mlkem.cc.inc b/crypto/fipsmodule/mlkem/mlkem.cc.inc
index 265b0ca..c3773cc 100644
--- a/crypto/fipsmodule/mlkem/mlkem.cc.inc
+++ b/crypto/fipsmodule/mlkem/mlkem.cc.inc
@@ -1102,6 +1102,9 @@
     uint8_t out_encoded_public_key[BCM_MLKEM768_PUBLIC_KEY_BYTES],
     uint8_t optional_out_seed[BCM_MLKEM_SEED_BYTES],
     struct BCM_mlkem768_private_key *out_private_key) {
+  if (out_encoded_public_key == nullptr || out_private_key == nullptr) {
+    return bcm_status::failure;
+  }
   BCM_mlkem768_generate_key(out_encoded_public_key, optional_out_seed,
                             out_private_key);
   return BCM_mlkem768_check_fips(out_private_key);
@@ -1163,6 +1166,9 @@
     uint8_t out_encoded_public_key[BCM_MLKEM1024_PUBLIC_KEY_BYTES],
     uint8_t optional_out_seed[BCM_MLKEM_SEED_BYTES],
     struct BCM_mlkem1024_private_key *out_private_key) {
+  if (out_encoded_public_key == nullptr || out_private_key == nullptr) {
+    return bcm_status::failure;
+  }
   BCM_mlkem1024_generate_key(out_encoded_public_key, optional_out_seed,
                              out_private_key);
   return BCM_mlkem1024_check_fips(out_private_key);
diff --git a/crypto/fipsmodule/slhdsa/slhdsa.cc.inc b/crypto/fipsmodule/slhdsa/slhdsa.cc.inc
index e8f09b9..b3e5644 100644
--- a/crypto/fipsmodule/slhdsa/slhdsa.cc.inc
+++ b/crypto/fipsmodule/slhdsa/slhdsa.cc.inc
@@ -86,7 +86,7 @@
     abort();
   }
 
-  return bcm_infallible::approved;
+  return bcm_infallible::not_approved;
 }
 
 // Note that this overreads by a byte. This is fine in the context that it's
@@ -294,6 +294,18 @@
                                              seed);
 }
 
+bcm_status BCM_slhdsa_sha2_128s_generate_key_from_seed_fips(
+    uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
+    uint8_t out_secret_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES],
+    const uint8_t seed[3 * BCM_SLHDSA_SHA2_128S_N]) {
+  if (out_public_key == nullptr || out_secret_key == nullptr) {
+    return bcm_status::failure;
+  }
+  BCM_slhdsa_sha2_128s_generate_key_from_seed(out_public_key, out_secret_key,
+                                              seed);
+  return bcm_status::approved;
+}
+
 bcm_infallible BCM_slhdsa_sha2_128s_generate_key(
     uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
     uint8_t out_private_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES]) {
@@ -303,6 +315,16 @@
                                                      out_private_key, seed);
 }
 
+bcm_status BCM_slhdsa_sha2_128s_generate_key_fips(
+    uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
+    uint8_t out_private_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES]) {
+  if (out_public_key == nullptr || out_private_key == nullptr) {
+    return bcm_status::failure;
+  }
+  BCM_slhdsa_sha2_128s_generate_key(out_public_key, out_private_key);
+  return bcm_status::approved;
+}
+
 bcm_infallible BCM_slhdsa_sha2_128s_public_from_private(
     uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
     const uint8_t private_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES]) {
diff --git a/crypto/mldsa/mldsa_test.cc b/crypto/mldsa/mldsa_test.cc
index cc1d75c..112b444 100644
--- a/crypto/mldsa/mldsa_test.cc
+++ b/crypto/mldsa/mldsa_test.cc
@@ -547,4 +547,18 @@
             bcm_status::approved);
 }
 
+TEST(MLDSATest, NullptrArgumentsToCreate) {
+  // For FIPS reasons, this should fail rather than crash.
+  ASSERT_EQ(BCM_mldsa65_generate_key_fips(nullptr, nullptr, nullptr),
+            bcm_status::failure);
+  ASSERT_EQ(BCM_mldsa87_generate_key_fips(nullptr, nullptr, nullptr),
+            bcm_status::failure);
+  ASSERT_EQ(
+      BCM_mldsa65_generate_key_external_entropy_fips(nullptr, nullptr, nullptr),
+      bcm_status::failure);
+  ASSERT_EQ(
+      BCM_mldsa87_generate_key_external_entropy_fips(nullptr, nullptr, nullptr),
+      bcm_status::failure);
+}
+
 }  // namespace
diff --git a/crypto/mlkem/mlkem_test.cc b/crypto/mlkem/mlkem_test.cc
index 213991a..5b4d686 100644
--- a/crypto/mlkem/mlkem_test.cc
+++ b/crypto/mlkem/mlkem_test.cc
@@ -544,4 +544,12 @@
       bcm_status::approved);
 }
 
+TEST(MLKEMTest, NullptrArgumentsToCreate) {
+  // For FIPS reasons, this should fail rather than crash.
+  ASSERT_EQ(BCM_mlkem768_generate_key_fips(nullptr, nullptr, nullptr),
+            bcm_status::failure);
+  ASSERT_EQ(BCM_mlkem1024_generate_key_fips(nullptr, nullptr, nullptr),
+            bcm_status::failure);
+}
+
 }  // namespace
diff --git a/crypto/slhdsa/slhdsa_test.cc b/crypto/slhdsa/slhdsa_test.cc
index d6a7011..c00a2f9 100644
--- a/crypto/slhdsa/slhdsa_test.cc
+++ b/crypto/slhdsa/slhdsa_test.cc
@@ -222,4 +222,13 @@
 
 TEST(SLHDSATest, Self) { boringssl_self_test_slhdsa(); }
 
+TEST(SLHDSATest, NullptrArgumentsToCreate) {
+  // For FIPS reasons, this should fail rather than crash.
+  ASSERT_EQ(BCM_slhdsa_sha2_128s_generate_key_fips(nullptr, nullptr),
+            bcm_status::failure);
+  ASSERT_EQ(BCM_slhdsa_sha2_128s_generate_key_from_seed_fips(nullptr, nullptr,
+                                                             nullptr),
+            bcm_status::failure);
+}
+
 }  // namespace