| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h" | |
| #include <utility> | |
| #include "net/third_party/quiche/src/quic/core/proto/crypto_server_config_proto.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" | |
| #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" | |
| namespace quic { | |
| namespace { | |
| using ::testing::Test; | |
| class TestProofHandler : public QuicCryptoClientStream::ProofHandler { | |
| public: | |
| ~TestProofHandler() override {} | |
| void OnProofValid( | |
| const QuicCryptoClientConfig::CachedState& /*cached*/) override {} | |
| void OnProofVerifyDetailsAvailable( | |
| const ProofVerifyDetails& /*verify_details*/) override {} | |
| }; | |
| class InsecureProofVerifier : public ProofVerifier { | |
| public: | |
| InsecureProofVerifier() {} | |
| ~InsecureProofVerifier() override {} | |
| // ProofVerifier override. | |
| QuicAsyncStatus VerifyProof( | |
| const std::string& /*hostname*/, | |
| const uint16_t /*port*/, | |
| const std::string& /*server_config*/, | |
| QuicTransportVersion /*transport_version*/, | |
| QuicStringPiece /*chlo_hash*/, | |
| const std::vector<std::string>& /*certs*/, | |
| const std::string& /*cert_sct*/, | |
| const std::string& /*signature*/, | |
| const ProofVerifyContext* /*context*/, | |
| std::string* /*error_details*/, | |
| std::unique_ptr<ProofVerifyDetails>* /*verify_details*/, | |
| std::unique_ptr<ProofVerifierCallback> /*callback*/) override { | |
| return QUIC_SUCCESS; | |
| } | |
| QuicAsyncStatus VerifyCertChain( | |
| const std::string& /*hostname*/, | |
| const std::vector<std::string>& /*certs*/, | |
| const std::string& /*ocsp_response*/, | |
| const std::string& /*cert_sct*/, | |
| const ProofVerifyContext* /*context*/, | |
| std::string* /*error_details*/, | |
| std::unique_ptr<ProofVerifyDetails>* /*details*/, | |
| std::unique_ptr<ProofVerifierCallback> /*callback*/) override { | |
| return QUIC_SUCCESS; | |
| } | |
| std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override { | |
| return nullptr; | |
| } | |
| }; | |
| class DummyProofSource : public ProofSource { | |
| public: | |
| DummyProofSource() {} | |
| ~DummyProofSource() override {} | |
| // ProofSource override. | |
| void GetProof(const QuicSocketAddress& server_address, | |
| const std::string& hostname, | |
| const std::string& /*server_config*/, | |
| QuicTransportVersion /*transport_version*/, | |
| QuicStringPiece /*chlo_hash*/, | |
| std::unique_ptr<Callback> callback) override { | |
| QuicReferenceCountedPointer<ProofSource::Chain> chain = | |
| GetCertChain(server_address, hostname); | |
| QuicCryptoProof proof; | |
| proof.signature = "Dummy signature"; | |
| proof.leaf_cert_scts = "Dummy timestamp"; | |
| callback->Run(true, chain, proof, /*details=*/nullptr); | |
| } | |
| QuicReferenceCountedPointer<Chain> GetCertChain( | |
| const QuicSocketAddress& /*server_address*/, | |
| const std::string& /*hostname*/) override { | |
| std::vector<std::string> certs; | |
| certs.push_back("Dummy cert"); | |
| return QuicReferenceCountedPointer<ProofSource::Chain>( | |
| new ProofSource::Chain(certs)); | |
| } | |
| void ComputeTlsSignature( | |
| const QuicSocketAddress& /*server_address*/, | |
| const std::string& /*hostname*/, | |
| uint16_t /*signature_algorit*/, | |
| QuicStringPiece /*in*/, | |
| std::unique_ptr<SignatureCallback> callback) override { | |
| callback->Run(true, "Dummy signature"); | |
| } | |
| }; | |
| class Handshaker : public QuicCryptoClientHandshaker { | |
| public: | |
| Handshaker(const QuicServerId& server_id, | |
| QuicCryptoClientStream* stream, | |
| QuicSession* session, | |
| std::unique_ptr<ProofVerifyContext> verify_context, | |
| QuicCryptoClientConfig* crypto_config, | |
| QuicCryptoClientStream::ProofHandler* proof_handler) | |
| : QuicCryptoClientHandshaker(server_id, | |
| stream, | |
| session, | |
| std::move(verify_context), | |
| crypto_config, | |
| proof_handler) {} | |
| void DoSendCHLOTest(QuicCryptoClientConfig::CachedState* cached) { | |
| QuicCryptoClientHandshaker::DoSendCHLO(cached); | |
| } | |
| }; | |
| class QuicCryptoClientHandshakerTest : public Test { | |
| protected: | |
| QuicCryptoClientHandshakerTest() | |
| : proof_handler_(), | |
| helper_(), | |
| alarm_factory_(), | |
| server_id_("host", 123), | |
| connection_(new test::MockQuicConnection(&helper_, | |
| &alarm_factory_, | |
| Perspective::IS_CLIENT)), | |
| session_(connection_, false), | |
| crypto_client_config_(std::make_unique<InsecureProofVerifier>()), | |
| client_stream_(new QuicCryptoClientStream(server_id_, | |
| &session_, | |
| nullptr, | |
| &crypto_client_config_, | |
| &proof_handler_)), | |
| handshaker_(server_id_, | |
| client_stream_, | |
| &session_, | |
| nullptr, | |
| &crypto_client_config_, | |
| &proof_handler_), | |
| state_() { | |
| // Session takes the ownership of the client stream! (but handshaker also | |
| // takes a reference to it, but doesn't take the ownership). | |
| session_.SetCryptoStream(client_stream_); | |
| session_.Initialize(); | |
| } | |
| void InitializeServerParametersToEnableFullHello() { | |
| QuicCryptoServerConfig::ConfigOptions options; | |
| QuicServerConfigProtobuf config = QuicCryptoServerConfig::GenerateConfig( | |
| helper_.GetRandomGenerator(), helper_.GetClock(), options); | |
| state_.Initialize( | |
| config.config(), "sourcetoken", std::vector<std::string>{"Dummy cert"}, | |
| "", "chlo_hash", "signature", helper_.GetClock()->WallNow(), | |
| helper_.GetClock()->WallNow().Add(QuicTime::Delta::FromSeconds(30))); | |
| state_.SetProofValid(); | |
| } | |
| TestProofHandler proof_handler_; | |
| test::MockQuicConnectionHelper helper_; | |
| test::MockAlarmFactory alarm_factory_; | |
| QuicServerId server_id_; | |
| // Session takes the ownership of the connection. | |
| test::MockQuicConnection* connection_; | |
| test::MockQuicSession session_; | |
| QuicCryptoClientConfig crypto_client_config_; | |
| QuicCryptoClientStream* client_stream_; | |
| Handshaker handshaker_; | |
| QuicCryptoClientConfig::CachedState state_; | |
| }; | |
| TEST_F(QuicCryptoClientHandshakerTest, TestSendFullPaddingInInchoateHello) { | |
| handshaker_.DoSendCHLOTest(&state_); | |
| EXPECT_TRUE(connection_->fully_pad_during_crypto_handshake()); | |
| } | |
| TEST_F(QuicCryptoClientHandshakerTest, TestDisabledPaddingInInchoateHello) { | |
| crypto_client_config_.set_pad_inchoate_hello(false); | |
| handshaker_.DoSendCHLOTest(&state_); | |
| EXPECT_FALSE(connection_->fully_pad_during_crypto_handshake()); | |
| } | |
| TEST_F(QuicCryptoClientHandshakerTest, | |
| TestPaddingInFullHelloEvenIfInchoateDisabled) { | |
| // Disable inchoate, but full hello should still be padded. | |
| crypto_client_config_.set_pad_inchoate_hello(false); | |
| InitializeServerParametersToEnableFullHello(); | |
| handshaker_.DoSendCHLOTest(&state_); | |
| EXPECT_TRUE(connection_->fully_pad_during_crypto_handshake()); | |
| } | |
| TEST_F(QuicCryptoClientHandshakerTest, TestNoPaddingInFullHelloWhenDisabled) { | |
| crypto_client_config_.set_pad_full_hello(false); | |
| InitializeServerParametersToEnableFullHello(); | |
| handshaker_.DoSendCHLOTest(&state_); | |
| EXPECT_FALSE(connection_->fully_pad_during_crypto_handshake()); | |
| } | |
| } // namespace | |
| } // namespace quic |