Change ProofVerifier::VerifyCertChain to support not copying certs

PiperOrigin-RevId: 924927539
diff --git a/build/source_list.bzl b/build/source_list.bzl
index 601aea1..822ed4d 100644
--- a/build/source_list.bzl
+++ b/build/source_list.bzl
@@ -568,6 +568,7 @@
     "quic/core/crypto/p256_key_exchange.cc",
     "quic/core/crypto/proof_source.cc",
     "quic/core/crypto/proof_source_x509.cc",
+    "quic/core/crypto/proof_verifier.cc",
     "quic/core/crypto/quic_client_session_cache.cc",
     "quic/core/crypto/quic_compressed_certs_cache.cc",
     "quic/core/crypto/quic_crypter.cc",
diff --git a/build/source_list.gni b/build/source_list.gni
index 1182613..c5e5f30 100644
--- a/build/source_list.gni
+++ b/build/source_list.gni
@@ -568,6 +568,7 @@
     "src/quiche/quic/core/crypto/p256_key_exchange.cc",
     "src/quiche/quic/core/crypto/proof_source.cc",
     "src/quiche/quic/core/crypto/proof_source_x509.cc",
+    "src/quiche/quic/core/crypto/proof_verifier.cc",
     "src/quiche/quic/core/crypto/quic_client_session_cache.cc",
     "src/quiche/quic/core/crypto/quic_compressed_certs_cache.cc",
     "src/quiche/quic/core/crypto/quic_crypter.cc",
diff --git a/build/source_list.json b/build/source_list.json
index c686b3b..bc6cb56 100644
--- a/build/source_list.json
+++ b/build/source_list.json
@@ -567,6 +567,7 @@
     "quiche/quic/core/crypto/p256_key_exchange.cc",
     "quiche/quic/core/crypto/proof_source.cc",
     "quiche/quic/core/crypto/proof_source_x509.cc",
+    "quiche/quic/core/crypto/proof_verifier.cc",
     "quiche/quic/core/crypto/quic_client_session_cache.cc",
     "quiche/quic/core/crypto/quic_compressed_certs_cache.cc",
     "quiche/quic/core/crypto/quic_crypter.cc",
diff --git a/quiche/quic/core/crypto/proof_verifier.cc b/quiche/quic/core/crypto/proof_verifier.cc
new file mode 100644
index 0000000..bf78a4b
--- /dev/null
+++ b/quiche/quic/core/crypto/proof_verifier.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "quiche/quic/core/crypto/proof_verifier.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "quiche/quic/core/quic_types.h"
+#include "quiche/common/platform/api/quiche_logging.h"
+
+namespace quic {
+
+QuicAsyncStatus ProofVerifier::VerifyCertChain(
+    const std::string& hostname, uint16_t port,
+    const std::vector<absl::string_view>& certs,
+    const std::string& ocsp_response, const std::string& cert_sct,
+    const ProofVerifyContext* context, std::string* error_details,
+    std::unique_ptr<ProofVerifyDetails>* details, uint8_t* out_alert,
+    std::unique_ptr<ProofVerifierCallback> callback) {
+  // To avoid needing an atomic migration of all quiche consumers to use the new
+  // VerifyCertChain function definition, this shim is provided so that old
+  // ProofVerifier implementations continue to work.
+  //
+  // TODO(b/517611362): Remove this once all ProofVerifier implementations
+  // have stopped implementing the old VerifyCertChain.
+  std::vector<std::string> certs_str;
+  certs_str.reserve(certs.size());
+  for (absl::string_view cert : certs) {
+    certs_str.push_back(std::string(cert));
+  }
+  return VerifyCertChain(hostname, port, certs_str, ocsp_response, cert_sct,
+                         context, error_details, details, out_alert,
+                         std::move(callback));
+}
+
+QuicAsyncStatus ProofVerifier::VerifyCertChain(
+    const std::string&, uint16_t, const std::vector<std::string>&,
+    const std::string&, const std::string&, const ProofVerifyContext*,
+    std::string*, std::unique_ptr<ProofVerifyDetails>*, uint8_t*,
+    std::unique_ptr<ProofVerifierCallback>) {
+  // This function exists only for ProofVerifiers that don't implement the new
+  // VerifyCertChain (that takes a vector of absl::string_views for the certs).
+  // A ProofVerifier needs to implement one of the VerifyCertChain functions
+  // (and it should implement the other one). If it implements neither, it will
+  // end up here.
+  QUICHE_NOTREACHED();
+  return QUIC_FAILURE;
+}
+
+}  // namespace quic
diff --git a/quiche/quic/core/crypto/proof_verifier.h b/quiche/quic/core/crypto/proof_verifier.h
index fe4a808..15031e5 100644
--- a/quiche/quic/core/crypto/proof_verifier.h
+++ b/quiche/quic/core/crypto/proof_verifier.h
@@ -101,10 +101,23 @@
   // In this case, the ProofVerifier will take ownership of |callback|.
   virtual QuicAsyncStatus VerifyCertChain(
       const std::string& hostname, uint16_t port,
+      const std::vector<absl::string_view>& certs,
+      const std::string& ocsp_response, const std::string& cert_sct,
+      const ProofVerifyContext* context, std::string* error_details,
+      std::unique_ptr<ProofVerifyDetails>* details, uint8_t* out_alert,
+      std::unique_ptr<ProofVerifierCallback> callback);
+
+  // Deprecated: Same as VerifyCertChain above, but |certs| contains
+  // std::strings instead of absl::string_views.
+  //
+  // TODO(b/517611362): Remove this once all ProofVerifier implementations
+  // have migrated to the new VerifyCertChain.
+  virtual QuicAsyncStatus VerifyCertChain(
+      const std::string& hostname, uint16_t port,
       const std::vector<std::string>& certs, const std::string& ocsp_response,
       const std::string& cert_sct, const ProofVerifyContext* context,
       std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details,
-      uint8_t* out_alert, std::unique_ptr<ProofVerifierCallback> callback) = 0;
+      uint8_t* out_alert, std::unique_ptr<ProofVerifierCallback> callback);
 
   // Returns a ProofVerifyContext instance which can be use for subsequent
   // verifications. Applications may chose create a different context and
diff --git a/quiche/quic/core/tls_client_handshaker.cc b/quiche/quic/core/tls_client_handshaker.cc
index 298ffb0..a9829df 100644
--- a/quiche/quic/core/tls_client_handshaker.cc
+++ b/quiche/quic/core/tls_client_handshaker.cc
@@ -556,7 +556,7 @@
 }
 
 QuicAsyncStatus TlsClientHandshaker::VerifyCertChain(
-    const std::vector<std::string>& certs, std::string* error_details,
+    const std::vector<absl::string_view>& certs, std::string* error_details,
     std::unique_ptr<ProofVerifyDetails>* details, uint8_t* out_alert,
     std::unique_ptr<ProofVerifierCallback> callback) {
   matched_trust_anchor_id_ = SSL_peer_matched_trust_anchor(ssl());
diff --git a/quiche/quic/core/tls_client_handshaker.h b/quiche/quic/core/tls_client_handshaker.h
index 522bf60..6322ac6 100644
--- a/quiche/quic/core/tls_client_handshaker.h
+++ b/quiche/quic/core/tls_client_handshaker.h
@@ -106,7 +106,7 @@
   void ProcessPostHandshakeMessage() override;
   bool ShouldCloseConnectionOnUnexpectedError(int ssl_error) override;
   QuicAsyncStatus VerifyCertChain(
-      const std::vector<std::string>& certs, std::string* error_details,
+      const std::vector<absl::string_view>& certs, std::string* error_details,
       std::unique_ptr<ProofVerifyDetails>* details, uint8_t* out_alert,
       std::unique_ptr<ProofVerifierCallback> callback) override;
   void OnProofVerifyDetailsAvailable(
diff --git a/quiche/quic/core/tls_client_handshaker_test.cc b/quiche/quic/core/tls_client_handshaker_test.cc
index 6d5c114..d9bede8 100644
--- a/quiche/quic/core/tls_client_handshaker_test.cc
+++ b/quiche/quic/core/tls_client_handshaker_test.cc
@@ -80,10 +80,10 @@
 
   QuicAsyncStatus VerifyCertChain(
       const std::string& hostname, const uint16_t port,
-      const std::vector<std::string>& certs, const std::string& ocsp_response,
-      const std::string& cert_sct, const ProofVerifyContext* context,
-      std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details,
-      uint8_t* out_alert,
+      const std::vector<absl::string_view>& certs,
+      const std::string& ocsp_response, const std::string& cert_sct,
+      const ProofVerifyContext* context, std::string* error_details,
+      std::unique_ptr<ProofVerifyDetails>* details, uint8_t* out_alert,
       std::unique_ptr<ProofVerifierCallback> callback) override {
     if (!active_) {
       return verifier_->VerifyCertChain(
@@ -125,7 +125,7 @@
   class VerifyChainPendingOp {
    public:
     VerifyChainPendingOp(const std::string& hostname, const uint16_t port,
-                         const std::vector<std::string>& certs,
+                         const std::vector<absl::string_view>& certs,
                          const std::string& ocsp_response,
                          const std::string& cert_sct,
                          const ProofVerifyContext* context,
@@ -162,7 +162,7 @@
    private:
     std::string hostname_;
     const uint16_t port_;
-    std::vector<std::string> certs_;
+    std::vector<absl::string_view> certs_;
     std::string ocsp_response_;
     std::string cert_sct_;
     const ProofVerifyContext* context_;
diff --git a/quiche/quic/core/tls_handshaker.cc b/quiche/quic/core/tls_handshaker.cc
index 9eca933..228e9dd 100644
--- a/quiche/quic/core/tls_handshaker.cc
+++ b/quiche/quic/core/tls_handshaker.cc
@@ -258,12 +258,11 @@
     *out_alert = SSL_AD_INTERNAL_ERROR;
     return ssl_verify_invalid;
   }
-  // TODO(nharper): Pass the CRYPTO_BUFFERs into the QUIC stack to avoid copies.
-  std::vector<std::string> certs;
+  std::vector<absl::string_view> certs;
   for (CRYPTO_BUFFER* cert : cert_chain) {
-    certs.push_back(
-        std::string(reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert)),
-                    CRYPTO_BUFFER_len(cert)));
+    certs.push_back(absl::string_view(
+        reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert)),
+        CRYPTO_BUFFER_len(cert)));
   }
   QUIC_DVLOG(1) << "VerifyCert: peer cert_chain length: " << certs.size();
 
diff --git a/quiche/quic/core/tls_handshaker.h b/quiche/quic/core/tls_handshaker.h
index ac7c6c2..cc2ddae 100644
--- a/quiche/quic/core/tls_handshaker.h
+++ b/quiche/quic/core/tls_handshaker.h
@@ -112,7 +112,7 @@
   // certificate_unknown. Implementations of VerifyCertChain may retain the
   // |out_alert| pointer while performing an async operation.
   virtual QuicAsyncStatus VerifyCertChain(
-      const std::vector<std::string>& certs, std::string* error_details,
+      const std::vector<absl::string_view>& certs, std::string* error_details,
       std::unique_ptr<ProofVerifyDetails>* details, uint8_t* out_alert,
       std::unique_ptr<ProofVerifierCallback> callback) = 0;
   // Called when certificate verification is completed.
diff --git a/quiche/quic/core/tls_server_handshaker.cc b/quiche/quic/core/tls_server_handshaker.cc
index 065edbe..df6adde 100644
--- a/quiche/quic/core/tls_server_handshaker.cc
+++ b/quiche/quic/core/tls_server_handshaker.cc
@@ -683,7 +683,7 @@
 // proof verifier is not set, the method will assume the certificate chain is
 // valid and return QUIC_SUCCESS.
 QuicAsyncStatus TlsServerHandshaker::VerifyCertChain(
-    const std::vector<std::string>& certs, std::string* error_details,
+    const std::vector<absl::string_view>& certs, std::string* error_details,
     std::unique_ptr<ProofVerifyDetails>* details, uint8_t* out_alert,
     std::unique_ptr<ProofVerifierCallback> callback) {
   if (proof_verifier_ == nullptr) {
diff --git a/quiche/quic/core/tls_server_handshaker.h b/quiche/quic/core/tls_server_handshaker.h
index 01ff093..f3bf04d 100644
--- a/quiche/quic/core/tls_server_handshaker.h
+++ b/quiche/quic/core/tls_server_handshaker.h
@@ -168,7 +168,7 @@
   void FinishHandshake() override;
   void ProcessPostHandshakeMessage() override {}
   QuicAsyncStatus VerifyCertChain(
-      const std::vector<std::string>& certs, std::string* error_details,
+      const std::vector<absl::string_view>& certs, std::string* error_details,
       std::unique_ptr<ProofVerifyDetails>* details, uint8_t* out_alert,
       std::unique_ptr<ProofVerifierCallback> callback) override;
   void OnProofVerifyDetailsAvailable(
diff --git a/quiche/quic/core/tls_server_handshaker_test.cc b/quiche/quic/core/tls_server_handshaker_test.cc
index 3490a65..bbc5623 100644
--- a/quiche/quic/core/tls_server_handshaker_test.cc
+++ b/quiche/quic/core/tls_server_handshaker_test.cc
@@ -112,7 +112,7 @@
 
   MOCK_METHOD(QuicAsyncStatus, VerifyCertChain,
               (const std::string& hostname, uint16_t port,
-               const std::vector<std::string>& certs,
+               const std::vector<absl::string_view>& certs,
                const std::string& ocsp_response, const std::string& cert_sct,
                const ProofVerifyContext* context, std::string* error_details,
                std::unique_ptr<ProofVerifyDetails>* details, uint8_t* out_alert,
@@ -189,7 +189,7 @@
 
  protected:
   QuicAsyncStatus VerifyCertChain(
-      const std::vector<std::string>& certs, std::string* error_details,
+      const std::vector<absl::string_view>& certs, std::string* error_details,
       std::unique_ptr<ProofVerifyDetails>* details, uint8_t* out_alert,
       std::unique_ptr<ProofVerifierCallback> callback) override {
     received_client_cert_ = true;
diff --git a/quiche/quic/masque/masque_connection_pool.cc b/quiche/quic/masque/masque_connection_pool.cc
index 7641503..9449966 100644
--- a/quiche/quic/masque/masque_connection_pool.cc
+++ b/quiche/quic/masque/masque_connection_pool.cc
@@ -645,11 +645,11 @@
     *out_alert = SSL_AD_INTERNAL_ERROR;
     return ssl_verify_invalid;
   }
-  std::vector<std::string> certs;
+  std::vector<absl::string_view> certs;
   for (CRYPTO_BUFFER* cert : cert_chain) {
-    certs.push_back(
-        std::string(reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert)),
-                    CRYPTO_BUFFER_len(cert)));
+    certs.push_back(absl::string_view(
+        reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert)),
+        CRYPTO_BUFFER_len(cert)));
   }
   const uint8_t* ocsp_response_raw;
   size_t ocsp_response_len;
diff --git a/quiche/quic/masque/masque_tcp_client_bin.cc b/quiche/quic/masque/masque_tcp_client_bin.cc
index 828d442..dde3fe1 100644
--- a/quiche/quic/masque/masque_tcp_client_bin.cc
+++ b/quiche/quic/masque/masque_tcp_client_bin.cc
@@ -169,11 +169,11 @@
       *out_alert = SSL_AD_INTERNAL_ERROR;
       return ssl_verify_invalid;
     }
-    std::vector<std::string> certs;
+    std::vector<absl::string_view> certs;
     for (CRYPTO_BUFFER* cert : cert_chain) {
-      certs.push_back(
-          std::string(reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert)),
-                      CRYPTO_BUFFER_len(cert)));
+      certs.push_back(absl::string_view(
+          reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert)),
+          CRYPTO_BUFFER_len(cert)));
     }
     const uint8_t* ocsp_response_raw;
     size_t ocsp_response_len;