|  | // 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 |