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