For mTLS, change QuicCryptoClientConfig to include a quic::ClientProofSource instead of a quic::ProofSource. Also set the cert and key in quic::TlsClientHandshaker's constructor, both will be used if server requests it.

Split from cl/402574728.

PiperOrigin-RevId: 404341798
diff --git a/quic/core/crypto/certificate_view.cc b/quic/core/crypto/certificate_view.cc
index 4024a78..f0b1c18 100644
--- a/quic/core/crypto/certificate_view.cc
+++ b/quic/core/crypto/certificate_view.cc
@@ -586,7 +586,7 @@
 }
 
 std::string CertificatePrivateKey::Sign(absl::string_view input,
-                                        uint16_t signature_algorithm) {
+                                        uint16_t signature_algorithm) const {
   if (!ValidForSignatureAlgorithm(signature_algorithm)) {
     QUIC_BUG(quic_bug_10640_2)
         << "Mismatch between the requested signature algorithm and the "
@@ -626,12 +626,13 @@
   return output;
 }
 
-bool CertificatePrivateKey::MatchesPublicKey(const CertificateView& view) {
+bool CertificatePrivateKey::MatchesPublicKey(
+    const CertificateView& view) const {
   return EVP_PKEY_cmp(view.public_key(), private_key_.get()) == 1;
 }
 
 bool CertificatePrivateKey::ValidForSignatureAlgorithm(
-    uint16_t signature_algorithm) {
+    uint16_t signature_algorithm) const {
   return PublicKeyTypeFromSignatureAlgorithm(signature_algorithm) ==
          PublicKeyTypeFromKey(private_key_.get());
 }
diff --git a/quic/core/crypto/certificate_view.h b/quic/core/crypto/certificate_view.h
index 0f88165..f2826cd 100644
--- a/quic/core/crypto/certificate_view.h
+++ b/quic/core/crypto/certificate_view.h
@@ -105,17 +105,17 @@
       std::istream* input);
 
   // |signature_algorithm| is a TLS signature algorithm ID.
-  std::string Sign(absl::string_view input, uint16_t signature_algorithm);
+  std::string Sign(absl::string_view input, uint16_t signature_algorithm) const;
 
   // Verifies that the private key in question matches the public key of the
   // certificate |view|.
-  bool MatchesPublicKey(const CertificateView& view);
+  bool MatchesPublicKey(const CertificateView& view) const;
 
   // Verifies that the private key can be used with the specified TLS signature
   // algorithm.
-  bool ValidForSignatureAlgorithm(uint16_t signature_algorithm);
+  bool ValidForSignatureAlgorithm(uint16_t signature_algorithm) const;
 
-  EVP_PKEY* private_key() { return private_key_.get(); }
+  EVP_PKEY* private_key() const { return private_key_.get(); }
 
  private:
   CertificatePrivateKey() = default;
diff --git a/quic/core/crypto/client_proof_source.cc b/quic/core/crypto/client_proof_source.cc
new file mode 100644
index 0000000..4e4d442
--- /dev/null
+++ b/quic/core/crypto/client_proof_source.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2021 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 "quic/core/crypto/client_proof_source.h"
+
+#include "absl/strings/match.h"
+
+namespace quic {
+
+bool DefaultClientProofSource::AddCertAndKey(
+    std::vector<std::string> server_hostnames,
+    QuicReferenceCountedPointer<Chain> chain,
+    CertificatePrivateKey private_key) {
+  if (!ValidateCertAndKey(chain, private_key)) {
+    return false;
+  }
+
+  auto cert_and_key =
+      std::make_shared<CertAndKey>(std::move(chain), std::move(private_key));
+  for (const std::string& domain : server_hostnames) {
+    cert_and_keys_[domain] = cert_and_key;
+  }
+  return true;
+}
+
+const ClientProofSource::CertAndKey* DefaultClientProofSource::GetCertAndKey(
+    absl::string_view hostname) const {
+  const CertAndKey* result = LookupExact(hostname);
+  if (result != nullptr || hostname == "*") {
+    return result;
+  }
+
+  // Either a full or a wildcard domain lookup failed. In the former case,
+  // derive the wildcard domain and look it up.
+  if (hostname.size() > 1 && !absl::StartsWith(hostname, "*.")) {
+    auto dot_pos = hostname.find('.');
+    if (dot_pos != std::string::npos) {
+      std::string wildcard = absl::StrCat("*", hostname.substr(dot_pos));
+      const CertAndKey* result = LookupExact(wildcard);
+      if (result != nullptr) {
+        return result;
+      }
+    }
+  }
+
+  // Return default cert, if any.
+  return LookupExact("*");
+}
+
+const ClientProofSource::CertAndKey* DefaultClientProofSource::LookupExact(
+    absl::string_view map_key) const {
+  const auto it = cert_and_keys_.find(map_key);
+  QUIC_DVLOG(1) << "LookupExact(" << map_key
+                << ") found:" << (it != cert_and_keys_.end());
+  if (it != cert_and_keys_.end()) {
+    return it->second.get();
+  }
+  return nullptr;
+}
+
+}  // namespace quic
diff --git a/quic/core/crypto/client_proof_source.h b/quic/core/crypto/client_proof_source.h
new file mode 100644
index 0000000..d1ab26c
--- /dev/null
+++ b/quic/core/crypto/client_proof_source.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2021 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.
+
+#ifndef QUICHE_QUIC_CORE_CRYPTO_CLIENT_PROOF_SOURCE_H_
+#define QUICHE_QUIC_CORE_CRYPTO_CLIENT_PROOF_SOURCE_H_
+
+#include <memory>
+
+#include "absl/container/flat_hash_map.h"
+#include "quic/core/crypto/certificate_view.h"
+#include "quic/core/crypto/proof_source.h"
+
+namespace quic {
+
+// ClientProofSource is the interface for a QUIC client to provide client certs
+// and keys based on server hostname. It is only used by TLS handshakes.
+class QUIC_EXPORT_PRIVATE ClientProofSource {
+ public:
+  using Chain = ProofSource::Chain;
+
+  virtual ~ClientProofSource() {}
+
+  struct QUIC_EXPORT_PRIVATE CertAndKey {
+    CertAndKey(QuicReferenceCountedPointer<Chain> chain,
+               CertificatePrivateKey private_key)
+        : chain(std::move(chain)), private_key(std::move(private_key)) {}
+
+    QuicReferenceCountedPointer<Chain> chain;
+    CertificatePrivateKey private_key;
+  };
+
+  // Get the client certificate to be sent to the server with |server_hostname|
+  // and its corresponding private key. It returns nullptr if the cert and key
+  // can not be found.
+  //
+  // |server_hostname| is typically a full domain name(www.foo.com), but it
+  // could also be a wildcard domain(*.foo.com), or a "*" which will return the
+  // default cert.
+  virtual const CertAndKey* GetCertAndKey(
+      absl::string_view server_hostname) const = 0;
+};
+
+// DefaultClientProofSource is an implementation that simply keeps an in memory
+// map of server hostnames to certs.
+class QUIC_EXPORT_PRIVATE DefaultClientProofSource : public ClientProofSource {
+ public:
+  ~DefaultClientProofSource() override {}
+
+  // Associate all hostnames in |server_hostnames| with {|chain|,|private_key|}.
+  // Elements of |server_hostnames| can be full domain names(www.foo.com),
+  // wildcard domains(*.foo.com), or "*" which means the given cert chain is the
+  // default one.
+  // If any element of |server_hostnames| is already associated with a cert
+  // chain, it will be updated to be associated with the new cert chain.
+  bool AddCertAndKey(std::vector<std::string> server_hostnames,
+                     QuicReferenceCountedPointer<Chain> chain,
+                     CertificatePrivateKey private_key);
+
+  // ClientProofSource implementation
+  const CertAndKey* GetCertAndKey(absl::string_view hostname) const override;
+
+ private:
+  const CertAndKey* LookupExact(absl::string_view map_key) const;
+  absl::flat_hash_map<std::string, std::shared_ptr<CertAndKey>> cert_and_keys_;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_CRYPTO_CLIENT_PROOF_SOURCE_H_
diff --git a/quic/core/crypto/client_proof_source_test.cc b/quic/core/crypto/client_proof_source_test.cc
new file mode 100644
index 0000000..08f5b76
--- /dev/null
+++ b/quic/core/crypto/client_proof_source_test.cc
@@ -0,0 +1,212 @@
+// Copyright (c) 2021 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 "quic/core/crypto/client_proof_source.h"
+
+#include "quic/platform/api/quic_expect_bug.h"
+#include "quic/platform/api/quic_test.h"
+#include "quic/test_tools/test_certificates.h"
+
+namespace quic {
+namespace test {
+
+QuicReferenceCountedPointer<ClientProofSource::Chain> TestCertChain() {
+  return QuicReferenceCountedPointer<ClientProofSource::Chain>(
+      new ClientProofSource::Chain({std::string(kTestCertificate)}));
+}
+
+CertificatePrivateKey TestPrivateKey() {
+  CBS private_key_cbs;
+  CBS_init(&private_key_cbs,
+           reinterpret_cast<const uint8_t*>(kTestCertificatePrivateKey.data()),
+           kTestCertificatePrivateKey.size());
+
+  return CertificatePrivateKey(
+      bssl::UniquePtr<EVP_PKEY>(EVP_parse_private_key(&private_key_cbs)));
+}
+
+const ClientProofSource::CertAndKey* TestCertAndKey() {
+  static const ClientProofSource::CertAndKey cert_and_key(TestCertChain(),
+                                                          TestPrivateKey());
+  return &cert_and_key;
+}
+
+QuicReferenceCountedPointer<ClientProofSource::Chain> NullCertChain() {
+  return QuicReferenceCountedPointer<ClientProofSource::Chain>();
+}
+
+QuicReferenceCountedPointer<ClientProofSource::Chain> EmptyCertChain() {
+  return QuicReferenceCountedPointer<ClientProofSource::Chain>(
+      new ClientProofSource::Chain(std::vector<std::string>()));
+}
+
+QuicReferenceCountedPointer<ClientProofSource::Chain> BadCertChain() {
+  return QuicReferenceCountedPointer<ClientProofSource::Chain>(
+      new ClientProofSource::Chain({"This is the content of a bad cert."}));
+}
+
+CertificatePrivateKey EmptyPrivateKey() {
+  return CertificatePrivateKey(bssl::UniquePtr<EVP_PKEY>(EVP_PKEY_new()));
+}
+
+#define VERIFY_CERT_AND_KEY_MATCHES(lhs, rhs) \
+  do {                                        \
+    SCOPED_TRACE(testing::Message());         \
+    VerifyCertAndKeyMatches(lhs, rhs);        \
+  } while (0)
+
+void VerifyCertAndKeyMatches(const ClientProofSource::CertAndKey* lhs,
+                             const ClientProofSource::CertAndKey* rhs) {
+  if (lhs == rhs) {
+    return;
+  }
+
+  if (lhs == nullptr) {
+    ADD_FAILURE() << "lhs is nullptr, but rhs is not";
+    return;
+  }
+
+  if (rhs == nullptr) {
+    ADD_FAILURE() << "rhs is nullptr, but lhs is not";
+    return;
+  }
+
+  if (1 != EVP_PKEY_cmp(lhs->private_key.private_key(),
+                        rhs->private_key.private_key())) {
+    ADD_FAILURE() << "Private keys mismatch";
+    return;
+  }
+
+  const ClientProofSource::Chain* lhs_chain = lhs->chain.get();
+  const ClientProofSource::Chain* rhs_chain = rhs->chain.get();
+
+  if (lhs_chain == rhs_chain) {
+    return;
+  }
+
+  if (lhs_chain == nullptr) {
+    ADD_FAILURE() << "lhs->chain is nullptr, but rhs->chain is not";
+    return;
+  }
+
+  if (rhs_chain == nullptr) {
+    ADD_FAILURE() << "rhs->chain is nullptr, but lhs->chain is not";
+    return;
+  }
+
+  if (lhs_chain->certs.size() != rhs_chain->certs.size()) {
+    ADD_FAILURE() << "Cert chain length differ. lhs:" << lhs_chain->certs.size()
+                  << ", rhs:" << rhs_chain->certs.size();
+    return;
+  }
+
+  for (size_t i = 0; i < lhs_chain->certs.size(); ++i) {
+    if (lhs_chain->certs[i] != rhs_chain->certs[i]) {
+      ADD_FAILURE() << "The " << i << "-th certs differ.";
+      return;
+    }
+  }
+
+  // All good.
+}
+
+TEST(DefaultClientProofSource, FullDomain) {
+  DefaultClientProofSource proof_source;
+  ASSERT_TRUE(proof_source.AddCertAndKey({"www.google.com"}, TestCertChain(),
+                                         TestPrivateKey()));
+  VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("www.google.com"),
+                              TestCertAndKey());
+  EXPECT_EQ(proof_source.GetCertAndKey("*.google.com"), nullptr);
+  EXPECT_EQ(proof_source.GetCertAndKey("*"), nullptr);
+}
+
+TEST(DefaultClientProofSource, WildcardDomain) {
+  DefaultClientProofSource proof_source;
+  ASSERT_TRUE(proof_source.AddCertAndKey({"*.google.com"}, TestCertChain(),
+                                         TestPrivateKey()));
+  VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("www.google.com"),
+                              TestCertAndKey());
+  VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("*.google.com"),
+                              TestCertAndKey());
+  EXPECT_EQ(proof_source.GetCertAndKey("*"), nullptr);
+}
+
+TEST(DefaultClientProofSource, DefaultDomain) {
+  DefaultClientProofSource proof_source;
+  ASSERT_TRUE(
+      proof_source.AddCertAndKey({"*"}, TestCertChain(), TestPrivateKey()));
+  VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("www.google.com"),
+                              TestCertAndKey());
+  VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("*.google.com"),
+                              TestCertAndKey());
+  VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("*"),
+                              TestCertAndKey());
+}
+
+TEST(DefaultClientProofSource, FullAndWildcard) {
+  DefaultClientProofSource proof_source;
+  ASSERT_TRUE(proof_source.AddCertAndKey({"www.google.com", "*.google.com"},
+                                         TestCertChain(), TestPrivateKey()));
+  VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("www.google.com"),
+                              TestCertAndKey());
+  VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("foo.google.com"),
+                              TestCertAndKey());
+  EXPECT_EQ(proof_source.GetCertAndKey("www.example.com"), nullptr);
+  EXPECT_EQ(proof_source.GetCertAndKey("*"), nullptr);
+}
+
+TEST(DefaultClientProofSource, FullWildcardAndDefault) {
+  DefaultClientProofSource proof_source;
+  ASSERT_TRUE(
+      proof_source.AddCertAndKey({"www.google.com", "*.google.com", "*"},
+                                 TestCertChain(), TestPrivateKey()));
+  VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("www.google.com"),
+                              TestCertAndKey());
+  VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("foo.google.com"),
+                              TestCertAndKey());
+  VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("www.example.com"),
+                              TestCertAndKey());
+  VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("*.google.com"),
+                              TestCertAndKey());
+  VERIFY_CERT_AND_KEY_MATCHES(proof_source.GetCertAndKey("*"),
+                              TestCertAndKey());
+}
+
+TEST(DefaultClientProofSource, EmptyCerts) {
+  DefaultClientProofSource proof_source;
+  bool ok;
+  EXPECT_QUIC_BUG(
+      ok = proof_source.AddCertAndKey({"*"}, NullCertChain(), TestPrivateKey()),
+      "Certificate chain is empty");
+  ASSERT_FALSE(ok);
+
+  EXPECT_QUIC_BUG(ok = proof_source.AddCertAndKey({"*"}, EmptyCertChain(),
+                                                  TestPrivateKey()),
+                  "Certificate chain is empty");
+  ASSERT_FALSE(ok);
+  EXPECT_EQ(proof_source.GetCertAndKey("*"), nullptr);
+}
+
+TEST(DefaultClientProofSource, BadCerts) {
+  DefaultClientProofSource proof_source;
+  bool ok;
+  EXPECT_QUIC_BUG(
+      ok = proof_source.AddCertAndKey({"*"}, BadCertChain(), TestPrivateKey()),
+      "Unabled to parse leaf certificate");
+  ASSERT_FALSE(ok);
+  EXPECT_EQ(proof_source.GetCertAndKey("*"), nullptr);
+}
+
+TEST(DefaultClientProofSource, KeyMismatch) {
+  DefaultClientProofSource proof_source;
+  bool ok;
+  EXPECT_QUIC_BUG(ok = proof_source.AddCertAndKey(
+                      {"www.google.com"}, TestCertChain(), EmptyPrivateKey()),
+                  "Private key does not match the leaf certificate");
+  ASSERT_FALSE(ok);
+  EXPECT_EQ(proof_source.GetCertAndKey("*"), nullptr);
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/core/crypto/proof_source.cc b/quic/core/crypto/proof_source.cc
index bb3a795..9cb85c2 100644
--- a/quic/core/crypto/proof_source.cc
+++ b/quic/core/crypto/proof_source.cc
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "quic/core/crypto/proof_source.h"
+
 #include <string>
 
-#include "quic/core/crypto/proof_source.h"
+#include "quic/platform/api/quic_bug_tracker.h"
 
 namespace quic {
 
@@ -30,4 +32,28 @@
   return crypto_buffers;
 }
 
+bool ValidateCertAndKey(
+    const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
+    const CertificatePrivateKey& key) {
+  if (chain.get() == nullptr || chain->certs.empty()) {
+    QUIC_BUG(quic_proof_source_empty_chain) << "Certificate chain is empty";
+    return false;
+  }
+
+  std::unique_ptr<CertificateView> leaf =
+      CertificateView::ParseSingleCertificate(chain->certs[0]);
+  if (leaf == nullptr) {
+    QUIC_BUG(quic_proof_source_unparsable_leaf_cert)
+        << "Unabled to parse leaf certificate";
+    return false;
+  }
+
+  if (!key.MatchesPublicKey(*leaf)) {
+    QUIC_BUG(quic_proof_source_key_mismatch)
+        << "Private key does not match the leaf certificate";
+    return false;
+  }
+  return true;
+}
+
 }  // namespace quic
diff --git a/quic/core/crypto/proof_source.h b/quic/core/crypto/proof_source.h
index c4a1f2c..fcc6cce 100644
--- a/quic/core/crypto/proof_source.h
+++ b/quic/core/crypto/proof_source.h
@@ -11,6 +11,7 @@
 
 #include "absl/strings/string_view.h"
 #include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "quic/core/crypto/certificate_view.h"
 #include "quic/core/crypto/quic_crypto_proof.h"
 #include "quic/core/quic_versions.h"
 #include "quic/platform/api/quic_export.h"
@@ -342,6 +343,12 @@
   friend class test::FakeProofSourceHandle;
 };
 
+// Returns true if |chain| contains a parsable DER-encoded X.509 leaf cert and
+// it matches with |key|.
+QUIC_EXPORT_PRIVATE bool ValidateCertAndKey(
+    const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
+    const CertificatePrivateKey& key);
+
 }  // namespace quic
 
 #endif  // QUICHE_QUIC_CORE_CRYPTO_PROOF_SOURCE_H_
diff --git a/quic/core/crypto/quic_crypto_client_config.cc b/quic/core/crypto/quic_crypto_client_config.cc
index 99f9279..6ecf0e8 100644
--- a/quic/core/crypto/quic_crypto_client_config.cc
+++ b/quic/core/crypto/quic_crypto_client_config.cc
@@ -801,12 +801,12 @@
   return session_cache_.get();
 }
 
-ProofSource* QuicCryptoClientConfig::proof_source() const {
+ClientProofSource* QuicCryptoClientConfig::proof_source() const {
   return proof_source_.get();
 }
 
 void QuicCryptoClientConfig::set_proof_source(
-    std::unique_ptr<ProofSource> proof_source) {
+    std::unique_ptr<ClientProofSource> proof_source) {
   proof_source_ = std::move(proof_source);
 }
 
diff --git a/quic/core/crypto/quic_crypto_client_config.h b/quic/core/crypto/quic_crypto_client_config.h
index 847fc96..e316f8f 100644
--- a/quic/core/crypto/quic_crypto_client_config.h
+++ b/quic/core/crypto/quic_crypto_client_config.h
@@ -14,9 +14,9 @@
 #include "absl/strings/string_view.h"
 #include "third_party/boringssl/src/include/openssl/base.h"
 #include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "quic/core/crypto/client_proof_source.h"
 #include "quic/core/crypto/crypto_handshake.h"
 #include "quic/core/crypto/crypto_protocol.h"
-#include "quic/core/crypto/proof_source.h"
 #include "quic/core/crypto/transport_parameters.h"
 #include "quic/core/quic_packets.h"
 #include "quic/core/quic_server_id.h"
@@ -336,8 +336,8 @@
 
   ProofVerifier* proof_verifier() const;
   SessionCache* session_cache() const;
-  ProofSource* proof_source() const;
-  void set_proof_source(std::unique_ptr<ProofSource> proof_source);
+  ClientProofSource* proof_source() const;
+  void set_proof_source(std::unique_ptr<ClientProofSource> proof_source);
   SSL_CTX* ssl_ctx() const;
 
   // Initialize the CachedState from |canonical_crypto_config| for the
@@ -429,7 +429,7 @@
 
   std::unique_ptr<ProofVerifier> proof_verifier_;
   std::unique_ptr<SessionCache> session_cache_;
-  std::unique_ptr<ProofSource> proof_source_;
+  std::unique_ptr<ClientProofSource> proof_source_;
 
   bssl::UniquePtr<SSL_CTX> ssl_ctx_;
 
diff --git a/quic/core/crypto/tls_client_connection.cc b/quic/core/crypto/tls_client_connection.cc
index bfd20b2..8e31bba 100644
--- a/quic/core/crypto/tls_client_connection.cc
+++ b/quic/core/crypto/tls_client_connection.cc
@@ -34,6 +34,12 @@
   return ssl_ctx;
 }
 
+void TlsClientConnection::SetCertChain(
+    const std::vector<CRYPTO_BUFFER*>& cert_chain, EVP_PKEY* privkey) {
+  SSL_set_chain_and_key(ssl(), cert_chain.data(), cert_chain.size(), privkey,
+                        /*privkey_method=*/nullptr);
+}
+
 // static
 int TlsClientConnection::NewSessionCallback(SSL* ssl, SSL_SESSION* session) {
   static_cast<TlsClientConnection*>(ConnectionFromSsl(ssl))
diff --git a/quic/core/crypto/tls_client_connection.h b/quic/core/crypto/tls_client_connection.h
index ce4b948..574441e 100644
--- a/quic/core/crypto/tls_client_connection.h
+++ b/quic/core/crypto/tls_client_connection.h
@@ -37,6 +37,11 @@
   // Creates and configures an SSL_CTX that is appropriate for clients to use.
   static bssl::UniquePtr<SSL_CTX> CreateSslCtx(bool enable_early_data);
 
+  // Set the client cert and private key to be used on this connection, if
+  // requested by the server.
+  void SetCertChain(const std::vector<CRYPTO_BUFFER*>& cert_chain,
+                    EVP_PKEY* privkey);
+
  private:
   // Registered as the callback for SSL_CTX_sess_set_new_cb, which calls
   // Delegate::InsertSession.
diff --git a/quic/core/tls_client_handshaker.cc b/quic/core/tls_client_handshaker.cc
index 50ba814..2717db0 100644
--- a/quic/core/tls_client_handshaker.cc
+++ b/quic/core/tls_client_handshaker.cc
@@ -51,6 +51,15 @@
     SSL_set1_sigalgs_list(ssl(),
                           crypto_config->tls_signature_algorithms()->c_str());
   }
+  if (crypto_config->proof_source() != nullptr) {
+    const ClientProofSource::CertAndKey* cert_and_key =
+        crypto_config->proof_source()->GetCertAndKey(server_id.host());
+    if (cert_and_key != nullptr) {
+      QUIC_DVLOG(1) << "Setting client cert and key for " << server_id.host();
+      tls_connection_.SetCertChain(cert_and_key->chain->ToCryptoBuffers().value,
+                                   cert_and_key->private_key.private_key());
+    }
+  }
 }
 
 TlsClientHandshaker::~TlsClientHandshaker() {}