Allow QuicToyClient to provide a client certificate to the server, if requested. PiperOrigin-RevId: 407883023
diff --git a/quic/tools/quic_toy_client.cc b/quic/tools/quic_toy_client.cc index 0db266b..83fd7c0 100644 --- a/quic/tools/quic_toy_client.cc +++ b/quic/tools/quic_toy_client.cc
@@ -42,6 +42,7 @@ #include "quic/tools/quic_toy_client.h" +#include <fstream> #include <iostream> #include <memory> #include <string> @@ -184,6 +185,16 @@ "If true, don't verify the server certificate."); DEFINE_QUIC_COMMAND_LINE_FLAG( + std::string, default_client_cert, "", + "The path to the file containing PEM-encoded client default certificate to " + "be sent to the server, if server requested client certs."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + std::string, default_client_cert_key, "", + "The path to the file containing PEM-encoded private key of the client's " + "default certificate for signing, if server requested client certs."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( bool, drop_response_body, false, @@ -219,6 +230,42 @@ "Max inbound header list size. 0 means default."); namespace quic { +namespace { + +// Creates a ClientProofSource which only contains a default client certificate. +// Return nullptr for failure. +std::unique_ptr<ClientProofSource> CreateTestClientProofSource( + absl::string_view default_client_cert_file, + absl::string_view default_client_cert_key_file) { + std::ifstream cert_stream(std::string{default_client_cert_file}, + std::ios::binary); + std::vector<std::string> certs = + CertificateView::LoadPemFromStream(&cert_stream); + if (certs.empty()) { + std::cerr << "Failed to load client certs." << std::endl; + return nullptr; + } + + std::ifstream key_stream(std::string{default_client_cert_key_file}, + std::ios::binary); + std::unique_ptr<CertificatePrivateKey> private_key = + CertificatePrivateKey::LoadPemFromStream(&key_stream); + if (private_key == nullptr) { + std::cerr << "Failed to load client cert key." << std::endl; + return nullptr; + } + + auto proof_source = std::make_unique<DefaultClientProofSource>(); + proof_source->AddCertAndKey( + {"*"}, + QuicReferenceCountedPointer<ClientProofSource::Chain>( + new ClientProofSource::Chain(certs)), + std::move(*private_key)); + + return proof_source; +} + +} // namespace QuicToyClient::QuicToyClient(ClientFactory* client_factory) : client_factory_(client_factory) {} @@ -320,6 +367,18 @@ return 1; } + if (!GetQuicFlag(FLAGS_default_client_cert).empty() && + !GetQuicFlag(FLAGS_default_client_cert_key).empty()) { + std::unique_ptr<ClientProofSource> proof_source = + CreateTestClientProofSource(GetQuicFlag(FLAGS_default_client_cert), + GetQuicFlag(FLAGS_default_client_cert_key)); + if (proof_source == nullptr) { + std::cerr << "Failed to create client proof source." << std::endl; + return 1; + } + client->crypto_config()->set_proof_source(std::move(proof_source)); + } + int32_t initial_mtu = GetQuicFlag(FLAGS_initial_mtu); client->set_initial_max_packet_length( initial_mtu != 0 ? initial_mtu : quic::kDefaultMaxPacketSize);