1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/test_tools/crypto_test_utils.h"
6
7 #include <algorithm>
8 #include <cstddef>
9 #include <memory>
10 #include <optional>
11 #include <string>
12 #include <utility>
13 #include <vector>
14
15 #include "absl/strings/escaping.h"
16 #include "absl/strings/str_cat.h"
17 #include "absl/strings/string_view.h"
18 #include "absl/types/span.h"
19 #include "quiche/quic/core/crypto/certificate_view.h"
20 #include "quiche/quic/core/crypto/crypto_handshake.h"
21 #include "quiche/quic/core/crypto/crypto_utils.h"
22 #include "quiche/quic/core/crypto/proof_source_x509.h"
23 #include "quiche/quic/core/crypto/quic_crypto_server_config.h"
24 #include "quiche/quic/core/crypto/quic_decrypter.h"
25 #include "quiche/quic/core/crypto/quic_encrypter.h"
26 #include "quiche/quic/core/crypto/quic_random.h"
27 #include "quiche/quic/core/proto/crypto_server_config_proto.h"
28 #include "quiche/quic/core/quic_clock.h"
29 #include "quiche/quic/core/quic_connection.h"
30 #include "quiche/quic/core/quic_crypto_client_stream.h"
31 #include "quiche/quic/core/quic_crypto_server_stream_base.h"
32 #include "quiche/quic/core/quic_crypto_stream.h"
33 #include "quiche/quic/core/quic_packets.h"
34 #include "quiche/quic/core/quic_server_id.h"
35 #include "quiche/quic/core/quic_types.h"
36 #include "quiche/quic/core/quic_utils.h"
37 #include "quiche/quic/core/quic_versions.h"
38 #include "quiche/quic/platform/api/quic_hostname_utils.h"
39 #include "quiche/quic/platform/api/quic_logging.h"
40 #include "quiche/quic/platform/api/quic_socket_address.h"
41 #include "quiche/quic/platform/api/quic_test.h"
42 #include "quiche/quic/test_tools/quic_connection_peer.h"
43 #include "quiche/quic/test_tools/quic_framer_peer.h"
44 #include "quiche/quic/test_tools/quic_stream_peer.h"
45 #include "quiche/quic/test_tools/quic_test_utils.h"
46 #include "quiche/quic/test_tools/simple_quic_framer.h"
47 #include "quiche/quic/test_tools/test_certificates.h"
48 #include "quiche/common/platform/api/quiche_logging.h"
49 #include "quiche/common/quiche_callbacks.h"
50 #include "quiche/common/test_tools/quiche_test_utils.h"
51
52 namespace quic {
53 namespace test {
54
55 namespace crypto_test_utils {
56
57 namespace {
58
59 using testing::_;
60
61 // CryptoFramerVisitor is a framer visitor that records handshake messages.
62 class CryptoFramerVisitor : public CryptoFramerVisitorInterface {
63 public:
CryptoFramerVisitor()64 CryptoFramerVisitor() : error_(false) {}
65
OnError(CryptoFramer *)66 void OnError(CryptoFramer* /*framer*/) override { error_ = true; }
67
OnHandshakeMessage(const CryptoHandshakeMessage & message)68 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
69 messages_.push_back(message);
70 }
71
error() const72 bool error() const { return error_; }
73
messages() const74 const std::vector<CryptoHandshakeMessage>& messages() const {
75 return messages_;
76 }
77
78 private:
79 bool error_;
80 std::vector<CryptoHandshakeMessage> messages_;
81 };
82
83 // HexChar parses |c| as a hex character. If valid, it sets |*value| to the
84 // value of the hex character and returns true. Otherwise it returns false.
HexChar(char c,uint8_t * value)85 bool HexChar(char c, uint8_t* value) {
86 if (c >= '0' && c <= '9') {
87 *value = c - '0';
88 return true;
89 }
90 if (c >= 'a' && c <= 'f') {
91 *value = c - 'a' + 10;
92 return true;
93 }
94 if (c >= 'A' && c <= 'F') {
95 *value = c - 'A' + 10;
96 return true;
97 }
98 return false;
99 }
100
MovePackets(const QuicConnection & source_conn,absl::Span<const QuicEncryptedPacket * const> packets,QuicCryptoStream & dest_stream,QuicConnection & dest_conn,Perspective dest_perspective,bool process_stream_data)101 void MovePackets(const QuicConnection& source_conn,
102 absl::Span<const QuicEncryptedPacket* const> packets,
103 QuicCryptoStream& dest_stream, QuicConnection& dest_conn,
104 Perspective dest_perspective, bool process_stream_data) {
105 QUICHE_CHECK(!packets.empty());
106
107 SimpleQuicFramer framer(source_conn.supported_versions(), dest_perspective);
108 QuicFramerPeer::SetLastSerializedServerConnectionId(framer.framer(),
109 TestConnectionId());
110
111 SimpleQuicFramer null_encryption_framer(source_conn.supported_versions(),
112 dest_perspective);
113 QuicFramerPeer::SetLastSerializedServerConnectionId(
114 null_encryption_framer.framer(), TestConnectionId());
115
116 for (const QuicEncryptedPacket* const packet : packets) {
117 if (!dest_conn.connected()) {
118 QUIC_LOG(INFO) << "Destination connection disconnected. Skipping packet.";
119 continue;
120 }
121 // In order to properly test the code we need to perform encryption and
122 // decryption so that the crypters latch when expected. The crypters are in
123 // |dest_conn|, but we don't want to try and use them there. Instead we swap
124 // them into |framer|, perform the decryption with them, and then swap ther
125 // back.
126 QuicConnectionPeer::SwapCrypters(&dest_conn, framer.framer());
127 QuicConnectionPeer::AddBytesReceived(&dest_conn, packet->length());
128 if (!framer.ProcessPacket(*packet)) {
129 // The framer will be unable to decrypt zero-rtt packets sent during
130 // handshake or forward-secure packets sent after the handshake is
131 // complete. Don't treat them as handshake packets.
132 QuicConnectionPeer::SwapCrypters(&dest_conn, framer.framer());
133 continue;
134 }
135 QuicConnectionPeer::SwapCrypters(&dest_conn, framer.framer());
136
137 // Install a packet flusher such that the packets generated by |dest_conn|
138 // in response to this packet are more likely to be coalesced and/or batched
139 // in the writer.
140 QuicConnection::ScopedPacketFlusher flusher(&dest_conn);
141
142 dest_conn.OnDecryptedPacket(packet->length(),
143 framer.last_decrypted_level());
144
145 if (dest_stream.handshake_protocol() == PROTOCOL_TLS1_3) {
146 // Try to process the packet with a framer that only has the NullDecrypter
147 // for decryption. If ProcessPacket succeeds, that means the packet was
148 // encrypted with the NullEncrypter. With the TLS handshaker in use, no
149 // packets should ever be encrypted with the NullEncrypter, instead
150 // they're encrypted with an obfuscation cipher based on QUIC version and
151 // connection ID.
152 QUIC_LOG(INFO) << "Attempting to decrypt with NullDecrypter: "
153 "expect a decryption failure on the next log line.";
154 ASSERT_FALSE(null_encryption_framer.ProcessPacket(*packet))
155 << "No TLS packets should be encrypted with the NullEncrypter";
156 }
157
158 // Since we're using QuicFramers separate from the connections to move
159 // packets, the QuicConnection never gets notified about what level the last
160 // packet was decrypted at. This is needed by TLS to know what encryption
161 // level was used for the data it's receiving, so we plumb this information
162 // from the SimpleQuicFramer back into the connection.
163 dest_conn.OnDecryptedPacket(packet->length(),
164 framer.last_decrypted_level());
165
166 QuicConnectionPeer::SetCurrentPacket(&dest_conn, packet->AsStringPiece());
167 for (const auto& stream_frame : framer.stream_frames()) {
168 if (process_stream_data &&
169 dest_stream.handshake_protocol() == PROTOCOL_TLS1_3) {
170 // Deliver STREAM_FRAME such that application state is available and can
171 // be stored along with resumption ticket in session cache,
172 dest_conn.OnStreamFrame(*stream_frame);
173 } else {
174 // Ignore stream frames that are sent on other streams in the crypto
175 // event.
176 if (stream_frame->stream_id == dest_stream.id()) {
177 dest_stream.OnStreamFrame(*stream_frame);
178 }
179 }
180 }
181 for (const auto& crypto_frame : framer.crypto_frames()) {
182 dest_stream.OnCryptoFrame(*crypto_frame);
183 }
184 if (!framer.connection_close_frames().empty() && dest_conn.connected()) {
185 dest_conn.OnConnectionCloseFrame(framer.connection_close_frames()[0]);
186 }
187 }
188
189 QuicConnectionPeer::SetCurrentPacket(&dest_conn,
190 absl::string_view(nullptr, 0));
191 }
192
193 } // anonymous namespace
194
FakeClientOptions()195 FakeClientOptions::FakeClientOptions() {}
196
~FakeClientOptions()197 FakeClientOptions::~FakeClientOptions() {}
198
199 namespace {
200 // This class is used by GenerateFullCHLO() to extract SCID and STK from
201 // REJ and to construct a full CHLO with these fields and given inchoate
202 // CHLO.
203 class FullChloGenerator {
204 public:
FullChloGenerator(QuicCryptoServerConfig * crypto_config,QuicSocketAddress server_addr,QuicSocketAddress client_addr,const QuicClock * clock,ParsedQuicVersion version,quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> signed_config,QuicCompressedCertsCache * compressed_certs_cache,CryptoHandshakeMessage * out)205 FullChloGenerator(
206 QuicCryptoServerConfig* crypto_config, QuicSocketAddress server_addr,
207 QuicSocketAddress client_addr, const QuicClock* clock,
208 ParsedQuicVersion version,
209 quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig>
210 signed_config,
211 QuicCompressedCertsCache* compressed_certs_cache,
212 CryptoHandshakeMessage* out)
213 : crypto_config_(crypto_config),
214 server_addr_(server_addr),
215 client_addr_(client_addr),
216 clock_(clock),
217 version_(version),
218 signed_config_(signed_config),
219 compressed_certs_cache_(compressed_certs_cache),
220 out_(out),
221 params_(new QuicCryptoNegotiatedParameters) {}
222
223 class ValidateClientHelloCallback : public ValidateClientHelloResultCallback {
224 public:
ValidateClientHelloCallback(FullChloGenerator * generator)225 explicit ValidateClientHelloCallback(FullChloGenerator* generator)
226 : generator_(generator) {}
Run(quiche::QuicheReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result,std::unique_ptr<ProofSource::Details>)227 void Run(quiche::QuicheReferenceCountedPointer<
228 ValidateClientHelloResultCallback::Result>
229 result,
230 std::unique_ptr<ProofSource::Details> /* details */) override {
231 generator_->ValidateClientHelloDone(std::move(result));
232 }
233
234 private:
235 FullChloGenerator* generator_;
236 };
237
238 std::unique_ptr<ValidateClientHelloCallback>
GetValidateClientHelloCallback()239 GetValidateClientHelloCallback() {
240 return std::make_unique<ValidateClientHelloCallback>(this);
241 }
242
243 private:
ValidateClientHelloDone(quiche::QuicheReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result)244 void ValidateClientHelloDone(quiche::QuicheReferenceCountedPointer<
245 ValidateClientHelloResultCallback::Result>
246 result) {
247 result_ = result;
248 crypto_config_->ProcessClientHello(
249 result_, /*reject_only=*/false, TestConnectionId(1), server_addr_,
250 client_addr_, version_, {version_}, clock_, QuicRandom::GetInstance(),
251 compressed_certs_cache_, params_, signed_config_,
252 /*total_framing_overhead=*/50, kDefaultMaxPacketSize,
253 GetProcessClientHelloCallback());
254 }
255
256 class ProcessClientHelloCallback : public ProcessClientHelloResultCallback {
257 public:
ProcessClientHelloCallback(FullChloGenerator * generator)258 explicit ProcessClientHelloCallback(FullChloGenerator* generator)
259 : generator_(generator) {}
Run(QuicErrorCode error,const std::string & error_details,std::unique_ptr<CryptoHandshakeMessage> message,std::unique_ptr<DiversificationNonce>,std::unique_ptr<ProofSource::Details>)260 void Run(QuicErrorCode error, const std::string& error_details,
261 std::unique_ptr<CryptoHandshakeMessage> message,
262 std::unique_ptr<DiversificationNonce> /*diversification_nonce*/,
263 std::unique_ptr<ProofSource::Details> /*proof_source_details*/)
264 override {
265 ASSERT_TRUE(message) << QuicErrorCodeToString(error) << " "
266 << error_details;
267 generator_->ProcessClientHelloDone(std::move(message));
268 }
269
270 private:
271 FullChloGenerator* generator_;
272 };
273
GetProcessClientHelloCallback()274 std::unique_ptr<ProcessClientHelloCallback> GetProcessClientHelloCallback() {
275 return std::make_unique<ProcessClientHelloCallback>(this);
276 }
277
ProcessClientHelloDone(std::unique_ptr<CryptoHandshakeMessage> rej)278 void ProcessClientHelloDone(std::unique_ptr<CryptoHandshakeMessage> rej) {
279 // Verify output is a REJ.
280 EXPECT_THAT(rej->tag(), testing::Eq(kREJ));
281
282 QUIC_VLOG(1) << "Extract valid STK and SCID from\n" << rej->DebugString();
283 absl::string_view srct;
284 ASSERT_TRUE(rej->GetStringPiece(kSourceAddressTokenTag, &srct));
285
286 absl::string_view scfg;
287 ASSERT_TRUE(rej->GetStringPiece(kSCFG, &scfg));
288 std::unique_ptr<CryptoHandshakeMessage> server_config(
289 CryptoFramer::ParseMessage(scfg));
290
291 absl::string_view scid;
292 ASSERT_TRUE(server_config->GetStringPiece(kSCID, &scid));
293
294 *out_ = result_->client_hello;
295 out_->SetStringPiece(kSCID, scid);
296 out_->SetStringPiece(kSourceAddressTokenTag, srct);
297 uint64_t xlct = LeafCertHashForTesting();
298 out_->SetValue(kXLCT, xlct);
299 }
300
301 protected:
302 QuicCryptoServerConfig* crypto_config_;
303 QuicSocketAddress server_addr_;
304 QuicSocketAddress client_addr_;
305 const QuicClock* clock_;
306 ParsedQuicVersion version_;
307 quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> signed_config_;
308 QuicCompressedCertsCache* compressed_certs_cache_;
309 CryptoHandshakeMessage* out_;
310
311 quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
312 quiche::QuicheReferenceCountedPointer<
313 ValidateClientHelloResultCallback::Result>
314 result_;
315 };
316
317 } // namespace
318
CryptoServerConfigForTesting()319 std::unique_ptr<QuicCryptoServerConfig> CryptoServerConfigForTesting() {
320 return std::make_unique<QuicCryptoServerConfig>(
321 QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
322 ProofSourceForTesting(), KeyExchangeSource::Default());
323 }
324
HandshakeWithFakeServer(QuicConfig * server_quic_config,QuicCryptoServerConfig * crypto_config,MockQuicConnectionHelper * helper,MockAlarmFactory * alarm_factory,PacketSavingConnection * client_conn,QuicCryptoClientStreamBase * client,std::string alpn)325 int HandshakeWithFakeServer(QuicConfig* server_quic_config,
326 QuicCryptoServerConfig* crypto_config,
327 MockQuicConnectionHelper* helper,
328 MockAlarmFactory* alarm_factory,
329 PacketSavingConnection* client_conn,
330 QuicCryptoClientStreamBase* client,
331 std::string alpn) {
332 auto* server_conn = new testing::NiceMock<PacketSavingConnection>(
333 helper, alarm_factory, Perspective::IS_SERVER,
334 ParsedVersionOfIndex(client_conn->supported_versions(), 0));
335
336 QuicCompressedCertsCache compressed_certs_cache(
337 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
338 SetupCryptoServerConfigForTest(
339 server_conn->clock(), server_conn->random_generator(), crypto_config);
340
341 TestQuicSpdyServerSession server_session(
342 server_conn, *server_quic_config, client_conn->supported_versions(),
343 crypto_config, &compressed_certs_cache);
344 // Call SetServerApplicationStateForResumption so that the fake server
345 // supports 0-RTT in TLS.
346 server_session.Initialize();
347 server_session.GetMutableCryptoStream()
348 ->SetServerApplicationStateForResumption(
349 std::make_unique<ApplicationState>());
350 EXPECT_CALL(*server_session.helper(),
351 CanAcceptClientHello(testing::_, testing::_, testing::_,
352 testing::_, testing::_))
353 .Times(testing::AnyNumber());
354 EXPECT_CALL(*server_conn, OnCanWrite()).Times(testing::AnyNumber());
355 EXPECT_CALL(*client_conn, OnCanWrite()).Times(testing::AnyNumber());
356 EXPECT_CALL(*server_conn, SendCryptoData(_, _, _))
357 .Times(testing::AnyNumber());
358 EXPECT_CALL(server_session, SelectAlpn(_))
359 .WillRepeatedly([alpn](const std::vector<absl::string_view>& alpns) {
360 return std::find(alpns.cbegin(), alpns.cend(), alpn);
361 });
362
363 // The client's handshake must have been started already.
364 QUICHE_CHECK_NE(0u, client_conn->encrypted_packets_.size());
365
366 CommunicateHandshakeMessages(client_conn, client, server_conn,
367 server_session.GetMutableCryptoStream());
368 if (client_conn->connected() && server_conn->connected()) {
369 CompareClientAndServerKeys(client, server_session.GetMutableCryptoStream());
370 }
371
372 return client->num_sent_client_hellos();
373 }
374
HandshakeWithFakeClient(MockQuicConnectionHelper * helper,MockAlarmFactory * alarm_factory,PacketSavingConnection * server_conn,QuicCryptoServerStreamBase * server,const QuicServerId & server_id,const FakeClientOptions & options,std::string alpn)375 int HandshakeWithFakeClient(MockQuicConnectionHelper* helper,
376 MockAlarmFactory* alarm_factory,
377 PacketSavingConnection* server_conn,
378 QuicCryptoServerStreamBase* server,
379 const QuicServerId& server_id,
380 const FakeClientOptions& options,
381 std::string alpn) {
382 // This function does not do version negotiation; read the supported versions
383 // directly from the server connection instead.
384 ParsedQuicVersionVector supported_versions =
385 server_conn->supported_versions();
386 if (options.only_tls_versions) {
387 supported_versions.erase(
388 std::remove_if(supported_versions.begin(), supported_versions.end(),
389 [](const ParsedQuicVersion& version) {
390 return version.handshake_protocol != PROTOCOL_TLS1_3;
391 }),
392 supported_versions.end());
393 QUICHE_CHECK(!options.only_quic_crypto_versions);
394 } else if (options.only_quic_crypto_versions) {
395 supported_versions.erase(
396 std::remove_if(supported_versions.begin(), supported_versions.end(),
397 [](const ParsedQuicVersion& version) {
398 return version.handshake_protocol !=
399 PROTOCOL_QUIC_CRYPTO;
400 }),
401 supported_versions.end());
402 }
403 PacketSavingConnection* client_conn = new PacketSavingConnection(
404 helper, alarm_factory, Perspective::IS_CLIENT, supported_versions);
405 // Advance the time, because timers do not like uninitialized times.
406 client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1));
407
408 QuicCryptoClientConfig crypto_config(ProofVerifierForTesting());
409 TestQuicSpdyClientSession client_session(client_conn, DefaultQuicConfig(),
410 supported_versions, server_id,
411 &crypto_config);
412
413 EXPECT_CALL(client_session, OnProofValid(testing::_))
414 .Times(testing::AnyNumber());
415 EXPECT_CALL(client_session, OnProofVerifyDetailsAvailable(testing::_))
416 .Times(testing::AnyNumber());
417 EXPECT_CALL(*client_conn, OnCanWrite()).Times(testing::AnyNumber());
418 if (!alpn.empty()) {
419 EXPECT_CALL(client_session, GetAlpnsToOffer())
420 .WillRepeatedly(testing::Return(std::vector<std::string>({alpn})));
421 } else {
422 EXPECT_CALL(client_session, GetAlpnsToOffer())
423 .WillRepeatedly(testing::Return(std::vector<std::string>(
424 {AlpnForVersion(client_conn->version())})));
425 }
426 client_session.GetMutableCryptoStream()->CryptoConnect();
427 QUICHE_CHECK_EQ(1u, client_conn->encrypted_packets_.size());
428
429 CommunicateHandshakeMessages(client_conn,
430 client_session.GetMutableCryptoStream(),
431 server_conn, server);
432
433 if (server->one_rtt_keys_available() && server->encryption_established()) {
434 CompareClientAndServerKeys(client_session.GetMutableCryptoStream(), server);
435 }
436
437 return client_session.GetCryptoStream()->num_sent_client_hellos();
438 }
439
SetupCryptoServerConfigForTest(const QuicClock * clock,QuicRandom * rand,QuicCryptoServerConfig * crypto_config)440 void SetupCryptoServerConfigForTest(const QuicClock* clock, QuicRandom* rand,
441 QuicCryptoServerConfig* crypto_config) {
442 QuicCryptoServerConfig::ConfigOptions options;
443 options.channel_id_enabled = true;
444 std::unique_ptr<CryptoHandshakeMessage> scfg =
445 crypto_config->AddDefaultConfig(rand, clock, options);
446 }
447
SendHandshakeMessageToStream(QuicCryptoStream * stream,const CryptoHandshakeMessage & message,Perspective)448 void SendHandshakeMessageToStream(QuicCryptoStream* stream,
449 const CryptoHandshakeMessage& message,
450 Perspective /*perspective*/) {
451 const QuicData& data = message.GetSerialized();
452 QuicSession* session = QuicStreamPeer::session(stream);
453 if (!QuicVersionUsesCryptoFrames(session->transport_version())) {
454 QuicStreamFrame frame(
455 QuicUtils::GetCryptoStreamId(session->transport_version()), false,
456 stream->crypto_bytes_read(), data.AsStringPiece());
457 stream->OnStreamFrame(frame);
458 } else {
459 EncryptionLevel level = session->connection()->last_decrypted_level();
460 QuicCryptoFrame frame(level, stream->BytesReadOnLevel(level),
461 data.AsStringPiece());
462 stream->OnCryptoFrame(frame);
463 }
464 }
465
CommunicateHandshakeMessages(PacketSavingConnection * client_conn,QuicCryptoStream * client,PacketSavingConnection * server_conn,QuicCryptoStream * server)466 void CommunicateHandshakeMessages(PacketSavingConnection* client_conn,
467 QuicCryptoStream* client,
468 PacketSavingConnection* server_conn,
469 QuicCryptoStream* server) {
470 CommunicateHandshakeMessages(*client_conn, *client, *server_conn, *server,
471 /*packets_from_client=*/*client_conn,
472 /*packets_from_server=*/*server_conn);
473 }
474
CommunicateHandshakeMessages(QuicConnection & client_conn,QuicCryptoStream & client,QuicConnection & server_conn,QuicCryptoStream & server,PacketProvider & packets_from_client,PacketProvider & packets_from_server)475 void CommunicateHandshakeMessages(QuicConnection& client_conn,
476 QuicCryptoStream& client,
477 QuicConnection& server_conn,
478 QuicCryptoStream& server,
479 PacketProvider& packets_from_client,
480 PacketProvider& packets_from_server) {
481 while (
482 client_conn.connected() && server_conn.connected() &&
483 (!client.one_rtt_keys_available() || !server.one_rtt_keys_available())) {
484 QUICHE_CHECK(!packets_from_client.GetPackets().empty());
485 QUIC_LOG(INFO) << "Processing " << packets_from_client.GetPackets().size()
486 << " packets client->server";
487 MovePackets(client_conn, packets_from_client.GetPackets(), server,
488 server_conn, Perspective::IS_SERVER,
489 /*process_stream_data=*/false);
490 packets_from_client.ClearPackets();
491
492 if (client.one_rtt_keys_available() && server.one_rtt_keys_available() &&
493 packets_from_server.GetPackets().empty()) {
494 break;
495 }
496 QUIC_LOG(INFO) << "Processing " << packets_from_server.GetPackets().size()
497 << " packets server->client";
498 MovePackets(server_conn, packets_from_server.GetPackets(), client,
499 client_conn, Perspective::IS_CLIENT,
500 /*process_stream_data=*/false);
501 packets_from_server.ClearPackets();
502 }
503 }
504
CommunicateHandshakeMessagesUntil(PacketSavingConnection * client_conn,QuicCryptoStream * client,quiche::UnretainedCallback<bool ()> client_condition,PacketSavingConnection * server_conn,QuicCryptoStream * server,quiche::UnretainedCallback<bool ()> server_condition,bool process_stream_data)505 bool CommunicateHandshakeMessagesUntil(
506 PacketSavingConnection* client_conn, QuicCryptoStream* client,
507 quiche::UnretainedCallback<bool()> client_condition,
508 PacketSavingConnection* server_conn, QuicCryptoStream* server,
509 quiche::UnretainedCallback<bool()> server_condition,
510 bool process_stream_data) {
511 return CommunicateHandshakeMessagesUntil(
512 *client_conn, *client, client_condition, *server_conn, *server,
513 server_condition, process_stream_data,
514 /*packets_from_client=*/*client_conn,
515 /*packets_from_server=*/*server_conn);
516 }
517
CommunicateHandshakeMessagesUntil(QuicConnection & client_conn,QuicCryptoStream & client,quiche::UnretainedCallback<bool ()> client_condition,QuicConnection & server_conn,QuicCryptoStream & server,quiche::UnretainedCallback<bool ()> server_condition,bool process_stream_data,PacketProvider & packets_from_client,PacketProvider & packets_from_server)518 bool CommunicateHandshakeMessagesUntil(
519 QuicConnection& client_conn, QuicCryptoStream& client,
520 quiche::UnretainedCallback<bool()> client_condition,
521 QuicConnection& server_conn, QuicCryptoStream& server,
522 quiche::UnretainedCallback<bool()> server_condition,
523 bool process_stream_data, PacketProvider& packets_from_client,
524 PacketProvider& packets_from_server) {
525 while (client_conn.connected() && server_conn.connected() &&
526 (!client_condition() || !server_condition()) &&
527 (!packets_from_client.GetPackets().empty() ||
528 !packets_from_server.GetPackets().empty())) {
529 if (!server_condition() && !packets_from_client.GetPackets().empty()) {
530 QUIC_LOG(INFO) << "Processing " << packets_from_client.GetPackets().size()
531 << " packets client->server";
532 MovePackets(client_conn, packets_from_client.GetPackets(), server,
533 server_conn, Perspective::IS_SERVER, process_stream_data);
534 packets_from_client.ClearPackets();
535 }
536 if (!client_condition() && !packets_from_server.GetPackets().empty()) {
537 QUIC_LOG(INFO) << "Processing " << packets_from_server.GetPackets().size()
538 << " packets server->client";
539 MovePackets(server_conn, packets_from_server.GetPackets(), client,
540 client_conn, Perspective::IS_CLIENT, process_stream_data);
541 packets_from_server.ClearPackets();
542 }
543 }
544 bool result = client_condition() && server_condition();
545 if (!result) {
546 QUIC_LOG(INFO) << "CommunicateHandshakeMessagesUnti failed with state: "
547 "client connected? "
548 << client_conn.connected() << " server connected? "
549 << server_conn.connected() << " client condition met? "
550 << client_condition() << " server condition met? "
551 << server_condition();
552 }
553 return result;
554 }
555
AdvanceHandshake(PacketSavingConnection * client_conn,QuicCryptoStream * client,size_t client_i,PacketSavingConnection * server_conn,QuicCryptoStream * server,size_t server_i)556 std::pair<size_t, size_t> AdvanceHandshake(PacketSavingConnection* client_conn,
557 QuicCryptoStream* client,
558 size_t client_i,
559 PacketSavingConnection* server_conn,
560 QuicCryptoStream* server,
561 size_t server_i) {
562 std::vector<QuicEncryptedPacket*> client_packets;
563 for (; client_i < client_conn->encrypted_packets_.size(); ++client_i) {
564 client_packets.push_back(client_conn->encrypted_packets_[client_i].get());
565 }
566 AdvanceHandshake(client_packets, *client_conn, *client, {}, *server_conn,
567 *server);
568
569 // Gather server packets separately to account for any packets sent on
570 // `server_conn` in response to the client packets.
571 std::vector<QuicEncryptedPacket*> server_packets;
572 for (; server_i < server_conn->encrypted_packets_.size(); ++server_i) {
573 server_packets.push_back(server_conn->encrypted_packets_[server_i].get());
574 }
575 AdvanceHandshake({}, *client_conn, *client, server_packets, *server_conn,
576 *server);
577
578 return std::make_pair(client_i, server_i);
579 }
580
AdvanceHandshake(absl::Span<const QuicEncryptedPacket * const> packets_from_client,QuicConnection & client_conn,QuicCryptoStream & client,absl::Span<const QuicEncryptedPacket * const> packets_from_server,QuicConnection & server_conn,QuicCryptoStream & server)581 void AdvanceHandshake(
582 absl::Span<const QuicEncryptedPacket* const> packets_from_client,
583 QuicConnection& client_conn, QuicCryptoStream& client,
584 absl::Span<const QuicEncryptedPacket* const> packets_from_server,
585 QuicConnection& server_conn, QuicCryptoStream& server) {
586 if (!packets_from_client.empty()) {
587 QUIC_LOG(INFO) << "Processing " << packets_from_client.size()
588 << " packets client->server";
589 MovePackets(client_conn, packets_from_client, server, server_conn,
590 Perspective::IS_SERVER, /*process_stream_data=*/false);
591 }
592
593 if (!packets_from_server.empty()) {
594 QUIC_LOG(INFO) << "Processing " << packets_from_server.size()
595 << " packets server->client";
596 MovePackets(server_conn, packets_from_server, client, client_conn,
597 Perspective::IS_CLIENT, /*process_stream_data=*/false);
598 }
599 }
600
GetValueForTag(const CryptoHandshakeMessage & message,QuicTag tag)601 std::string GetValueForTag(const CryptoHandshakeMessage& message, QuicTag tag) {
602 auto it = message.tag_value_map().find(tag);
603 if (it == message.tag_value_map().end()) {
604 return std::string();
605 }
606 return it->second;
607 }
608
LeafCertHashForTesting()609 uint64_t LeafCertHashForTesting() {
610 quiche::QuicheReferenceCountedPointer<ProofSource::Chain> chain;
611 QuicSocketAddress server_address(QuicIpAddress::Any4(), 42);
612 QuicSocketAddress client_address(QuicIpAddress::Any4(), 43);
613 QuicCryptoProof proof;
614 std::unique_ptr<ProofSource> proof_source(ProofSourceForTesting());
615
616 class Callback : public ProofSource::Callback {
617 public:
618 Callback(bool* ok,
619 quiche::QuicheReferenceCountedPointer<ProofSource::Chain>* chain)
620 : ok_(ok), chain_(chain) {}
621
622 void Run(
623 bool ok,
624 const quiche::QuicheReferenceCountedPointer<ProofSource::Chain>& chain,
625 const QuicCryptoProof& /* proof */,
626 std::unique_ptr<ProofSource::Details> /* details */) override {
627 *ok_ = ok;
628 *chain_ = chain;
629 }
630
631 private:
632 bool* ok_;
633 quiche::QuicheReferenceCountedPointer<ProofSource::Chain>* chain_;
634 };
635
636 // Note: relies on the callback being invoked synchronously
637 bool ok = false;
638 proof_source->GetProof(
639 server_address, client_address, "", "",
640 AllSupportedVersionsWithQuicCrypto().front().transport_version, "",
641 std::unique_ptr<ProofSource::Callback>(new Callback(&ok, &chain)));
642 if (!ok || chain->certs.empty()) {
643 QUICHE_DCHECK(false) << "Proof generation failed";
644 return 0;
645 }
646
647 return QuicUtils::FNV1a_64_Hash(chain->certs[0]);
648 }
649
FillInDummyReject(CryptoHandshakeMessage * rej)650 void FillInDummyReject(CryptoHandshakeMessage* rej) {
651 rej->set_tag(kREJ);
652
653 // Minimum SCFG that passes config validation checks.
654 // clang-format off
655 unsigned char scfg[] = {
656 // SCFG
657 0x53, 0x43, 0x46, 0x47,
658 // num entries
659 0x01, 0x00,
660 // padding
661 0x00, 0x00,
662 // EXPY
663 0x45, 0x58, 0x50, 0x59,
664 // EXPY end offset
665 0x08, 0x00, 0x00, 0x00,
666 // Value
667 '1', '2', '3', '4',
668 '5', '6', '7', '8'
669 };
670 // clang-format on
671 rej->SetValue(kSCFG, scfg);
672 rej->SetStringPiece(kServerNonceTag, "SERVER_NONCE");
673 int64_t ttl = 2 * 24 * 60 * 60;
674 rej->SetValue(kSTTL, ttl);
675 std::vector<QuicTag> reject_reasons;
676 reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
677 rej->SetVector(kRREJ, reject_reasons);
678 }
679
680 namespace {
681
682 #define RETURN_STRING_LITERAL(x) \
683 case x: \
684 return #x
685
EncryptionLevelString(EncryptionLevel level)686 std::string EncryptionLevelString(EncryptionLevel level) {
687 switch (level) {
688 RETURN_STRING_LITERAL(ENCRYPTION_INITIAL);
689 RETURN_STRING_LITERAL(ENCRYPTION_HANDSHAKE);
690 RETURN_STRING_LITERAL(ENCRYPTION_ZERO_RTT);
691 RETURN_STRING_LITERAL(ENCRYPTION_FORWARD_SECURE);
692 default:
693 return "";
694 }
695 }
696
CompareCrypters(const QuicEncrypter * encrypter,const QuicDecrypter * decrypter,std::string label)697 void CompareCrypters(const QuicEncrypter* encrypter,
698 const QuicDecrypter* decrypter, std::string label) {
699 if (encrypter == nullptr || decrypter == nullptr) {
700 ADD_FAILURE() << "Expected non-null crypters; have " << encrypter << " and "
701 << decrypter << " for " << label;
702 return;
703 }
704 absl::string_view encrypter_key = encrypter->GetKey();
705 absl::string_view encrypter_iv = encrypter->GetNoncePrefix();
706 absl::string_view decrypter_key = decrypter->GetKey();
707 absl::string_view decrypter_iv = decrypter->GetNoncePrefix();
708 quiche::test::CompareCharArraysWithHexError(
709 label + " key", encrypter_key.data(), encrypter_key.length(),
710 decrypter_key.data(), decrypter_key.length());
711 quiche::test::CompareCharArraysWithHexError(
712 label + " iv", encrypter_iv.data(), encrypter_iv.length(),
713 decrypter_iv.data(), decrypter_iv.length());
714 }
715
716 } // namespace
717
CompareClientAndServerKeys(QuicCryptoClientStreamBase * client,QuicCryptoServerStreamBase * server)718 void CompareClientAndServerKeys(QuicCryptoClientStreamBase* client,
719 QuicCryptoServerStreamBase* server) {
720 QuicFramer* client_framer = QuicConnectionPeer::GetFramer(
721 QuicStreamPeer::session(client)->connection());
722 QuicFramer* server_framer = QuicConnectionPeer::GetFramer(
723 QuicStreamPeer::session(server)->connection());
724 for (EncryptionLevel level :
725 {ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
726 SCOPED_TRACE(EncryptionLevelString(level));
727 const QuicEncrypter* client_encrypter(
728 QuicFramerPeer::GetEncrypter(client_framer, level));
729 const QuicDecrypter* server_decrypter(
730 QuicFramerPeer::GetDecrypter(server_framer, level));
731 if (level == ENCRYPTION_FORWARD_SECURE ||
732 !((level == ENCRYPTION_HANDSHAKE || level == ENCRYPTION_ZERO_RTT ||
733 client_encrypter == nullptr) &&
734 (level == ENCRYPTION_ZERO_RTT || server_decrypter == nullptr))) {
735 CompareCrypters(client_encrypter, server_decrypter,
736 "client " + EncryptionLevelString(level) + " write");
737 }
738 const QuicEncrypter* server_encrypter(
739 QuicFramerPeer::GetEncrypter(server_framer, level));
740 const QuicDecrypter* client_decrypter(
741 QuicFramerPeer::GetDecrypter(client_framer, level));
742 if (level == ENCRYPTION_FORWARD_SECURE ||
743 !(server_encrypter == nullptr &&
744 (level == ENCRYPTION_HANDSHAKE || level == ENCRYPTION_ZERO_RTT ||
745 client_decrypter == nullptr))) {
746 CompareCrypters(server_encrypter, client_decrypter,
747 "server " + EncryptionLevelString(level) + " write");
748 }
749 }
750
751 absl::string_view client_subkey_secret =
752 client->crypto_negotiated_params().subkey_secret;
753 absl::string_view server_subkey_secret =
754 server->crypto_negotiated_params().subkey_secret;
755 quiche::test::CompareCharArraysWithHexError(
756 "subkey secret", client_subkey_secret.data(),
757 client_subkey_secret.length(), server_subkey_secret.data(),
758 server_subkey_secret.length());
759 }
760
ParseTag(const char * tagstr)761 QuicTag ParseTag(const char* tagstr) {
762 const size_t len = strlen(tagstr);
763 QUICHE_CHECK_NE(0u, len);
764
765 QuicTag tag = 0;
766
767 if (tagstr[0] == '#') {
768 QUICHE_CHECK_EQ(static_cast<size_t>(1 + 2 * 4), len);
769 tagstr++;
770
771 for (size_t i = 0; i < 8; i++) {
772 tag <<= 4;
773
774 uint8_t v = 0;
775 QUICHE_CHECK(HexChar(tagstr[i], &v));
776 tag |= v;
777 }
778
779 return tag;
780 }
781
782 QUICHE_CHECK_LE(len, 4u);
783 for (size_t i = 0; i < 4; i++) {
784 tag >>= 8;
785 if (i < len) {
786 tag |= static_cast<uint32_t>(tagstr[i]) << 24;
787 }
788 }
789
790 return tag;
791 }
792
CreateCHLO(std::vector<std::pair<std::string,std::string>> tags_and_values)793 CryptoHandshakeMessage CreateCHLO(
794 std::vector<std::pair<std::string, std::string>> tags_and_values) {
795 return CreateCHLO(tags_and_values, -1);
796 }
797
CreateCHLO(std::vector<std::pair<std::string,std::string>> tags_and_values,int minimum_size_bytes)798 CryptoHandshakeMessage CreateCHLO(
799 std::vector<std::pair<std::string, std::string>> tags_and_values,
800 int minimum_size_bytes) {
801 CryptoHandshakeMessage msg;
802 msg.set_tag(MakeQuicTag('C', 'H', 'L', 'O'));
803
804 if (minimum_size_bytes > 0) {
805 msg.set_minimum_size(minimum_size_bytes);
806 }
807
808 for (const auto& tag_and_value : tags_and_values) {
809 const std::string& tag = tag_and_value.first;
810 const std::string& value = tag_and_value.second;
811
812 const QuicTag quic_tag = ParseTag(tag.c_str());
813
814 size_t value_len = value.length();
815 if (value_len > 0 && value[0] == '#') {
816 // This is ascii encoded hex.
817 std::string hex_value =
818 absl::HexStringToBytes(absl::string_view(&value[1]));
819 msg.SetStringPiece(quic_tag, hex_value);
820 continue;
821 }
822 msg.SetStringPiece(quic_tag, value);
823 }
824
825 // The CryptoHandshakeMessage needs to be serialized and parsed to ensure
826 // that any padding is included.
827 std::unique_ptr<QuicData> bytes =
828 CryptoFramer::ConstructHandshakeMessage(msg);
829 std::unique_ptr<CryptoHandshakeMessage> parsed(
830 CryptoFramer::ParseMessage(bytes->AsStringPiece()));
831 QUICHE_CHECK(parsed);
832
833 return *parsed;
834 }
835
GenerateDefaultInchoateCHLO(const QuicClock * clock,QuicTransportVersion version,QuicCryptoServerConfig * crypto_config)836 CryptoHandshakeMessage GenerateDefaultInchoateCHLO(
837 const QuicClock* clock, QuicTransportVersion version,
838 QuicCryptoServerConfig* crypto_config) {
839 // clang-format off
840 return CreateCHLO(
841 {{"PDMD", "X509"},
842 {"AEAD", "AESG"},
843 {"KEXS", "C255"},
844 {"PUBS", GenerateClientPublicValuesHex().c_str()},
845 {"NONC", GenerateClientNonceHex(clock, crypto_config).c_str()},
846 {"VER\0", QuicVersionLabelToString(
847 CreateQuicVersionLabel(
848 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version))).c_str()}},
849 kClientHelloMinimumSize);
850 // clang-format on
851 }
852
GenerateClientNonceHex(const QuicClock * clock,QuicCryptoServerConfig * crypto_config)853 std::string GenerateClientNonceHex(const QuicClock* clock,
854 QuicCryptoServerConfig* crypto_config) {
855 QuicCryptoServerConfig::ConfigOptions old_config_options;
856 QuicCryptoServerConfig::ConfigOptions new_config_options;
857 old_config_options.id = "old-config-id";
858 crypto_config->AddDefaultConfig(QuicRandom::GetInstance(), clock,
859 old_config_options);
860 QuicServerConfigProtobuf primary_config = crypto_config->GenerateConfig(
861 QuicRandom::GetInstance(), clock, new_config_options);
862 primary_config.set_primary_time(clock->WallNow().ToUNIXSeconds());
863 std::unique_ptr<CryptoHandshakeMessage> msg =
864 crypto_config->AddConfig(primary_config, clock->WallNow());
865 absl::string_view orbit;
866 QUICHE_CHECK(msg->GetStringPiece(kORBT, &orbit));
867 std::string nonce;
868 CryptoUtils::GenerateNonce(clock->WallNow(), QuicRandom::GetInstance(), orbit,
869 &nonce);
870 return ("#" + absl::BytesToHexString(nonce));
871 }
872
GenerateClientPublicValuesHex()873 std::string GenerateClientPublicValuesHex() {
874 char public_value[32];
875 memset(public_value, 42, sizeof(public_value));
876 return ("#" + absl::BytesToHexString(
877 absl::string_view(public_value, sizeof(public_value))));
878 }
879
GenerateFullCHLO(const CryptoHandshakeMessage & inchoate_chlo,QuicCryptoServerConfig * crypto_config,QuicSocketAddress server_addr,QuicSocketAddress client_addr,QuicTransportVersion transport_version,const QuicClock * clock,quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> signed_config,QuicCompressedCertsCache * compressed_certs_cache,CryptoHandshakeMessage * out)880 void GenerateFullCHLO(
881 const CryptoHandshakeMessage& inchoate_chlo,
882 QuicCryptoServerConfig* crypto_config, QuicSocketAddress server_addr,
883 QuicSocketAddress client_addr, QuicTransportVersion transport_version,
884 const QuicClock* clock,
885 quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> signed_config,
886 QuicCompressedCertsCache* compressed_certs_cache,
887 CryptoHandshakeMessage* out) {
888 // Pass a inchoate CHLO.
889 FullChloGenerator generator(
890 crypto_config, server_addr, client_addr, clock,
891 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, transport_version), signed_config,
892 compressed_certs_cache, out);
893 crypto_config->ValidateClientHello(
894 inchoate_chlo, client_addr, server_addr, transport_version, clock,
895 signed_config, generator.GetValidateClientHelloCallback());
896 }
897
898 namespace {
899
900 constexpr char kTestProofHostname[] = "test.example.com";
901
902 class TestProofSource : public ProofSourceX509 {
903 public:
TestProofSource()904 TestProofSource()
905 : ProofSourceX509(
906 quiche::QuicheReferenceCountedPointer<ProofSource::Chain>(
907 new ProofSource::Chain(
908 std::vector<std::string>{std::string(kTestCertificate)})),
909 std::move(*CertificatePrivateKey::LoadFromDer(
910 kTestCertificatePrivateKey))) {
911 QUICHE_DCHECK(valid());
912 }
913
914 protected:
MaybeAddSctsForHostname(absl::string_view,std::string & leaf_cert_scts)915 void MaybeAddSctsForHostname(absl::string_view /*hostname*/,
916 std::string& leaf_cert_scts) override {
917 leaf_cert_scts = "Certificate Transparency is really nice";
918 }
919 };
920
921 class TestProofVerifier : public ProofVerifier {
922 public:
TestProofVerifier()923 TestProofVerifier()
924 : certificate_(std::move(
925 *CertificateView::ParseSingleCertificate(kTestCertificate))) {}
926
927 class Details : public ProofVerifyDetails {
928 public:
Clone() const929 ProofVerifyDetails* Clone() const override { return new Details(*this); }
930 };
931
VerifyProof(const std::string & hostname,const uint16_t port,const std::string & server_config,QuicTransportVersion,absl::string_view chlo_hash,const std::vector<std::string> & certs,const std::string & cert_sct,const std::string & signature,const ProofVerifyContext * context,std::string * error_details,std::unique_ptr<ProofVerifyDetails> * details,std::unique_ptr<ProofVerifierCallback> callback)932 QuicAsyncStatus VerifyProof(
933 const std::string& hostname, const uint16_t port,
934 const std::string& server_config,
935 QuicTransportVersion /*transport_version*/, absl::string_view chlo_hash,
936 const std::vector<std::string>& certs, const std::string& cert_sct,
937 const std::string& signature, const ProofVerifyContext* context,
938 std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details,
939 std::unique_ptr<ProofVerifierCallback> callback) override {
940 std::optional<std::string> payload =
941 CryptoUtils::GenerateProofPayloadToBeSigned(chlo_hash, server_config);
942 if (!payload.has_value()) {
943 *error_details = "Failed to serialize signed payload";
944 return QUIC_FAILURE;
945 }
946 if (!certificate_.VerifySignature(*payload, signature,
947 SSL_SIGN_RSA_PSS_RSAE_SHA256)) {
948 *error_details = "Invalid signature";
949 return QUIC_FAILURE;
950 }
951
952 uint8_t out_alert;
953 return VerifyCertChain(hostname, port, certs, /*ocsp_response=*/"",
954 cert_sct, context, error_details, details,
955 &out_alert, std::move(callback));
956 }
957
VerifyCertChain(const std::string & hostname,const uint16_t,const std::vector<std::string> & certs,const std::string &,const std::string &,const ProofVerifyContext *,std::string * error_details,std::unique_ptr<ProofVerifyDetails> * details,uint8_t *,std::unique_ptr<ProofVerifierCallback>)958 QuicAsyncStatus VerifyCertChain(
959 const std::string& hostname, const uint16_t /*port*/,
960 const std::vector<std::string>& certs,
961 const std::string& /*ocsp_response*/, const std::string& /*cert_sct*/,
962 const ProofVerifyContext* /*context*/, std::string* error_details,
963 std::unique_ptr<ProofVerifyDetails>* details, uint8_t* /*out_alert*/,
964 std::unique_ptr<ProofVerifierCallback> /*callback*/) override {
965 std::string normalized_hostname =
966 QuicHostnameUtils::NormalizeHostname(hostname);
967 if (normalized_hostname != kTestProofHostname) {
968 *error_details = absl::StrCat("Invalid hostname, expected ",
969 kTestProofHostname, " got ", hostname);
970 return QUIC_FAILURE;
971 }
972 if (certs.empty() || certs.front() != kTestCertificate) {
973 *error_details = "Received certificate different from the expected";
974 return QUIC_FAILURE;
975 }
976 *details = std::make_unique<Details>();
977 return QUIC_SUCCESS;
978 }
979
CreateDefaultContext()980 std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
981 return nullptr;
982 }
983
984 private:
985 CertificateView certificate_;
986 };
987
988 } // namespace
989
ProofSourceForTesting()990 std::unique_ptr<ProofSource> ProofSourceForTesting() {
991 return std::make_unique<TestProofSource>();
992 }
993
ProofVerifierForTesting()994 std::unique_ptr<ProofVerifier> ProofVerifierForTesting() {
995 return std::make_unique<TestProofVerifier>();
996 }
997
CertificateHostnameForTesting()998 std::string CertificateHostnameForTesting() { return kTestProofHostname; }
999
ProofVerifyContextForTesting()1000 std::unique_ptr<ProofVerifyContext> ProofVerifyContextForTesting() {
1001 return nullptr;
1002 }
1003
1004 } // namespace crypto_test_utils
1005 } // namespace test
1006 } // namespace quic
1007