xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_crypto_client_stream_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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/core/quic_crypto_client_stream.h"
6 
7 #include <memory>
8 #include <string>
9 #include <utility>
10 
11 #include "absl/base/macros.h"
12 #include "quiche/quic/core/crypto/aes_128_gcm_12_encrypter.h"
13 #include "quiche/quic/core/crypto/quic_decrypter.h"
14 #include "quiche/quic/core/crypto/quic_encrypter.h"
15 #include "quiche/quic/core/quic_packets.h"
16 #include "quiche/quic/core/quic_server_id.h"
17 #include "quiche/quic/core/quic_utils.h"
18 #include "quiche/quic/platform/api/quic_flags.h"
19 #include "quiche/quic/platform/api/quic_test.h"
20 #include "quiche/quic/test_tools/crypto_test_utils.h"
21 #include "quiche/quic/test_tools/quic_stream_peer.h"
22 #include "quiche/quic/test_tools/quic_stream_sequencer_peer.h"
23 #include "quiche/quic/test_tools/quic_test_utils.h"
24 #include "quiche/quic/test_tools/simple_quic_framer.h"
25 #include "quiche/quic/test_tools/simple_session_cache.h"
26 #include "quiche/common/test_tools/quiche_test_utils.h"
27 
28 using testing::_;
29 
30 namespace quic {
31 namespace test {
32 namespace {
33 
34 const char kServerHostname[] = "test.example.com";
35 const uint16_t kServerPort = 443;
36 
37 // This test tests the client-side of the QUIC crypto handshake. It does not
38 // test the TLS handshake - that is in tls_client_handshaker_test.cc.
39 class QuicCryptoClientStreamTest : public QuicTest {
40  public:
QuicCryptoClientStreamTest()41   QuicCryptoClientStreamTest()
42       : supported_versions_(AllSupportedVersionsWithQuicCrypto()),
43         server_id_(kServerHostname, kServerPort, false),
44         crypto_config_(crypto_test_utils::ProofVerifierForTesting(),
45                        std::make_unique<test::SimpleSessionCache>()),
46         server_crypto_config_(
47             crypto_test_utils::CryptoServerConfigForTesting()) {
48     CreateConnection();
49   }
50 
CreateSession()51   void CreateSession() {
52     session_ = std::make_unique<TestQuicSpdyClientSession>(
53         connection_, DefaultQuicConfig(), supported_versions_, server_id_,
54         &crypto_config_);
55     EXPECT_CALL(*session_, GetAlpnsToOffer())
56         .WillRepeatedly(testing::Return(std::vector<std::string>(
57             {AlpnForVersion(connection_->version())})));
58   }
59 
CreateConnection()60   void CreateConnection() {
61     connection_ =
62         new PacketSavingConnection(&client_helper_, &alarm_factory_,
63                                    Perspective::IS_CLIENT, supported_versions_);
64     // Advance the time, because timers do not like uninitialized times.
65     connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
66     CreateSession();
67   }
68 
CompleteCryptoHandshake()69   void CompleteCryptoHandshake() {
70     int proof_verify_details_calls = 1;
71     if (stream()->handshake_protocol() != PROTOCOL_TLS1_3) {
72       EXPECT_CALL(*session_, OnProofValid(testing::_))
73           .Times(testing::AtLeast(1));
74       proof_verify_details_calls = 0;
75     }
76     EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_))
77         .Times(testing::AtLeast(proof_verify_details_calls));
78     stream()->CryptoConnect();
79     QuicConfig config;
80     crypto_test_utils::HandshakeWithFakeServer(
81         &config, server_crypto_config_.get(), &server_helper_, &alarm_factory_,
82         connection_, stream(), AlpnForVersion(connection_->version()));
83   }
84 
stream()85   QuicCryptoClientStream* stream() {
86     return session_->GetMutableCryptoStream();
87   }
88 
89   MockQuicConnectionHelper server_helper_;
90   MockQuicConnectionHelper client_helper_;
91   MockAlarmFactory alarm_factory_;
92   PacketSavingConnection* connection_;
93   ParsedQuicVersionVector supported_versions_;
94   std::unique_ptr<TestQuicSpdyClientSession> session_;
95   QuicServerId server_id_;
96   CryptoHandshakeMessage message_;
97   QuicCryptoClientConfig crypto_config_;
98   std::unique_ptr<QuicCryptoServerConfig> server_crypto_config_;
99 };
100 
TEST_F(QuicCryptoClientStreamTest,NotInitiallyConected)101 TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) {
102   EXPECT_FALSE(stream()->encryption_established());
103   EXPECT_FALSE(stream()->one_rtt_keys_available());
104 }
105 
TEST_F(QuicCryptoClientStreamTest,ConnectedAfterSHLO)106 TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
107   CompleteCryptoHandshake();
108   EXPECT_TRUE(stream()->encryption_established());
109   EXPECT_TRUE(stream()->one_rtt_keys_available());
110   EXPECT_FALSE(stream()->IsResumption());
111   EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_no_session_offered);
112 }
113 
TEST_F(QuicCryptoClientStreamTest,MessageAfterHandshake)114 TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
115   CompleteCryptoHandshake();
116 
117   EXPECT_CALL(
118       *connection_,
119       CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE, _, _));
120   message_.set_tag(kCHLO);
121   crypto_test_utils::SendHandshakeMessageToStream(stream(), message_,
122                                                   Perspective::IS_CLIENT);
123 }
124 
TEST_F(QuicCryptoClientStreamTest,BadMessageType)125 TEST_F(QuicCryptoClientStreamTest, BadMessageType) {
126   stream()->CryptoConnect();
127 
128   message_.set_tag(kCHLO);
129 
130   EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
131                                             "Expected REJ", _));
132   crypto_test_utils::SendHandshakeMessageToStream(stream(), message_,
133                                                   Perspective::IS_CLIENT);
134 }
135 
TEST_F(QuicCryptoClientStreamTest,NegotiatedParameters)136 TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
137   CompleteCryptoHandshake();
138 
139   const QuicConfig* config = session_->config();
140   EXPECT_EQ(kMaximumIdleTimeoutSecs, config->IdleNetworkTimeout().ToSeconds());
141 
142   const QuicCryptoNegotiatedParameters& crypto_params(
143       stream()->crypto_negotiated_params());
144   EXPECT_EQ(crypto_config_.aead[0], crypto_params.aead);
145   EXPECT_EQ(crypto_config_.kexs[0], crypto_params.key_exchange);
146 }
147 
TEST_F(QuicCryptoClientStreamTest,ExpiredServerConfig)148 TEST_F(QuicCryptoClientStreamTest, ExpiredServerConfig) {
149   // Seed the config with a cached server config.
150   CompleteCryptoHandshake();
151 
152   // Recreate connection with the new config.
153   CreateConnection();
154 
155   // Advance time 5 years to ensure that we pass the expiry time of the cached
156   // server config.
157   connection_->AdvanceTime(
158       QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
159 
160   EXPECT_CALL(*session_, OnProofValid(testing::_));
161   stream()->CryptoConnect();
162   // Check that a client hello was sent.
163   ASSERT_EQ(1u, connection_->encrypted_packets_.size());
164   EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level());
165 }
166 
TEST_F(QuicCryptoClientStreamTest,ClientTurnedOffZeroRtt)167 TEST_F(QuicCryptoClientStreamTest, ClientTurnedOffZeroRtt) {
168   // Seed the config with a cached server config.
169   CompleteCryptoHandshake();
170 
171   // Recreate connection with the new config.
172   CreateConnection();
173 
174   // Set connection option.
175   QuicTagVector options;
176   options.push_back(kQNZ2);
177   session_->config()->SetClientConnectionOptions(options);
178 
179   CompleteCryptoHandshake();
180   // Check that two client hellos were sent, one inchoate and one normal.
181   EXPECT_EQ(2, stream()->num_sent_client_hellos());
182   EXPECT_FALSE(stream()->EarlyDataAccepted());
183   EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_disabled);
184 }
185 
TEST_F(QuicCryptoClientStreamTest,ClockSkew)186 TEST_F(QuicCryptoClientStreamTest, ClockSkew) {
187   // Test that if the client's clock is skewed with respect to the server,
188   // the handshake succeeds. In the past, the client would get the server
189   // config, notice that it had already expired and then close the connection.
190 
191   // Advance time 5 years to ensure that we pass the expiry time in the server
192   // config, but the TTL is used instead.
193   connection_->AdvanceTime(
194       QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
195 
196   // The handshakes completes!
197   CompleteCryptoHandshake();
198 }
199 
TEST_F(QuicCryptoClientStreamTest,InvalidCachedServerConfig)200 TEST_F(QuicCryptoClientStreamTest, InvalidCachedServerConfig) {
201   // Seed the config with a cached server config.
202   CompleteCryptoHandshake();
203 
204   // Recreate connection with the new config.
205   CreateConnection();
206 
207   QuicCryptoClientConfig::CachedState* state =
208       crypto_config_.LookupOrCreate(server_id_);
209 
210   std::vector<std::string> certs = state->certs();
211   std::string cert_sct = state->cert_sct();
212   std::string signature = state->signature();
213   std::string chlo_hash = state->chlo_hash();
214   state->SetProof(certs, cert_sct, chlo_hash, signature + signature);
215 
216   EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_))
217       .Times(testing::AnyNumber());
218   stream()->CryptoConnect();
219   // Check that a client hello was sent.
220   ASSERT_EQ(1u, connection_->encrypted_packets_.size());
221 }
222 
TEST_F(QuicCryptoClientStreamTest,ServerConfigUpdate)223 TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) {
224   // Test that the crypto client stream can receive server config updates after
225   // the connection has been established.
226   CompleteCryptoHandshake();
227 
228   QuicCryptoClientConfig::CachedState* state =
229       crypto_config_.LookupOrCreate(server_id_);
230 
231   // Ensure cached STK is different to what we send in the handshake.
232   EXPECT_NE("xstk", state->source_address_token());
233 
234   // Initialize using {...} syntax to avoid trailing \0 if converting from
235   // string.
236   unsigned char stk[] = {'x', 's', 't', 'k'};
237 
238   // Minimum SCFG that passes config validation checks.
239   unsigned char scfg[] = {// SCFG
240                           0x53, 0x43, 0x46, 0x47,
241                           // num entries
242                           0x01, 0x00,
243                           // padding
244                           0x00, 0x00,
245                           // EXPY
246                           0x45, 0x58, 0x50, 0x59,
247                           // EXPY end offset
248                           0x08, 0x00, 0x00, 0x00,
249                           // Value
250                           '1', '2', '3', '4', '5', '6', '7', '8'};
251 
252   CryptoHandshakeMessage server_config_update;
253   server_config_update.set_tag(kSCUP);
254   server_config_update.SetValue(kSourceAddressTokenTag, stk);
255   server_config_update.SetValue(kSCFG, scfg);
256   const uint64_t expiry_seconds = 60 * 60 * 24 * 2;
257   server_config_update.SetValue(kSTTL, expiry_seconds);
258 
259   crypto_test_utils::SendHandshakeMessageToStream(
260       stream(), server_config_update, Perspective::IS_SERVER);
261 
262   // Make sure that the STK and SCFG are cached correctly.
263   EXPECT_EQ("xstk", state->source_address_token());
264 
265   const std::string& cached_scfg = state->server_config();
266   quiche::test::CompareCharArraysWithHexError(
267       "scfg", cached_scfg.data(), cached_scfg.length(),
268       reinterpret_cast<char*>(scfg), ABSL_ARRAYSIZE(scfg));
269 
270   QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(stream());
271   EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
272 }
273 
TEST_F(QuicCryptoClientStreamTest,ServerConfigUpdateWithCert)274 TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) {
275   // Test that the crypto client stream can receive and use server config
276   // updates with certificates after the connection has been established.
277   CompleteCryptoHandshake();
278 
279   // Build a server config update message with certificates
280   QuicCryptoServerConfig crypto_config(
281       QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
282       crypto_test_utils::ProofSourceForTesting(), KeyExchangeSource::Default());
283   crypto_test_utils::SetupCryptoServerConfigForTest(
284       connection_->clock(), QuicRandom::GetInstance(), &crypto_config);
285   SourceAddressTokens tokens;
286   QuicCompressedCertsCache cache(1);
287   CachedNetworkParameters network_params;
288   CryptoHandshakeMessage server_config_update;
289 
290   class Callback : public BuildServerConfigUpdateMessageResultCallback {
291    public:
292     Callback(bool* ok, CryptoHandshakeMessage* message)
293         : ok_(ok), message_(message) {}
294     void Run(bool ok, const CryptoHandshakeMessage& message) override {
295       *ok_ = ok;
296       *message_ = message;
297     }
298 
299    private:
300     bool* ok_;
301     CryptoHandshakeMessage* message_;
302   };
303 
304   // Note: relies on the callback being invoked synchronously
305   bool ok = false;
306   crypto_config.BuildServerConfigUpdateMessage(
307       session_->transport_version(), stream()->chlo_hash(), tokens,
308       QuicSocketAddress(QuicIpAddress::Loopback6(), 1234),
309       QuicSocketAddress(QuicIpAddress::Loopback6(), 4321), connection_->clock(),
310       QuicRandom::GetInstance(), &cache, stream()->crypto_negotiated_params(),
311       &network_params,
312       std::unique_ptr<BuildServerConfigUpdateMessageResultCallback>(
313           new Callback(&ok, &server_config_update)));
314   EXPECT_TRUE(ok);
315 
316   EXPECT_CALL(*session_, OnProofValid(testing::_));
317   crypto_test_utils::SendHandshakeMessageToStream(
318       stream(), server_config_update, Perspective::IS_SERVER);
319 
320   // Recreate connection with the new config and verify a 0-RTT attempt.
321   CreateConnection();
322 
323   EXPECT_CALL(*session_, OnProofValid(testing::_));
324   EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_))
325       .Times(testing::AnyNumber());
326   stream()->CryptoConnect();
327   EXPECT_TRUE(session_->IsEncryptionEstablished());
328 }
329 
TEST_F(QuicCryptoClientStreamTest,ServerConfigUpdateBeforeHandshake)330 TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateBeforeHandshake) {
331   EXPECT_CALL(
332       *connection_,
333       CloseConnection(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE, _, _));
334   CryptoHandshakeMessage server_config_update;
335   server_config_update.set_tag(kSCUP);
336   crypto_test_utils::SendHandshakeMessageToStream(
337       stream(), server_config_update, Perspective::IS_SERVER);
338 }
339 
340 }  // namespace
341 }  // namespace test
342 }  // namespace quic
343