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(),