QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1 | // Copyright (c) 2017 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 | |
dschinazi | aaaf1a4 | 2020-04-16 11:44:31 -0700 | [diff] [blame] | 5 | #include <memory> |
vasilvv | 872e7a3 | 2019-03-12 16:42:44 -0700 | [diff] [blame] | 6 | #include <string> |
bnc | 463f235 | 2019-10-10 04:49:34 -0700 | [diff] [blame] | 7 | #include <utility> |
vasilvv | 872e7a3 | 2019-03-12 16:42:44 -0700 | [diff] [blame] | 8 | |
dschinazi | aaaf1a4 | 2020-04-16 11:44:31 -0700 | [diff] [blame] | 9 | #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" |
nharper | 6ebe83b | 2019-06-13 17:43:52 -0700 | [diff] [blame] | 10 | #include "net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h" |
| 11 | #include "net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 12 | #include "net/third_party/quiche/src/quic/core/quic_utils.h" |
| 13 | #include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" |
| 14 | #include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 15 | #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" |
| 16 | #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" |
| 17 | #include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h" |
| 18 | #include "net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h" |
| 19 | #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" |
nharper | 0f51d2e | 2019-12-11 17:52:05 -0800 | [diff] [blame] | 20 | #include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h" |
bnc | 4e9283d | 2019-12-17 07:08:57 -0800 | [diff] [blame] | 21 | #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" |
dmcardle | cf0bfcf | 2019-12-13 08:08:21 -0800 | [diff] [blame] | 22 | #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 23 | |
| 24 | namespace quic { |
| 25 | namespace test { |
| 26 | namespace { |
| 27 | |
| 28 | using ::testing::_; |
vasilvv | ad7424f | 2019-08-30 00:27:14 -0700 | [diff] [blame] | 29 | using ::testing::ElementsAreArray; |
vasilvv | 4724c9c | 2019-08-29 11:52:11 -0700 | [diff] [blame] | 30 | using ::testing::Return; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 31 | |
nharper | 0f51d2e | 2019-12-11 17:52:05 -0800 | [diff] [blame] | 32 | class TestProofVerifier : public ProofVerifier { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 33 | public: |
nharper | 0f51d2e | 2019-12-11 17:52:05 -0800 | [diff] [blame] | 34 | TestProofVerifier() |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 35 | : verifier_(crypto_test_utils::ProofVerifierForTesting()) {} |
| 36 | |
| 37 | QuicAsyncStatus VerifyProof( |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 38 | const std::string& hostname, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 39 | const uint16_t port, |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 40 | const std::string& server_config, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 41 | QuicTransportVersion quic_version, |
dmcardle | cf0bfcf | 2019-12-13 08:08:21 -0800 | [diff] [blame] | 42 | quiche::QuicheStringPiece chlo_hash, |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 43 | const std::vector<std::string>& certs, |
| 44 | const std::string& cert_sct, |
| 45 | const std::string& signature, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 46 | const ProofVerifyContext* context, |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 47 | std::string* error_details, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 48 | std::unique_ptr<ProofVerifyDetails>* details, |
| 49 | std::unique_ptr<ProofVerifierCallback> callback) override { |
| 50 | return verifier_->VerifyProof( |
| 51 | hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct, |
| 52 | signature, context, error_details, details, std::move(callback)); |
| 53 | } |
| 54 | |
| 55 | QuicAsyncStatus VerifyCertChain( |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 56 | const std::string& hostname, |
nharper | 5ab78c8 | 2020-06-05 15:03:44 -0700 | [diff] [blame] | 57 | const uint16_t port, |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 58 | const std::vector<std::string>& certs, |
QUICHE team | 38c190b | 2019-05-08 09:12:01 -0700 | [diff] [blame] | 59 | const std::string& ocsp_response, |
| 60 | const std::string& cert_sct, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 61 | const ProofVerifyContext* context, |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 62 | std::string* error_details, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 63 | std::unique_ptr<ProofVerifyDetails>* details, |
| 64 | std::unique_ptr<ProofVerifierCallback> callback) override { |
| 65 | if (!active_) { |
nharper | 5ab78c8 | 2020-06-05 15:03:44 -0700 | [diff] [blame] | 66 | return verifier_->VerifyCertChain(hostname, port, certs, ocsp_response, |
QUICHE team | 38c190b | 2019-05-08 09:12:01 -0700 | [diff] [blame] | 67 | cert_sct, context, error_details, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 68 | details, std::move(callback)); |
| 69 | } |
vasilvv | 0fc587f | 2019-09-06 13:33:08 -0700 | [diff] [blame] | 70 | pending_ops_.push_back(std::make_unique<VerifyChainPendingOp>( |
nharper | 5ab78c8 | 2020-06-05 15:03:44 -0700 | [diff] [blame] | 71 | hostname, port, certs, ocsp_response, cert_sct, context, error_details, |
QUICHE team | 38c190b | 2019-05-08 09:12:01 -0700 | [diff] [blame] | 72 | details, std::move(callback), verifier_.get())); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 73 | return QUIC_PENDING; |
| 74 | } |
| 75 | |
| 76 | std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override { |
| 77 | return nullptr; |
| 78 | } |
| 79 | |
| 80 | void Activate() { active_ = true; } |
| 81 | |
| 82 | size_t NumPendingCallbacks() const { return pending_ops_.size(); } |
| 83 | |
| 84 | void InvokePendingCallback(size_t n) { |
| 85 | CHECK(NumPendingCallbacks() > n); |
| 86 | pending_ops_[n]->Run(); |
| 87 | auto it = pending_ops_.begin() + n; |
| 88 | pending_ops_.erase(it); |
| 89 | } |
| 90 | |
| 91 | private: |
| 92 | // Implementation of ProofVerifierCallback that fails if the callback is ever |
| 93 | // run. |
| 94 | class FailingProofVerifierCallback : public ProofVerifierCallback { |
| 95 | public: |
dschinazi | 17d4242 | 2019-06-18 16:35:07 -0700 | [diff] [blame] | 96 | void Run(bool /*ok*/, |
| 97 | const std::string& /*error_details*/, |
| 98 | std::unique_ptr<ProofVerifyDetails>* /*details*/) override { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 99 | FAIL(); |
| 100 | } |
| 101 | }; |
| 102 | |
| 103 | class VerifyChainPendingOp { |
| 104 | public: |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 105 | VerifyChainPendingOp(const std::string& hostname, |
nharper | 5ab78c8 | 2020-06-05 15:03:44 -0700 | [diff] [blame] | 106 | const uint16_t port, |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 107 | const std::vector<std::string>& certs, |
QUICHE team | 38c190b | 2019-05-08 09:12:01 -0700 | [diff] [blame] | 108 | const std::string& ocsp_response, |
| 109 | const std::string& cert_sct, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 110 | const ProofVerifyContext* context, |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 111 | std::string* error_details, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 112 | std::unique_ptr<ProofVerifyDetails>* details, |
| 113 | std::unique_ptr<ProofVerifierCallback> callback, |
| 114 | ProofVerifier* delegate) |
| 115 | : hostname_(hostname), |
nharper | 5ab78c8 | 2020-06-05 15:03:44 -0700 | [diff] [blame] | 116 | port_(port), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 117 | certs_(certs), |
QUICHE team | 38c190b | 2019-05-08 09:12:01 -0700 | [diff] [blame] | 118 | ocsp_response_(ocsp_response), |
| 119 | cert_sct_(cert_sct), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 120 | context_(context), |
| 121 | error_details_(error_details), |
| 122 | details_(details), |
| 123 | callback_(std::move(callback)), |
| 124 | delegate_(delegate) {} |
| 125 | |
| 126 | void Run() { |
nharper | 0f51d2e | 2019-12-11 17:52:05 -0800 | [diff] [blame] | 127 | // TestProofVerifier depends on crypto_test_utils::ProofVerifierForTesting |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 128 | // running synchronously. It passes a FailingProofVerifierCallback and |
| 129 | // runs the original callback after asserting that the verification ran |
| 130 | // synchronously. |
| 131 | QuicAsyncStatus status = delegate_->VerifyCertChain( |
nharper | 5ab78c8 | 2020-06-05 15:03:44 -0700 | [diff] [blame] | 132 | hostname_, port_, certs_, ocsp_response_, cert_sct_, context_, |
QUICHE team | 38c190b | 2019-05-08 09:12:01 -0700 | [diff] [blame] | 133 | error_details_, details_, |
vasilvv | 0fc587f | 2019-09-06 13:33:08 -0700 | [diff] [blame] | 134 | std::make_unique<FailingProofVerifierCallback>()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 135 | ASSERT_NE(status, QUIC_PENDING); |
| 136 | callback_->Run(status == QUIC_SUCCESS, *error_details_, details_); |
| 137 | } |
| 138 | |
| 139 | private: |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 140 | std::string hostname_; |
nharper | 5ab78c8 | 2020-06-05 15:03:44 -0700 | [diff] [blame] | 141 | const uint16_t port_; |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 142 | std::vector<std::string> certs_; |
QUICHE team | 38c190b | 2019-05-08 09:12:01 -0700 | [diff] [blame] | 143 | std::string ocsp_response_; |
| 144 | std::string cert_sct_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 145 | const ProofVerifyContext* context_; |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 146 | std::string* error_details_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 147 | std::unique_ptr<ProofVerifyDetails>* details_; |
| 148 | std::unique_ptr<ProofVerifierCallback> callback_; |
| 149 | ProofVerifier* delegate_; |
| 150 | }; |
| 151 | |
| 152 | std::unique_ptr<ProofVerifier> verifier_; |
| 153 | bool active_ = false; |
| 154 | std::vector<std::unique_ptr<VerifyChainPendingOp>> pending_ops_; |
| 155 | }; |
| 156 | |
| 157 | class TestQuicCryptoStream : public QuicCryptoStream { |
| 158 | public: |
| 159 | explicit TestQuicCryptoStream(QuicSession* session) |
| 160 | : QuicCryptoStream(session) {} |
| 161 | |
| 162 | ~TestQuicCryptoStream() override = default; |
| 163 | |
| 164 | virtual TlsHandshaker* handshaker() const = 0; |
| 165 | |
| 166 | bool encryption_established() const override { |
| 167 | return handshaker()->encryption_established(); |
| 168 | } |
| 169 | |
fayang | 685367a | 2020-01-14 10:40:15 -0800 | [diff] [blame] | 170 | bool one_rtt_keys_available() const override { |
| 171 | return handshaker()->one_rtt_keys_available(); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 172 | } |
| 173 | |
| 174 | const QuicCryptoNegotiatedParameters& crypto_negotiated_params() |
| 175 | const override { |
| 176 | return handshaker()->crypto_negotiated_params(); |
| 177 | } |
| 178 | |
| 179 | CryptoMessageParser* crypto_message_parser() override { |
| 180 | return handshaker()->crypto_message_parser(); |
| 181 | } |
| 182 | |
dmcardle | cf0bfcf | 2019-12-13 08:08:21 -0800 | [diff] [blame] | 183 | void WriteCryptoData(EncryptionLevel level, |
| 184 | quiche::QuicheStringPiece data) override { |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 185 | pending_writes_.push_back(std::make_pair(std::string(data), level)); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 186 | } |
| 187 | |
fayang | d58736d | 2019-11-27 13:35:31 -0800 | [diff] [blame] | 188 | void OnPacketDecrypted(EncryptionLevel /*level*/) override {} |
fayang | 2f2915d | 2020-01-24 06:47:15 -0800 | [diff] [blame] | 189 | void OnOneRttPacketAcknowledged() override {} |
fayang | 44ae4e9 | 2020-04-28 13:09:42 -0700 | [diff] [blame] | 190 | void OnHandshakePacketSent() override {} |
fayang | d58736d | 2019-11-27 13:35:31 -0800 | [diff] [blame] | 191 | |
fayang | 9a863cf | 2020-01-16 14:12:11 -0800 | [diff] [blame] | 192 | HandshakeState GetHandshakeState() const override { |
| 193 | return handshaker()->GetHandshakeState(); |
| 194 | } |
nharper | ac52a86 | 2020-06-08 12:41:06 -0700 | [diff] [blame^] | 195 | void SetServerApplicationStateForResumption( |
| 196 | std::unique_ptr<ApplicationState> /*application_state*/) override {} |
fayang | 9a863cf | 2020-01-16 14:12:11 -0800 | [diff] [blame] | 197 | |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 198 | const std::vector<std::pair<std::string, EncryptionLevel>>& pending_writes() { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 199 | return pending_writes_; |
| 200 | } |
| 201 | |
| 202 | // Sends the pending frames to |stream| and clears the array of pending |
| 203 | // writes. |
| 204 | void SendCryptoMessagesToPeer(QuicCryptoStream* stream) { |
| 205 | QUIC_LOG(INFO) << "Sending " << pending_writes_.size() << " frames"; |
| 206 | // This is a minimal re-implementation of QuicCryptoStream::OnDataAvailable. |
| 207 | // It doesn't work to call QuicStream::OnStreamFrame because |
| 208 | // QuicCryptoStream::OnDataAvailable currently (as an implementation detail) |
| 209 | // relies on the QuicConnection to know the EncryptionLevel to pass into |
| 210 | // CryptoMessageParser::ProcessInput. Since the crypto messages in this test |
| 211 | // never reach the framer or connection and never get encrypted/decrypted, |
| 212 | // QuicCryptoStream::OnDataAvailable isn't able to call ProcessInput with |
| 213 | // the correct EncryptionLevel. Instead, that can be short-circuited by |
| 214 | // directly calling ProcessInput here. |
| 215 | for (size_t i = 0; i < pending_writes_.size(); ++i) { |
| 216 | if (!stream->crypto_message_parser()->ProcessInput( |
| 217 | pending_writes_[i].first, pending_writes_[i].second)) { |
renjietang | 87df0d0 | 2020-02-13 11:53:52 -0800 | [diff] [blame] | 218 | OnUnrecoverableError(stream->crypto_message_parser()->error(), |
| 219 | stream->crypto_message_parser()->error_detail()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 220 | break; |
| 221 | } |
| 222 | } |
| 223 | pending_writes_.clear(); |
| 224 | } |
| 225 | |
| 226 | private: |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 227 | std::vector<std::pair<std::string, EncryptionLevel>> pending_writes_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 228 | }; |
| 229 | |
nharper | 40bdf53 | 2019-10-03 11:16:22 -0700 | [diff] [blame] | 230 | class MockProofHandler : public QuicCryptoClientStream::ProofHandler { |
| 231 | public: |
| 232 | MockProofHandler() = default; |
| 233 | ~MockProofHandler() override {} |
| 234 | |
wub | 713afae | 2020-04-27 07:48:31 -0700 | [diff] [blame] | 235 | MOCK_METHOD( // NOLINT(build/deprecated) |
| 236 | void, |
| 237 | OnProofValid, |
| 238 | (const QuicCryptoClientConfig::CachedState&), |
| 239 | (override)); |
| 240 | MOCK_METHOD( // NOLINT(build/deprecated) |
| 241 | void, |
| 242 | OnProofVerifyDetailsAvailable, |
| 243 | (const ProofVerifyDetails&), |
| 244 | (override)); |
nharper | 40bdf53 | 2019-10-03 11:16:22 -0700 | [diff] [blame] | 245 | }; |
| 246 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 247 | class TestQuicCryptoClientStream : public TestQuicCryptoStream { |
| 248 | public: |
| 249 | explicit TestQuicCryptoClientStream(QuicSession* session) |
nharper | 0f51d2e | 2019-12-11 17:52:05 -0800 | [diff] [blame] | 250 | : TestQuicCryptoClientStream(session, |
| 251 | QuicServerId("test.example.com", 443), |
| 252 | std::make_unique<TestProofVerifier>()) {} |
| 253 | |
| 254 | TestQuicCryptoClientStream(QuicSession* session, |
| 255 | const QuicServerId& server_id, |
| 256 | std::unique_ptr<ProofVerifier> proof_verifier) |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 257 | : TestQuicCryptoStream(session), |
nharper | 0f51d2e | 2019-12-11 17:52:05 -0800 | [diff] [blame] | 258 | crypto_config_(std::move(proof_verifier), |
nharper | df7a77b | 2019-11-11 13:12:45 -0800 | [diff] [blame] | 259 | /*session_cache*/ nullptr), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 260 | handshaker_(new TlsClientHandshaker( |
nharper | 0f51d2e | 2019-12-11 17:52:05 -0800 | [diff] [blame] | 261 | server_id, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 262 | this, |
| 263 | session, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 264 | crypto_test_utils::ProofVerifyContextForTesting(), |
nharper | df7a77b | 2019-11-11 13:12:45 -0800 | [diff] [blame] | 265 | &crypto_config_, |
renjietang | bcc066a | 2020-04-21 18:05:57 -0700 | [diff] [blame] | 266 | &proof_handler_, |
| 267 | /*has_application_state = */ false)) {} |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 268 | |
| 269 | ~TestQuicCryptoClientStream() override = default; |
| 270 | |
| 271 | TlsHandshaker* handshaker() const override { return handshaker_.get(); } |
vasilvv | 4724c9c | 2019-08-29 11:52:11 -0700 | [diff] [blame] | 272 | TlsClientHandshaker* client_handshaker() const { return handshaker_.get(); } |
nharper | 40bdf53 | 2019-10-03 11:16:22 -0700 | [diff] [blame] | 273 | const MockProofHandler& proof_handler() { return proof_handler_; } |
fayang | 0106294 | 2020-01-22 07:23:23 -0800 | [diff] [blame] | 274 | void OnHandshakeDoneReceived() override {} |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 275 | |
| 276 | bool CryptoConnect() { return handshaker_->CryptoConnect(); } |
| 277 | |
nharper | 0f51d2e | 2019-12-11 17:52:05 -0800 | [diff] [blame] | 278 | TestProofVerifier* GetTestProofVerifier() const { |
| 279 | return static_cast<TestProofVerifier*>(crypto_config_.proof_verifier()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 280 | } |
| 281 | |
| 282 | private: |
nharper | 40bdf53 | 2019-10-03 11:16:22 -0700 | [diff] [blame] | 283 | MockProofHandler proof_handler_; |
nharper | df7a77b | 2019-11-11 13:12:45 -0800 | [diff] [blame] | 284 | QuicCryptoClientConfig crypto_config_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 285 | std::unique_ptr<TlsClientHandshaker> handshaker_; |
| 286 | }; |
| 287 | |
nharper | f579b5e | 2020-01-21 14:11:18 -0800 | [diff] [blame] | 288 | class TestTlsServerHandshaker : public TlsServerHandshaker { |
| 289 | public: |
| 290 | TestTlsServerHandshaker(QuicSession* session, |
dschinazi | aaaf1a4 | 2020-04-16 11:44:31 -0700 | [diff] [blame] | 291 | const QuicCryptoServerConfig& crypto_config, |
nharper | f579b5e | 2020-01-21 14:11:18 -0800 | [diff] [blame] | 292 | TestQuicCryptoStream* test_stream) |
dschinazi | aaaf1a4 | 2020-04-16 11:44:31 -0700 | [diff] [blame] | 293 | : TlsServerHandshaker(session, crypto_config), |
nharper | f579b5e | 2020-01-21 14:11:18 -0800 | [diff] [blame] | 294 | test_stream_(test_stream) {} |
| 295 | |
| 296 | void WriteCryptoData(EncryptionLevel level, |
| 297 | quiche::QuicheStringPiece data) override { |
| 298 | test_stream_->WriteCryptoData(level, data); |
| 299 | } |
| 300 | |
| 301 | private: |
| 302 | TestQuicCryptoStream* test_stream_; |
| 303 | }; |
| 304 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 305 | class TestQuicCryptoServerStream : public TestQuicCryptoStream { |
| 306 | public: |
dschinazi | aaaf1a4 | 2020-04-16 11:44:31 -0700 | [diff] [blame] | 307 | TestQuicCryptoServerStream(QuicSession* session) |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 308 | : TestQuicCryptoStream(session), |
dschinazi | aaaf1a4 | 2020-04-16 11:44:31 -0700 | [diff] [blame] | 309 | crypto_config_(QuicCryptoServerConfig::TESTING, |
| 310 | QuicRandom::GetInstance(), |
| 311 | std::make_unique<FakeProofSource>(), |
| 312 | KeyExchangeSource::Default()), |
| 313 | handshaker_( |
| 314 | new TestTlsServerHandshaker(session, crypto_config_, this)) {} |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 315 | |
| 316 | ~TestQuicCryptoServerStream() override = default; |
| 317 | |
| 318 | void CancelOutstandingCallbacks() { |
| 319 | handshaker_->CancelOutstandingCallbacks(); |
| 320 | } |
| 321 | |
fayang | d58736d | 2019-11-27 13:35:31 -0800 | [diff] [blame] | 322 | void OnPacketDecrypted(EncryptionLevel level) override { |
| 323 | handshaker_->OnPacketDecrypted(level); |
| 324 | } |
fayang | 0106294 | 2020-01-22 07:23:23 -0800 | [diff] [blame] | 325 | void OnHandshakeDoneReceived() override { DCHECK(false); } |
fayang | d58736d | 2019-11-27 13:35:31 -0800 | [diff] [blame] | 326 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 327 | TlsHandshaker* handshaker() const override { return handshaker_.get(); } |
| 328 | |
dschinazi | aaaf1a4 | 2020-04-16 11:44:31 -0700 | [diff] [blame] | 329 | FakeProofSource* GetFakeProofSource() const { |
| 330 | return static_cast<FakeProofSource*>(crypto_config_.proof_source()); |
| 331 | } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 332 | |
| 333 | private: |
dschinazi | aaaf1a4 | 2020-04-16 11:44:31 -0700 | [diff] [blame] | 334 | QuicCryptoServerConfig crypto_config_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 335 | std::unique_ptr<TlsServerHandshaker> handshaker_; |
| 336 | }; |
| 337 | |
| 338 | void ExchangeHandshakeMessages(TestQuicCryptoStream* client, |
nharper | f579b5e | 2020-01-21 14:11:18 -0800 | [diff] [blame] | 339 | TestQuicCryptoServerStream* server) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 340 | while (!client->pending_writes().empty() || |
| 341 | !server->pending_writes().empty()) { |
| 342 | client->SendCryptoMessagesToPeer(server); |
| 343 | server->SendCryptoMessagesToPeer(client); |
| 344 | } |
| 345 | } |
| 346 | |
dschinazi | 38cc1ee | 2020-02-28 14:33:58 -0800 | [diff] [blame] | 347 | class TlsHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 348 | public: |
| 349 | TlsHandshakerTest() |
dschinazi | 38cc1ee | 2020-02-28 14:33:58 -0800 | [diff] [blame] | 350 | : version_(GetParam()), |
| 351 | client_conn_(new MockQuicConnection(&conn_helper_, |
| 352 | &alarm_factory_, |
| 353 | Perspective::IS_CLIENT, |
| 354 | {version_})), |
| 355 | server_conn_(new MockQuicConnection(&conn_helper_, |
| 356 | &alarm_factory_, |
| 357 | Perspective::IS_SERVER, |
| 358 | {version_})), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 359 | client_session_(client_conn_, /*create_mock_crypto_stream=*/false), |
| 360 | server_session_(server_conn_, /*create_mock_crypto_stream=*/false) { |
| 361 | client_stream_ = new TestQuicCryptoClientStream(&client_session_); |
| 362 | client_session_.SetCryptoStream(client_stream_); |
dschinazi | aaaf1a4 | 2020-04-16 11:44:31 -0700 | [diff] [blame] | 363 | server_stream_ = new TestQuicCryptoServerStream(&server_session_); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 364 | server_session_.SetCryptoStream(server_stream_); |
| 365 | client_session_.Initialize(); |
| 366 | server_session_.Initialize(); |
| 367 | EXPECT_FALSE(client_stream_->encryption_established()); |
fayang | 685367a | 2020-01-14 10:40:15 -0800 | [diff] [blame] | 368 | EXPECT_FALSE(client_stream_->one_rtt_keys_available()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 369 | EXPECT_FALSE(server_stream_->encryption_established()); |
fayang | 685367a | 2020-01-14 10:40:15 -0800 | [diff] [blame] | 370 | EXPECT_FALSE(server_stream_->one_rtt_keys_available()); |
vasilvv | ad7424f | 2019-08-30 00:27:14 -0700 | [diff] [blame] | 371 | const std::string default_alpn = |
| 372 | AlpnForVersion(client_session_.connection()->version()); |
vasilvv | 4724c9c | 2019-08-29 11:52:11 -0700 | [diff] [blame] | 373 | ON_CALL(client_session_, GetAlpnsToOffer()) |
vasilvv | ad7424f | 2019-08-30 00:27:14 -0700 | [diff] [blame] | 374 | .WillByDefault(Return(std::vector<std::string>({default_alpn}))); |
| 375 | ON_CALL(server_session_, SelectAlpn(_)) |
| 376 | .WillByDefault( |
dmcardle | cf0bfcf | 2019-12-13 08:08:21 -0800 | [diff] [blame] | 377 | [default_alpn]( |
| 378 | const std::vector<quiche::QuicheStringPiece>& alpns) { |
vasilvv | ad7424f | 2019-08-30 00:27:14 -0700 | [diff] [blame] | 379 | return std::find(alpns.begin(), alpns.end(), default_alpn); |
| 380 | }); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 381 | } |
| 382 | |
nharper | 8f75992 | 2019-10-09 11:08:36 -0700 | [diff] [blame] | 383 | void ExpectHandshakeSuccessful() { |
fayang | 685367a | 2020-01-14 10:40:15 -0800 | [diff] [blame] | 384 | EXPECT_TRUE(client_stream_->one_rtt_keys_available()); |
nharper | 8f75992 | 2019-10-09 11:08:36 -0700 | [diff] [blame] | 385 | EXPECT_TRUE(client_stream_->encryption_established()); |
fayang | 685367a | 2020-01-14 10:40:15 -0800 | [diff] [blame] | 386 | EXPECT_TRUE(server_stream_->one_rtt_keys_available()); |
nharper | 8f75992 | 2019-10-09 11:08:36 -0700 | [diff] [blame] | 387 | EXPECT_TRUE(server_stream_->encryption_established()); |
fayang | 0106294 | 2020-01-22 07:23:23 -0800 | [diff] [blame] | 388 | EXPECT_EQ(HANDSHAKE_COMPLETE, client_stream_->GetHandshakeState()); |
| 389 | EXPECT_EQ(HANDSHAKE_CONFIRMED, server_stream_->GetHandshakeState()); |
nharper | 8f75992 | 2019-10-09 11:08:36 -0700 | [diff] [blame] | 390 | |
| 391 | const auto& client_crypto_params = |
| 392 | client_stream_->crypto_negotiated_params(); |
| 393 | const auto& server_crypto_params = |
| 394 | server_stream_->crypto_negotiated_params(); |
| 395 | // The TLS params should be filled in on the client. |
| 396 | EXPECT_NE(0, client_crypto_params.cipher_suite); |
| 397 | EXPECT_NE(0, client_crypto_params.key_exchange_group); |
| 398 | EXPECT_NE(0, client_crypto_params.peer_signature_algorithm); |
| 399 | |
| 400 | // The cipher suite and key exchange group should match on the client and |
| 401 | // server. |
| 402 | EXPECT_EQ(client_crypto_params.cipher_suite, |
| 403 | server_crypto_params.cipher_suite); |
| 404 | EXPECT_EQ(client_crypto_params.key_exchange_group, |
| 405 | server_crypto_params.key_exchange_group); |
| 406 | // We don't support client certs on the server (yet), so the server |
| 407 | // shouldn't have a peer signature algorithm to report. |
| 408 | EXPECT_EQ(0, server_crypto_params.peer_signature_algorithm); |
| 409 | } |
| 410 | |
dschinazi | 38cc1ee | 2020-02-28 14:33:58 -0800 | [diff] [blame] | 411 | ParsedQuicVersion version_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 412 | MockQuicConnectionHelper conn_helper_; |
| 413 | MockAlarmFactory alarm_factory_; |
| 414 | MockQuicConnection* client_conn_; |
| 415 | MockQuicConnection* server_conn_; |
| 416 | MockQuicSession client_session_; |
| 417 | MockQuicSession server_session_; |
| 418 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 419 | TestQuicCryptoClientStream* client_stream_; |
| 420 | TestQuicCryptoServerStream* server_stream_; |
| 421 | }; |
| 422 | |
dschinazi | 38cc1ee | 2020-02-28 14:33:58 -0800 | [diff] [blame] | 423 | std::vector<ParsedQuicVersion> AllSupportedTlsVersions() { |
| 424 | std::vector<ParsedQuicVersion> tls_versions; |
| 425 | for (const ParsedQuicVersion& version : AllSupportedVersions()) { |
| 426 | if (version.handshake_protocol == PROTOCOL_TLS1_3) { |
| 427 | tls_versions.push_back(version); |
| 428 | } |
| 429 | } |
| 430 | return tls_versions; |
| 431 | } |
| 432 | |
| 433 | INSTANTIATE_TEST_SUITE_P(TlsHandshakerTests, |
| 434 | TlsHandshakerTest, |
| 435 | ::testing::ValuesIn(AllSupportedTlsVersions()), |
| 436 | ::testing::PrintToStringParamName()); |
| 437 | |
| 438 | TEST_P(TlsHandshakerTest, CryptoHandshake) { |
fayang | fa3b1d6 | 2019-11-18 08:02:13 -0800 | [diff] [blame] | 439 | EXPECT_FALSE(client_conn_->IsHandshakeComplete()); |
| 440 | EXPECT_FALSE(server_conn_->IsHandshakeComplete()); |
fayang | bd79392 | 2019-08-26 14:19:24 -0700 | [diff] [blame] | 441 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 442 | EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); |
| 443 | EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); |
nharper | 40bdf53 | 2019-10-03 11:16:22 -0700 | [diff] [blame] | 444 | EXPECT_CALL(client_stream_->proof_handler(), OnProofVerifyDetailsAvailable); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 445 | client_stream_->CryptoConnect(); |
| 446 | ExchangeHandshakeMessages(client_stream_, server_stream_); |
| 447 | |
nharper | 8f75992 | 2019-10-09 11:08:36 -0700 | [diff] [blame] | 448 | ExpectHandshakeSuccessful(); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 449 | } |
| 450 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 451 | } // namespace |
| 452 | } // namespace test |
| 453 | } // namespace quic |