blob: 8aa58a6c0d617ca89e14ed1082cd548bba27981d [file] [log] [blame]
Avi Drissman64595482022-09-14 20:52:291// Copyright 2012 The Chromium Authors
[email protected]9f59fac2012-03-21 23:18:112// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]6e7845ae2013-03-29 21:48:115#include "net/cert/multi_threaded_cert_verifier.h"
[email protected]9f59fac2012-03-21 23:18:116
Matthew Denton9d571bb2020-04-30 23:23:497#include "base/check_op.h"
Avi Drissman41c4a412023-01-11 22:45:378#include "base/functional/bind.h"
9#include "base/functional/callback_helpers.h"
Keishi Hattori0e45c022021-11-27 09:25:5210#include "base/memory/raw_ptr.h"
Ryan Sleevi2cb68172019-10-09 14:03:1111#include "base/memory/weak_ptr.h"
Gabriel Charetted5c656c2020-02-26 16:35:2212#include "base/task/thread_pool.h"
Francois Dorayd56d158d2017-10-19 19:26:3413#include "base/threading/thread_restrictions.h"
ssid6d6b40102016-04-05 18:59:5614#include "base/trace_event/trace_event.h"
Collin5baeeba52022-01-20 02:07:5915#include "crypto/crypto_buildflags.h"
[email protected]9f59fac2012-03-21 23:18:1116#include "net/base/net_errors.h"
xunjieli0b7f5b62016-12-06 20:43:4817#include "net/base/trace_constants.h"
[email protected]6e7845ae2013-03-29 21:48:1118#include "net/cert/cert_verify_proc.h"
rsleevi6df54182016-06-13 14:34:2319#include "net/cert/cert_verify_result.h"
[email protected]6e7845ae2013-03-29 21:48:1120#include "net/cert/crl_set.h"
21#include "net/cert/x509_certificate.h"
Matt Mueller787422342020-03-27 23:28:1822#include "net/log/net_log_event_type.h"
23#include "net/log/net_log_source_type.h"
24#include "net/log/net_log_with_source.h"
[email protected]9f59fac2012-03-21 23:18:1125
Collin5baeeba52022-01-20 02:07:5926#if BUILDFLAG(USE_NSS_CERTS)
Matthew Dentonb6730bf2020-06-25 04:54:1127#include "net/cert/x509_util_nss.h"
28#endif
29
[email protected]9f59fac2012-03-21 23:18:1130namespace net {
31
Francois Dorayd56d158d2017-10-19 19:26:3432// Allows DoVerifyOnWorkerThread to wait on a base::WaitableEvent.
33// DoVerifyOnWorkerThread may wait on network operations done on a separate
34// sequence. For instance when using the NSS-based implementation of certificate
35// verification, the library requires a blocking callback for fetching OCSP and
36// AIA responses.
37class MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives
38 : public base::ScopedAllowBaseSyncPrimitives {};
39
[email protected]9f59fac2012-03-21 23:18:1140namespace {
41
Matthew Denton9d571bb2020-04-30 23:23:4942// Used to pass the result of DoVerifyOnWorkerThread() to
43// MultiThreadedCertVerifier::InternalRequest::OnJobComplete().
rsleevi6df54182016-06-13 14:34:2344struct ResultHelper {
45 int error;
46 CertVerifyResult result;
Matt Mueller787422342020-03-27 23:28:1847 NetLogWithSource net_log;
[email protected]94bf72f2012-06-19 19:37:2848};
49
Ryan Sleevi24fe2682018-08-16 21:33:4650int GetFlagsForConfig(const CertVerifier::Config& config) {
51 int flags = 0;
52
53 if (config.enable_rev_checking)
54 flags |= CertVerifyProc::VERIFY_REV_CHECKING_ENABLED;
55 if (config.require_rev_checking_local_anchors)
56 flags |= CertVerifyProc::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS;
57 if (config.enable_sha1_local_anchors)
58 flags |= CertVerifyProc::VERIFY_ENABLE_SHA1_LOCAL_ANCHORS;
59 if (config.disable_symantec_enforcement)
60 flags |= CertVerifyProc::VERIFY_DISABLE_SYMANTEC_ENFORCEMENT;
61
62 return flags;
63}
64
Matthew Denton9d571bb2020-04-30 23:23:4965// Runs the verification synchronously on a worker thread.
Francois Doray524a99e2017-09-26 18:48:1766std::unique_ptr<ResultHelper> DoVerifyOnWorkerThread(
67 const scoped_refptr<CertVerifyProc>& verify_proc,
68 const scoped_refptr<X509Certificate>& cert,
69 const std::string& hostname,
70 const std::string& ocsp_response,
Matt Mueller7d5464b2019-05-15 20:18:4571 const std::string& sct_list,
Francois Doray524a99e2017-09-26 18:48:1772 int flags,
73 const scoped_refptr<CRLSet>& crl_set,
Matt Mueller787422342020-03-27 23:28:1874 const CertificateList& additional_trust_anchors,
75 const NetLogWithSource& net_log) {
Alexandr Ilin33126632018-11-14 14:48:1776 TRACE_EVENT0(NetTracingCategory(), "DoVerifyOnWorkerThread");
Francois Doray524a99e2017-09-26 18:48:1777 auto verify_result = std::make_unique<ResultHelper>();
Matt Mueller787422342020-03-27 23:28:1878 verify_result->net_log = net_log;
Francois Dorayd56d158d2017-10-19 19:26:3479 MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives
80 allow_base_sync_primitives;
Francois Doray524a99e2017-09-26 18:48:1781 verify_result->error = verify_proc->Verify(
Matt Mueller7d5464b2019-05-15 20:18:4582 cert.get(), hostname, ocsp_response, sct_list, flags, crl_set.get(),
Matt Mueller787422342020-03-27 23:28:1883 additional_trust_anchors, &verify_result->result, net_log);
Matt Muellercc42ea12019-08-14 23:27:3784 // The CertVerifyResult is created and populated on the worker thread and
85 // then returned to the network thread. Detach now before returning the
86 // result, since any further access will be on the network thread.
87 verify_result->result.DetachFromSequence();
Francois Doray524a99e2017-09-26 18:48:1788 return verify_result;
eroman7f9236a2015-05-11 21:23:4389}
[email protected]9f59fac2012-03-21 23:18:1190
Matthew Denton9d571bb2020-04-30 23:23:4991} // namespace
92
Ryan Sleevi2cb68172019-10-09 14:03:1193// Helper to allow callers to cancel pending CertVerifier::Verify requests.
94// Note that because the CertVerifyProc is blocking, it's not actually
95// possible to cancel the in-progress request; instead, this simply guarantees
96// that the provided callback will not be invoked if the Request is deleted.
Matthew Denton9d571bb2020-04-30 23:23:4997class MultiThreadedCertVerifier::InternalRequest
98 : public CertVerifier::Request,
99 public base::LinkNode<InternalRequest> {
[email protected]9f59fac2012-03-21 23:18:11100 public:
Ryan Sleevi2cb68172019-10-09 14:03:11101 InternalRequest(CompletionOnceCallback callback,
102 CertVerifyResult* caller_result);
103 ~InternalRequest() override;
eroman7f9236a2015-05-11 21:23:43104
Francois Doray524a99e2017-09-26 18:48:17105 void Start(const scoped_refptr<CertVerifyProc>& verify_proc,
Ryan Sleevi24fe2682018-08-16 21:33:46106 const CertVerifier::Config& config,
Matt Mueller787422342020-03-27 23:28:18107 const CertVerifier::RequestParams& params,
108 const NetLogWithSource& caller_net_log);
[email protected]9f59fac2012-03-21 23:18:11109
Matthew Denton9d571bb2020-04-30 23:23:49110 void ResetCallback() { callback_.Reset(); }
111
eroman7f9236a2015-05-11 21:23:43112 private:
Matt Mueller787422342020-03-27 23:28:18113 // This is a static method with a |self| weak pointer instead of a regular
114 // method, so that PostTask will still run it even if the weakptr is no
115 // longer valid.
116 static void OnJobComplete(base::WeakPtr<InternalRequest> self,
117 std::unique_ptr<ResultHelper> verify_result);
eroman7f9236a2015-05-11 21:23:43118
Ryan Sleevi2cb68172019-10-09 14:03:11119 CompletionOnceCallback callback_;
Keishi Hattori0e45c022021-11-27 09:25:52120 raw_ptr<CertVerifyResult> caller_result_;
[email protected]9f59fac2012-03-21 23:18:11121
Ryan Sleevi2cb68172019-10-09 14:03:11122 base::WeakPtrFactory<InternalRequest> weak_factory_{this};
[email protected]9f59fac2012-03-21 23:18:11123};
124
Matthew Denton9d571bb2020-04-30 23:23:49125MultiThreadedCertVerifier::InternalRequest::InternalRequest(
126 CompletionOnceCallback callback,
127 CertVerifyResult* caller_result)
Ryan Sleevi2cb68172019-10-09 14:03:11128 : callback_(std::move(callback)), caller_result_(caller_result) {}
129
Matthew Denton9d571bb2020-04-30 23:23:49130MultiThreadedCertVerifier::InternalRequest::~InternalRequest() {
131 if (callback_) {
132 // This InternalRequest was eagerly cancelled as the callback is still
133 // valid, so |this| needs to be removed from MultiThreadedCertVerifier's
134 // list.
135 RemoveFromList();
136 }
137}
Ryan Sleevi2cb68172019-10-09 14:03:11138
Matthew Denton9d571bb2020-04-30 23:23:49139void MultiThreadedCertVerifier::InternalRequest::Start(
140 const scoped_refptr<CertVerifyProc>& verify_proc,
141 const CertVerifier::Config& config,
142 const CertVerifier::RequestParams& params,
143 const NetLogWithSource& caller_net_log) {
Matt Mueller787422342020-03-27 23:28:18144 const NetLogWithSource net_log(NetLogWithSource::Make(
145 caller_net_log.net_log(), NetLogSourceType::CERT_VERIFIER_TASK));
146 net_log.BeginEvent(NetLogEventType::CERT_VERIFIER_TASK);
147 caller_net_log.AddEventReferencingSource(
148 NetLogEventType::CERT_VERIFIER_TASK_BOUND, net_log.source());
149
Ryan Sleevi2cb68172019-10-09 14:03:11150 int flags = GetFlagsForConfig(config);
151 if (params.flags() & CertVerifier::VERIFY_DISABLE_NETWORK_FETCHES) {
152 flags &= ~CertVerifyProc::VERIFY_REV_CHECKING_ENABLED;
153 flags &= ~CertVerifyProc::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS;
154 }
155 DCHECK(config.crl_set);
Gabriel Charetted5c656c2020-02-26 16:35:22156 base::ThreadPool::PostTaskAndReplyWithResult(
Ryan Sleevi2cb68172019-10-09 14:03:11157 FROM_HERE,
Gabriel Charetted5c656c2020-02-26 16:35:22158 {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
Ryan Sleevi2cb68172019-10-09 14:03:11159 base::BindOnce(&DoVerifyOnWorkerThread, verify_proc, params.certificate(),
160 params.hostname(), params.ocsp_response(),
161 params.sct_list(), flags, config.crl_set,
Matt Mueller787422342020-03-27 23:28:18162 config.additional_trust_anchors, net_log),
Matthew Denton9d571bb2020-04-30 23:23:49163 base::BindOnce(&MultiThreadedCertVerifier::InternalRequest::OnJobComplete,
Ryan Sleevi2cb68172019-10-09 14:03:11164 weak_factory_.GetWeakPtr()));
165}
166
Matt Mueller787422342020-03-27 23:28:18167// static
Matthew Denton9d571bb2020-04-30 23:23:49168void MultiThreadedCertVerifier::InternalRequest::OnJobComplete(
Matt Mueller787422342020-03-27 23:28:18169 base::WeakPtr<InternalRequest> self,
Ryan Sleevi2cb68172019-10-09 14:03:11170 std::unique_ptr<ResultHelper> verify_result) {
Matt Mueller787422342020-03-27 23:28:18171 // Always log the EndEvent, even if the Request has been destroyed.
172 verify_result->net_log.EndEvent(NetLogEventType::CERT_VERIFIER_TASK);
173
174 // Check |self| weakptr and don't continue if the Request was destroyed.
175 if (!self)
176 return;
177
Matthew Denton9d571bb2020-04-30 23:23:49178 DCHECK(verify_result);
179
180 // If the MultiThreadedCertVerifier has been deleted, the callback will have
181 // been reset to null.
182 if (!self->callback_)
183 return;
184
185 // If ~MultiThreadedCertVerifier has not Reset() our callback, then this
186 // InternalRequest will not have been removed from MultiThreadedCertVerifier's
187 // list yet.
188 self->RemoveFromList();
189
Matt Mueller787422342020-03-27 23:28:18190 *self->caller_result_ = verify_result->result;
191 // Note: May delete |self|.
192 std::move(self->callback_).Run(verify_result->error);
Ryan Sleevi2cb68172019-10-09 14:03:11193}
194
[email protected]ec012fe22012-09-19 04:17:02195MultiThreadedCertVerifier::MultiThreadedCertVerifier(
Sergey Ulanov49085572017-07-10 23:25:46196 scoped_refptr<CertVerifyProc> verify_proc)
Hubert Chao2a000d72022-04-25 19:43:30197 : MultiThreadedCertVerifier(std::move(verify_proc), nullptr) {}
198
199MultiThreadedCertVerifier::MultiThreadedCertVerifier(
200 scoped_refptr<CertVerifyProc> verify_proc,
201 scoped_refptr<CertVerifyProcFactory> verify_proc_factory)
202 : verify_proc_(std::move(verify_proc)),
203 verify_proc_factory_(std::move(verify_proc_factory)) {
Ryan Sleevi2cb68172019-10-09 14:03:11204 // Guarantee there is always a CRLSet (this can be overridden via SetConfig).
Matthew Braithwaite468ae9b7d2019-03-06 03:57:21205 config_.crl_set = CRLSet::BuiltinCRLSet();
206}
[email protected]9f59fac2012-03-21 23:18:11207
208MultiThreadedCertVerifier::~MultiThreadedCertVerifier() {
gab47aa7da2017-06-02 16:09:43209 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
Matthew Denton9d571bb2020-04-30 23:23:49210 // Reset the callbacks for each InternalRequest to fulfill the respective
211 // net::CertVerifier contract.
Matthew Denton19aeffd42020-12-15 01:09:52212 for (base::LinkNode<InternalRequest>* node = request_list_.head();
213 node != request_list_.end();) {
214 // Resetting the callback may delete the request, so save a pointer to the
215 // next node first.
216 base::LinkNode<InternalRequest>* next_node = node->next();
217 node->value()->ResetCallback();
218 node = next_node;
Matthew Denton9d571bb2020-04-30 23:23:49219 }
[email protected]ef155122013-03-23 19:11:24220}
221
rsleevi06bd78552016-06-08 22:34:46222int MultiThreadedCertVerifier::Verify(const RequestParams& params,
[email protected]9f59fac2012-03-21 23:18:11223 CertVerifyResult* verify_result,
Bence Béky9387759c2018-07-04 18:51:33224 CompletionOnceCallback callback,
danakj3a4770d2016-04-16 03:09:29225 std::unique_ptr<Request>* out_req,
tfarina42834112016-09-22 13:38:20226 const NetLogWithSource& net_log) {
eroman7f9236a2015-05-11 21:23:43227 out_req->reset();
228
gab47aa7da2017-06-02 16:09:43229 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
[email protected]9f59fac2012-03-21 23:18:11230
rsleevi06bd78552016-06-08 22:34:46231 if (callback.is_null() || !verify_result || params.hostname().empty())
[email protected]9f59fac2012-03-21 23:18:11232 return ERR_INVALID_ARGUMENT;
[email protected]9f59fac2012-03-21 23:18:11233
Ryan Sleevi2cb68172019-10-09 14:03:11234 std::unique_ptr<InternalRequest> request =
235 std::make_unique<InternalRequest>(std::move(callback), verify_result);
Matt Mueller787422342020-03-27 23:28:18236 request->Start(verify_proc_, config_, params, net_log);
Matthew Denton9d571bb2020-04-30 23:23:49237 request_list_.Append(request.get());
dchengc7eeda422015-12-26 03:56:48238 *out_req = std::move(request);
[email protected]9f59fac2012-03-21 23:18:11239 return ERR_IO_PENDING;
240}
241
Hubert Chao2a000d72022-04-25 19:43:30242void MultiThreadedCertVerifier::UpdateChromeRootStoreData(
243 scoped_refptr<CertNetFetcher> cert_net_fetcher,
244 const ChromeRootStoreData* root_store_data) {
245 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
246 // TODO(hchao): investigate to see if we can make this a DCHECK.
247 if (verify_proc_factory_) {
248 verify_proc_ = verify_proc_factory_->CreateCertVerifyProc(
249 std::move(cert_net_fetcher), root_store_data);
250 }
251}
252
Ryan Sleevi24fe2682018-08-16 21:33:46253void MultiThreadedCertVerifier::SetConfig(const CertVerifier::Config& config) {
Matt Mueller52678942022-03-02 21:33:14254 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
Matthew Dentonef6b10c2020-04-28 10:49:44255 LOG_IF(DFATAL, verify_proc_ &&
256 !verify_proc_->SupportsAdditionalTrustAnchors() &&
257 !config.additional_trust_anchors.empty())
258 << "Attempted to set a CertVerifier::Config with additional trust "
259 "anchors, but |verify_proc_| does not support additional trust "
260 "anchors.";
Matthew Dentonb6730bf2020-06-25 04:54:11261
262// TODO(https://crbug.com/978854): Pass these into the actual CertVerifyProc
263// rather than relying on global side-effects.
Collin5baeeba52022-01-20 02:07:59264#if !BUILDFLAG(USE_NSS_CERTS)
Matthew Dentonb6730bf2020-06-25 04:54:11265 // Not yet implemented.
266 DCHECK(config.additional_untrusted_authorities.empty());
267#else
Matt Muellerc1561132022-04-27 22:53:47268 // Construct a temporary list and then swap that into the member variable, to
269 // be polite to any verifications that might be in progress in a background
270 // thread. This ensures that, at least for certs that are present in both the
271 // old and new config, there will not be a time when the refcount drops to
272 // zero. For the case where a cert was in the old config and is not in the
273 // new config, it might be removed while a verification is still going on
274 // that might be able to use it. Oh well. Ideally the list should be passed
275 // into CertVerifyProc as noted by the TODO(https://crbug.com/978854), since
276 // the workers could then keep a reference to the appropriate certs as long
277 // as they need.
278 net::ScopedCERTCertificateList temp_certs;
Matthew Dentonb6730bf2020-06-25 04:54:11279 for (const auto& cert : config.additional_untrusted_authorities) {
Matt Muellerc1561132022-04-27 22:53:47280 ScopedCERTCertificate nss_cert =
Matthew Dentonb6730bf2020-06-25 04:54:11281 x509_util::CreateCERTCertificateFromX509Certificate(cert.get());
Matt Muellerc1561132022-04-27 22:53:47282 if (nss_cert)
283 temp_certs.push_back(std::move(nss_cert));
Matthew Dentonb6730bf2020-06-25 04:54:11284 }
Matt Muellerc1561132022-04-27 22:53:47285 temp_certs_ = std::move(temp_certs);
Matthew Dentonb6730bf2020-06-25 04:54:11286#endif
287
Ryan Sleevi24fe2682018-08-16 21:33:46288 config_ = config;
Matthew Braithwaite468ae9b7d2019-03-06 03:57:21289 if (!config_.crl_set)
290 config_.crl_set = CRLSet::BuiltinCRLSet();
eroman7f9236a2015-05-11 21:23:43291}
292
[email protected]9f59fac2012-03-21 23:18:11293} // namespace net