Index: net/quic/quic_stream_factory.cc |
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc |
index c011f6a9d5e6d1af82acbfd5bdb85ada4da14778..bca22e2cdb4d9fc71b5530381b46f23cdf95d3b4 100644 |
--- a/net/quic/quic_stream_factory.cc |
+++ b/net/quic/quic_stream_factory.cc |
@@ -34,6 +34,7 @@ |
#include "net/http/bidirectional_stream_impl.h" |
#include "net/quic/bidirectional_stream_quic_impl.h" |
#include "net/quic/crypto/channel_id_chromium.h" |
+#include "net/quic/crypto/proof_verifier.h" |
#include "net/quic/crypto/proof_verifier_chromium.h" |
#include "net/quic/crypto/properties_based_quic_server_info.h" |
#include "net/quic/crypto/quic_random.h" |
@@ -167,6 +168,84 @@ QuicConfig InitializeQuicConfig(const QuicTagVector& connection_options, |
} // namespace |
+class QuicStreamFactory::CertVerifierJob { |
+ public: |
+ class IgnoreProofVerifierCallback : public ProofVerifierCallback { |
+ public: |
+ explicit IgnoreProofVerifierCallback(CertVerifierJob* job) : job_(job) {} |
+ |
+ ~IgnoreProofVerifierCallback() override {} |
+ |
+ void Run(bool ok, |
+ const std::string& error_details, |
+ std::unique_ptr<ProofVerifyDetails>* details) override { |
+ LOG(ERROR) << __FUNCTION__; |
+ if (job_ == nullptr) |
+ return; |
+ job_->verify_callback_ = nullptr; |
+ job_->OnComplete(); |
+ } |
+ |
+ void Cancel() { job_ = nullptr; } |
+ |
+ private: |
+ CertVerifierJob* job_; |
+ }; |
+ |
+ CertVerifierJob(const QuicServerId& server_id, |
+ int cert_verify_flags, |
+ QuicCryptoClientConfig* crypto_config, |
+ const BoundNetLog& net_log) |
+ : server_id_(server_id), |
+ crypto_config_(crypto_config), |
+ verify_callback_(new IgnoreProofVerifierCallback(this)), |
+ verify_context_( |
+ new ProofVerifyContextChromium(cert_verify_flags, net_log)), |
+ net_log_(net_log), |
+ weak_factory_(this) {} |
+ |
+ ~CertVerifierJob() { |
+ if (verify_callback_) |
+ verify_callback_->Cancel(); |
+ } |
+ |
+ QuicAsyncStatus Run(const CompletionCallback& callback) { |
+ QuicCryptoClientConfig::CachedState* cached = |
+ crypto_config_->LookupOrCreate(server_id_); |
+ LOG(ERROR) << __FUNCTION__; |
+ // Pass empty chlo_hash, signature and cert_sct so that only certificate is |
+ // verified. |
+ QuicAsyncStatus status = crypto_config_->proof_verifier()->VerifyProof( |
+ server_id_.host(), server_id_.port(), cached->server_config(), |
+ QUIC_VERSION_25, /*chlo_hash=*/"", cached->certs(), |
+ /*cert_sct=*/"", /*signature=*/"", verify_context_.get(), |
+ &verify_error_details_, &verify_details_, verify_callback_); |
+ if (status != QUIC_FAILURE) |
+ callback_ = callback; |
+ return status; |
+ } |
+ |
+ void OnComplete() { |
+ if (!callback_.is_null()) |
+ callback_.Run(OK); |
+ } |
+ |
+ const QuicServerId& server_id() const { return server_id_; } |
+ |
+ private: |
+ QuicServerId server_id_; |
+ QuicCryptoClientConfig* crypto_config_; |
+ IgnoreProofVerifierCallback* verify_callback_; |
+ std::unique_ptr<ProofVerifyContext> verify_context_; |
+ std::unique_ptr<ProofVerifyDetails> verify_details_; |
+ std::string verify_error_details_; |
+ const BoundNetLog net_log_; |
+ CompletionCallback callback_; |
+ base::WeakPtrFactory<CertVerifierJob> weak_factory_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(CertVerifierJob); |
+}; |
+ |
// Responsible for creating a new QUIC session to the specified server, and |
// for notifying any associated requests when complete. |
class QuicStreamFactory::Job { |
@@ -631,6 +710,7 @@ QuicStreamFactory::QuicStreamFactory( |
int idle_connection_timeout_seconds, |
bool migrate_sessions_on_network_change, |
bool migrate_sessions_early, |
+ bool race_cert_verification, |
const QuicTagVector& connection_options, |
bool enable_token_binding) |
: require_confirmation_(true), |
@@ -684,6 +764,7 @@ QuicStreamFactory::QuicStreamFactory( |
NetworkChangeNotifier::AreNetworkHandlesSupported()), |
migrate_sessions_early_(migrate_sessions_early && |
migrate_sessions_on_network_change_), |
+ race_cert_verification_(race_cert_verification), |
port_seed_(random_generator_->RandUint64()), |
check_persisted_supports_quic_(true), |
has_initialized_data_(false), |
@@ -748,6 +829,10 @@ QuicStreamFactory::~QuicStreamFactory() { |
STLDeleteElements(&(active_jobs_[server_id])); |
active_jobs_.erase(server_id); |
} |
+ while (!active_cert_verifier_jobs_.empty()) { |
+ delete active_cert_verifier_jobs_.begin()->second; |
+ active_cert_verifier_jobs_.erase(active_cert_verifier_jobs_.begin()); |
+ } |
if (migrate_sessions_on_network_change_) { |
NetworkChangeNotifier::RemoveNetworkObserver(this); |
} else if (close_sessions_on_ip_change_) { |
@@ -882,6 +967,8 @@ int QuicStreamFactory::Create(const QuicServerId& server_id, |
} |
} |
+ StartCertVerifyJob(server_id, cert_verify_flags, net_log); |
+ |
QuicSessionKey key(destination, server_id); |
std::unique_ptr<Job> job( |
new Job(this, host_resolver_, key, WasQuicRecentlyBroken(server_id), |
@@ -1014,6 +1101,11 @@ void QuicStreamFactory::OnJobComplete(Job* job, int rv) { |
job_requests_map_.erase(server_id); |
} |
+void QuicStreamFactory::OnCertVerifyJobComplete(CertVerifierJob* job, int rv) { |
+ LOG(ERROR) << __FUNCTION__; |
+ active_cert_verifier_jobs_.erase(job->server_id()); |
+} |
+ |
std::unique_ptr<QuicHttpStream> QuicStreamFactory::CreateFromSession( |
QuicChromiumClientSession* session) { |
return std::unique_ptr<QuicHttpStream>( |
@@ -1542,6 +1634,11 @@ bool QuicStreamFactory::HasActiveJob(const QuicServerId& server_id) const { |
return ContainsKey(active_jobs_, server_id); |
} |
+bool QuicStreamFactory::HasActiveCertVerifierJob( |
+ const QuicServerId& server_id) const { |
+ return ContainsKey(active_cert_verifier_jobs_, server_id); |
+} |
+ |
int QuicStreamFactory::ConfigureSocket(DatagramClientSocket* socket, |
IPEndPoint addr, |
NetworkHandle network) { |
@@ -1749,6 +1846,28 @@ bool QuicStreamFactory::CryptoConfigCacheIsEmpty( |
return cached->IsEmpty(); |
} |
+void QuicStreamFactory::StartCertVerifyJob(const QuicServerId& server_id, |
+ int cert_verify_flags, |
+ const BoundNetLog& net_log) { |
+ LOG(ERROR) << __FUNCTION__ << " " << race_cert_verification_; |
+ if (!race_cert_verification_) |
+ return; |
+ QuicCryptoClientConfig::CachedState* cached = |
+ crypto_config_.LookupOrCreate(server_id); |
+ if (!cached || cached->certs().empty() || cached->proof_valid() || |
+ HasActiveCertVerifierJob(server_id)) { |
+ LOG(ERROR) << __FUNCTION__ << " " << __LINE__; |
+ return; |
+ } |
+ std::unique_ptr<CertVerifierJob> cert_verifier_job(new CertVerifierJob( |
+ server_id, cert_verify_flags, &crypto_config_, net_log)); |
+ QuicAsyncStatus status = cert_verifier_job->Run( |
+ base::Bind(&QuicStreamFactory::OnCertVerifyJobComplete, |
+ base::Unretained(this), cert_verifier_job.get())); |
+ if (status != QUIC_FAILURE) |
+ active_cert_verifier_jobs_[server_id] = cert_verifier_job.release(); |
+} |
+ |
void QuicStreamFactory::InitializeCachedStateInCryptoConfig( |
const QuicServerId& server_id, |
const std::unique_ptr<QuicServerInfo>& server_info, |