Add ML-KEM and ML-DSA to EVP_PKEY_from_raw_public_key

For simplicity, just implement those APIs with the default set and then
add ML-KEM to it. It's a little unfortunate that a user of
EVP_PKEY_from_raw_public_key now pulls in RSA, but we have alg-based
APIs available for folks who want dead code elimination, and that's
probably good enough.

Bug: 497718229
Change-Id: I635c85d8ac695942a4d9219a2f39606bd7ca7e0f
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/92367
Auto-Submit: David Benjamin <davidben@google.com>
Reviewed-by: Lily Chen <chlily@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/evp/evp.cc b/crypto/evp/evp.cc
index 2936e68..7581c39 100644
--- a/crypto/evp/evp.cc
+++ b/crypto/evp/evp.cc
@@ -264,32 +264,24 @@
 
 EVP_PKEY *EVP_PKEY_new_raw_private_key(int type, ENGINE *unused,
                                        const uint8_t *in, size_t len) {
-  // To avoid pulling in all key types, look for specifically the key types that
-  // support |set_priv_raw|.
-  switch (type) {
-    case EVP_PKEY_X25519:
-      return EVP_PKEY_from_raw_private_key(EVP_pkey_x25519(), in, len);
-    case EVP_PKEY_ED25519:
-      return EVP_PKEY_from_raw_private_key(EVP_pkey_ed25519(), in, len);
-    default:
-      OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
-      return nullptr;
+  for (const EVP_PKEY_ALG *alg : GetDefaultEVPAlgorithms()) {
+    if (alg->method && alg->method->pkey_id == type) {
+      return EVP_PKEY_from_raw_private_key(alg, in, len);
+    }
   }
+  OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
+  return nullptr;
 }
 
 EVP_PKEY *EVP_PKEY_new_raw_public_key(int type, ENGINE *unused,
                                       const uint8_t *in, size_t len) {
-  // To avoid pulling in all key types, look for specifically the key types that
-  // support |set_pub_raw|.
-  switch (type) {
-    case EVP_PKEY_X25519:
-      return EVP_PKEY_from_raw_public_key(EVP_pkey_x25519(), in, len);
-    case EVP_PKEY_ED25519:
-      return EVP_PKEY_from_raw_public_key(EVP_pkey_ed25519(), in, len);
-    default:
-      OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
-      return nullptr;
+  for (const EVP_PKEY_ALG *alg : GetDefaultEVPAlgorithms()) {
+    if (alg->method && alg->method->pkey_id == type) {
+      return EVP_PKEY_from_raw_public_key(alg, in, len);
+    }
   }
+  OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
+  return nullptr;
 }
 
 int EVP_PKEY_get_raw_private_key(const EVP_PKEY *pkey, uint8_t *out,
diff --git a/crypto/evp/evp_extra_test.cc b/crypto/evp/evp_extra_test.cc
index afb2cdc..dcd3f95 100644
--- a/crypto/evp/evp_extra_test.cc
+++ b/crypto/evp/evp_extra_test.cc
@@ -1509,5 +1509,54 @@
   }
 }
 
+// Test that APIs using the non-alg-based APIs also work when expected.
+TEST(EVPExtraTest, NewRawKey) {
+  struct {
+    int type;
+    const EVP_PKEY_ALG *alg;
+    bool supports_raw_private_key;
+  } kTests[] = {
+      {EVP_PKEY_X25519, EVP_pkey_x25519(), true},
+      {EVP_PKEY_ED25519, EVP_pkey_ed25519(), true},
+      // ML-KEM and ML-DSA do not support raw private keys, only raw public
+      // keys. OpenSSL interprets "raw private key" as the less efficient
+      // semi-expanded representation, instead of seeds.
+      {EVP_PKEY_ML_DSA_44, EVP_pkey_ml_dsa_44(), false},
+      {EVP_PKEY_ML_DSA_65, EVP_pkey_ml_dsa_65(), false},
+      {EVP_PKEY_ML_DSA_87, EVP_pkey_ml_dsa_87(), false},
+      {EVP_PKEY_ML_KEM_768, EVP_pkey_ml_kem_768(), false},
+      {EVP_PKEY_ML_KEM_1024, EVP_pkey_ml_kem_1024(), false},
+  };
+  for (const auto &t : kTests) {
+    SCOPED_TRACE(t.type);
+    UniquePtr<EVP_PKEY> pkey(EVP_PKEY_generate_from_alg(t.alg));
+    ASSERT_TRUE(pkey);
+
+    {
+      size_t len;
+      ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), nullptr, &len));
+      std::vector<uint8_t> raw(len);
+      ASSERT_TRUE(EVP_PKEY_get_raw_public_key(pkey.get(), raw.data(), &len));
+      raw.resize(len);
+      UniquePtr<EVP_PKEY> pkey2(
+          EVP_PKEY_new_raw_public_key(t.type, nullptr, raw.data(), raw.size()));
+      ASSERT_TRUE(pkey2);
+      EXPECT_EQ(EVP_PKEY_eq(pkey.get(), pkey2.get()), 1);
+    }
+
+    if (t.supports_raw_private_key) {
+      size_t len;
+      ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), nullptr, &len));
+      std::vector<uint8_t> raw(len);
+      ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey.get(), raw.data(), &len));
+      raw.resize(len);
+      UniquePtr<EVP_PKEY> pkey2(EVP_PKEY_new_raw_private_key(
+          t.type, nullptr, raw.data(), raw.size()));
+      ASSERT_TRUE(pkey2);
+      EXPECT_EQ(EVP_PKEY_eq(pkey.get(), pkey2.get()), 1);
+    }
+  }
+}
+
 }  // namespace
 BSSL_NAMESPACE_END
diff --git a/crypto/evp/evp_test.cc b/crypto/evp/evp_test.cc
index 2d4cc0b..684d1a9 100644
--- a/crypto/evp/evp_test.cc
+++ b/crypto/evp/evp_test.cc
@@ -126,10 +126,10 @@
      {EVP_pkey_ml_dsa_87(), /*kem=*/nullptr, EVP_PKEY_ML_DSA_87, true}},
 
     {"ML-KEM-768",
-     {EVP_pkey_ml_kem_768(), EVP_kem_ml_kem_768(), EVP_PKEY_ML_KEM_768, false}},
+     {EVP_pkey_ml_kem_768(), EVP_kem_ml_kem_768(), EVP_PKEY_ML_KEM_768, true}},
     {"ML-KEM-1024",
      {EVP_pkey_ml_kem_1024(), EVP_kem_ml_kem_1024(), EVP_PKEY_ML_KEM_1024,
-      false}},
+      true}},
 };
 
 using KeyMap = std::map<std::string, bssl::UniquePtr<EVP_PKEY>>;
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
index 4e451a2..029c375 100644
--- a/crypto/evp/internal.h
+++ b/crypto/evp/internal.h
@@ -347,6 +347,8 @@
       EVP_pkey_ml_dsa_44(),
       EVP_pkey_ml_dsa_65(),
       EVP_pkey_ml_dsa_87(),
+      EVP_pkey_ml_kem_768(),
+      EVP_pkey_ml_kem_1024(),
       // TODO(crbug.com/438761503): Remove DSA from this set, after callers that
       // need DSA pass in |EVP_pkey_dsa| explicitly.
       EVP_pkey_dsa(),