blob: 6716dec26051ba0562417247b40e793c7f547c60 [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>
bnc463f2352019-10-10 04:49:34 -07009#include <utility>
QUICHE teama6ef0a62019-03-07 20:34:33 -050010
11#include "third_party/boringssl/src/include/openssl/bn.h"
12#include "third_party/boringssl/src/include/openssl/ec.h"
13#include "third_party/boringssl/src/include/openssl/ecdsa.h"
14#include "third_party/boringssl/src/include/openssl/nid.h"
15#include "third_party/boringssl/src/include/openssl/sha.h"
16#include "net/third_party/quiche/src/quic/core/crypto/channel_id.h"
17#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set.h"
18#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
19#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
20#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
21#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
22#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
dschinazi56fb53e2019-06-21 15:30:04 -070023#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config_proto.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050024#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
25#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h"
26#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
27#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
28#include "net/third_party/quiche/src/quic/core/quic_utils.h"
vasilvvefc6af82019-10-11 12:46:56 -070029#include "net/third_party/quiche/src/quic/core/quic_versions.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050030#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"
QUICHE teama6ef0a62019-03-07 20:34:33 -050033#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
34#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
35#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
36#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
37#include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h"
38#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h"
39#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
40#include "net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h"
41
42namespace quic {
43namespace test {
44
QUICHE teama6ef0a62019-03-07 20:34:33 -050045namespace crypto_test_utils {
46
47namespace {
48
vasilvve6472f62019-10-02 06:50:56 -070049using testing::_;
50
QUICHE teama6ef0a62019-03-07 20:34:33 -050051// CryptoFramerVisitor is a framer visitor that records handshake messages.
52class CryptoFramerVisitor : public CryptoFramerVisitorInterface {
53 public:
54 CryptoFramerVisitor() : error_(false) {}
55
dschinazi17d42422019-06-18 16:35:07 -070056 void OnError(CryptoFramer* /*framer*/) override { error_ = true; }
QUICHE teama6ef0a62019-03-07 20:34:33 -050057
58 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
59 messages_.push_back(message);
60 }
61
62 bool error() const { return error_; }
63
64 const std::vector<CryptoHandshakeMessage>& messages() const {
65 return messages_;
66 }
67
68 private:
69 bool error_;
70 std::vector<CryptoHandshakeMessage> messages_;
71};
72
73// HexChar parses |c| as a hex character. If valid, it sets |*value| to the
74// value of the hex character and returns true. Otherwise it returns false.
75bool HexChar(char c, uint8_t* value) {
76 if (c >= '0' && c <= '9') {
77 *value = c - '0';
78 return true;
79 }
80 if (c >= 'a' && c <= 'f') {
81 *value = c - 'a' + 10;
82 return true;
83 }
84 if (c >= 'A' && c <= 'F') {
85 *value = c - 'A' + 10;
86 return true;
87 }
88 return false;
89}
90
QUICHE teama6ef0a62019-03-07 20:34:33 -050091} // anonymous namespace
92
nharper6153bc72019-05-08 12:04:34 -070093FakeClientOptions::FakeClientOptions() {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050094
95FakeClientOptions::~FakeClientOptions() {}
96
97namespace {
98// This class is used by GenerateFullCHLO() to extract SCID and STK from
wub0a4b9c52019-05-28 13:18:58 -070099// REJ and to construct a full CHLO with these fields and given inchoate
QUICHE teama6ef0a62019-03-07 20:34:33 -0500100// CHLO.
101class FullChloGenerator {
102 public:
103 FullChloGenerator(
104 QuicCryptoServerConfig* crypto_config,
105 QuicSocketAddress server_addr,
106 QuicSocketAddress client_addr,
107 const QuicClock* clock,
108 QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
109 QuicCompressedCertsCache* compressed_certs_cache,
110 CryptoHandshakeMessage* out)
111 : crypto_config_(crypto_config),
112 server_addr_(server_addr),
113 client_addr_(client_addr),
114 clock_(clock),
115 signed_config_(signed_config),
116 compressed_certs_cache_(compressed_certs_cache),
117 out_(out),
118 params_(new QuicCryptoNegotiatedParameters) {}
119
120 class ValidateClientHelloCallback : public ValidateClientHelloResultCallback {
121 public:
122 explicit ValidateClientHelloCallback(FullChloGenerator* generator)
123 : generator_(generator) {}
124 void Run(QuicReferenceCountedPointer<
125 ValidateClientHelloResultCallback::Result> result,
126 std::unique_ptr<ProofSource::Details> /* details */) override {
127 generator_->ValidateClientHelloDone(std::move(result));
128 }
129
130 private:
131 FullChloGenerator* generator_;
132 };
133
134 std::unique_ptr<ValidateClientHelloCallback>
135 GetValidateClientHelloCallback() {
vasilvv0fc587f2019-09-06 13:33:08 -0700136 return std::make_unique<ValidateClientHelloCallback>(this);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500137 }
138
139 private:
140 void ValidateClientHelloDone(
141 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
142 result) {
143 result_ = result;
144 crypto_config_->ProcessClientHello(
145 result_, /*reject_only=*/false, TestConnectionId(1), server_addr_,
146 client_addr_, AllSupportedVersions().front(), AllSupportedVersions(),
wubecf9bd82019-06-05 04:57:02 -0700147 clock_, QuicRandom::GetInstance(), compressed_certs_cache_, params_,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500148 signed_config_, /*total_framing_overhead=*/50, kDefaultMaxPacketSize,
149 GetProcessClientHelloCallback());
150 }
151
152 class ProcessClientHelloCallback : public ProcessClientHelloResultCallback {
153 public:
154 explicit ProcessClientHelloCallback(FullChloGenerator* generator)
155 : generator_(generator) {}
dschinazi17d42422019-06-18 16:35:07 -0700156 void Run(QuicErrorCode /*error*/,
157 const std::string& /*error_details*/,
158 std::unique_ptr<CryptoHandshakeMessage> message,
159 std::unique_ptr<DiversificationNonce> /*diversification_nonce*/,
160 std::unique_ptr<ProofSource::Details> /*proof_source_details*/)
161 override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500162 generator_->ProcessClientHelloDone(std::move(message));
163 }
164
165 private:
166 FullChloGenerator* generator_;
167 };
168
169 std::unique_ptr<ProcessClientHelloCallback> GetProcessClientHelloCallback() {
vasilvv0fc587f2019-09-06 13:33:08 -0700170 return std::make_unique<ProcessClientHelloCallback>(this);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500171 }
172
173 void ProcessClientHelloDone(std::unique_ptr<CryptoHandshakeMessage> rej) {
wub0a4b9c52019-05-28 13:18:58 -0700174 // Verify output is a REJ.
175 EXPECT_THAT(rej->tag(), testing::Eq(kREJ));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500176
nharperff86db32019-05-08 10:38:23 -0700177 QUIC_VLOG(1) << "Extract valid STK and SCID from\n" << rej->DebugString();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500178 QuicStringPiece srct;
179 ASSERT_TRUE(rej->GetStringPiece(kSourceAddressTokenTag, &srct));
180
181 QuicStringPiece scfg;
182 ASSERT_TRUE(rej->GetStringPiece(kSCFG, &scfg));
183 std::unique_ptr<CryptoHandshakeMessage> server_config(
184 CryptoFramer::ParseMessage(scfg));
185
186 QuicStringPiece scid;
187 ASSERT_TRUE(server_config->GetStringPiece(kSCID, &scid));
188
189 *out_ = result_->client_hello;
190 out_->SetStringPiece(kSCID, scid);
191 out_->SetStringPiece(kSourceAddressTokenTag, srct);
192 uint64_t xlct = LeafCertHashForTesting();
193 out_->SetValue(kXLCT, xlct);
194 }
195
196 protected:
197 QuicCryptoServerConfig* crypto_config_;
198 QuicSocketAddress server_addr_;
199 QuicSocketAddress client_addr_;
200 const QuicClock* clock_;
201 QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_;
202 QuicCompressedCertsCache* compressed_certs_cache_;
203 CryptoHandshakeMessage* out_;
204
205 QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
206 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
207 result_;
208};
209
210} // namespace
211
rch83f29bd2019-11-13 11:47:34 -0800212std::unique_ptr<QuicCryptoServerConfig> CryptoServerConfigForTesting() {
213 return std::make_unique<QuicCryptoServerConfig>(
nharperdf7a77b2019-11-11 13:12:45 -0800214 QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
215 ProofSourceForTesting(), KeyExchangeSource::Default());
216}
217
QUICHE teama6ef0a62019-03-07 20:34:33 -0500218int HandshakeWithFakeServer(QuicConfig* server_quic_config,
nharperdf7a77b2019-11-11 13:12:45 -0800219 QuicCryptoServerConfig* crypto_config,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500220 MockQuicConnectionHelper* helper,
221 MockAlarmFactory* alarm_factory,
222 PacketSavingConnection* client_conn,
vasilvve6472f62019-10-02 06:50:56 -0700223 QuicCryptoClientStream* client,
224 std::string alpn) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500225 PacketSavingConnection* server_conn = new PacketSavingConnection(
226 helper, alarm_factory, Perspective::IS_SERVER,
227 ParsedVersionOfIndex(client_conn->supported_versions(), 0));
228
QUICHE teama6ef0a62019-03-07 20:34:33 -0500229 QuicCompressedCertsCache compressed_certs_cache(
230 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
nharperba5f32c2019-05-13 12:21:31 -0700231 SetupCryptoServerConfigForTest(
nharperdf7a77b2019-11-11 13:12:45 -0800232 server_conn->clock(), server_conn->random_generator(), crypto_config);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500233
234 TestQuicSpdyServerSession server_session(
235 server_conn, *server_quic_config, client_conn->supported_versions(),
nharperdf7a77b2019-11-11 13:12:45 -0800236 crypto_config, &compressed_certs_cache);
wuba89eee32019-11-22 13:02:52 -0800237 server_session.Initialize();
wub256b2d62019-11-25 08:46:55 -0800238 if (!GetQuicReloadableFlag(quic_version_negotiated_by_default_at_server)) {
239 server_session.OnSuccessfulVersionNegotiation(
240 client_conn->supported_versions().front());
241 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500242 EXPECT_CALL(*server_session.helper(),
243 CanAcceptClientHello(testing::_, testing::_, testing::_,
244 testing::_, testing::_))
245 .Times(testing::AnyNumber());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500246 EXPECT_CALL(*server_conn, OnCanWrite()).Times(testing::AnyNumber());
247 EXPECT_CALL(*client_conn, OnCanWrite()).Times(testing::AnyNumber());
vasilvve6472f62019-10-02 06:50:56 -0700248 EXPECT_CALL(server_session, SelectAlpn(_))
249 .WillRepeatedly([alpn](const std::vector<QuicStringPiece>& alpns) {
250 return std::find(alpns.cbegin(), alpns.cend(), alpn);
251 });
QUICHE teama6ef0a62019-03-07 20:34:33 -0500252
253 // The client's handshake must have been started already.
254 CHECK_NE(0u, client_conn->encrypted_packets_.size());
255
256 CommunicateHandshakeMessages(client_conn, client, server_conn,
257 server_session.GetMutableCryptoStream());
258 CompareClientAndServerKeys(client, server_session.GetMutableCryptoStream());
259
260 return client->num_sent_client_hellos();
261}
262
263int HandshakeWithFakeClient(MockQuicConnectionHelper* helper,
264 MockAlarmFactory* alarm_factory,
265 PacketSavingConnection* server_conn,
266 QuicCryptoServerStream* server,
267 const QuicServerId& server_id,
vasilvvefc6af82019-10-11 12:46:56 -0700268 const FakeClientOptions& options,
269 std::string alpn) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500270 ParsedQuicVersionVector supported_versions = AllSupportedVersions();
271 if (options.only_tls_versions) {
272 supported_versions.clear();
273 for (QuicTransportVersion transport_version :
274 AllSupportedTransportVersions()) {
275 supported_versions.push_back(
276 ParsedQuicVersion(PROTOCOL_TLS1_3, transport_version));
277 }
278 }
279 PacketSavingConnection* client_conn = new PacketSavingConnection(
280 helper, alarm_factory, Perspective::IS_CLIENT, supported_versions);
281 // Advance the time, because timers do not like uninitialized times.
282 client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1));
283
nharper6ebe83b2019-06-13 17:43:52 -0700284 QuicCryptoClientConfig crypto_config(ProofVerifierForTesting());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500285 TestQuicSpdyClientSession client_session(client_conn, DefaultQuicConfig(),
286 supported_versions, server_id,
287 &crypto_config);
288
289 EXPECT_CALL(client_session, OnProofValid(testing::_))
290 .Times(testing::AnyNumber());
291 EXPECT_CALL(client_session, OnProofVerifyDetailsAvailable(testing::_))
292 .Times(testing::AnyNumber());
293 EXPECT_CALL(*client_conn, OnCanWrite()).Times(testing::AnyNumber());
vasilvvefc6af82019-10-11 12:46:56 -0700294 if (!alpn.empty()) {
295 EXPECT_CALL(client_session, GetAlpnsToOffer())
296 .WillRepeatedly(testing::Return(std::vector<std::string>({alpn})));
297 } else {
298 EXPECT_CALL(client_session, GetAlpnsToOffer())
299 .WillRepeatedly(testing::Return(std::vector<std::string>(
300 {AlpnForVersion(client_conn->version())})));
301 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500302 client_session.GetMutableCryptoStream()->CryptoConnect();
303 CHECK_EQ(1u, client_conn->encrypted_packets_.size());
304
nharper6153bc72019-05-08 12:04:34 -0700305 CommunicateHandshakeMessages(client_conn,
306 client_session.GetMutableCryptoStream(),
307 server_conn, server);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500308
309 if (server->handshake_confirmed() && server->encryption_established()) {
310 CompareClientAndServerKeys(client_session.GetMutableCryptoStream(), server);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500311 }
312
313 return client_session.GetCryptoStream()->num_sent_client_hellos();
314}
315
316void SetupCryptoServerConfigForTest(const QuicClock* clock,
317 QuicRandom* rand,
nharperba5f32c2019-05-13 12:21:31 -0700318 QuicCryptoServerConfig* crypto_config) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500319 QuicCryptoServerConfig::ConfigOptions options;
320 options.channel_id_enabled = true;
QUICHE teamd5af58a2019-03-14 20:35:50 -0700321 std::unique_ptr<CryptoHandshakeMessage> scfg =
322 crypto_config->AddDefaultConfig(rand, clock, options);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500323}
324
325void SendHandshakeMessageToStream(QuicCryptoStream* stream,
326 const CryptoHandshakeMessage& message,
dschinazi17d42422019-06-18 16:35:07 -0700327 Perspective /*perspective*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500328 const QuicData& data = message.GetSerialized();
329 QuicSession* session = QuicStreamPeer::session(stream);
renjietangd1d00852019-09-06 10:43:12 -0700330 if (!QuicVersionUsesCryptoFrames(session->transport_version())) {
331 QuicStreamFrame frame(
332 QuicUtils::GetCryptoStreamId(session->transport_version()), false,
333 stream->crypto_bytes_read(), data.AsStringPiece());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500334 stream->OnStreamFrame(frame);
335 } else {
336 EncryptionLevel level = session->connection()->last_decrypted_level();
337 QuicCryptoFrame frame(level, stream->BytesReadOnLevel(level),
338 data.AsStringPiece());
339 stream->OnCryptoFrame(frame);
340 }
341}
342
343void CommunicateHandshakeMessages(PacketSavingConnection* client_conn,
344 QuicCryptoStream* client,
345 PacketSavingConnection* server_conn,
346 QuicCryptoStream* server) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500347 size_t client_i = 0, server_i = 0;
348 while (!client->handshake_confirmed() || !server->handshake_confirmed()) {
349 ASSERT_GT(client_conn->encrypted_packets_.size(), client_i);
350 QUIC_LOG(INFO) << "Processing "
351 << client_conn->encrypted_packets_.size() - client_i
352 << " packets client->server";
353 MovePackets(client_conn, &client_i, server, server_conn,
354 Perspective::IS_SERVER);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500355
nharperdf7a77b2019-11-11 13:12:45 -0800356 if (client->handshake_confirmed() && server->handshake_confirmed() &&
357 server_conn->encrypted_packets_.size() == server_i) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500358 break;
359 }
360 ASSERT_GT(server_conn->encrypted_packets_.size(), server_i);
361 QUIC_LOG(INFO) << "Processing "
362 << server_conn->encrypted_packets_.size() - server_i
363 << " packets server->client";
364 MovePackets(server_conn, &server_i, client, client_conn,
365 Perspective::IS_CLIENT);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500366 }
367}
368
369std::pair<size_t, size_t> AdvanceHandshake(PacketSavingConnection* client_conn,
370 QuicCryptoStream* client,
371 size_t client_i,
372 PacketSavingConnection* server_conn,
373 QuicCryptoStream* server,
374 size_t server_i) {
375 QUIC_LOG(INFO) << "Processing "
376 << client_conn->encrypted_packets_.size() - client_i
377 << " packets client->server";
378 MovePackets(client_conn, &client_i, server, server_conn,
379 Perspective::IS_SERVER);
380
381 QUIC_LOG(INFO) << "Processing "
382 << server_conn->encrypted_packets_.size() - server_i
383 << " packets server->client";
384 if (server_conn->encrypted_packets_.size() - server_i == 2) {
385 QUIC_LOG(INFO) << "here";
386 }
387 MovePackets(server_conn, &server_i, client, client_conn,
388 Perspective::IS_CLIENT);
389
390 return std::make_pair(client_i, server_i);
391}
392
vasilvvc48c8712019-03-11 13:38:16 -0700393std::string GetValueForTag(const CryptoHandshakeMessage& message, QuicTag tag) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500394 auto it = message.tag_value_map().find(tag);
395 if (it == message.tag_value_map().end()) {
vasilvvc48c8712019-03-11 13:38:16 -0700396 return std::string();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500397 }
398 return it->second;
399}
400
401uint64_t LeafCertHashForTesting() {
402 QuicReferenceCountedPointer<ProofSource::Chain> chain;
403 QuicSocketAddress server_address(QuicIpAddress::Any4(), 42);
404 QuicCryptoProof proof;
405 std::unique_ptr<ProofSource> proof_source(ProofSourceForTesting());
406
407 class Callback : public ProofSource::Callback {
408 public:
409 Callback(bool* ok, QuicReferenceCountedPointer<ProofSource::Chain>* chain)
410 : ok_(ok), chain_(chain) {}
411
412 void Run(bool ok,
413 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
414 const QuicCryptoProof& /* proof */,
415 std::unique_ptr<ProofSource::Details> /* details */) override {
416 *ok_ = ok;
417 *chain_ = chain;
418 }
419
420 private:
421 bool* ok_;
422 QuicReferenceCountedPointer<ProofSource::Chain>* chain_;
423 };
424
425 // Note: relies on the callback being invoked synchronously
426 bool ok = false;
427 proof_source->GetProof(
428 server_address, "", "", AllSupportedTransportVersions().front(), "",
429 std::unique_ptr<ProofSource::Callback>(new Callback(&ok, &chain)));
430 if (!ok || chain->certs.empty()) {
431 DCHECK(false) << "Proof generation failed";
432 return 0;
433 }
434
435 return QuicUtils::FNV1a_64_Hash(chain->certs.at(0));
436}
437
438class MockCommonCertSets : public CommonCertSets {
439 public:
440 MockCommonCertSets(QuicStringPiece cert, uint64_t hash, uint32_t index)
441 : cert_(cert), hash_(hash), index_(index) {}
442
443 QuicStringPiece GetCommonHashes() const override {
444 QUIC_BUG << "not implemented";
445 return QuicStringPiece();
446 }
447
448 QuicStringPiece GetCert(uint64_t hash, uint32_t index) const override {
449 if (hash == hash_ && index == index_) {
450 return cert_;
451 }
452 return QuicStringPiece();
453 }
454
455 bool MatchCert(QuicStringPiece cert,
456 QuicStringPiece common_set_hashes,
457 uint64_t* out_hash,
458 uint32_t* out_index) const override {
459 if (cert != cert_) {
460 return false;
461 }
462
463 if (common_set_hashes.size() % sizeof(uint64_t) != 0) {
464 return false;
465 }
466 bool client_has_set = false;
467 for (size_t i = 0; i < common_set_hashes.size(); i += sizeof(uint64_t)) {
468 uint64_t hash;
469 memcpy(&hash, common_set_hashes.data() + i, sizeof(hash));
470 if (hash == hash_) {
471 client_has_set = true;
472 break;
473 }
474 }
475
476 if (!client_has_set) {
477 return false;
478 }
479
480 *out_hash = hash_;
481 *out_index = index_;
482 return true;
483 }
484
485 private:
vasilvvc48c8712019-03-11 13:38:16 -0700486 const std::string cert_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500487 const uint64_t hash_;
488 const uint32_t index_;
489};
490
491CommonCertSets* MockCommonCertSets(QuicStringPiece cert,
492 uint64_t hash,
493 uint32_t index) {
494 return new class MockCommonCertSets(cert, hash, index);
495}
496
wub9b9cc812019-05-20 09:01:52 -0700497void FillInDummyReject(CryptoHandshakeMessage* rej) {
498 rej->set_tag(kREJ);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500499
500 // Minimum SCFG that passes config validation checks.
501 // clang-format off
502 unsigned char scfg[] = {
503 // SCFG
504 0x53, 0x43, 0x46, 0x47,
505 // num entries
506 0x01, 0x00,
507 // padding
508 0x00, 0x00,
509 // EXPY
510 0x45, 0x58, 0x50, 0x59,
511 // EXPY end offset
512 0x08, 0x00, 0x00, 0x00,
513 // Value
514 '1', '2', '3', '4',
515 '5', '6', '7', '8'
516 };
517 // clang-format on
518 rej->SetValue(kSCFG, scfg);
519 rej->SetStringPiece(kServerNonceTag, "SERVER_NONCE");
520 int64_t ttl = 2 * 24 * 60 * 60;
521 rej->SetValue(kSTTL, ttl);
522 std::vector<QuicTag> reject_reasons;
523 reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
524 rej->SetVector(kRREJ, reject_reasons);
525}
526
QUICHE teamfbfd3622019-03-26 10:59:32 -0700527namespace {
528
529#define RETURN_STRING_LITERAL(x) \
530 case x: \
531 return #x
532
533std::string EncryptionLevelString(EncryptionLevel level) {
534 switch (level) {
535 RETURN_STRING_LITERAL(ENCRYPTION_INITIAL);
536 RETURN_STRING_LITERAL(ENCRYPTION_HANDSHAKE);
537 RETURN_STRING_LITERAL(ENCRYPTION_ZERO_RTT);
538 RETURN_STRING_LITERAL(ENCRYPTION_FORWARD_SECURE);
539 default:
540 return "";
541 }
542}
543
544void CompareCrypters(const QuicEncrypter* encrypter,
545 const QuicDecrypter* decrypter,
546 std::string label) {
zhongyi546cc452019-04-12 15:27:49 -0700547 if (encrypter == nullptr || decrypter == nullptr) {
548 ADD_FAILURE() << "Expected non-null crypters; have " << encrypter << " and "
549 << decrypter;
550 return;
551 }
QUICHE teamfbfd3622019-03-26 10:59:32 -0700552 QuicStringPiece encrypter_key = encrypter->GetKey();
553 QuicStringPiece encrypter_iv = encrypter->GetNoncePrefix();
554 QuicStringPiece decrypter_key = decrypter->GetKey();
555 QuicStringPiece decrypter_iv = decrypter->GetNoncePrefix();
556 CompareCharArraysWithHexError(label + " key", encrypter_key.data(),
557 encrypter_key.length(), decrypter_key.data(),
558 decrypter_key.length());
559 CompareCharArraysWithHexError(label + " iv", encrypter_iv.data(),
560 encrypter_iv.length(), decrypter_iv.data(),
561 decrypter_iv.length());
562}
563
564} // namespace
565
QUICHE teama6ef0a62019-03-07 20:34:33 -0500566void CompareClientAndServerKeys(QuicCryptoClientStream* client,
567 QuicCryptoServerStream* server) {
568 QuicFramer* client_framer = QuicConnectionPeer::GetFramer(
569 QuicStreamPeer::session(client)->connection());
570 QuicFramer* server_framer = QuicConnectionPeer::GetFramer(
571 QuicStreamPeer::session(server)->connection());
QUICHE teamfbfd3622019-03-26 10:59:32 -0700572 for (EncryptionLevel level :
573 {ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
574 SCOPED_TRACE(EncryptionLevelString(level));
575 const QuicEncrypter* client_encrypter(
576 QuicFramerPeer::GetEncrypter(client_framer, level));
577 const QuicDecrypter* server_decrypter(
578 QuicFramerPeer::GetDecrypter(server_framer, level));
579 if (level == ENCRYPTION_FORWARD_SECURE ||
580 !(client_encrypter == nullptr && server_decrypter == nullptr)) {
581 CompareCrypters(client_encrypter, server_decrypter,
582 "client " + EncryptionLevelString(level) + " write");
583 }
584 const QuicEncrypter* server_encrypter(
585 QuicFramerPeer::GetEncrypter(server_framer, level));
586 const QuicDecrypter* client_decrypter(
587 QuicFramerPeer::GetDecrypter(client_framer, level));
588 if (level == ENCRYPTION_FORWARD_SECURE ||
589 !(server_encrypter == nullptr && client_decrypter == nullptr)) {
590 CompareCrypters(server_encrypter, client_decrypter,
591 "server " + EncryptionLevelString(level) + " write");
592 }
593 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500594
595 QuicStringPiece client_subkey_secret =
596 client->crypto_negotiated_params().subkey_secret;
597 QuicStringPiece server_subkey_secret =
598 server->crypto_negotiated_params().subkey_secret;
QUICHE teamfbfd3622019-03-26 10:59:32 -0700599 CompareCharArraysWithHexError("subkey secret", client_subkey_secret.data(),
600 client_subkey_secret.length(),
601 server_subkey_secret.data(),
602 server_subkey_secret.length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500603
604 const char kSampleLabel[] = "label";
605 const char kSampleContext[] = "context";
606 const size_t kSampleOutputLength = 32;
vasilvvc48c8712019-03-11 13:38:16 -0700607 std::string client_key_extraction;
608 std::string server_key_extraction;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500609 EXPECT_TRUE(client->ExportKeyingMaterial(kSampleLabel, kSampleContext,
610 kSampleOutputLength,
611 &client_key_extraction));
612 EXPECT_TRUE(server->ExportKeyingMaterial(kSampleLabel, kSampleContext,
613 kSampleOutputLength,
614 &server_key_extraction));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500615 CompareCharArraysWithHexError(
616 "sample key extraction", client_key_extraction.data(),
617 client_key_extraction.length(), server_key_extraction.data(),
618 server_key_extraction.length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500619}
620
621QuicTag ParseTag(const char* tagstr) {
622 const size_t len = strlen(tagstr);
623 CHECK_NE(0u, len);
624
625 QuicTag tag = 0;
626
627 if (tagstr[0] == '#') {
628 CHECK_EQ(static_cast<size_t>(1 + 2 * 4), len);
629 tagstr++;
630
631 for (size_t i = 0; i < 8; i++) {
632 tag <<= 4;
633
634 uint8_t v = 0;
635 CHECK(HexChar(tagstr[i], &v));
636 tag |= v;
637 }
638
639 return tag;
640 }
641
642 CHECK_LE(len, 4u);
643 for (size_t i = 0; i < 4; i++) {
644 tag >>= 8;
645 if (i < len) {
646 tag |= static_cast<uint32_t>(tagstr[i]) << 24;
647 }
648 }
649
650 return tag;
651}
652
653CryptoHandshakeMessage CreateCHLO(
vasilvvc48c8712019-03-11 13:38:16 -0700654 std::vector<std::pair<std::string, std::string>> tags_and_values) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500655 return CreateCHLO(tags_and_values, -1);
656}
657
658CryptoHandshakeMessage CreateCHLO(
vasilvvc48c8712019-03-11 13:38:16 -0700659 std::vector<std::pair<std::string, std::string>> tags_and_values,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500660 int minimum_size_bytes) {
661 CryptoHandshakeMessage msg;
662 msg.set_tag(MakeQuicTag('C', 'H', 'L', 'O'));
663
664 if (minimum_size_bytes > 0) {
665 msg.set_minimum_size(minimum_size_bytes);
666 }
667
668 for (const auto& tag_and_value : tags_and_values) {
vasilvvc48c8712019-03-11 13:38:16 -0700669 const std::string& tag = tag_and_value.first;
670 const std::string& value = tag_and_value.second;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500671
672 const QuicTag quic_tag = ParseTag(tag.c_str());
673
674 size_t value_len = value.length();
675 if (value_len > 0 && value[0] == '#') {
676 // This is ascii encoded hex.
vasilvvc48c8712019-03-11 13:38:16 -0700677 std::string hex_value =
QUICHE teama6ef0a62019-03-07 20:34:33 -0500678 QuicTextUtils::HexDecode(QuicStringPiece(&value[1]));
679 msg.SetStringPiece(quic_tag, hex_value);
680 continue;
681 }
682 msg.SetStringPiece(quic_tag, value);
683 }
684
685 // The CryptoHandshakeMessage needs to be serialized and parsed to ensure
686 // that any padding is included.
QUICHE team3fe6a8b2019-03-14 09:10:38 -0700687 std::unique_ptr<QuicData> bytes =
688 CryptoFramer::ConstructHandshakeMessage(msg);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500689 std::unique_ptr<CryptoHandshakeMessage> parsed(
690 CryptoFramer::ParseMessage(bytes->AsStringPiece()));
691 CHECK(parsed);
692
693 return *parsed;
694}
695
QUICHE teama6ef0a62019-03-07 20:34:33 -0500696void MovePackets(PacketSavingConnection* source_conn,
697 size_t* inout_packet_index,
698 QuicCryptoStream* dest_stream,
699 PacketSavingConnection* dest_conn,
700 Perspective dest_perspective) {
701 SimpleQuicFramer framer(source_conn->supported_versions(), dest_perspective);
dschinazib953d022019-08-01 18:05:58 -0700702 QuicFramerPeer::SetLastSerializedServerConnectionId(framer.framer(),
703 TestConnectionId());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500704
705 SimpleQuicFramer null_encryption_framer(source_conn->supported_versions(),
706 dest_perspective);
dschinazib953d022019-08-01 18:05:58 -0700707 QuicFramerPeer::SetLastSerializedServerConnectionId(
708 null_encryption_framer.framer(), TestConnectionId());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500709
710 size_t index = *inout_packet_index;
711 for (; index < source_conn->encrypted_packets_.size(); index++) {
712 // In order to properly test the code we need to perform encryption and
713 // decryption so that the crypters latch when expected. The crypters are in
714 // |dest_conn|, but we don't want to try and use them there. Instead we swap
715 // them into |framer|, perform the decryption with them, and then swap ther
716 // back.
717 QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
fayang5f135052019-08-22 17:59:40 -0700718 QuicConnectionPeer::AddBytesReceived(
719 dest_conn, source_conn->encrypted_packets_[index]->length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500720 if (!framer.ProcessPacket(*source_conn->encrypted_packets_[index])) {
721 // The framer will be unable to decrypt forward-secure packets sent after
722 // the handshake is complete. Don't treat them as handshake packets.
723 break;
724 }
725 QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
726 dest_conn->OnDecryptedPacket(framer.last_decrypted_level());
727
728 if (dest_stream->handshake_protocol() == PROTOCOL_TLS1_3) {
729 // Try to process the packet with a framer that only has the NullDecrypter
730 // for decryption. If ProcessPacket succeeds, that means the packet was
731 // encrypted with the NullEncrypter. With the TLS handshaker in use, no
732 // packets should ever be encrypted with the NullEncrypter, instead
733 // they're encrypted with an obfuscation cipher based on QUIC version and
734 // connection ID.
735 ASSERT_FALSE(null_encryption_framer.ProcessPacket(
736 *source_conn->encrypted_packets_[index]))
737 << "No TLS packets should be encrypted with the NullEncrypter";
738 }
739
740 // Since we're using QuicFramers separate from the connections to move
741 // packets, the QuicConnection never gets notified about what level the last
742 // packet was decrypted at. This is needed by TLS to know what encryption
743 // level was used for the data it's receiving, so we plumb this information
744 // from the SimpleQuicFramer back into the connection.
745 dest_conn->OnDecryptedPacket(framer.last_decrypted_level());
746
747 QuicConnectionPeer::SetCurrentPacket(
748 dest_conn, source_conn->encrypted_packets_[index]->AsStringPiece());
749 for (const auto& stream_frame : framer.stream_frames()) {
renjietange01b3eb2019-08-20 11:04:54 -0700750 // Ignore stream frames that are sent on other streams in the crypto
751 // event.
752 if (stream_frame->stream_id == dest_stream->id()) {
753 dest_stream->OnStreamFrame(*stream_frame);
754 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500755 }
756 for (const auto& crypto_frame : framer.crypto_frames()) {
757 dest_stream->OnCryptoFrame(*crypto_frame);
758 }
759 }
760 *inout_packet_index = index;
761
762 QuicConnectionPeer::SetCurrentPacket(dest_conn, QuicStringPiece(nullptr, 0));
763}
764
765CryptoHandshakeMessage GenerateDefaultInchoateCHLO(
766 const QuicClock* clock,
767 QuicTransportVersion version,
768 QuicCryptoServerConfig* crypto_config) {
769 // clang-format off
770 return CreateCHLO(
771 {{"PDMD", "X509"},
772 {"AEAD", "AESG"},
773 {"KEXS", "C255"},
774 {"PUBS", GenerateClientPublicValuesHex().c_str()},
775 {"NONC", GenerateClientNonceHex(clock, crypto_config).c_str()},
776 {"VER\0", QuicVersionLabelToString(
777 QuicVersionToQuicVersionLabel(version)).c_str()}},
778 kClientHelloMinimumSize);
779 // clang-format on
780}
781
vasilvvc48c8712019-03-11 13:38:16 -0700782std::string GenerateClientNonceHex(const QuicClock* clock,
783 QuicCryptoServerConfig* crypto_config) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500784 QuicCryptoServerConfig::ConfigOptions old_config_options;
785 QuicCryptoServerConfig::ConfigOptions new_config_options;
786 old_config_options.id = "old-config-id";
QUICHE teamd5af58a2019-03-14 20:35:50 -0700787 crypto_config->AddDefaultConfig(QuicRandom::GetInstance(), clock,
788 old_config_options);
QUICHE teambbaa8be2019-03-21 12:54:17 -0700789 QuicServerConfigProtobuf primary_config = crypto_config->GenerateConfig(
790 QuicRandom::GetInstance(), clock, new_config_options);
791 primary_config.set_primary_time(clock->WallNow().ToUNIXSeconds());
QUICHE teamd5af58a2019-03-14 20:35:50 -0700792 std::unique_ptr<CryptoHandshakeMessage> msg =
wub76855422019-10-24 08:53:04 -0700793 crypto_config->AddConfig(primary_config, clock->WallNow());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500794 QuicStringPiece orbit;
795 CHECK(msg->GetStringPiece(kORBT, &orbit));
vasilvvc48c8712019-03-11 13:38:16 -0700796 std::string nonce;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500797 CryptoUtils::GenerateNonce(clock->WallNow(), QuicRandom::GetInstance(), orbit,
798 &nonce);
799 return ("#" + QuicTextUtils::HexEncode(nonce));
800}
801
vasilvvc48c8712019-03-11 13:38:16 -0700802std::string GenerateClientPublicValuesHex() {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500803 char public_value[32];
804 memset(public_value, 42, sizeof(public_value));
805 return ("#" + QuicTextUtils::HexEncode(public_value, sizeof(public_value)));
806}
807
808void GenerateFullCHLO(const CryptoHandshakeMessage& inchoate_chlo,
809 QuicCryptoServerConfig* crypto_config,
810 QuicSocketAddress server_addr,
811 QuicSocketAddress client_addr,
812 QuicTransportVersion version,
813 const QuicClock* clock,
814 QuicReferenceCountedPointer<QuicSignedServerConfig> proof,
815 QuicCompressedCertsCache* compressed_certs_cache,
816 CryptoHandshakeMessage* out) {
817 // Pass a inchoate CHLO.
818 FullChloGenerator generator(crypto_config, server_addr, client_addr, clock,
819 proof, compressed_certs_cache, out);
820 crypto_config->ValidateClientHello(
821 inchoate_chlo, client_addr.host(), server_addr, version, clock, proof,
822 generator.GetValidateClientHelloCallback());
823}
824
825} // namespace crypto_test_utils
826} // namespace test
827} // namespace quic