1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/test_tools/crypto_test_utils.h"
6
7 #include <utility>
8
9 #include "absl/strings/escaping.h"
10 #include "absl/strings/string_view.h"
11 #include "quiche/quic/core/proto/crypto_server_config_proto.h"
12 #include "quiche/quic/core/quic_utils.h"
13 #include "quiche/quic/platform/api/quic_test.h"
14 #include "quiche/quic/test_tools/mock_clock.h"
15
16 namespace quic {
17 namespace test {
18
19 class ShloVerifier {
20 public:
ShloVerifier(QuicCryptoServerConfig * crypto_config,QuicSocketAddress server_addr,QuicSocketAddress client_addr,const QuicClock * clock,quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> signed_config,QuicCompressedCertsCache * compressed_certs_cache,ParsedQuicVersion version)21 ShloVerifier(QuicCryptoServerConfig* crypto_config,
22 QuicSocketAddress server_addr, QuicSocketAddress client_addr,
23 const QuicClock* clock,
24 quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig>
25 signed_config,
26 QuicCompressedCertsCache* compressed_certs_cache,
27 ParsedQuicVersion version)
28 : crypto_config_(crypto_config),
29 server_addr_(server_addr),
30 client_addr_(client_addr),
31 clock_(clock),
32 signed_config_(signed_config),
33 compressed_certs_cache_(compressed_certs_cache),
34 params_(new QuicCryptoNegotiatedParameters),
35 version_(version) {}
36
37 class ValidateClientHelloCallback : public ValidateClientHelloResultCallback {
38 public:
ValidateClientHelloCallback(ShloVerifier * shlo_verifier)39 explicit ValidateClientHelloCallback(ShloVerifier* shlo_verifier)
40 : shlo_verifier_(shlo_verifier) {}
Run(quiche::QuicheReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result,std::unique_ptr<ProofSource::Details>)41 void Run(quiche::QuicheReferenceCountedPointer<
42 ValidateClientHelloResultCallback::Result>
43 result,
44 std::unique_ptr<ProofSource::Details> /* details */) override {
45 shlo_verifier_->ValidateClientHelloDone(result);
46 }
47
48 private:
49 ShloVerifier* shlo_verifier_;
50 };
51
52 std::unique_ptr<ValidateClientHelloCallback>
GetValidateClientHelloCallback()53 GetValidateClientHelloCallback() {
54 return std::make_unique<ValidateClientHelloCallback>(this);
55 }
56
server_nonce()57 absl::string_view server_nonce() { return server_nonce_; }
chlo_accepted() const58 bool chlo_accepted() const { return chlo_accepted_; }
59
60 private:
ValidateClientHelloDone(const quiche::QuicheReferenceCountedPointer<ValidateClientHelloResultCallback::Result> & result)61 void ValidateClientHelloDone(
62 const quiche::QuicheReferenceCountedPointer<
63 ValidateClientHelloResultCallback::Result>& result) {
64 result_ = result;
65 crypto_config_->ProcessClientHello(
66 result_, /*reject_only=*/false,
67 /*connection_id=*/TestConnectionId(1), server_addr_, client_addr_,
68 version_, AllSupportedVersions(), clock_, QuicRandom::GetInstance(),
69 compressed_certs_cache_, params_, signed_config_,
70 /*total_framing_overhead=*/50, kDefaultMaxPacketSize,
71 GetProcessClientHelloCallback());
72 }
73
74 class ProcessClientHelloCallback : public ProcessClientHelloResultCallback {
75 public:
ProcessClientHelloCallback(ShloVerifier * shlo_verifier)76 explicit ProcessClientHelloCallback(ShloVerifier* shlo_verifier)
77 : shlo_verifier_(shlo_verifier) {}
Run(QuicErrorCode,const std::string &,std::unique_ptr<CryptoHandshakeMessage> message,std::unique_ptr<DiversificationNonce>,std::unique_ptr<ProofSource::Details>)78 void Run(QuicErrorCode /*error*/, const std::string& /*error_details*/,
79 std::unique_ptr<CryptoHandshakeMessage> message,
80 std::unique_ptr<DiversificationNonce> /*diversification_nonce*/,
81 std::unique_ptr<ProofSource::Details> /*proof_source_details*/)
82 override {
83 shlo_verifier_->ProcessClientHelloDone(std::move(message));
84 }
85
86 private:
87 ShloVerifier* shlo_verifier_;
88 };
89
GetProcessClientHelloCallback()90 std::unique_ptr<ProcessClientHelloCallback> GetProcessClientHelloCallback() {
91 return std::make_unique<ProcessClientHelloCallback>(this);
92 }
93
ProcessClientHelloDone(std::unique_ptr<CryptoHandshakeMessage> message)94 void ProcessClientHelloDone(std::unique_ptr<CryptoHandshakeMessage> message) {
95 if (message->tag() == kSHLO) {
96 chlo_accepted_ = true;
97 } else {
98 QUIC_LOG(INFO) << "Fail to pass validation. Get "
99 << message->DebugString();
100 chlo_accepted_ = false;
101 EXPECT_EQ(1u, result_->info.reject_reasons.size());
102 EXPECT_EQ(SERVER_NONCE_REQUIRED_FAILURE, result_->info.reject_reasons[0]);
103 server_nonce_ = result_->info.server_nonce;
104 }
105 }
106
107 QuicCryptoServerConfig* crypto_config_;
108 QuicSocketAddress server_addr_;
109 QuicSocketAddress client_addr_;
110 const QuicClock* clock_;
111 quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> signed_config_;
112 QuicCompressedCertsCache* compressed_certs_cache_;
113
114 quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
115 quiche::QuicheReferenceCountedPointer<
116 ValidateClientHelloResultCallback::Result>
117 result_;
118
119 const ParsedQuicVersion version_;
120 bool chlo_accepted_ = false;
121 absl::string_view server_nonce_;
122 };
123
124 class CryptoTestUtilsTest : public QuicTest {};
125
TEST_F(CryptoTestUtilsTest,TestGenerateFullCHLO)126 TEST_F(CryptoTestUtilsTest, TestGenerateFullCHLO) {
127 MockClock clock;
128 QuicCryptoServerConfig crypto_config(
129 QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
130 crypto_test_utils::ProofSourceForTesting(), KeyExchangeSource::Default());
131 QuicSocketAddress server_addr(QuicIpAddress::Any4(), 5);
132 QuicSocketAddress client_addr(QuicIpAddress::Loopback4(), 1);
133 quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> signed_config(
134 new QuicSignedServerConfig);
135 QuicCompressedCertsCache compressed_certs_cache(
136 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
137 CryptoHandshakeMessage full_chlo;
138
139 QuicCryptoServerConfig::ConfigOptions old_config_options;
140 old_config_options.id = "old-config-id";
141 crypto_config.AddDefaultConfig(QuicRandom::GetInstance(), &clock,
142 old_config_options);
143 QuicCryptoServerConfig::ConfigOptions new_config_options;
144 QuicServerConfigProtobuf primary_config = crypto_config.GenerateConfig(
145 QuicRandom::GetInstance(), &clock, new_config_options);
146 primary_config.set_primary_time(clock.WallNow().ToUNIXSeconds());
147 std::unique_ptr<CryptoHandshakeMessage> msg =
148 crypto_config.AddConfig(primary_config, clock.WallNow());
149 absl::string_view orbit;
150 ASSERT_TRUE(msg->GetStringPiece(kORBT, &orbit));
151 std::string nonce;
152 CryptoUtils::GenerateNonce(clock.WallNow(), QuicRandom::GetInstance(), orbit,
153 &nonce);
154 std::string nonce_hex = "#" + absl::BytesToHexString(nonce);
155
156 char public_value[32];
157 memset(public_value, 42, sizeof(public_value));
158 std::string pub_hex = "#" + absl::BytesToHexString(absl::string_view(
159 public_value, sizeof(public_value)));
160
161 // The methods below use a PROTOCOL_QUIC_CRYPTO version so we pick the
162 // first one from the list of supported versions.
163 QuicTransportVersion transport_version = QUIC_VERSION_UNSUPPORTED;
164 for (const ParsedQuicVersion& version : AllSupportedVersions()) {
165 if (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) {
166 transport_version = version.transport_version;
167 break;
168 }
169 }
170 ASSERT_NE(QUIC_VERSION_UNSUPPORTED, transport_version);
171
172 CryptoHandshakeMessage inchoate_chlo = crypto_test_utils::CreateCHLO(
173 {{"PDMD", "X509"},
174 {"AEAD", "AESG"},
175 {"KEXS", "C255"},
176 {"COPT", "SREJ"},
177 {"PUBS", pub_hex},
178 {"NONC", nonce_hex},
179 {"VER\0",
180 QuicVersionLabelToString(CreateQuicVersionLabel(
181 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, transport_version)))}},
182 kClientHelloMinimumSize);
183
184 crypto_test_utils::GenerateFullCHLO(inchoate_chlo, &crypto_config,
185 server_addr, client_addr,
186 transport_version, &clock, signed_config,
187 &compressed_certs_cache, &full_chlo);
188 // Verify that full_chlo can pass crypto_config's verification.
189 ShloVerifier shlo_verifier(
190 &crypto_config, server_addr, client_addr, &clock, signed_config,
191 &compressed_certs_cache,
192 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, transport_version));
193 crypto_config.ValidateClientHello(
194 full_chlo, client_addr, server_addr, transport_version, &clock,
195 signed_config, shlo_verifier.GetValidateClientHelloCallback());
196 ASSERT_EQ(shlo_verifier.chlo_accepted(),
197 !GetQuicReloadableFlag(quic_require_handshake_confirmation));
198 if (!shlo_verifier.chlo_accepted()) {
199 ShloVerifier shlo_verifier2(
200 &crypto_config, server_addr, client_addr, &clock, signed_config,
201 &compressed_certs_cache,
202 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, transport_version));
203 full_chlo.SetStringPiece(
204 kServerNonceTag,
205 "#" + absl::BytesToHexString(shlo_verifier.server_nonce()));
206 crypto_config.ValidateClientHello(
207 full_chlo, client_addr, server_addr, transport_version, &clock,
208 signed_config, shlo_verifier2.GetValidateClientHelloCallback());
209 EXPECT_TRUE(shlo_verifier2.chlo_accepted()) << full_chlo.DebugString();
210 }
211 }
212
213 } // namespace test
214 } // namespace quic
215