Switch libssl to the new SPKI parsing APIs

Bug: 42290364
Change-Id: I91bc1950e5759c5267131fc0bc301104aeca7d7b
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/81654
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/ssl/internal.h b/ssl/internal.h
index 4a442e4..18e2494 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -878,6 +878,12 @@
                                                       size_t max_out,
                                                       Span<const uint8_t> in);
 
+// ssl_parse_peer_subject_public_key_info decodes a SubjectPublicKeyInfo
+// representing the peer TLS key. It returns a newly-allocated |EVP_PKEY| or
+// nullptr on error.
+bssl::UniquePtr<EVP_PKEY> ssl_parse_peer_subject_public_key_info(
+    Span<const uint8_t> spki);
+
 // ssl_pkey_supports_algorithm returns whether |pkey| may be used to sign
 // |sigalg|.
 bool ssl_pkey_supports_algorithm(const SSL *ssl, EVP_PKEY *pkey,
diff --git a/ssl/ssl_cert.cc b/ssl/ssl_cert.cc
index c0d510b..3be7d14 100644
--- a/ssl/ssl_cert.cc
+++ b/ssl/ssl_cert.cc
@@ -262,13 +262,14 @@
 }
 
 UniquePtr<EVP_PKEY> ssl_cert_parse_pubkey(const CBS *in) {
-  CBS buf = *in, tbs_cert;
-  if (!ssl_cert_skip_to_spki(&buf, &tbs_cert)) {
+  CBS buf = *in, tbs_cert, spki;
+  if (!ssl_cert_skip_to_spki(&buf, &tbs_cert) ||
+      !CBS_get_asn1_element(&tbs_cert, &spki, CBS_ASN1_SEQUENCE)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_CANNOT_PARSE_LEAF_CERT);
     return nullptr;
   }
 
-  return UniquePtr<EVP_PKEY>(EVP_parse_public_key(&tbs_cert));
+  return ssl_parse_peer_subject_public_key_info(spki);
 }
 
 bool ssl_compare_public_and_private_key(const EVP_PKEY *pubkey,
diff --git a/ssl/ssl_credential.cc b/ssl/ssl_credential.cc
index 95c1a76..bbbd767 100644
--- a/ssl/ssl_credential.cc
+++ b/ssl/ssl_credential.cc
@@ -428,9 +428,8 @@
     return 0;
   }
 
-  UniquePtr<EVP_PKEY> pubkey(EVP_parse_public_key(&spki));
-  if (pubkey == nullptr || CBS_len(&spki) != 0) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+  UniquePtr<EVP_PKEY> pubkey = ssl_parse_peer_subject_public_key_info(spki);
+  if (pubkey == nullptr) {
     return 0;
   }
 
diff --git a/ssl/ssl_privkey.cc b/ssl/ssl_privkey.cc
index 8e54853..5db3dc6 100644
--- a/ssl/ssl_privkey.cc
+++ b/ssl/ssl_privkey.cc
@@ -109,6 +109,19 @@
   return NULL;
 }
 
+bssl::UniquePtr<EVP_PKEY> ssl_parse_peer_subject_public_key_info(
+    Span<const uint8_t> spki) {
+  // Ideally the set of reachable algorithms would flow from |SSL_CTX| for dead
+  // code elimination, but for now we just specify every algorithm that might be
+  // reachable from libssl.
+  const EVP_PKEY_ALG *const algs[] = {
+      EVP_pkey_rsa(),     EVP_pkey_ec_p256(), EVP_pkey_ec_p384(),
+      EVP_pkey_ec_p521(), EVP_pkey_ed25519(),
+  };
+  return bssl::UniquePtr<EVP_PKEY>(EVP_PKEY_from_subject_public_key_info(
+      spki.data(), spki.size(), algs, std::size(algs)));
+}
+
 bool ssl_pkey_supports_algorithm(const SSL *ssl, EVP_PKEY *pkey,
                                  uint16_t sigalg, bool is_verify) {
   const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg);