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_handshaker.h"
6 
7 #include <utility>
8 
9 #include "absl/strings/string_view.h"
10 #include "quiche/quic/core/proto/crypto_server_config_proto.h"
11 #include "quiche/quic/platform/api/quic_test.h"
12 #include "quiche/quic/test_tools/quic_test_utils.h"
13 
14 namespace quic::test {
15 namespace {
16 
17 class TestProofHandler : public QuicCryptoClientStream::ProofHandler {
18  public:
~TestProofHandler()19   ~TestProofHandler() override {}
OnProofValid(const QuicCryptoClientConfig::CachedState &)20   void OnProofValid(
21       const QuicCryptoClientConfig::CachedState& /*cached*/) override {}
OnProofVerifyDetailsAvailable(const ProofVerifyDetails &)22   void OnProofVerifyDetailsAvailable(
23       const ProofVerifyDetails& /*verify_details*/) override {}
24 };
25 
26 class InsecureProofVerifier : public ProofVerifier {
27  public:
InsecureProofVerifier()28   InsecureProofVerifier() {}
~InsecureProofVerifier()29   ~InsecureProofVerifier() override {}
30 
31   // ProofVerifier override.
VerifyProof(const std::string &,const uint16_t,const std::string &,QuicTransportVersion,absl::string_view,const std::vector<std::string> &,const std::string &,const std::string &,const ProofVerifyContext *,std::string *,std::unique_ptr<ProofVerifyDetails> *,std::unique_ptr<ProofVerifierCallback>)32   QuicAsyncStatus VerifyProof(
33       const std::string& /*hostname*/, const uint16_t /*port*/,
34       const std::string& /*server_config*/,
35       QuicTransportVersion /*transport_version*/,
36       absl::string_view /*chlo_hash*/,
37       const std::vector<std::string>& /*certs*/,
38       const std::string& /*cert_sct*/, const std::string& /*signature*/,
39       const ProofVerifyContext* /*context*/, std::string* /*error_details*/,
40       std::unique_ptr<ProofVerifyDetails>* /*verify_details*/,
41       std::unique_ptr<ProofVerifierCallback> /*callback*/) override {
42     return QUIC_SUCCESS;
43   }
44 
VerifyCertChain(const std::string &,const uint16_t,const std::vector<std::string> &,const std::string &,const std::string &,const ProofVerifyContext *,std::string *,std::unique_ptr<ProofVerifyDetails> *,uint8_t *,std::unique_ptr<ProofVerifierCallback>)45   QuicAsyncStatus VerifyCertChain(
46       const std::string& /*hostname*/, const uint16_t /*port*/,
47       const std::vector<std::string>& /*certs*/,
48       const std::string& /*ocsp_response*/, const std::string& /*cert_sct*/,
49       const ProofVerifyContext* /*context*/, std::string* /*error_details*/,
50       std::unique_ptr<ProofVerifyDetails>* /*details*/, uint8_t* /*out_alert*/,
51       std::unique_ptr<ProofVerifierCallback> /*callback*/) override {
52     return QUIC_SUCCESS;
53   }
54 
CreateDefaultContext()55   std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
56     return nullptr;
57   }
58 };
59 
60 class DummyProofSource : public ProofSource {
61  public:
DummyProofSource()62   DummyProofSource() {}
~DummyProofSource()63   ~DummyProofSource() override {}
64 
65   // ProofSource override.
GetProof(const QuicSocketAddress & server_address,const QuicSocketAddress & client_address,const std::string & hostname,const std::string &,QuicTransportVersion,absl::string_view,std::unique_ptr<Callback> callback)66   void GetProof(const QuicSocketAddress& server_address,
67                 const QuicSocketAddress& client_address,
68                 const std::string& hostname,
69                 const std::string& /*server_config*/,
70                 QuicTransportVersion /*transport_version*/,
71                 absl::string_view /*chlo_hash*/,
72                 std::unique_ptr<Callback> callback) override {
73     bool cert_matched_sni;
74     quiche::QuicheReferenceCountedPointer<ProofSource::Chain> chain =
75         GetCertChain(server_address, client_address, hostname,
76                      &cert_matched_sni);
77     QuicCryptoProof proof;
78     proof.signature = "Dummy signature";
79     proof.leaf_cert_scts = "Dummy timestamp";
80     proof.cert_matched_sni = cert_matched_sni;
81     callback->Run(true, chain, proof, /*details=*/nullptr);
82   }
83 
GetCertChain(const QuicSocketAddress &,const QuicSocketAddress &,const std::string &,bool *)84   quiche::QuicheReferenceCountedPointer<Chain> GetCertChain(
85       const QuicSocketAddress& /*server_address*/,
86       const QuicSocketAddress& /*client_address*/,
87       const std::string& /*hostname*/, bool* /*cert_matched_sni*/) override {
88     std::vector<std::string> certs;
89     certs.push_back("Dummy cert");
90     return quiche::QuicheReferenceCountedPointer<ProofSource::Chain>(
91         new ProofSource::Chain(certs));
92   }
93 
ComputeTlsSignature(const QuicSocketAddress &,const QuicSocketAddress &,const std::string &,uint16_t,absl::string_view,std::unique_ptr<SignatureCallback> callback)94   void ComputeTlsSignature(
95       const QuicSocketAddress& /*server_address*/,
96       const QuicSocketAddress& /*client_address*/,
97       const std::string& /*hostname*/, uint16_t /*signature_algorit*/,
98       absl::string_view /*in*/,
99       std::unique_ptr<SignatureCallback> callback) override {
100     callback->Run(true, "Dummy signature", /*details=*/nullptr);
101   }
102 
SupportedTlsSignatureAlgorithms() const103   absl::InlinedVector<uint16_t, 8> SupportedTlsSignatureAlgorithms()
104       const override {
105     return {};
106   }
107 
GetTicketCrypter()108   TicketCrypter* GetTicketCrypter() override { return nullptr; }
109 };
110 
111 class Handshaker : public QuicCryptoClientHandshaker {
112  public:
Handshaker(const QuicServerId & server_id,QuicCryptoClientStream * stream,QuicSession * session,std::unique_ptr<ProofVerifyContext> verify_context,QuicCryptoClientConfig * crypto_config,QuicCryptoClientStream::ProofHandler * proof_handler)113   Handshaker(const QuicServerId& server_id, QuicCryptoClientStream* stream,
114              QuicSession* session,
115              std::unique_ptr<ProofVerifyContext> verify_context,
116              QuicCryptoClientConfig* crypto_config,
117              QuicCryptoClientStream::ProofHandler* proof_handler)
118       : QuicCryptoClientHandshaker(server_id, stream, session,
119                                    std::move(verify_context), crypto_config,
120                                    proof_handler) {}
121 
DoSendCHLOTest(QuicCryptoClientConfig::CachedState * cached)122   void DoSendCHLOTest(QuicCryptoClientConfig::CachedState* cached) {
123     QuicCryptoClientHandshaker::DoSendCHLO(cached);
124   }
125 };
126 
127 class QuicCryptoClientHandshakerTest
128     : public QuicTestWithParam<ParsedQuicVersion> {
129  protected:
QuicCryptoClientHandshakerTest()130   QuicCryptoClientHandshakerTest()
131       : version_(GetParam()),
132         proof_handler_(),
133         helper_(),
134         alarm_factory_(),
135         server_id_("host", 123),
136         connection_(new test::MockQuicConnection(
137             &helper_, &alarm_factory_, Perspective::IS_CLIENT, {version_})),
138         session_(connection_, false),
139         crypto_client_config_(std::make_unique<InsecureProofVerifier>()),
140         client_stream_(
141             new QuicCryptoClientStream(server_id_, &session_, nullptr,
142                                        &crypto_client_config_, &proof_handler_,
143                                        /*has_application_state = */ false)),
144         handshaker_(server_id_, client_stream_, &session_, nullptr,
145                     &crypto_client_config_, &proof_handler_),
146         state_() {
147     // Session takes the ownership of the client stream! (but handshaker also
148     // takes a reference to it, but doesn't take the ownership).
149     session_.SetCryptoStream(client_stream_);
150     session_.Initialize();
151   }
152 
InitializeServerParametersToEnableFullHello()153   void InitializeServerParametersToEnableFullHello() {
154     QuicCryptoServerConfig::ConfigOptions options;
155     QuicServerConfigProtobuf config = QuicCryptoServerConfig::GenerateConfig(
156         helper_.GetRandomGenerator(), helper_.GetClock(), options);
157     state_.Initialize(
158         config.config(), "sourcetoken", std::vector<std::string>{"Dummy cert"},
159         "", "chlo_hash", "signature", helper_.GetClock()->WallNow(),
160         helper_.GetClock()->WallNow().Add(QuicTime::Delta::FromSeconds(30)));
161 
162     state_.SetProofValid();
163   }
164 
165   ParsedQuicVersion version_;
166   TestProofHandler proof_handler_;
167   test::MockQuicConnectionHelper helper_;
168   test::MockAlarmFactory alarm_factory_;
169   QuicServerId server_id_;
170   // Session takes the ownership of the connection.
171   test::MockQuicConnection* connection_;
172   test::MockQuicSession session_;
173   QuicCryptoClientConfig crypto_client_config_;
174   QuicCryptoClientStream* client_stream_;
175   Handshaker handshaker_;
176   QuicCryptoClientConfig::CachedState state_;
177 };
178 
179 INSTANTIATE_TEST_SUITE_P(
180     QuicCryptoClientHandshakerTests, QuicCryptoClientHandshakerTest,
181     ::testing::ValuesIn(AllSupportedVersionsWithQuicCrypto()),
182     ::testing::PrintToStringParamName());
183 
TEST_P(QuicCryptoClientHandshakerTest,TestSendFullPaddingInInchoateHello)184 TEST_P(QuicCryptoClientHandshakerTest, TestSendFullPaddingInInchoateHello) {
185   handshaker_.DoSendCHLOTest(&state_);
186 
187   EXPECT_TRUE(connection_->fully_pad_during_crypto_handshake());
188 }
189 
TEST_P(QuicCryptoClientHandshakerTest,TestDisabledPaddingInInchoateHello)190 TEST_P(QuicCryptoClientHandshakerTest, TestDisabledPaddingInInchoateHello) {
191   crypto_client_config_.set_pad_inchoate_hello(false);
192   handshaker_.DoSendCHLOTest(&state_);
193   EXPECT_FALSE(connection_->fully_pad_during_crypto_handshake());
194 }
195 
TEST_P(QuicCryptoClientHandshakerTest,TestPaddingInFullHelloEvenIfInchoateDisabled)196 TEST_P(QuicCryptoClientHandshakerTest,
197        TestPaddingInFullHelloEvenIfInchoateDisabled) {
198   // Disable inchoate, but full hello should still be padded.
199   crypto_client_config_.set_pad_inchoate_hello(false);
200 
201   InitializeServerParametersToEnableFullHello();
202 
203   handshaker_.DoSendCHLOTest(&state_);
204   EXPECT_TRUE(connection_->fully_pad_during_crypto_handshake());
205 }
206 
TEST_P(QuicCryptoClientHandshakerTest,TestNoPaddingInFullHelloWhenDisabled)207 TEST_P(QuicCryptoClientHandshakerTest, TestNoPaddingInFullHelloWhenDisabled) {
208   crypto_client_config_.set_pad_full_hello(false);
209 
210   InitializeServerParametersToEnableFullHello();
211 
212   handshaker_.DoSendCHLOTest(&state_);
213   EXPECT_FALSE(connection_->fully_pad_during_crypto_handshake());
214 }
215 
216 }  // namespace
217 }  // namespace quic::test
218