blob: 64718143a0147e5fba90a285b2cba28cb6532198 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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 "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
6
7#include <memory>
8#include <string>
9
10#include "third_party/boringssl/src/include/openssl/bn.h"
11#include "third_party/boringssl/src/include/openssl/ec.h"
12#include "third_party/boringssl/src/include/openssl/ecdsa.h"
13#include "third_party/boringssl/src/include/openssl/nid.h"
14#include "third_party/boringssl/src/include/openssl/sha.h"
15#include "net/third_party/quiche/src/quic/core/crypto/channel_id.h"
16#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set.h"
17#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
18#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
19#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
20#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
21#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
22#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.pb.h"
23#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
24#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h"
25#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
26#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
27#include "net/third_party/quiche/src/quic/core/quic_utils.h"
28#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
29#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
30#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
31#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
32#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
33#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
34#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
35#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
36#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
37#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
38#include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h"
39#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h"
40#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
41#include "net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h"
42
43namespace quic {
44namespace test {
45
QUICHE teama6ef0a62019-03-07 20:34:33 -050046namespace crypto_test_utils {
47
48namespace {
49
50// CryptoFramerVisitor is a framer visitor that records handshake messages.
51class CryptoFramerVisitor : public CryptoFramerVisitorInterface {
52 public:
53 CryptoFramerVisitor() : error_(false) {}
54
55 void OnError(CryptoFramer* framer) override { error_ = true; }
56
57 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
58 messages_.push_back(message);
59 }
60
61 bool error() const { return error_; }
62
63 const std::vector<CryptoHandshakeMessage>& messages() const {
64 return messages_;
65 }
66
67 private:
68 bool error_;
69 std::vector<CryptoHandshakeMessage> messages_;
70};
71
72// HexChar parses |c| as a hex character. If valid, it sets |*value| to the
73// value of the hex character and returns true. Otherwise it returns false.
74bool HexChar(char c, uint8_t* value) {
75 if (c >= '0' && c <= '9') {
76 *value = c - '0';
77 return true;
78 }
79 if (c >= 'a' && c <= 'f') {
80 *value = c - 'a' + 10;
81 return true;
82 }
83 if (c >= 'A' && c <= 'F') {
84 *value = c - 'A' + 10;
85 return true;
86 }
87 return false;
88}
89
QUICHE teama6ef0a62019-03-07 20:34:33 -050090} // anonymous namespace
91
nharper6153bc72019-05-08 12:04:34 -070092FakeClientOptions::FakeClientOptions() {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050093
94FakeClientOptions::~FakeClientOptions() {}
95
96namespace {
97// This class is used by GenerateFullCHLO() to extract SCID and STK from
98// REJ/SREJ and to construct a full CHLO with these fields and given inchoate
99// CHLO.
100class FullChloGenerator {
101 public:
102 FullChloGenerator(
103 QuicCryptoServerConfig* crypto_config,
104 QuicSocketAddress server_addr,
105 QuicSocketAddress client_addr,
106 const QuicClock* clock,
107 QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
108 QuicCompressedCertsCache* compressed_certs_cache,
109 CryptoHandshakeMessage* out)
110 : crypto_config_(crypto_config),
111 server_addr_(server_addr),
112 client_addr_(client_addr),
113 clock_(clock),
114 signed_config_(signed_config),
115 compressed_certs_cache_(compressed_certs_cache),
116 out_(out),
117 params_(new QuicCryptoNegotiatedParameters) {}
118
119 class ValidateClientHelloCallback : public ValidateClientHelloResultCallback {
120 public:
121 explicit ValidateClientHelloCallback(FullChloGenerator* generator)
122 : generator_(generator) {}
123 void Run(QuicReferenceCountedPointer<
124 ValidateClientHelloResultCallback::Result> result,
125 std::unique_ptr<ProofSource::Details> /* details */) override {
126 generator_->ValidateClientHelloDone(std::move(result));
127 }
128
129 private:
130 FullChloGenerator* generator_;
131 };
132
133 std::unique_ptr<ValidateClientHelloCallback>
134 GetValidateClientHelloCallback() {
135 return QuicMakeUnique<ValidateClientHelloCallback>(this);
136 }
137
138 private:
139 void ValidateClientHelloDone(
140 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
141 result) {
142 result_ = result;
143 crypto_config_->ProcessClientHello(
144 result_, /*reject_only=*/false, TestConnectionId(1), server_addr_,
145 client_addr_, AllSupportedVersions().front(), AllSupportedVersions(),
146 /*use_stateless_rejects=*/true,
147 /*server_designated_connection_id=*/TestConnectionId(2), clock_,
148 QuicRandom::GetInstance(), compressed_certs_cache_, params_,
149 signed_config_, /*total_framing_overhead=*/50, kDefaultMaxPacketSize,
150 GetProcessClientHelloCallback());
151 }
152
153 class ProcessClientHelloCallback : public ProcessClientHelloResultCallback {
154 public:
155 explicit ProcessClientHelloCallback(FullChloGenerator* generator)
156 : generator_(generator) {}
157 void Run(
158 QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700159 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500160 std::unique_ptr<CryptoHandshakeMessage> message,
161 std::unique_ptr<DiversificationNonce> diversification_nonce,
162 std::unique_ptr<ProofSource::Details> proof_source_details) override {
163 generator_->ProcessClientHelloDone(std::move(message));
164 }
165
166 private:
167 FullChloGenerator* generator_;
168 };
169
170 std::unique_ptr<ProcessClientHelloCallback> GetProcessClientHelloCallback() {
171 return QuicMakeUnique<ProcessClientHelloCallback>(this);
172 }
173
174 void ProcessClientHelloDone(std::unique_ptr<CryptoHandshakeMessage> rej) {
175 // Verify output is a REJ or SREJ.
176 EXPECT_THAT(rej->tag(),
177 testing::AnyOf(testing::Eq(kSREJ), testing::Eq(kREJ)));
178
nharperff86db32019-05-08 10:38:23 -0700179 QUIC_VLOG(1) << "Extract valid STK and SCID from\n" << rej->DebugString();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500180 QuicStringPiece srct;
181 ASSERT_TRUE(rej->GetStringPiece(kSourceAddressTokenTag, &srct));
182
183 QuicStringPiece scfg;
184 ASSERT_TRUE(rej->GetStringPiece(kSCFG, &scfg));
185 std::unique_ptr<CryptoHandshakeMessage> server_config(
186 CryptoFramer::ParseMessage(scfg));
187
188 QuicStringPiece scid;
189 ASSERT_TRUE(server_config->GetStringPiece(kSCID, &scid));
190
191 *out_ = result_->client_hello;
192 out_->SetStringPiece(kSCID, scid);
193 out_->SetStringPiece(kSourceAddressTokenTag, srct);
194 uint64_t xlct = LeafCertHashForTesting();
195 out_->SetValue(kXLCT, xlct);
196 }
197
198 protected:
199 QuicCryptoServerConfig* crypto_config_;
200 QuicSocketAddress server_addr_;
201 QuicSocketAddress client_addr_;
202 const QuicClock* clock_;
203 QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_;
204 QuicCompressedCertsCache* compressed_certs_cache_;
205 CryptoHandshakeMessage* out_;
206
207 QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
208 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
209 result_;
210};
211
212} // namespace
213
214int HandshakeWithFakeServer(QuicConfig* server_quic_config,
215 MockQuicConnectionHelper* helper,
216 MockAlarmFactory* alarm_factory,
217 PacketSavingConnection* client_conn,
nharperba5f32c2019-05-13 12:21:31 -0700218 QuicCryptoClientStream* client) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500219 PacketSavingConnection* server_conn = new PacketSavingConnection(
220 helper, alarm_factory, Perspective::IS_SERVER,
221 ParsedVersionOfIndex(client_conn->supported_versions(), 0));
222
223 QuicCryptoServerConfig crypto_config(
224 QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
225 ProofSourceForTesting(), KeyExchangeSource::Default(),
226 TlsServerHandshaker::CreateSslCtx());
227 QuicCompressedCertsCache compressed_certs_cache(
228 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
nharperba5f32c2019-05-13 12:21:31 -0700229 SetupCryptoServerConfigForTest(
230 server_conn->clock(), server_conn->random_generator(), &crypto_config);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500231
232 TestQuicSpdyServerSession server_session(
233 server_conn, *server_quic_config, client_conn->supported_versions(),
234 &crypto_config, &compressed_certs_cache);
235 server_session.OnSuccessfulVersionNegotiation(
236 client_conn->supported_versions().front());
237 EXPECT_CALL(*server_session.helper(),
238 CanAcceptClientHello(testing::_, testing::_, testing::_,
239 testing::_, testing::_))
240 .Times(testing::AnyNumber());
241 EXPECT_CALL(*server_session.helper(),
242 GenerateConnectionIdForReject(testing::_, testing::_))
243 .Times(testing::AnyNumber());
244 EXPECT_CALL(*server_conn, OnCanWrite()).Times(testing::AnyNumber());
245 EXPECT_CALL(*client_conn, OnCanWrite()).Times(testing::AnyNumber());
246
247 // The client's handshake must have been started already.
248 CHECK_NE(0u, client_conn->encrypted_packets_.size());
249
250 CommunicateHandshakeMessages(client_conn, client, server_conn,
251 server_session.GetMutableCryptoStream());
252 CompareClientAndServerKeys(client, server_session.GetMutableCryptoStream());
253
254 return client->num_sent_client_hellos();
255}
256
257int HandshakeWithFakeClient(MockQuicConnectionHelper* helper,
258 MockAlarmFactory* alarm_factory,
259 PacketSavingConnection* server_conn,
260 QuicCryptoServerStream* server,
261 const QuicServerId& server_id,
262 const FakeClientOptions& options) {
263 ParsedQuicVersionVector supported_versions = AllSupportedVersions();
264 if (options.only_tls_versions) {
265 supported_versions.clear();
266 for (QuicTransportVersion transport_version :
267 AllSupportedTransportVersions()) {
268 supported_versions.push_back(
269 ParsedQuicVersion(PROTOCOL_TLS1_3, transport_version));
270 }
271 }
272 PacketSavingConnection* client_conn = new PacketSavingConnection(
273 helper, alarm_factory, Perspective::IS_CLIENT, supported_versions);
274 // Advance the time, because timers do not like uninitialized times.
275 client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1));
276
277 QuicCryptoClientConfig crypto_config(ProofVerifierForTesting(),
278 TlsClientHandshaker::CreateSslCtx());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500279 TestQuicSpdyClientSession client_session(client_conn, DefaultQuicConfig(),
280 supported_versions, server_id,
281 &crypto_config);
282
283 EXPECT_CALL(client_session, OnProofValid(testing::_))
284 .Times(testing::AnyNumber());
285 EXPECT_CALL(client_session, OnProofVerifyDetailsAvailable(testing::_))
286 .Times(testing::AnyNumber());
287 EXPECT_CALL(*client_conn, OnCanWrite()).Times(testing::AnyNumber());
288 client_session.GetMutableCryptoStream()->CryptoConnect();
289 CHECK_EQ(1u, client_conn->encrypted_packets_.size());
290
nharper6153bc72019-05-08 12:04:34 -0700291 CommunicateHandshakeMessages(client_conn,
292 client_session.GetMutableCryptoStream(),
293 server_conn, server);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500294
295 if (server->handshake_confirmed() && server->encryption_established()) {
296 CompareClientAndServerKeys(client_session.GetMutableCryptoStream(), server);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500297 }
298
299 return client_session.GetCryptoStream()->num_sent_client_hellos();
300}
301
302void SetupCryptoServerConfigForTest(const QuicClock* clock,
303 QuicRandom* rand,
nharperba5f32c2019-05-13 12:21:31 -0700304 QuicCryptoServerConfig* crypto_config) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500305 QuicCryptoServerConfig::ConfigOptions options;
306 options.channel_id_enabled = true;
QUICHE teamd5af58a2019-03-14 20:35:50 -0700307 std::unique_ptr<CryptoHandshakeMessage> scfg =
308 crypto_config->AddDefaultConfig(rand, clock, options);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500309}
310
311void SendHandshakeMessageToStream(QuicCryptoStream* stream,
312 const CryptoHandshakeMessage& message,
313 Perspective perspective) {
314 const QuicData& data = message.GetSerialized();
315 QuicSession* session = QuicStreamPeer::session(stream);
QUICHE teamea740082019-03-11 17:58:43 -0700316 if (!QuicVersionUsesCryptoFrames(
317 session->connection()->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500318 QuicStreamFrame frame(QuicUtils::GetCryptoStreamId(
319 session->connection()->transport_version()),
320 false, stream->crypto_bytes_read(),
321 data.AsStringPiece());
322 stream->OnStreamFrame(frame);
323 } else {
324 EncryptionLevel level = session->connection()->last_decrypted_level();
325 QuicCryptoFrame frame(level, stream->BytesReadOnLevel(level),
326 data.AsStringPiece());
327 stream->OnCryptoFrame(frame);
328 }
329}
330
331void CommunicateHandshakeMessages(PacketSavingConnection* client_conn,
332 QuicCryptoStream* client,
333 PacketSavingConnection* server_conn,
334 QuicCryptoStream* server) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500335 size_t client_i = 0, server_i = 0;
336 while (!client->handshake_confirmed() || !server->handshake_confirmed()) {
337 ASSERT_GT(client_conn->encrypted_packets_.size(), client_i);
338 QUIC_LOG(INFO) << "Processing "
339 << client_conn->encrypted_packets_.size() - client_i
340 << " packets client->server";
341 MovePackets(client_conn, &client_i, server, server_conn,
342 Perspective::IS_SERVER);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500343
344 if (client->handshake_confirmed() && server->handshake_confirmed()) {
345 break;
346 }
347 ASSERT_GT(server_conn->encrypted_packets_.size(), server_i);
348 QUIC_LOG(INFO) << "Processing "
349 << server_conn->encrypted_packets_.size() - server_i
350 << " packets server->client";
351 MovePackets(server_conn, &server_i, client, client_conn,
352 Perspective::IS_CLIENT);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500353 }
354}
355
356std::pair<size_t, size_t> AdvanceHandshake(PacketSavingConnection* client_conn,
357 QuicCryptoStream* client,
358 size_t client_i,
359 PacketSavingConnection* server_conn,
360 QuicCryptoStream* server,
361 size_t server_i) {
362 QUIC_LOG(INFO) << "Processing "
363 << client_conn->encrypted_packets_.size() - client_i
364 << " packets client->server";
365 MovePackets(client_conn, &client_i, server, server_conn,
366 Perspective::IS_SERVER);
367
368 QUIC_LOG(INFO) << "Processing "
369 << server_conn->encrypted_packets_.size() - server_i
370 << " packets server->client";
371 if (server_conn->encrypted_packets_.size() - server_i == 2) {
372 QUIC_LOG(INFO) << "here";
373 }
374 MovePackets(server_conn, &server_i, client, client_conn,
375 Perspective::IS_CLIENT);
376
377 return std::make_pair(client_i, server_i);
378}
379
vasilvvc48c8712019-03-11 13:38:16 -0700380std::string GetValueForTag(const CryptoHandshakeMessage& message, QuicTag tag) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500381 auto it = message.tag_value_map().find(tag);
382 if (it == message.tag_value_map().end()) {
vasilvvc48c8712019-03-11 13:38:16 -0700383 return std::string();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500384 }
385 return it->second;
386}
387
388uint64_t LeafCertHashForTesting() {
389 QuicReferenceCountedPointer<ProofSource::Chain> chain;
390 QuicSocketAddress server_address(QuicIpAddress::Any4(), 42);
391 QuicCryptoProof proof;
392 std::unique_ptr<ProofSource> proof_source(ProofSourceForTesting());
393
394 class Callback : public ProofSource::Callback {
395 public:
396 Callback(bool* ok, QuicReferenceCountedPointer<ProofSource::Chain>* chain)
397 : ok_(ok), chain_(chain) {}
398
399 void Run(bool ok,
400 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
401 const QuicCryptoProof& /* proof */,
402 std::unique_ptr<ProofSource::Details> /* details */) override {
403 *ok_ = ok;
404 *chain_ = chain;
405 }
406
407 private:
408 bool* ok_;
409 QuicReferenceCountedPointer<ProofSource::Chain>* chain_;
410 };
411
412 // Note: relies on the callback being invoked synchronously
413 bool ok = false;
414 proof_source->GetProof(
415 server_address, "", "", AllSupportedTransportVersions().front(), "",
416 std::unique_ptr<ProofSource::Callback>(new Callback(&ok, &chain)));
417 if (!ok || chain->certs.empty()) {
418 DCHECK(false) << "Proof generation failed";
419 return 0;
420 }
421
422 return QuicUtils::FNV1a_64_Hash(chain->certs.at(0));
423}
424
425class MockCommonCertSets : public CommonCertSets {
426 public:
427 MockCommonCertSets(QuicStringPiece cert, uint64_t hash, uint32_t index)
428 : cert_(cert), hash_(hash), index_(index) {}
429
430 QuicStringPiece GetCommonHashes() const override {
431 QUIC_BUG << "not implemented";
432 return QuicStringPiece();
433 }
434
435 QuicStringPiece GetCert(uint64_t hash, uint32_t index) const override {
436 if (hash == hash_ && index == index_) {
437 return cert_;
438 }
439 return QuicStringPiece();
440 }
441
442 bool MatchCert(QuicStringPiece cert,
443 QuicStringPiece common_set_hashes,
444 uint64_t* out_hash,
445 uint32_t* out_index) const override {
446 if (cert != cert_) {
447 return false;
448 }
449
450 if (common_set_hashes.size() % sizeof(uint64_t) != 0) {
451 return false;
452 }
453 bool client_has_set = false;
454 for (size_t i = 0; i < common_set_hashes.size(); i += sizeof(uint64_t)) {
455 uint64_t hash;
456 memcpy(&hash, common_set_hashes.data() + i, sizeof(hash));
457 if (hash == hash_) {
458 client_has_set = true;
459 break;
460 }
461 }
462
463 if (!client_has_set) {
464 return false;
465 }
466
467 *out_hash = hash_;
468 *out_index = index_;
469 return true;
470 }
471
472 private:
vasilvvc48c8712019-03-11 13:38:16 -0700473 const std::string cert_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500474 const uint64_t hash_;
475 const uint32_t index_;
476};
477
478CommonCertSets* MockCommonCertSets(QuicStringPiece cert,
479 uint64_t hash,
480 uint32_t index) {
481 return new class MockCommonCertSets(cert, hash, index);
482}
483
wub9b9cc812019-05-20 09:01:52 -0700484void FillInDummyReject(CryptoHandshakeMessage* rej) {
485 rej->set_tag(kREJ);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500486
487 // Minimum SCFG that passes config validation checks.
488 // clang-format off
489 unsigned char scfg[] = {
490 // SCFG
491 0x53, 0x43, 0x46, 0x47,
492 // num entries
493 0x01, 0x00,
494 // padding
495 0x00, 0x00,
496 // EXPY
497 0x45, 0x58, 0x50, 0x59,
498 // EXPY end offset
499 0x08, 0x00, 0x00, 0x00,
500 // Value
501 '1', '2', '3', '4',
502 '5', '6', '7', '8'
503 };
504 // clang-format on
505 rej->SetValue(kSCFG, scfg);
506 rej->SetStringPiece(kServerNonceTag, "SERVER_NONCE");
507 int64_t ttl = 2 * 24 * 60 * 60;
508 rej->SetValue(kSTTL, ttl);
509 std::vector<QuicTag> reject_reasons;
510 reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
511 rej->SetVector(kRREJ, reject_reasons);
512}
513
QUICHE teamfbfd3622019-03-26 10:59:32 -0700514namespace {
515
516#define RETURN_STRING_LITERAL(x) \
517 case x: \
518 return #x
519
520std::string EncryptionLevelString(EncryptionLevel level) {
521 switch (level) {
522 RETURN_STRING_LITERAL(ENCRYPTION_INITIAL);
523 RETURN_STRING_LITERAL(ENCRYPTION_HANDSHAKE);
524 RETURN_STRING_LITERAL(ENCRYPTION_ZERO_RTT);
525 RETURN_STRING_LITERAL(ENCRYPTION_FORWARD_SECURE);
526 default:
527 return "";
528 }
529}
530
531void CompareCrypters(const QuicEncrypter* encrypter,
532 const QuicDecrypter* decrypter,
533 std::string label) {
zhongyi546cc452019-04-12 15:27:49 -0700534 if (encrypter == nullptr || decrypter == nullptr) {
535 ADD_FAILURE() << "Expected non-null crypters; have " << encrypter << " and "
536 << decrypter;
537 return;
538 }
QUICHE teamfbfd3622019-03-26 10:59:32 -0700539 QuicStringPiece encrypter_key = encrypter->GetKey();
540 QuicStringPiece encrypter_iv = encrypter->GetNoncePrefix();
541 QuicStringPiece decrypter_key = decrypter->GetKey();
542 QuicStringPiece decrypter_iv = decrypter->GetNoncePrefix();
543 CompareCharArraysWithHexError(label + " key", encrypter_key.data(),
544 encrypter_key.length(), decrypter_key.data(),
545 decrypter_key.length());
546 CompareCharArraysWithHexError(label + " iv", encrypter_iv.data(),
547 encrypter_iv.length(), decrypter_iv.data(),
548 decrypter_iv.length());
549}
550
551} // namespace
552
QUICHE teama6ef0a62019-03-07 20:34:33 -0500553void CompareClientAndServerKeys(QuicCryptoClientStream* client,
554 QuicCryptoServerStream* server) {
555 QuicFramer* client_framer = QuicConnectionPeer::GetFramer(
556 QuicStreamPeer::session(client)->connection());
557 QuicFramer* server_framer = QuicConnectionPeer::GetFramer(
558 QuicStreamPeer::session(server)->connection());
QUICHE teamfbfd3622019-03-26 10:59:32 -0700559 for (EncryptionLevel level :
560 {ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
561 SCOPED_TRACE(EncryptionLevelString(level));
562 const QuicEncrypter* client_encrypter(
563 QuicFramerPeer::GetEncrypter(client_framer, level));
564 const QuicDecrypter* server_decrypter(
565 QuicFramerPeer::GetDecrypter(server_framer, level));
566 if (level == ENCRYPTION_FORWARD_SECURE ||
567 !(client_encrypter == nullptr && server_decrypter == nullptr)) {
568 CompareCrypters(client_encrypter, server_decrypter,
569 "client " + EncryptionLevelString(level) + " write");
570 }
571 const QuicEncrypter* server_encrypter(
572 QuicFramerPeer::GetEncrypter(server_framer, level));
573 const QuicDecrypter* client_decrypter(
574 QuicFramerPeer::GetDecrypter(client_framer, level));
575 if (level == ENCRYPTION_FORWARD_SECURE ||
576 !(server_encrypter == nullptr && client_decrypter == nullptr)) {
577 CompareCrypters(server_encrypter, client_decrypter,
578 "server " + EncryptionLevelString(level) + " write");
579 }
580 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500581
582 QuicStringPiece client_subkey_secret =
583 client->crypto_negotiated_params().subkey_secret;
584 QuicStringPiece server_subkey_secret =
585 server->crypto_negotiated_params().subkey_secret;
QUICHE teamfbfd3622019-03-26 10:59:32 -0700586 CompareCharArraysWithHexError("subkey secret", client_subkey_secret.data(),
587 client_subkey_secret.length(),
588 server_subkey_secret.data(),
589 server_subkey_secret.length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500590
591 const char kSampleLabel[] = "label";
592 const char kSampleContext[] = "context";
593 const size_t kSampleOutputLength = 32;
vasilvvc48c8712019-03-11 13:38:16 -0700594 std::string client_key_extraction;
595 std::string server_key_extraction;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500596 EXPECT_TRUE(client->ExportKeyingMaterial(kSampleLabel, kSampleContext,
597 kSampleOutputLength,
598 &client_key_extraction));
599 EXPECT_TRUE(server->ExportKeyingMaterial(kSampleLabel, kSampleContext,
600 kSampleOutputLength,
601 &server_key_extraction));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500602 CompareCharArraysWithHexError(
603 "sample key extraction", client_key_extraction.data(),
604 client_key_extraction.length(), server_key_extraction.data(),
605 server_key_extraction.length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500606}
607
608QuicTag ParseTag(const char* tagstr) {
609 const size_t len = strlen(tagstr);
610 CHECK_NE(0u, len);
611
612 QuicTag tag = 0;
613
614 if (tagstr[0] == '#') {
615 CHECK_EQ(static_cast<size_t>(1 + 2 * 4), len);
616 tagstr++;
617
618 for (size_t i = 0; i < 8; i++) {
619 tag <<= 4;
620
621 uint8_t v = 0;
622 CHECK(HexChar(tagstr[i], &v));
623 tag |= v;
624 }
625
626 return tag;
627 }
628
629 CHECK_LE(len, 4u);
630 for (size_t i = 0; i < 4; i++) {
631 tag >>= 8;
632 if (i < len) {
633 tag |= static_cast<uint32_t>(tagstr[i]) << 24;
634 }
635 }
636
637 return tag;
638}
639
640CryptoHandshakeMessage CreateCHLO(
vasilvvc48c8712019-03-11 13:38:16 -0700641 std::vector<std::pair<std::string, std::string>> tags_and_values) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500642 return CreateCHLO(tags_and_values, -1);
643}
644
645CryptoHandshakeMessage CreateCHLO(
vasilvvc48c8712019-03-11 13:38:16 -0700646 std::vector<std::pair<std::string, std::string>> tags_and_values,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500647 int minimum_size_bytes) {
648 CryptoHandshakeMessage msg;
649 msg.set_tag(MakeQuicTag('C', 'H', 'L', 'O'));
650
651 if (minimum_size_bytes > 0) {
652 msg.set_minimum_size(minimum_size_bytes);
653 }
654
655 for (const auto& tag_and_value : tags_and_values) {
vasilvvc48c8712019-03-11 13:38:16 -0700656 const std::string& tag = tag_and_value.first;
657 const std::string& value = tag_and_value.second;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500658
659 const QuicTag quic_tag = ParseTag(tag.c_str());
660
661 size_t value_len = value.length();
662 if (value_len > 0 && value[0] == '#') {
663 // This is ascii encoded hex.
vasilvvc48c8712019-03-11 13:38:16 -0700664 std::string hex_value =
QUICHE teama6ef0a62019-03-07 20:34:33 -0500665 QuicTextUtils::HexDecode(QuicStringPiece(&value[1]));
666 msg.SetStringPiece(quic_tag, hex_value);
667 continue;
668 }
669 msg.SetStringPiece(quic_tag, value);
670 }
671
672 // The CryptoHandshakeMessage needs to be serialized and parsed to ensure
673 // that any padding is included.
QUICHE team3fe6a8b2019-03-14 09:10:38 -0700674 std::unique_ptr<QuicData> bytes =
675 CryptoFramer::ConstructHandshakeMessage(msg);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500676 std::unique_ptr<CryptoHandshakeMessage> parsed(
677 CryptoFramer::ParseMessage(bytes->AsStringPiece()));
678 CHECK(parsed);
679
680 return *parsed;
681}
682
QUICHE teama6ef0a62019-03-07 20:34:33 -0500683void MovePackets(PacketSavingConnection* source_conn,
684 size_t* inout_packet_index,
685 QuicCryptoStream* dest_stream,
686 PacketSavingConnection* dest_conn,
687 Perspective dest_perspective) {
688 SimpleQuicFramer framer(source_conn->supported_versions(), dest_perspective);
689
690 SimpleQuicFramer null_encryption_framer(source_conn->supported_versions(),
691 dest_perspective);
692
693 size_t index = *inout_packet_index;
694 for (; index < source_conn->encrypted_packets_.size(); index++) {
695 // In order to properly test the code we need to perform encryption and
696 // decryption so that the crypters latch when expected. The crypters are in
697 // |dest_conn|, but we don't want to try and use them there. Instead we swap
698 // them into |framer|, perform the decryption with them, and then swap ther
699 // back.
700 QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
701 if (!framer.ProcessPacket(*source_conn->encrypted_packets_[index])) {
702 // The framer will be unable to decrypt forward-secure packets sent after
703 // the handshake is complete. Don't treat them as handshake packets.
704 break;
705 }
706 QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
707 dest_conn->OnDecryptedPacket(framer.last_decrypted_level());
708
709 if (dest_stream->handshake_protocol() == PROTOCOL_TLS1_3) {
710 // Try to process the packet with a framer that only has the NullDecrypter
711 // for decryption. If ProcessPacket succeeds, that means the packet was
712 // encrypted with the NullEncrypter. With the TLS handshaker in use, no
713 // packets should ever be encrypted with the NullEncrypter, instead
714 // they're encrypted with an obfuscation cipher based on QUIC version and
715 // connection ID.
716 ASSERT_FALSE(null_encryption_framer.ProcessPacket(
717 *source_conn->encrypted_packets_[index]))
718 << "No TLS packets should be encrypted with the NullEncrypter";
719 }
720
721 // Since we're using QuicFramers separate from the connections to move
722 // packets, the QuicConnection never gets notified about what level the last
723 // packet was decrypted at. This is needed by TLS to know what encryption
724 // level was used for the data it's receiving, so we plumb this information
725 // from the SimpleQuicFramer back into the connection.
726 dest_conn->OnDecryptedPacket(framer.last_decrypted_level());
727
728 QuicConnectionPeer::SetCurrentPacket(
729 dest_conn, source_conn->encrypted_packets_[index]->AsStringPiece());
730 for (const auto& stream_frame : framer.stream_frames()) {
731 dest_stream->OnStreamFrame(*stream_frame);
732 }
733 for (const auto& crypto_frame : framer.crypto_frames()) {
734 dest_stream->OnCryptoFrame(*crypto_frame);
735 }
736 }
737 *inout_packet_index = index;
738
739 QuicConnectionPeer::SetCurrentPacket(dest_conn, QuicStringPiece(nullptr, 0));
740}
741
742CryptoHandshakeMessage GenerateDefaultInchoateCHLO(
743 const QuicClock* clock,
744 QuicTransportVersion version,
745 QuicCryptoServerConfig* crypto_config) {
746 // clang-format off
747 return CreateCHLO(
748 {{"PDMD", "X509"},
749 {"AEAD", "AESG"},
750 {"KEXS", "C255"},
751 {"PUBS", GenerateClientPublicValuesHex().c_str()},
752 {"NONC", GenerateClientNonceHex(clock, crypto_config).c_str()},
753 {"VER\0", QuicVersionLabelToString(
754 QuicVersionToQuicVersionLabel(version)).c_str()}},
755 kClientHelloMinimumSize);
756 // clang-format on
757}
758
vasilvvc48c8712019-03-11 13:38:16 -0700759std::string GenerateClientNonceHex(const QuicClock* clock,
760 QuicCryptoServerConfig* crypto_config) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500761 QuicCryptoServerConfig::ConfigOptions old_config_options;
762 QuicCryptoServerConfig::ConfigOptions new_config_options;
763 old_config_options.id = "old-config-id";
QUICHE teamd5af58a2019-03-14 20:35:50 -0700764 crypto_config->AddDefaultConfig(QuicRandom::GetInstance(), clock,
765 old_config_options);
QUICHE teambbaa8be2019-03-21 12:54:17 -0700766 QuicServerConfigProtobuf primary_config = crypto_config->GenerateConfig(
767 QuicRandom::GetInstance(), clock, new_config_options);
768 primary_config.set_primary_time(clock->WallNow().ToUNIXSeconds());
QUICHE teamd5af58a2019-03-14 20:35:50 -0700769 std::unique_ptr<CryptoHandshakeMessage> msg =
770 crypto_config->AddConfig(std::move(primary_config), clock->WallNow());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500771 QuicStringPiece orbit;
772 CHECK(msg->GetStringPiece(kORBT, &orbit));
vasilvvc48c8712019-03-11 13:38:16 -0700773 std::string nonce;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500774 CryptoUtils::GenerateNonce(clock->WallNow(), QuicRandom::GetInstance(), orbit,
775 &nonce);
776 return ("#" + QuicTextUtils::HexEncode(nonce));
777}
778
vasilvvc48c8712019-03-11 13:38:16 -0700779std::string GenerateClientPublicValuesHex() {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500780 char public_value[32];
781 memset(public_value, 42, sizeof(public_value));
782 return ("#" + QuicTextUtils::HexEncode(public_value, sizeof(public_value)));
783}
784
785void GenerateFullCHLO(const CryptoHandshakeMessage& inchoate_chlo,
786 QuicCryptoServerConfig* crypto_config,
787 QuicSocketAddress server_addr,
788 QuicSocketAddress client_addr,
789 QuicTransportVersion version,
790 const QuicClock* clock,
791 QuicReferenceCountedPointer<QuicSignedServerConfig> proof,
792 QuicCompressedCertsCache* compressed_certs_cache,
793 CryptoHandshakeMessage* out) {
794 // Pass a inchoate CHLO.
795 FullChloGenerator generator(crypto_config, server_addr, client_addr, clock,
796 proof, compressed_certs_cache, out);
797 crypto_config->ValidateClientHello(
798 inchoate_chlo, client_addr.host(), server_addr, version, clock, proof,
799 generator.GetValidateClientHelloCallback());
800}
801
802} // namespace crypto_test_utils
803} // namespace test
804} // namespace quic