Add support for legacy ECDSA private keys to certificate_view.h
NOKEYCHECK
PiperOrigin-RevId: 323862773
Change-Id: If8a9265debe9f3fd2b2c22ea4eaffb01a05c787e
diff --git a/quic/core/crypto/certificate_view.cc b/quic/core/crypto/certificate_view.cc
index af6b54c..fa6b30c 100644
--- a/quic/core/crypto/certificate_view.cc
+++ b/quic/core/crypto/certificate_view.cc
@@ -13,6 +13,7 @@
#include "third_party/boringssl/src/include/openssl/bytestring.h"
#include "third_party/boringssl/src/include/openssl/digest.h"
#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/ec_key.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/nid.h"
#include "third_party/boringssl/src/include/openssl/rsa.h"
@@ -459,6 +460,7 @@
std::unique_ptr<CertificatePrivateKey> CertificatePrivateKey::LoadPemFromStream(
std::istream* input) {
+skip:
PemReadResult result = ReadNextPemMessage(input);
if (result.status != PemReadResult::kOk) {
return nullptr;
@@ -480,6 +482,26 @@
EVP_PKEY_assign_RSA(key->private_key_.get(), rsa.release());
return key;
}
+ // EC keys are sometimes generated with "openssl ecparam -genkey". If the user
+ // forgets -noout, OpenSSL will output a redundant copy of the EC parameters.
+ // Skip those.
+ if (result.type == "EC PARAMETERS") {
+ goto skip;
+ }
+ // Legacy OpenSSL format: RFC 5915 ECPrivateKey message.
+ if (result.type == "EC PRIVATE KEY") {
+ CBS private_key_cbs = StringPieceToCbs(result.contents);
+ bssl::UniquePtr<EC_KEY> ec_key(
+ EC_KEY_parse_private_key(&private_key_cbs, /*group=*/nullptr));
+ if (ec_key == nullptr || CBS_len(&private_key_cbs) != 0) {
+ return nullptr;
+ }
+
+ std::unique_ptr<CertificatePrivateKey> key(new CertificatePrivateKey());
+ key->private_key_.reset(EVP_PKEY_new());
+ EVP_PKEY_assign_EC_KEY(key->private_key_.get(), ec_key.release());
+ return key;
+ }
// Unknown format.
return nullptr;
}
diff --git a/quic/core/crypto/certificate_view_test.cc b/quic/core/crypto/certificate_view_test.cc
index ad51214..e5ad8e9 100644
--- a/quic/core/crypto/certificate_view_test.cc
+++ b/quic/core/crypto/certificate_view_test.cc
@@ -131,6 +131,13 @@
EXPECT_TRUE(legacy_key->MatchesPublicKey(*view));
}
+TEST(CertificateViewTest, PrivateKeyEcdsaPem) {
+ std::stringstream pem_stream(kTestEcPrivateKeyLegacyPem);
+ std::unique_ptr<CertificatePrivateKey> key =
+ CertificatePrivateKey::LoadPemFromStream(&pem_stream);
+ ASSERT_TRUE(key != nullptr);
+}
+
TEST(CertificateViewTest, DerTime) {
EXPECT_THAT(ParseDerTime(CBS_ASN1_GENERALIZEDTIME, "19700101000024Z"),
Optional(QuicWallTime::FromUNIXSeconds(24)));
diff --git a/quic/test_tools/test_certificates.cc b/quic/test_tools/test_certificates.cc
index d179d00..025a816 100644
--- a/quic/test_tools/test_certificates.cc
+++ b/quic/test_tools/test_certificates.cc
@@ -720,5 +720,15 @@
kWildcardCertificatePrivateKeyRaw,
sizeof(kWildcardCertificatePrivateKeyRaw));
+QUIC_CONST_INIT const char kTestEcPrivateKeyLegacyPem[] =
+ R"(-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIMdjXX0hg399DlccZuYFXPKq+dMGduXWmQYClDYJNDGroAoGCCqGSM49
+AwEHoUQDQgAENCuPQTywFI8hbsGo68AeN1KVWmd09buzlu/2CAtsJcNoECUmpVXH
+4dwvWMv6zWn9RJ5EzI72R/5FVcO485s5MQ==
+-----END EC PRIVATE KEY-----)";
+
} // namespace test
} // namespace quic
diff --git a/quic/test_tools/test_certificates.h b/quic/test_tools/test_certificates.h
index e7d3035..f617941 100644
--- a/quic/test_tools/test_certificates.h
+++ b/quic/test_tools/test_certificates.h
@@ -43,6 +43,9 @@
QUIC_CONST_INIT extern const quiche::QuicheStringPiece
kWildcardCertificatePrivateKey;
+// PEM-encoded P-256 private key using legacy OpenSSL encoding.
+QUIC_CONST_INIT extern const char kTestEcPrivateKeyLegacyPem[];
+
} // namespace test
} // namespace quic