// Copyright 2019 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/cert/coalescing_cert_verifier.h" #include "base/containers/linked_list.h" #include "base/containers/unique_ptr_adapters.h" #include "base/functional/bind.h" #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/metrics/histogram_macros.h" #include "base/not_fatal_until.h" #include "base/ranges/algorithm.h" #include "base/strings/string_number_conversions.h" #include "base/time/time.h" #include "net/base/net_errors.h" #include "net/cert/cert_verify_result.h" #include "net/cert/crl_set.h" #include "net/cert/x509_certificate_net_log_param.h" #include "net/log/net_log_event_type.h" #include "net/log/net_log_source.h" #include "net/log/net_log_source_type.h" #include "net/log/net_log_values.h" #include "net/log/net_log_with_source.h" #include "third_party/boringssl/src/pki/pem.h" namespace net { // DESIGN OVERVIEW: // // The CoalescingCertVerifier implements an algorithm to group multiple calls // to Verify() into a single Job. This avoids overloading the underlying // CertVerifier, particularly those that are expensive to talk to (e.g. // talking to the system verifier or across processes), batching multiple // requests to CoaleacingCertVerifier::Verify() into a single underlying call. // // However, this makes lifetime management a bit more complex. // - The Job object represents all of the state for a single verification to // the CoalescingCertVerifier's underlying CertVerifier. // * It keeps the CertVerifyResult alive, which is required as long as // there is a pending verification. // * It keeps the CertVerify::Request to the underlying verifier alive, // as long as there is a pending Request attached to the Job. // * It keeps track of every CoalescingCertVerifier::Request that is // interested in receiving notification. However, it does NOT own // these objects, and thus needs to coordinate with the Request (via // AddRequest/AbortRequest) to make sure it never has a stale // pointer. // NB: It would have also been possible for the Job to only // hold WeakPtr<Request>s, rather than Request*, but that seemed less // clear as to the lifetime invariants, even if it was more clear // about how the pointers are used. // - The Job object is always owned by the CoalescingCertVerifier. If the // CoalescingCertVerifier is deleted, all in-flight requests to the // underlying verifier should be cancelled. When the Job goes away, all the // Requests will be orphaned. // - The Request object is always owned by the CALLER. It is a handle to // allow a caller to cancel a request, per the CertVerifier interface. If // the Request goes away, no caller callbacks should be invoked if the Job // it was (previously) attached to completes. // - Per the CertVerifier interface, when the CoalescingCertVerifier is // deleted, then regardless of there being any live Requests, none of those // caller callbacks should be invoked. // // Finally, to add to the complexity, it's possible that, during the handling // of a result from the underlying CertVerifier, a Job may begin dispatching // to its Requests. The Request may delete the CoalescingCertVerifier. If that // happens, then the Job being processed is also deleted, and none of the // other Requests should be notified. namespace { base::Value::Dict CertVerifierParams( const CertVerifier::RequestParams& params) { … } } // namespace // Job contains all the state for a single verification using the underlying // verifier. class CoalescingCertVerifier::Job { … }; // Tracks the state associated with a single CoalescingCertVerifier::Verify // request. // // There are two ways for requests to be cancelled: // - The caller of Verify() can delete the Request object, indicating // they are no longer interested in this particular request. // - The caller can delete the CoalescingCertVerifier, which should cause // all in-process Jobs to be aborted and deleted. Any Requests attached to // Jobs should be orphaned, and do nothing when the Request is (eventually) // deleted. class CoalescingCertVerifier::Request : public base::LinkNode<CoalescingCertVerifier::Request>, public CertVerifier::Request { … }; CoalescingCertVerifier::Job::Job(CoalescingCertVerifier* parent, const CertVerifier::RequestParams& params, NetLog* net_log, bool is_first_job) : … { … } CoalescingCertVerifier::Job::~Job() { … } void CoalescingCertVerifier::Job::AddRequest( CoalescingCertVerifier::Request* request) { … } void CoalescingCertVerifier::Job::AbortRequest( CoalescingCertVerifier::Request* request) { … } int CoalescingCertVerifier::Job::Start(CertVerifier* underlying_verifier) { … } void CoalescingCertVerifier::Job::OnVerifyComplete(int result) { … } void CoalescingCertVerifier::Job::LogMetrics() { … } CoalescingCertVerifier::Request::Request(CoalescingCertVerifier::Job* job, CertVerifyResult* verify_result, CompletionOnceCallback callback, const NetLogWithSource& net_log) : … { … } CoalescingCertVerifier::Request::~Request() { … } void CoalescingCertVerifier::Request::Complete(int result) { … } void CoalescingCertVerifier::Request::OnJobAbort() { … } CoalescingCertVerifier::CoalescingCertVerifier( std::unique_ptr<CertVerifier> verifier) : … { … } CoalescingCertVerifier::~CoalescingCertVerifier() { … } int CoalescingCertVerifier::Verify( const RequestParams& params, CertVerifyResult* verify_result, CompletionOnceCallback callback, std::unique_ptr<CertVerifier::Request>* out_req, const NetLogWithSource& net_log) { … } void CoalescingCertVerifier::SetConfig(const CertVerifier::Config& config) { … } void CoalescingCertVerifier::AddObserver(CertVerifier::Observer* observer) { … } void CoalescingCertVerifier::RemoveObserver(CertVerifier::Observer* observer) { … } CoalescingCertVerifier::Job* CoalescingCertVerifier::FindJob( const RequestParams& params) { … } void CoalescingCertVerifier::RemoveJob(Job* job) { … } void CoalescingCertVerifier::IncrementGenerationAndMakeCurrentJobsUnjoinable() { … } void CoalescingCertVerifier::OnCertVerifierChanged() { … } } // namespace net