EVP_PKEY_copy_parameters: Allocate new receiving key if not present For DSA and DH key types, allocate a new receiving key to copy the parameters into, if the passed EVP_PKEY doesn't have one (e.g. it starts empty). This matches code we already had for EC keys. Change-Id: I433ee847f72d5db59fd644019e34f7206a6a6964 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/93687 Auto-Submit: Lily Chen <chlily@google.com> Commit-Queue: Lily Chen <chlily@google.com> Presubmit-BoringSSL-Verified: boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com <boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/evp/evp_extra_test.cc b/crypto/evp/evp_extra_test.cc index d78c82e..27a918b 100644 --- a/crypto/evp/evp_extra_test.cc +++ b/crypto/evp/evp_extra_test.cc
@@ -1255,6 +1255,34 @@ EXPECT_EQ(EVP_PKEY_RSA, EVP_PKEY_id(rsa.get())); } +// Test copying parameters into an empty key. This should result in allocating a +// key for the receiving key, which did not already have one. +TEST(EVPExtraTest, CopyParamsIntoEmptyKey) { + UniquePtr<EVP_PKEY> dsa = ParsePrivateKey(EVP_PKEY_DSA, kExampleDSAKeyDER); + UniquePtr<EVP_PKEY> ec = ParsePrivateKey(EVP_PKEY_EC, kExampleECKeyDER); + + for (const EVP_PKEY* from_pkey : {dsa.get(), ec.get()}) { + SCOPED_TRACE(EVP_PKEY_id(from_pkey)); + ASSERT_TRUE(from_pkey); + ASSERT_FALSE(EVP_PKEY_missing_parameters(from_pkey)); + + UniquePtr<EVP_PKEY> to_pkey(EVP_PKEY_new()); + ASSERT_TRUE(to_pkey); + ASSERT_EQ(EVP_PKEY_NONE, EVP_PKEY_id(to_pkey.get())); + // EVP_PKEY_NONE has no parameters, so the params are not missing. + ASSERT_FALSE(EVP_PKEY_missing_parameters(to_pkey.get())); + ASSERT_FALSE(EVP_PKEY_has_private(to_pkey.get())); + ASSERT_FALSE(EVP_PKEY_has_public(to_pkey.get())); + + EXPECT_TRUE(EVP_PKEY_copy_parameters(to_pkey.get(), from_pkey)); + EXPECT_EQ(EVP_PKEY_id(to_pkey.get()), EVP_PKEY_id(from_pkey)); + EXPECT_FALSE(EVP_PKEY_missing_parameters(to_pkey.get())); + // Only params are copied, not keys. + EXPECT_FALSE(EVP_PKEY_has_private(to_pkey.get())); + EXPECT_FALSE(EVP_PKEY_has_public(to_pkey.get())); + } +} + TEST(EVPExtraTest, CompareDifferentTypes) { UniquePtr<EVP_PKEY> rsa = ParsePrivateKey(EVP_PKEY_RSA, kExampleRSAKeyDER); UniquePtr<EVP_PKEY> dsa = ParsePrivateKey(EVP_PKEY_DSA, kExampleDSAKeyDER);
diff --git a/crypto/evp/p_dh.cc b/crypto/evp/p_dh.cc index ab62dc7..26c4770 100644 --- a/crypto/evp/p_dh.cc +++ b/crypto/evp/p_dh.cc
@@ -57,6 +57,12 @@ OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS); return 0; } + if (to->pkey == nullptr) { + to->pkey = DH_new(); + if (to->pkey == nullptr) { + return 0; + } + } const DH *dh = reinterpret_cast<DH *>(from->pkey); const BIGNUM *q_old = DH_get0_q(dh);
diff --git a/crypto/evp/p_dsa.cc b/crypto/evp/p_dsa.cc index 2ea241f..6b6201c 100644 --- a/crypto/evp/p_dsa.cc +++ b/crypto/evp/p_dsa.cc
@@ -177,6 +177,12 @@ } static int dsa_copy_parameters(EvpPkey *to, const EvpPkey *from) { + if (to->pkey == nullptr) { + to->pkey = DSA_new(); + if (to->pkey == nullptr) { + return 0; + } + } DSAImpl *to_dsa = reinterpret_cast<DSAImpl *>(to->pkey); const DSAImpl *from_dsa = reinterpret_cast<const DSAImpl *>(from->pkey); if (!dup_bn_into(&to_dsa->p, from_dsa->p.get()) ||