blob: 543496f7bf17e2abcf3182ba78763e4be51ee651 [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"
QUICHE teama6ef0a62019-03-07 20:34:33 -050035#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
36#include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h"
37#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h"
38#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
39#include "net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h"
QUICHE team6dcf6ab2019-12-11 10:10:51 -080040#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
41#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
dmcardle8f7df532020-01-07 13:28:57 -080042#include "net/third_party/quiche/src/common/test_tools/quiche_test_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050043
44namespace quic {
45namespace test {
46
QUICHE teama6ef0a62019-03-07 20:34:33 -050047namespace crypto_test_utils {
48
49namespace {
50
vasilvve6472f62019-10-02 06:50:56 -070051using testing::_;
52
QUICHE teama6ef0a62019-03-07 20:34:33 -050053// CryptoFramerVisitor is a framer visitor that records handshake messages.
54class CryptoFramerVisitor : public CryptoFramerVisitorInterface {
55 public:
56 CryptoFramerVisitor() : error_(false) {}
57
dschinazi17d42422019-06-18 16:35:07 -070058 void OnError(CryptoFramer* /*framer*/) override { error_ = true; }
QUICHE teama6ef0a62019-03-07 20:34:33 -050059
60 void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
61 messages_.push_back(message);
62 }
63
64 bool error() const { return error_; }
65
66 const std::vector<CryptoHandshakeMessage>& messages() const {
67 return messages_;
68 }
69
70 private:
71 bool error_;
72 std::vector<CryptoHandshakeMessage> messages_;
73};
74
75// HexChar parses |c| as a hex character. If valid, it sets |*value| to the
76// value of the hex character and returns true. Otherwise it returns false.
77bool HexChar(char c, uint8_t* value) {
78 if (c >= '0' && c <= '9') {
79 *value = c - '0';
80 return true;
81 }
82 if (c >= 'a' && c <= 'f') {
83 *value = c - 'a' + 10;
84 return true;
85 }
86 if (c >= 'A' && c <= 'F') {
87 *value = c - 'A' + 10;
88 return true;
89 }
90 return false;
91}
92
QUICHE teama6ef0a62019-03-07 20:34:33 -050093} // anonymous namespace
94
nharper6153bc72019-05-08 12:04:34 -070095FakeClientOptions::FakeClientOptions() {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050096
97FakeClientOptions::~FakeClientOptions() {}
98
99namespace {
100// This class is used by GenerateFullCHLO() to extract SCID and STK from
wub0a4b9c52019-05-28 13:18:58 -0700101// REJ and to construct a full CHLO with these fields and given inchoate
QUICHE teama6ef0a62019-03-07 20:34:33 -0500102// CHLO.
103class FullChloGenerator {
104 public:
105 FullChloGenerator(
106 QuicCryptoServerConfig* crypto_config,
107 QuicSocketAddress server_addr,
108 QuicSocketAddress client_addr,
109 const QuicClock* clock,
110 QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
111 QuicCompressedCertsCache* compressed_certs_cache,
112 CryptoHandshakeMessage* out)
113 : crypto_config_(crypto_config),
114 server_addr_(server_addr),
115 client_addr_(client_addr),
116 clock_(clock),
117 signed_config_(signed_config),
118 compressed_certs_cache_(compressed_certs_cache),
119 out_(out),
120 params_(new QuicCryptoNegotiatedParameters) {}
121
122 class ValidateClientHelloCallback : public ValidateClientHelloResultCallback {
123 public:
124 explicit ValidateClientHelloCallback(FullChloGenerator* generator)
125 : generator_(generator) {}
126 void Run(QuicReferenceCountedPointer<
127 ValidateClientHelloResultCallback::Result> result,
128 std::unique_ptr<ProofSource::Details> /* details */) override {
129 generator_->ValidateClientHelloDone(std::move(result));
130 }
131
132 private:
133 FullChloGenerator* generator_;
134 };
135
136 std::unique_ptr<ValidateClientHelloCallback>
137 GetValidateClientHelloCallback() {
vasilvv0fc587f2019-09-06 13:33:08 -0700138 return std::make_unique<ValidateClientHelloCallback>(this);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500139 }
140
141 private:
142 void ValidateClientHelloDone(
143 QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
144 result) {
145 result_ = result;
146 crypto_config_->ProcessClientHello(
147 result_, /*reject_only=*/false, TestConnectionId(1), server_addr_,
148 client_addr_, AllSupportedVersions().front(), AllSupportedVersions(),
wubecf9bd82019-06-05 04:57:02 -0700149 clock_, QuicRandom::GetInstance(), compressed_certs_cache_, params_,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500150 signed_config_, /*total_framing_overhead=*/50, kDefaultMaxPacketSize,
151 GetProcessClientHelloCallback());
152 }
153
154 class ProcessClientHelloCallback : public ProcessClientHelloResultCallback {
155 public:
156 explicit ProcessClientHelloCallback(FullChloGenerator* generator)
157 : generator_(generator) {}
dschinazi17d42422019-06-18 16:35:07 -0700158 void Run(QuicErrorCode /*error*/,
159 const std::string& /*error_details*/,
160 std::unique_ptr<CryptoHandshakeMessage> message,
161 std::unique_ptr<DiversificationNonce> /*diversification_nonce*/,
162 std::unique_ptr<ProofSource::Details> /*proof_source_details*/)
163 override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500164 generator_->ProcessClientHelloDone(std::move(message));
165 }
166
167 private:
168 FullChloGenerator* generator_;
169 };
170
171 std::unique_ptr<ProcessClientHelloCallback> GetProcessClientHelloCallback() {
vasilvv0fc587f2019-09-06 13:33:08 -0700172 return std::make_unique<ProcessClientHelloCallback>(this);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500173 }
174
175 void ProcessClientHelloDone(std::unique_ptr<CryptoHandshakeMessage> rej) {
wub0a4b9c52019-05-28 13:18:58 -0700176 // Verify output is a REJ.
177 EXPECT_THAT(rej->tag(), testing::Eq(kREJ));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500178
nharperff86db32019-05-08 10:38:23 -0700179 QUIC_VLOG(1) << "Extract valid STK and SCID from\n" << rej->DebugString();
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800180 quiche::QuicheStringPiece srct;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500181 ASSERT_TRUE(rej->GetStringPiece(kSourceAddressTokenTag, &srct));
182
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800183 quiche::QuicheStringPiece scfg;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500184 ASSERT_TRUE(rej->GetStringPiece(kSCFG, &scfg));
185 std::unique_ptr<CryptoHandshakeMessage> server_config(
186 CryptoFramer::ParseMessage(scfg));
187
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800188 quiche::QuicheStringPiece scid;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500189 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
rch83f29bd2019-11-13 11:47:34 -0800214std::unique_ptr<QuicCryptoServerConfig> CryptoServerConfigForTesting() {
215 return std::make_unique<QuicCryptoServerConfig>(
nharperdf7a77b2019-11-11 13:12:45 -0800216 QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
217 ProofSourceForTesting(), KeyExchangeSource::Default());
218}
219
QUICHE teama6ef0a62019-03-07 20:34:33 -0500220int HandshakeWithFakeServer(QuicConfig* server_quic_config,
nharperdf7a77b2019-11-11 13:12:45 -0800221 QuicCryptoServerConfig* crypto_config,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500222 MockQuicConnectionHelper* helper,
223 MockAlarmFactory* alarm_factory,
224 PacketSavingConnection* client_conn,
vasilvve6472f62019-10-02 06:50:56 -0700225 QuicCryptoClientStream* client,
226 std::string alpn) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500227 PacketSavingConnection* server_conn = new PacketSavingConnection(
228 helper, alarm_factory, Perspective::IS_SERVER,
229 ParsedVersionOfIndex(client_conn->supported_versions(), 0));
230
QUICHE teama6ef0a62019-03-07 20:34:33 -0500231 QuicCompressedCertsCache compressed_certs_cache(
232 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
nharperba5f32c2019-05-13 12:21:31 -0700233 SetupCryptoServerConfigForTest(
nharperdf7a77b2019-11-11 13:12:45 -0800234 server_conn->clock(), server_conn->random_generator(), crypto_config);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500235
236 TestQuicSpdyServerSession server_session(
237 server_conn, *server_quic_config, client_conn->supported_versions(),
nharperdf7a77b2019-11-11 13:12:45 -0800238 crypto_config, &compressed_certs_cache);
wuba89eee32019-11-22 13:02:52 -0800239 server_session.Initialize();
wub256b2d62019-11-25 08:46:55 -0800240 if (!GetQuicReloadableFlag(quic_version_negotiated_by_default_at_server)) {
241 server_session.OnSuccessfulVersionNegotiation(
242 client_conn->supported_versions().front());
243 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500244 EXPECT_CALL(*server_session.helper(),
245 CanAcceptClientHello(testing::_, testing::_, testing::_,
246 testing::_, testing::_))
247 .Times(testing::AnyNumber());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500248 EXPECT_CALL(*server_conn, OnCanWrite()).Times(testing::AnyNumber());
249 EXPECT_CALL(*client_conn, OnCanWrite()).Times(testing::AnyNumber());
vasilvve6472f62019-10-02 06:50:56 -0700250 EXPECT_CALL(server_session, SelectAlpn(_))
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800251 .WillRepeatedly(
252 [alpn](const std::vector<quiche::QuicheStringPiece>& alpns) {
253 return std::find(alpns.cbegin(), alpns.cend(), alpn);
254 });
QUICHE teama6ef0a62019-03-07 20:34:33 -0500255
256 // The client's handshake must have been started already.
257 CHECK_NE(0u, client_conn->encrypted_packets_.size());
258
259 CommunicateHandshakeMessages(client_conn, client, server_conn,
260 server_session.GetMutableCryptoStream());
261 CompareClientAndServerKeys(client, server_session.GetMutableCryptoStream());
262
263 return client->num_sent_client_hellos();
264}
265
266int HandshakeWithFakeClient(MockQuicConnectionHelper* helper,
267 MockAlarmFactory* alarm_factory,
268 PacketSavingConnection* server_conn,
269 QuicCryptoServerStream* server,
270 const QuicServerId& server_id,
vasilvvefc6af82019-10-11 12:46:56 -0700271 const FakeClientOptions& options,
272 std::string alpn) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500273 ParsedQuicVersionVector supported_versions = AllSupportedVersions();
274 if (options.only_tls_versions) {
275 supported_versions.clear();
dschinazidc770fc2020-01-13 15:42:41 -0800276 for (ParsedQuicVersion version : AllSupportedVersions()) {
277 if (version.handshake_protocol != PROTOCOL_TLS1_3) {
278 continue;
279 }
280 supported_versions.push_back(version);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500281 }
282 }
283 PacketSavingConnection* client_conn = new PacketSavingConnection(
284 helper, alarm_factory, Perspective::IS_CLIENT, supported_versions);
285 // Advance the time, because timers do not like uninitialized times.
286 client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1));
287
nharper6ebe83b2019-06-13 17:43:52 -0700288 QuicCryptoClientConfig crypto_config(ProofVerifierForTesting());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500289 TestQuicSpdyClientSession client_session(client_conn, DefaultQuicConfig(),
290 supported_versions, server_id,
291 &crypto_config);
292
293 EXPECT_CALL(client_session, OnProofValid(testing::_))
294 .Times(testing::AnyNumber());
295 EXPECT_CALL(client_session, OnProofVerifyDetailsAvailable(testing::_))
296 .Times(testing::AnyNumber());
297 EXPECT_CALL(*client_conn, OnCanWrite()).Times(testing::AnyNumber());
vasilvvefc6af82019-10-11 12:46:56 -0700298 if (!alpn.empty()) {
299 EXPECT_CALL(client_session, GetAlpnsToOffer())
300 .WillRepeatedly(testing::Return(std::vector<std::string>({alpn})));
301 } else {
302 EXPECT_CALL(client_session, GetAlpnsToOffer())
303 .WillRepeatedly(testing::Return(std::vector<std::string>(
304 {AlpnForVersion(client_conn->version())})));
305 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500306 client_session.GetMutableCryptoStream()->CryptoConnect();
307 CHECK_EQ(1u, client_conn->encrypted_packets_.size());
308
nharper6153bc72019-05-08 12:04:34 -0700309 CommunicateHandshakeMessages(client_conn,
310 client_session.GetMutableCryptoStream(),
311 server_conn, server);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500312
fayang685367a2020-01-14 10:40:15 -0800313 if (server->one_rtt_keys_available() && server->encryption_established()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500314 CompareClientAndServerKeys(client_session.GetMutableCryptoStream(), server);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500315 }
316
317 return client_session.GetCryptoStream()->num_sent_client_hellos();
318}
319
320void SetupCryptoServerConfigForTest(const QuicClock* clock,
321 QuicRandom* rand,
nharperba5f32c2019-05-13 12:21:31 -0700322 QuicCryptoServerConfig* crypto_config) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500323 QuicCryptoServerConfig::ConfigOptions options;
324 options.channel_id_enabled = true;
QUICHE teamd5af58a2019-03-14 20:35:50 -0700325 std::unique_ptr<CryptoHandshakeMessage> scfg =
326 crypto_config->AddDefaultConfig(rand, clock, options);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500327}
328
329void SendHandshakeMessageToStream(QuicCryptoStream* stream,
330 const CryptoHandshakeMessage& message,
dschinazi17d42422019-06-18 16:35:07 -0700331 Perspective /*perspective*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500332 const QuicData& data = message.GetSerialized();
333 QuicSession* session = QuicStreamPeer::session(stream);
renjietangd1d00852019-09-06 10:43:12 -0700334 if (!QuicVersionUsesCryptoFrames(session->transport_version())) {
335 QuicStreamFrame frame(
336 QuicUtils::GetCryptoStreamId(session->transport_version()), false,
337 stream->crypto_bytes_read(), data.AsStringPiece());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500338 stream->OnStreamFrame(frame);
339 } else {
340 EncryptionLevel level = session->connection()->last_decrypted_level();
341 QuicCryptoFrame frame(level, stream->BytesReadOnLevel(level),
342 data.AsStringPiece());
343 stream->OnCryptoFrame(frame);
344 }
345}
346
347void CommunicateHandshakeMessages(PacketSavingConnection* client_conn,
348 QuicCryptoStream* client,
349 PacketSavingConnection* server_conn,
350 QuicCryptoStream* server) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500351 size_t client_i = 0, server_i = 0;
fayang685367a2020-01-14 10:40:15 -0800352 while (!client->one_rtt_keys_available() ||
353 !server->one_rtt_keys_available()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500354 ASSERT_GT(client_conn->encrypted_packets_.size(), client_i);
355 QUIC_LOG(INFO) << "Processing "
356 << client_conn->encrypted_packets_.size() - client_i
357 << " packets client->server";
358 MovePackets(client_conn, &client_i, server, server_conn,
359 Perspective::IS_SERVER);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500360
fayang685367a2020-01-14 10:40:15 -0800361 if (client->one_rtt_keys_available() && server->one_rtt_keys_available() &&
nharperdf7a77b2019-11-11 13:12:45 -0800362 server_conn->encrypted_packets_.size() == server_i) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500363 break;
364 }
365 ASSERT_GT(server_conn->encrypted_packets_.size(), server_i);
366 QUIC_LOG(INFO) << "Processing "
367 << server_conn->encrypted_packets_.size() - server_i
368 << " packets server->client";
369 MovePackets(server_conn, &server_i, client, client_conn,
370 Perspective::IS_CLIENT);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500371 }
372}
373
374std::pair<size_t, size_t> AdvanceHandshake(PacketSavingConnection* client_conn,
375 QuicCryptoStream* client,
376 size_t client_i,
377 PacketSavingConnection* server_conn,
378 QuicCryptoStream* server,
379 size_t server_i) {
380 QUIC_LOG(INFO) << "Processing "
381 << client_conn->encrypted_packets_.size() - client_i
382 << " packets client->server";
383 MovePackets(client_conn, &client_i, server, server_conn,
384 Perspective::IS_SERVER);
385
386 QUIC_LOG(INFO) << "Processing "
387 << server_conn->encrypted_packets_.size() - server_i
388 << " packets server->client";
389 if (server_conn->encrypted_packets_.size() - server_i == 2) {
390 QUIC_LOG(INFO) << "here";
391 }
392 MovePackets(server_conn, &server_i, client, client_conn,
393 Perspective::IS_CLIENT);
394
395 return std::make_pair(client_i, server_i);
396}
397
vasilvvc48c8712019-03-11 13:38:16 -0700398std::string GetValueForTag(const CryptoHandshakeMessage& message, QuicTag tag) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500399 auto it = message.tag_value_map().find(tag);
400 if (it == message.tag_value_map().end()) {
vasilvvc48c8712019-03-11 13:38:16 -0700401 return std::string();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500402 }
403 return it->second;
404}
405
406uint64_t LeafCertHashForTesting() {
407 QuicReferenceCountedPointer<ProofSource::Chain> chain;
408 QuicSocketAddress server_address(QuicIpAddress::Any4(), 42);
409 QuicCryptoProof proof;
410 std::unique_ptr<ProofSource> proof_source(ProofSourceForTesting());
411
412 class Callback : public ProofSource::Callback {
413 public:
414 Callback(bool* ok, QuicReferenceCountedPointer<ProofSource::Chain>* chain)
415 : ok_(ok), chain_(chain) {}
416
417 void Run(bool ok,
418 const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
419 const QuicCryptoProof& /* proof */,
420 std::unique_ptr<ProofSource::Details> /* details */) override {
421 *ok_ = ok;
422 *chain_ = chain;
423 }
424
425 private:
426 bool* ok_;
427 QuicReferenceCountedPointer<ProofSource::Chain>* chain_;
428 };
429
430 // Note: relies on the callback being invoked synchronously
431 bool ok = false;
432 proof_source->GetProof(
433 server_address, "", "", AllSupportedTransportVersions().front(), "",
434 std::unique_ptr<ProofSource::Callback>(new Callback(&ok, &chain)));
435 if (!ok || chain->certs.empty()) {
436 DCHECK(false) << "Proof generation failed";
437 return 0;
438 }
439
440 return QuicUtils::FNV1a_64_Hash(chain->certs.at(0));
441}
442
443class MockCommonCertSets : public CommonCertSets {
444 public:
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800445 MockCommonCertSets(quiche::QuicheStringPiece cert,
446 uint64_t hash,
447 uint32_t index)
QUICHE teama6ef0a62019-03-07 20:34:33 -0500448 : cert_(cert), hash_(hash), index_(index) {}
449
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800450 quiche::QuicheStringPiece GetCommonHashes() const override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500451 QUIC_BUG << "not implemented";
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800452 return quiche::QuicheStringPiece();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500453 }
454
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800455 quiche::QuicheStringPiece GetCert(uint64_t hash,
456 uint32_t index) const override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500457 if (hash == hash_ && index == index_) {
458 return cert_;
459 }
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800460 return quiche::QuicheStringPiece();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500461 }
462
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800463 bool MatchCert(quiche::QuicheStringPiece cert,
464 quiche::QuicheStringPiece common_set_hashes,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500465 uint64_t* out_hash,
466 uint32_t* out_index) const override {
467 if (cert != cert_) {
468 return false;
469 }
470
471 if (common_set_hashes.size() % sizeof(uint64_t) != 0) {
472 return false;
473 }
474 bool client_has_set = false;
475 for (size_t i = 0; i < common_set_hashes.size(); i += sizeof(uint64_t)) {
476 uint64_t hash;
477 memcpy(&hash, common_set_hashes.data() + i, sizeof(hash));
478 if (hash == hash_) {
479 client_has_set = true;
480 break;
481 }
482 }
483
484 if (!client_has_set) {
485 return false;
486 }
487
488 *out_hash = hash_;
489 *out_index = index_;
490 return true;
491 }
492
493 private:
vasilvvc48c8712019-03-11 13:38:16 -0700494 const std::string cert_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500495 const uint64_t hash_;
496 const uint32_t index_;
497};
498
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800499CommonCertSets* MockCommonCertSets(quiche::QuicheStringPiece cert,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500500 uint64_t hash,
501 uint32_t index) {
502 return new class MockCommonCertSets(cert, hash, index);
503}
504
wub9b9cc812019-05-20 09:01:52 -0700505void FillInDummyReject(CryptoHandshakeMessage* rej) {
506 rej->set_tag(kREJ);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500507
508 // Minimum SCFG that passes config validation checks.
509 // clang-format off
510 unsigned char scfg[] = {
511 // SCFG
512 0x53, 0x43, 0x46, 0x47,
513 // num entries
514 0x01, 0x00,
515 // padding
516 0x00, 0x00,
517 // EXPY
518 0x45, 0x58, 0x50, 0x59,
519 // EXPY end offset
520 0x08, 0x00, 0x00, 0x00,
521 // Value
522 '1', '2', '3', '4',
523 '5', '6', '7', '8'
524 };
525 // clang-format on
526 rej->SetValue(kSCFG, scfg);
527 rej->SetStringPiece(kServerNonceTag, "SERVER_NONCE");
528 int64_t ttl = 2 * 24 * 60 * 60;
529 rej->SetValue(kSTTL, ttl);
530 std::vector<QuicTag> reject_reasons;
531 reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
532 rej->SetVector(kRREJ, reject_reasons);
533}
534
QUICHE teamfbfd3622019-03-26 10:59:32 -0700535namespace {
536
537#define RETURN_STRING_LITERAL(x) \
538 case x: \
539 return #x
540
541std::string EncryptionLevelString(EncryptionLevel level) {
542 switch (level) {
543 RETURN_STRING_LITERAL(ENCRYPTION_INITIAL);
544 RETURN_STRING_LITERAL(ENCRYPTION_HANDSHAKE);
545 RETURN_STRING_LITERAL(ENCRYPTION_ZERO_RTT);
546 RETURN_STRING_LITERAL(ENCRYPTION_FORWARD_SECURE);
547 default:
548 return "";
549 }
550}
551
552void CompareCrypters(const QuicEncrypter* encrypter,
553 const QuicDecrypter* decrypter,
554 std::string label) {
zhongyi546cc452019-04-12 15:27:49 -0700555 if (encrypter == nullptr || decrypter == nullptr) {
556 ADD_FAILURE() << "Expected non-null crypters; have " << encrypter << " and "
557 << decrypter;
558 return;
559 }
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800560 quiche::QuicheStringPiece encrypter_key = encrypter->GetKey();
561 quiche::QuicheStringPiece encrypter_iv = encrypter->GetNoncePrefix();
562 quiche::QuicheStringPiece decrypter_key = decrypter->GetKey();
563 quiche::QuicheStringPiece decrypter_iv = decrypter->GetNoncePrefix();
dmcardle8f7df532020-01-07 13:28:57 -0800564 quiche::test::CompareCharArraysWithHexError(
565 label + " key", encrypter_key.data(), encrypter_key.length(),
566 decrypter_key.data(), decrypter_key.length());
567 quiche::test::CompareCharArraysWithHexError(
568 label + " iv", encrypter_iv.data(), encrypter_iv.length(),
569 decrypter_iv.data(), decrypter_iv.length());
QUICHE teamfbfd3622019-03-26 10:59:32 -0700570}
571
572} // namespace
573
QUICHE teama6ef0a62019-03-07 20:34:33 -0500574void CompareClientAndServerKeys(QuicCryptoClientStream* client,
575 QuicCryptoServerStream* server) {
576 QuicFramer* client_framer = QuicConnectionPeer::GetFramer(
577 QuicStreamPeer::session(client)->connection());
578 QuicFramer* server_framer = QuicConnectionPeer::GetFramer(
579 QuicStreamPeer::session(server)->connection());
QUICHE teamfbfd3622019-03-26 10:59:32 -0700580 for (EncryptionLevel level :
581 {ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
582 SCOPED_TRACE(EncryptionLevelString(level));
583 const QuicEncrypter* client_encrypter(
584 QuicFramerPeer::GetEncrypter(client_framer, level));
585 const QuicDecrypter* server_decrypter(
586 QuicFramerPeer::GetDecrypter(server_framer, level));
587 if (level == ENCRYPTION_FORWARD_SECURE ||
588 !(client_encrypter == nullptr && server_decrypter == nullptr)) {
589 CompareCrypters(client_encrypter, server_decrypter,
590 "client " + EncryptionLevelString(level) + " write");
591 }
592 const QuicEncrypter* server_encrypter(
593 QuicFramerPeer::GetEncrypter(server_framer, level));
594 const QuicDecrypter* client_decrypter(
595 QuicFramerPeer::GetDecrypter(client_framer, level));
596 if (level == ENCRYPTION_FORWARD_SECURE ||
597 !(server_encrypter == nullptr && client_decrypter == nullptr)) {
598 CompareCrypters(server_encrypter, client_decrypter,
599 "server " + EncryptionLevelString(level) + " write");
600 }
601 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500602
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800603 quiche::QuicheStringPiece client_subkey_secret =
QUICHE teama6ef0a62019-03-07 20:34:33 -0500604 client->crypto_negotiated_params().subkey_secret;
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800605 quiche::QuicheStringPiece server_subkey_secret =
QUICHE teama6ef0a62019-03-07 20:34:33 -0500606 server->crypto_negotiated_params().subkey_secret;
dmcardle8f7df532020-01-07 13:28:57 -0800607 quiche::test::CompareCharArraysWithHexError(
608 "subkey secret", client_subkey_secret.data(),
609 client_subkey_secret.length(), server_subkey_secret.data(),
610 server_subkey_secret.length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500611
612 const char kSampleLabel[] = "label";
613 const char kSampleContext[] = "context";
614 const size_t kSampleOutputLength = 32;
vasilvvc48c8712019-03-11 13:38:16 -0700615 std::string client_key_extraction;
616 std::string server_key_extraction;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500617 EXPECT_TRUE(client->ExportKeyingMaterial(kSampleLabel, kSampleContext,
618 kSampleOutputLength,
619 &client_key_extraction));
620 EXPECT_TRUE(server->ExportKeyingMaterial(kSampleLabel, kSampleContext,
621 kSampleOutputLength,
622 &server_key_extraction));
dmcardle8f7df532020-01-07 13:28:57 -0800623 quiche::test::CompareCharArraysWithHexError(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500624 "sample key extraction", client_key_extraction.data(),
625 client_key_extraction.length(), server_key_extraction.data(),
626 server_key_extraction.length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500627}
628
629QuicTag ParseTag(const char* tagstr) {
630 const size_t len = strlen(tagstr);
631 CHECK_NE(0u, len);
632
633 QuicTag tag = 0;
634
635 if (tagstr[0] == '#') {
636 CHECK_EQ(static_cast<size_t>(1 + 2 * 4), len);
637 tagstr++;
638
639 for (size_t i = 0; i < 8; i++) {
640 tag <<= 4;
641
642 uint8_t v = 0;
643 CHECK(HexChar(tagstr[i], &v));
644 tag |= v;
645 }
646
647 return tag;
648 }
649
650 CHECK_LE(len, 4u);
651 for (size_t i = 0; i < 4; i++) {
652 tag >>= 8;
653 if (i < len) {
654 tag |= static_cast<uint32_t>(tagstr[i]) << 24;
655 }
656 }
657
658 return tag;
659}
660
661CryptoHandshakeMessage CreateCHLO(
vasilvvc48c8712019-03-11 13:38:16 -0700662 std::vector<std::pair<std::string, std::string>> tags_and_values) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500663 return CreateCHLO(tags_and_values, -1);
664}
665
666CryptoHandshakeMessage CreateCHLO(
vasilvvc48c8712019-03-11 13:38:16 -0700667 std::vector<std::pair<std::string, std::string>> tags_and_values,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500668 int minimum_size_bytes) {
669 CryptoHandshakeMessage msg;
670 msg.set_tag(MakeQuicTag('C', 'H', 'L', 'O'));
671
672 if (minimum_size_bytes > 0) {
673 msg.set_minimum_size(minimum_size_bytes);
674 }
675
676 for (const auto& tag_and_value : tags_and_values) {
vasilvvc48c8712019-03-11 13:38:16 -0700677 const std::string& tag = tag_and_value.first;
678 const std::string& value = tag_and_value.second;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500679
680 const QuicTag quic_tag = ParseTag(tag.c_str());
681
682 size_t value_len = value.length();
683 if (value_len > 0 && value[0] == '#') {
684 // This is ascii encoded hex.
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800685 std::string hex_value = quiche::QuicheTextUtils::HexDecode(
686 quiche::QuicheStringPiece(&value[1]));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500687 msg.SetStringPiece(quic_tag, hex_value);
688 continue;
689 }
690 msg.SetStringPiece(quic_tag, value);
691 }
692
693 // The CryptoHandshakeMessage needs to be serialized and parsed to ensure
694 // that any padding is included.
QUICHE team3fe6a8b2019-03-14 09:10:38 -0700695 std::unique_ptr<QuicData> bytes =
696 CryptoFramer::ConstructHandshakeMessage(msg);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500697 std::unique_ptr<CryptoHandshakeMessage> parsed(
698 CryptoFramer::ParseMessage(bytes->AsStringPiece()));
699 CHECK(parsed);
700
701 return *parsed;
702}
703
QUICHE teama6ef0a62019-03-07 20:34:33 -0500704void MovePackets(PacketSavingConnection* source_conn,
705 size_t* inout_packet_index,
706 QuicCryptoStream* dest_stream,
707 PacketSavingConnection* dest_conn,
708 Perspective dest_perspective) {
709 SimpleQuicFramer framer(source_conn->supported_versions(), dest_perspective);
dschinazib953d022019-08-01 18:05:58 -0700710 QuicFramerPeer::SetLastSerializedServerConnectionId(framer.framer(),
711 TestConnectionId());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500712
713 SimpleQuicFramer null_encryption_framer(source_conn->supported_versions(),
714 dest_perspective);
dschinazib953d022019-08-01 18:05:58 -0700715 QuicFramerPeer::SetLastSerializedServerConnectionId(
716 null_encryption_framer.framer(), TestConnectionId());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500717
718 size_t index = *inout_packet_index;
719 for (; index < source_conn->encrypted_packets_.size(); index++) {
720 // In order to properly test the code we need to perform encryption and
721 // decryption so that the crypters latch when expected. The crypters are in
722 // |dest_conn|, but we don't want to try and use them there. Instead we swap
723 // them into |framer|, perform the decryption with them, and then swap ther
724 // back.
725 QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
fayang5f135052019-08-22 17:59:40 -0700726 QuicConnectionPeer::AddBytesReceived(
727 dest_conn, source_conn->encrypted_packets_[index]->length());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500728 if (!framer.ProcessPacket(*source_conn->encrypted_packets_[index])) {
729 // The framer will be unable to decrypt forward-secure packets sent after
730 // the handshake is complete. Don't treat them as handshake packets.
731 break;
732 }
733 QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
734 dest_conn->OnDecryptedPacket(framer.last_decrypted_level());
735
736 if (dest_stream->handshake_protocol() == PROTOCOL_TLS1_3) {
737 // Try to process the packet with a framer that only has the NullDecrypter
738 // for decryption. If ProcessPacket succeeds, that means the packet was
739 // encrypted with the NullEncrypter. With the TLS handshaker in use, no
740 // packets should ever be encrypted with the NullEncrypter, instead
741 // they're encrypted with an obfuscation cipher based on QUIC version and
742 // connection ID.
743 ASSERT_FALSE(null_encryption_framer.ProcessPacket(
744 *source_conn->encrypted_packets_[index]))
745 << "No TLS packets should be encrypted with the NullEncrypter";
746 }
747
748 // Since we're using QuicFramers separate from the connections to move
749 // packets, the QuicConnection never gets notified about what level the last
750 // packet was decrypted at. This is needed by TLS to know what encryption
751 // level was used for the data it's receiving, so we plumb this information
752 // from the SimpleQuicFramer back into the connection.
753 dest_conn->OnDecryptedPacket(framer.last_decrypted_level());
754
755 QuicConnectionPeer::SetCurrentPacket(
756 dest_conn, source_conn->encrypted_packets_[index]->AsStringPiece());
757 for (const auto& stream_frame : framer.stream_frames()) {
renjietange01b3eb2019-08-20 11:04:54 -0700758 // Ignore stream frames that are sent on other streams in the crypto
759 // event.
760 if (stream_frame->stream_id == dest_stream->id()) {
761 dest_stream->OnStreamFrame(*stream_frame);
762 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500763 }
764 for (const auto& crypto_frame : framer.crypto_frames()) {
765 dest_stream->OnCryptoFrame(*crypto_frame);
766 }
767 }
768 *inout_packet_index = index;
769
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800770 QuicConnectionPeer::SetCurrentPacket(dest_conn,
771 quiche::QuicheStringPiece(nullptr, 0));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500772}
773
774CryptoHandshakeMessage GenerateDefaultInchoateCHLO(
775 const QuicClock* clock,
776 QuicTransportVersion version,
777 QuicCryptoServerConfig* crypto_config) {
778 // clang-format off
779 return CreateCHLO(
780 {{"PDMD", "X509"},
781 {"AEAD", "AESG"},
782 {"KEXS", "C255"},
783 {"PUBS", GenerateClientPublicValuesHex().c_str()},
784 {"NONC", GenerateClientNonceHex(clock, crypto_config).c_str()},
785 {"VER\0", QuicVersionLabelToString(
786 QuicVersionToQuicVersionLabel(version)).c_str()}},
787 kClientHelloMinimumSize);
788 // clang-format on
789}
790
vasilvvc48c8712019-03-11 13:38:16 -0700791std::string GenerateClientNonceHex(const QuicClock* clock,
792 QuicCryptoServerConfig* crypto_config) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500793 QuicCryptoServerConfig::ConfigOptions old_config_options;
794 QuicCryptoServerConfig::ConfigOptions new_config_options;
795 old_config_options.id = "old-config-id";
QUICHE teamd5af58a2019-03-14 20:35:50 -0700796 crypto_config->AddDefaultConfig(QuicRandom::GetInstance(), clock,
797 old_config_options);
QUICHE teambbaa8be2019-03-21 12:54:17 -0700798 QuicServerConfigProtobuf primary_config = crypto_config->GenerateConfig(
799 QuicRandom::GetInstance(), clock, new_config_options);
800 primary_config.set_primary_time(clock->WallNow().ToUNIXSeconds());
QUICHE teamd5af58a2019-03-14 20:35:50 -0700801 std::unique_ptr<CryptoHandshakeMessage> msg =
wub76855422019-10-24 08:53:04 -0700802 crypto_config->AddConfig(primary_config, clock->WallNow());
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800803 quiche::QuicheStringPiece orbit;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500804 CHECK(msg->GetStringPiece(kORBT, &orbit));
vasilvvc48c8712019-03-11 13:38:16 -0700805 std::string nonce;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500806 CryptoUtils::GenerateNonce(clock->WallNow(), QuicRandom::GetInstance(), orbit,
807 &nonce);
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800808 return ("#" + quiche::QuicheTextUtils::HexEncode(nonce));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500809}
810
vasilvvc48c8712019-03-11 13:38:16 -0700811std::string GenerateClientPublicValuesHex() {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500812 char public_value[32];
813 memset(public_value, 42, sizeof(public_value));
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800814 return ("#" + quiche::QuicheTextUtils::HexEncode(public_value,
815 sizeof(public_value)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500816}
817
818void GenerateFullCHLO(const CryptoHandshakeMessage& inchoate_chlo,
819 QuicCryptoServerConfig* crypto_config,
820 QuicSocketAddress server_addr,
821 QuicSocketAddress client_addr,
822 QuicTransportVersion version,
823 const QuicClock* clock,
824 QuicReferenceCountedPointer<QuicSignedServerConfig> proof,
825 QuicCompressedCertsCache* compressed_certs_cache,
826 CryptoHandshakeMessage* out) {
827 // Pass a inchoate CHLO.
828 FullChloGenerator generator(crypto_config, server_addr, client_addr, clock,
829 proof, compressed_certs_cache, out);
830 crypto_config->ValidateClientHello(
831 inchoate_chlo, client_addr.host(), server_addr, version, clock, proof,
832 generator.GetValidateClientHelloCallback());
833}
834
835} // namespace crypto_test_utils
836} // namespace test
837} // namespace quic