multi_threaded_cert_verifier.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/cert/multi_threaded_cert_verifier.h"
  5. #include "base/bind.h"
  6. #include "base/callback_helpers.h"
  7. #include "base/check_op.h"
  8. #include "base/memory/raw_ptr.h"
  9. #include "base/memory/weak_ptr.h"
  10. #include "base/task/thread_pool.h"
  11. #include "base/threading/thread_restrictions.h"
  12. #include "base/trace_event/trace_event.h"
  13. #include "crypto/crypto_buildflags.h"
  14. #include "net/base/net_errors.h"
  15. #include "net/base/trace_constants.h"
  16. #include "net/cert/cert_verify_proc.h"
  17. #include "net/cert/cert_verify_result.h"
  18. #include "net/cert/crl_set.h"
  19. #include "net/cert/x509_certificate.h"
  20. #include "net/log/net_log_event_type.h"
  21. #include "net/log/net_log_source_type.h"
  22. #include "net/log/net_log_with_source.h"
  23. #if BUILDFLAG(USE_NSS_CERTS)
  24. #include "net/cert/x509_util_nss.h"
  25. #endif
  26. namespace net {
  27. // Allows DoVerifyOnWorkerThread to wait on a base::WaitableEvent.
  28. // DoVerifyOnWorkerThread may wait on network operations done on a separate
  29. // sequence. For instance when using the NSS-based implementation of certificate
  30. // verification, the library requires a blocking callback for fetching OCSP and
  31. // AIA responses.
  32. class MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives
  33. : public base::ScopedAllowBaseSyncPrimitives {};
  34. namespace {
  35. // Used to pass the result of DoVerifyOnWorkerThread() to
  36. // MultiThreadedCertVerifier::InternalRequest::OnJobComplete().
  37. struct ResultHelper {
  38. int error;
  39. CertVerifyResult result;
  40. NetLogWithSource net_log;
  41. };
  42. int GetFlagsForConfig(const CertVerifier::Config& config) {
  43. int flags = 0;
  44. if (config.enable_rev_checking)
  45. flags |= CertVerifyProc::VERIFY_REV_CHECKING_ENABLED;
  46. if (config.require_rev_checking_local_anchors)
  47. flags |= CertVerifyProc::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS;
  48. if (config.enable_sha1_local_anchors)
  49. flags |= CertVerifyProc::VERIFY_ENABLE_SHA1_LOCAL_ANCHORS;
  50. if (config.disable_symantec_enforcement)
  51. flags |= CertVerifyProc::VERIFY_DISABLE_SYMANTEC_ENFORCEMENT;
  52. return flags;
  53. }
  54. // Runs the verification synchronously on a worker thread.
  55. std::unique_ptr<ResultHelper> DoVerifyOnWorkerThread(
  56. const scoped_refptr<CertVerifyProc>& verify_proc,
  57. const scoped_refptr<X509Certificate>& cert,
  58. const std::string& hostname,
  59. const std::string& ocsp_response,
  60. const std::string& sct_list,
  61. int flags,
  62. const scoped_refptr<CRLSet>& crl_set,
  63. const CertificateList& additional_trust_anchors,
  64. const NetLogWithSource& net_log) {
  65. TRACE_EVENT0(NetTracingCategory(), "DoVerifyOnWorkerThread");
  66. auto verify_result = std::make_unique<ResultHelper>();
  67. verify_result->net_log = net_log;
  68. MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives
  69. allow_base_sync_primitives;
  70. verify_result->error = verify_proc->Verify(
  71. cert.get(), hostname, ocsp_response, sct_list, flags, crl_set.get(),
  72. additional_trust_anchors, &verify_result->result, net_log);
  73. // The CertVerifyResult is created and populated on the worker thread and
  74. // then returned to the network thread. Detach now before returning the
  75. // result, since any further access will be on the network thread.
  76. verify_result->result.DetachFromSequence();
  77. return verify_result;
  78. }
  79. } // namespace
  80. // Helper to allow callers to cancel pending CertVerifier::Verify requests.
  81. // Note that because the CertVerifyProc is blocking, it's not actually
  82. // possible to cancel the in-progress request; instead, this simply guarantees
  83. // that the provided callback will not be invoked if the Request is deleted.
  84. class MultiThreadedCertVerifier::InternalRequest
  85. : public CertVerifier::Request,
  86. public base::LinkNode<InternalRequest> {
  87. public:
  88. InternalRequest(CompletionOnceCallback callback,
  89. CertVerifyResult* caller_result);
  90. ~InternalRequest() override;
  91. void Start(const scoped_refptr<CertVerifyProc>& verify_proc,
  92. const CertVerifier::Config& config,
  93. const CertVerifier::RequestParams& params,
  94. const NetLogWithSource& caller_net_log);
  95. void ResetCallback() { callback_.Reset(); }
  96. private:
  97. // This is a static method with a |self| weak pointer instead of a regular
  98. // method, so that PostTask will still run it even if the weakptr is no
  99. // longer valid.
  100. static void OnJobComplete(base::WeakPtr<InternalRequest> self,
  101. std::unique_ptr<ResultHelper> verify_result);
  102. CompletionOnceCallback callback_;
  103. raw_ptr<CertVerifyResult> caller_result_;
  104. base::WeakPtrFactory<InternalRequest> weak_factory_{this};
  105. };
  106. MultiThreadedCertVerifier::InternalRequest::InternalRequest(
  107. CompletionOnceCallback callback,
  108. CertVerifyResult* caller_result)
  109. : callback_(std::move(callback)), caller_result_(caller_result) {}
  110. MultiThreadedCertVerifier::InternalRequest::~InternalRequest() {
  111. if (callback_) {
  112. // This InternalRequest was eagerly cancelled as the callback is still
  113. // valid, so |this| needs to be removed from MultiThreadedCertVerifier's
  114. // list.
  115. RemoveFromList();
  116. }
  117. }
  118. void MultiThreadedCertVerifier::InternalRequest::Start(
  119. const scoped_refptr<CertVerifyProc>& verify_proc,
  120. const CertVerifier::Config& config,
  121. const CertVerifier::RequestParams& params,
  122. const NetLogWithSource& caller_net_log) {
  123. const NetLogWithSource net_log(NetLogWithSource::Make(
  124. caller_net_log.net_log(), NetLogSourceType::CERT_VERIFIER_TASK));
  125. net_log.BeginEvent(NetLogEventType::CERT_VERIFIER_TASK);
  126. caller_net_log.AddEventReferencingSource(
  127. NetLogEventType::CERT_VERIFIER_TASK_BOUND, net_log.source());
  128. int flags = GetFlagsForConfig(config);
  129. if (params.flags() & CertVerifier::VERIFY_DISABLE_NETWORK_FETCHES) {
  130. flags &= ~CertVerifyProc::VERIFY_REV_CHECKING_ENABLED;
  131. flags &= ~CertVerifyProc::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS;
  132. }
  133. DCHECK(config.crl_set);
  134. base::ThreadPool::PostTaskAndReplyWithResult(
  135. FROM_HERE,
  136. {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
  137. base::BindOnce(&DoVerifyOnWorkerThread, verify_proc, params.certificate(),
  138. params.hostname(), params.ocsp_response(),
  139. params.sct_list(), flags, config.crl_set,
  140. config.additional_trust_anchors, net_log),
  141. base::BindOnce(&MultiThreadedCertVerifier::InternalRequest::OnJobComplete,
  142. weak_factory_.GetWeakPtr()));
  143. }
  144. // static
  145. void MultiThreadedCertVerifier::InternalRequest::OnJobComplete(
  146. base::WeakPtr<InternalRequest> self,
  147. std::unique_ptr<ResultHelper> verify_result) {
  148. // Always log the EndEvent, even if the Request has been destroyed.
  149. verify_result->net_log.EndEvent(NetLogEventType::CERT_VERIFIER_TASK);
  150. // Check |self| weakptr and don't continue if the Request was destroyed.
  151. if (!self)
  152. return;
  153. DCHECK(verify_result);
  154. // If the MultiThreadedCertVerifier has been deleted, the callback will have
  155. // been reset to null.
  156. if (!self->callback_)
  157. return;
  158. // If ~MultiThreadedCertVerifier has not Reset() our callback, then this
  159. // InternalRequest will not have been removed from MultiThreadedCertVerifier's
  160. // list yet.
  161. self->RemoveFromList();
  162. *self->caller_result_ = verify_result->result;
  163. // Note: May delete |self|.
  164. std::move(self->callback_).Run(verify_result->error);
  165. }
  166. MultiThreadedCertVerifier::MultiThreadedCertVerifier(
  167. scoped_refptr<CertVerifyProc> verify_proc)
  168. : MultiThreadedCertVerifier(std::move(verify_proc), nullptr) {}
  169. MultiThreadedCertVerifier::MultiThreadedCertVerifier(
  170. scoped_refptr<CertVerifyProc> verify_proc,
  171. scoped_refptr<CertVerifyProcFactory> verify_proc_factory)
  172. : verify_proc_(std::move(verify_proc)),
  173. verify_proc_factory_(std::move(verify_proc_factory)) {
  174. // Guarantee there is always a CRLSet (this can be overridden via SetConfig).
  175. config_.crl_set = CRLSet::BuiltinCRLSet();
  176. }
  177. MultiThreadedCertVerifier::~MultiThreadedCertVerifier() {
  178. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  179. // Reset the callbacks for each InternalRequest to fulfill the respective
  180. // net::CertVerifier contract.
  181. for (base::LinkNode<InternalRequest>* node = request_list_.head();
  182. node != request_list_.end();) {
  183. // Resetting the callback may delete the request, so save a pointer to the
  184. // next node first.
  185. base::LinkNode<InternalRequest>* next_node = node->next();
  186. node->value()->ResetCallback();
  187. node = next_node;
  188. }
  189. }
  190. int MultiThreadedCertVerifier::Verify(const RequestParams& params,
  191. CertVerifyResult* verify_result,
  192. CompletionOnceCallback callback,
  193. std::unique_ptr<Request>* out_req,
  194. const NetLogWithSource& net_log) {
  195. out_req->reset();
  196. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  197. if (callback.is_null() || !verify_result || params.hostname().empty())
  198. return ERR_INVALID_ARGUMENT;
  199. std::unique_ptr<InternalRequest> request =
  200. std::make_unique<InternalRequest>(std::move(callback), verify_result);
  201. request->Start(verify_proc_, config_, params, net_log);
  202. request_list_.Append(request.get());
  203. *out_req = std::move(request);
  204. return ERR_IO_PENDING;
  205. }
  206. void MultiThreadedCertVerifier::UpdateChromeRootStoreData(
  207. scoped_refptr<CertNetFetcher> cert_net_fetcher,
  208. const ChromeRootStoreData* root_store_data) {
  209. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  210. // TODO(hchao): investigate to see if we can make this a DCHECK.
  211. if (verify_proc_factory_) {
  212. verify_proc_ = verify_proc_factory_->CreateCertVerifyProc(
  213. std::move(cert_net_fetcher), root_store_data);
  214. }
  215. }
  216. void MultiThreadedCertVerifier::SetConfig(const CertVerifier::Config& config) {
  217. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  218. LOG_IF(DFATAL, verify_proc_ &&
  219. !verify_proc_->SupportsAdditionalTrustAnchors() &&
  220. !config.additional_trust_anchors.empty())
  221. << "Attempted to set a CertVerifier::Config with additional trust "
  222. "anchors, but |verify_proc_| does not support additional trust "
  223. "anchors.";
  224. // TODO(https://crbug.com/978854): Pass these into the actual CertVerifyProc
  225. // rather than relying on global side-effects.
  226. #if !BUILDFLAG(USE_NSS_CERTS)
  227. // Not yet implemented.
  228. DCHECK(config.additional_untrusted_authorities.empty());
  229. #else
  230. // Construct a temporary list and then swap that into the member variable, to
  231. // be polite to any verifications that might be in progress in a background
  232. // thread. This ensures that, at least for certs that are present in both the
  233. // old and new config, there will not be a time when the refcount drops to
  234. // zero. For the case where a cert was in the old config and is not in the
  235. // new config, it might be removed while a verification is still going on
  236. // that might be able to use it. Oh well. Ideally the list should be passed
  237. // into CertVerifyProc as noted by the TODO(https://crbug.com/978854), since
  238. // the workers could then keep a reference to the appropriate certs as long
  239. // as they need.
  240. net::ScopedCERTCertificateList temp_certs;
  241. for (const auto& cert : config.additional_untrusted_authorities) {
  242. ScopedCERTCertificate nss_cert =
  243. x509_util::CreateCERTCertificateFromX509Certificate(cert.get());
  244. if (nss_cert)
  245. temp_certs.push_back(std::move(nss_cert));
  246. }
  247. temp_certs_ = std::move(temp_certs);
  248. #endif
  249. config_ = config;
  250. if (!config_.crl_set)
  251. config_.crl_set = CRLSet::BuiltinCRLSet();
  252. }
  253. } // namespace net