| // Copyright 2016 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/stateless_rejector.h" | |
| #include <string> | |
| #include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" | |
| namespace quic { | |
| class StatelessRejector::ValidateCallback | |
| : public ValidateClientHelloResultCallback { | |
| public: | |
| explicit ValidateCallback( | |
| std::unique_ptr<StatelessRejector> rejector, | |
| std::unique_ptr<StatelessRejector::ProcessDoneCallback> cb) | |
| : rejector_(std::move(rejector)), cb_(std::move(cb)) {} | |
| ~ValidateCallback() override = default; | |
| void Run(QuicReferenceCountedPointer<Result> result, | |
| std::unique_ptr<ProofSource::Details> /* proof_source_details */) | |
| override { | |
| StatelessRejector* rejector_ptr = rejector_.get(); | |
| rejector_ptr->ProcessClientHello(std::move(result), std::move(rejector_), | |
| std::move(cb_)); | |
| } | |
| private: | |
| std::unique_ptr<StatelessRejector> rejector_; | |
| std::unique_ptr<StatelessRejector::ProcessDoneCallback> cb_; | |
| }; | |
| StatelessRejector::StatelessRejector( | |
| ParsedQuicVersion version, | |
| const ParsedQuicVersionVector& versions, | |
| const QuicCryptoServerConfig* crypto_config, | |
| QuicCompressedCertsCache* compressed_certs_cache, | |
| const QuicClock* clock, | |
| QuicRandom* random, | |
| QuicByteCount chlo_packet_size, | |
| const QuicSocketAddress& client_address, | |
| const QuicSocketAddress& server_address) | |
| : state_(UNKNOWN), | |
| error_(QUIC_INTERNAL_ERROR), | |
| version_(version), | |
| versions_(versions), | |
| connection_id_(EmptyQuicConnectionId()), | |
| chlo_packet_size_(chlo_packet_size), | |
| client_address_(client_address), | |
| server_address_(server_address), | |
| clock_(clock), | |
| random_(random), | |
| crypto_config_(crypto_config), | |
| compressed_certs_cache_(compressed_certs_cache), | |
| signed_config_(new QuicSignedServerConfig), | |
| params_(new QuicCryptoNegotiatedParameters) {} | |
| StatelessRejector::~StatelessRejector() = default; | |
| void StatelessRejector::OnChlo(QuicTransportVersion version, | |
| QuicConnectionId connection_id, | |
| QuicConnectionId server_designated_connection_id, | |
| const CryptoHandshakeMessage& message) { | |
| DCHECK_EQ(kCHLO, message.tag()); | |
| DCHECK_NE(connection_id, server_designated_connection_id); | |
| DCHECK_EQ(state_, UNKNOWN); | |
| if (!GetQuicReloadableFlag(enable_quic_stateless_reject_support) || | |
| !GetQuicReloadableFlag(quic_use_cheap_stateless_rejects) || | |
| !QuicCryptoServerStream::DoesPeerSupportStatelessRejects(message)) { | |
| state_ = UNSUPPORTED; | |
| return; | |
| } | |
| connection_id_ = connection_id; | |
| server_designated_connection_id_ = server_designated_connection_id; | |
| chlo_ = message; // Note: copies the message | |
| } | |
| void StatelessRejector::Process(std::unique_ptr<StatelessRejector> rejector, | |
| std::unique_ptr<ProcessDoneCallback> done_cb) { | |
| QUIC_BUG_IF(rejector->state() != UNKNOWN) << "StatelessRejector::Process " | |
| "called for a rejector which " | |
| "has already made a decision"; | |
| StatelessRejector* rejector_ptr = rejector.get(); | |
| rejector_ptr->crypto_config_->ValidateClientHello( | |
| rejector_ptr->chlo_, rejector_ptr->client_address_.host(), | |
| rejector_ptr->server_address_, rejector_ptr->version_.transport_version, | |
| rejector_ptr->clock_, rejector_ptr->signed_config_, | |
| std::unique_ptr<ValidateCallback>( | |
| new ValidateCallback(std::move(rejector), std::move(done_cb)))); | |
| } | |
| class StatelessRejector::ProcessClientHelloCallback | |
| : public ProcessClientHelloResultCallback { | |
| public: | |
| ProcessClientHelloCallback( | |
| std::unique_ptr<StatelessRejector> rejector, | |
| std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) | |
| : rejector_(std::move(rejector)), done_cb_(std::move(done_cb)) {} | |
| void Run(QuicErrorCode error, | |
| const std::string& error_details, | |
| std::unique_ptr<CryptoHandshakeMessage> message, | |
| std::unique_ptr<DiversificationNonce> diversification_nonce, | |
| std::unique_ptr<ProofSource::Details> /* proof_source_details */) | |
| override { | |
| StatelessRejector* rejector_ptr = rejector_.get(); | |
| rejector_ptr->ProcessClientHelloDone( | |
| error, error_details, std::move(message), std::move(rejector_), | |
| std::move(done_cb_)); | |
| } | |
| private: | |
| std::unique_ptr<StatelessRejector> rejector_; | |
| std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb_; | |
| }; | |
| void StatelessRejector::ProcessClientHello( | |
| QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> | |
| result, | |
| std::unique_ptr<StatelessRejector> rejector, | |
| std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) { | |
| std::unique_ptr<ProcessClientHelloCallback> cb( | |
| new ProcessClientHelloCallback(std::move(rejector), std::move(done_cb))); | |
| crypto_config_->ProcessClientHello( | |
| result, | |
| /*reject_only=*/true, connection_id_, server_address_, client_address_, | |
| version_, versions_, | |
| /*use_stateless_rejects=*/true, server_designated_connection_id_, clock_, | |
| random_, compressed_certs_cache_, params_, signed_config_, | |
| QuicCryptoStream::CryptoMessageFramingOverhead(version_.transport_version, | |
| connection_id_), | |
| chlo_packet_size_, std::move(cb)); | |
| } | |
| void StatelessRejector::ProcessClientHelloDone( | |
| QuicErrorCode error, | |
| const std::string& error_details, | |
| std::unique_ptr<CryptoHandshakeMessage> message, | |
| std::unique_ptr<StatelessRejector> rejector, | |
| std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) { | |
| reply_ = std::move(message); | |
| if (error != QUIC_NO_ERROR) { | |
| error_ = error; | |
| error_details_ = error_details; | |
| state_ = FAILED; | |
| } else if (reply_->tag() == kSREJ) { | |
| state_ = REJECTED; | |
| } else { | |
| state_ = ACCEPTED; | |
| } | |
| done_cb->Run(std::move(rejector)); | |
| } | |
| } // namespace quic |