OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/cert/multi_threaded_cert_verifier.h" | 5 #include "net/cert/multi_threaded_cert_verifier.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
12 #include "base/message_loop/message_loop.h" | 12 #include "base/message_loop/message_loop.h" |
13 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
14 #include "base/profiler/scoped_tracker.h" | 14 #include "base/profiler/scoped_tracker.h" |
| 15 #include "base/sha1.h" |
15 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
16 #include "base/synchronization/lock.h" | 17 #include "base/synchronization/lock.h" |
17 #include "base/threading/worker_pool.h" | 18 #include "base/threading/worker_pool.h" |
18 #include "base/time/time.h" | 19 #include "base/time/time.h" |
19 #include "base/values.h" | 20 #include "base/values.h" |
20 #include "net/base/hash_value.h" | 21 #include "net/base/hash_value.h" |
21 #include "net/base/net_errors.h" | 22 #include "net/base/net_errors.h" |
22 #include "net/cert/cert_trust_anchor_provider.h" | 23 #include "net/cert/cert_trust_anchor_provider.h" |
23 #include "net/cert/cert_verify_proc.h" | 24 #include "net/cert/cert_verify_proc.h" |
24 #include "net/cert/crl_set.h" | 25 #include "net/cert/crl_set.h" |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 | 212 |
212 | 213 |
213 // CertVerifierWorker runs on a worker thread and takes care of the blocking | 214 // CertVerifierWorker runs on a worker thread and takes care of the blocking |
214 // process of performing the certificate verification. Deletes itself | 215 // process of performing the certificate verification. Deletes itself |
215 // eventually if Start() succeeds. | 216 // eventually if Start() succeeds. |
216 class CertVerifierWorker { | 217 class CertVerifierWorker { |
217 public: | 218 public: |
218 CertVerifierWorker(CertVerifyProc* verify_proc, | 219 CertVerifierWorker(CertVerifyProc* verify_proc, |
219 X509Certificate* cert, | 220 X509Certificate* cert, |
220 const std::string& hostname, | 221 const std::string& hostname, |
| 222 const std::string& ocsp_response, |
221 int flags, | 223 int flags, |
222 CRLSet* crl_set, | 224 CRLSet* crl_set, |
223 const CertificateList& additional_trust_anchors, | 225 const CertificateList& additional_trust_anchors, |
224 MultiThreadedCertVerifier* cert_verifier) | 226 MultiThreadedCertVerifier* cert_verifier) |
225 : verify_proc_(verify_proc), | 227 : verify_proc_(verify_proc), |
226 cert_(cert), | 228 cert_(cert), |
227 hostname_(hostname), | 229 hostname_(hostname), |
| 230 ocsp_response_(ocsp_response), |
228 flags_(flags), | 231 flags_(flags), |
229 crl_set_(crl_set), | 232 crl_set_(crl_set), |
230 additional_trust_anchors_(additional_trust_anchors), | 233 additional_trust_anchors_(additional_trust_anchors), |
231 origin_loop_(base::MessageLoop::current()), | 234 origin_loop_(base::MessageLoop::current()), |
232 cert_verifier_(cert_verifier), | 235 cert_verifier_(cert_verifier), |
233 canceled_(false), | 236 canceled_(false), |
234 error_(ERR_FAILED) { | 237 error_(ERR_FAILED) {} |
235 } | |
236 | 238 |
237 // Returns the certificate being verified. May only be called /before/ | 239 // Returns the certificate being verified. May only be called /before/ |
238 // Start() is called. | 240 // Start() is called. |
239 X509Certificate* certificate() const { return cert_.get(); } | 241 X509Certificate* certificate() const { return cert_.get(); } |
240 | 242 |
241 bool Start() { | 243 bool Start() { |
242 DCHECK_EQ(base::MessageLoop::current(), origin_loop_); | 244 DCHECK_EQ(base::MessageLoop::current(), origin_loop_); |
243 | 245 |
244 return base::WorkerPool::PostTask( | 246 return base::WorkerPool::PostTask( |
245 FROM_HERE, base::Bind(&CertVerifierWorker::Run, base::Unretained(this)), | 247 FROM_HERE, base::Bind(&CertVerifierWorker::Run, base::Unretained(this)), |
246 true /* task is slow */); | 248 true /* task is slow */); |
247 } | 249 } |
248 | 250 |
249 // Cancel is called from the origin loop when the MultiThreadedCertVerifier is | 251 // Cancel is called from the origin loop when the MultiThreadedCertVerifier is |
250 // getting deleted. | 252 // getting deleted. |
251 void Cancel() { | 253 void Cancel() { |
252 DCHECK_EQ(base::MessageLoop::current(), origin_loop_); | 254 DCHECK_EQ(base::MessageLoop::current(), origin_loop_); |
253 base::AutoLock locked(lock_); | 255 base::AutoLock locked(lock_); |
254 canceled_ = true; | 256 canceled_ = true; |
255 } | 257 } |
256 | 258 |
257 private: | 259 private: |
258 void Run() { | 260 void Run() { |
259 // Runs on a worker thread. | 261 // Runs on a worker thread. |
260 error_ = verify_proc_->Verify(cert_.get(), | 262 error_ = verify_proc_->Verify(cert_.get(), hostname_, ocsp_response_, |
261 hostname_, | 263 flags_, crl_set_.get(), |
262 flags_, | 264 additional_trust_anchors_, &verify_result_); |
263 crl_set_.get(), | |
264 additional_trust_anchors_, | |
265 &verify_result_); | |
266 #if defined(USE_NSS_CERTS) || defined(OS_IOS) | 265 #if defined(USE_NSS_CERTS) || defined(OS_IOS) |
267 // Detach the thread from NSPR. | 266 // Detach the thread from NSPR. |
268 // Calling NSS functions attaches the thread to NSPR, which stores | 267 // Calling NSS functions attaches the thread to NSPR, which stores |
269 // the NSPR thread ID in thread-specific data. | 268 // the NSPR thread ID in thread-specific data. |
270 // The threads in our thread pool terminate after we have called | 269 // The threads in our thread pool terminate after we have called |
271 // PR_Cleanup. Unless we detach them from NSPR, net_unittests gets | 270 // PR_Cleanup. Unless we detach them from NSPR, net_unittests gets |
272 // segfaults on shutdown when the threads' thread-specific data | 271 // segfaults on shutdown when the threads' thread-specific data |
273 // destructors run. | 272 // destructors run. |
274 PR_DetachThread(); | 273 PR_DetachThread(); |
275 #endif | 274 #endif |
276 Finish(); | 275 Finish(); |
277 } | 276 } |
278 | 277 |
279 // DoReply runs on the origin thread. | 278 // DoReply runs on the origin thread. |
280 void DoReply() { | 279 void DoReply() { |
281 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is | 280 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is |
282 // fixed. | 281 // fixed. |
283 tracked_objects::ScopedTracker tracking_profile( | 282 tracked_objects::ScopedTracker tracking_profile( |
284 FROM_HERE_WITH_EXPLICIT_FUNCTION("477117 CertVerifierWorker::DoReply")); | 283 FROM_HERE_WITH_EXPLICIT_FUNCTION("477117 CertVerifierWorker::DoReply")); |
285 DCHECK_EQ(base::MessageLoop::current(), origin_loop_); | 284 DCHECK_EQ(base::MessageLoop::current(), origin_loop_); |
286 { | 285 { |
287 // We lock here because the worker thread could still be in Finished, | 286 // We lock here because the worker thread could still be in Finished, |
288 // after the PostTask, but before unlocking |lock_|. If we do not lock in | 287 // after the PostTask, but before unlocking |lock_|. If we do not lock in |
289 // this case, we will end up deleting a locked Lock, which can lead to | 288 // this case, we will end up deleting a locked Lock, which can lead to |
290 // memory leaks or worse errors. | 289 // memory leaks or worse errors. |
291 base::AutoLock locked(lock_); | 290 base::AutoLock locked(lock_); |
292 if (!canceled_) { | 291 if (!canceled_) { |
293 cert_verifier_->HandleResult(cert_.get(), | 292 cert_verifier_->HandleResult(cert_.get(), hostname_, ocsp_response_, |
294 hostname_, | 293 flags_, additional_trust_anchors_, error_, |
295 flags_, | |
296 additional_trust_anchors_, | |
297 error_, | |
298 verify_result_); | 294 verify_result_); |
299 } | 295 } |
300 } | 296 } |
301 delete this; | 297 delete this; |
302 } | 298 } |
303 | 299 |
304 void Finish() { | 300 void Finish() { |
305 // Runs on the worker thread. | 301 // Runs on the worker thread. |
306 // We assume that the origin loop outlives the MultiThreadedCertVerifier. If | 302 // We assume that the origin loop outlives the MultiThreadedCertVerifier. If |
307 // the MultiThreadedCertVerifier is deleted, it will call Cancel on us. If | 303 // the MultiThreadedCertVerifier is deleted, it will call Cancel on us. If |
(...skipping 16 matching lines...) Expand all Loading... |
324 } | 320 } |
325 } | 321 } |
326 | 322 |
327 if (canceled) | 323 if (canceled) |
328 delete this; | 324 delete this; |
329 } | 325 } |
330 | 326 |
331 scoped_refptr<CertVerifyProc> verify_proc_; | 327 scoped_refptr<CertVerifyProc> verify_proc_; |
332 scoped_refptr<X509Certificate> cert_; | 328 scoped_refptr<X509Certificate> cert_; |
333 const std::string hostname_; | 329 const std::string hostname_; |
| 330 const std::string ocsp_response_; |
334 const int flags_; | 331 const int flags_; |
335 scoped_refptr<CRLSet> crl_set_; | 332 scoped_refptr<CRLSet> crl_set_; |
336 const CertificateList additional_trust_anchors_; | 333 const CertificateList additional_trust_anchors_; |
337 base::MessageLoop* const origin_loop_; | 334 base::MessageLoop* const origin_loop_; |
338 MultiThreadedCertVerifier* const cert_verifier_; | 335 MultiThreadedCertVerifier* const cert_verifier_; |
339 | 336 |
340 // lock_ protects canceled_. | 337 // lock_ protects canceled_. |
341 base::Lock lock_; | 338 base::Lock lock_; |
342 | 339 |
343 // If canceled_ is true, | 340 // If canceled_ is true, |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 } | 450 } |
454 | 451 |
455 void MultiThreadedCertVerifier::SetCertTrustAnchorProvider( | 452 void MultiThreadedCertVerifier::SetCertTrustAnchorProvider( |
456 CertTrustAnchorProvider* trust_anchor_provider) { | 453 CertTrustAnchorProvider* trust_anchor_provider) { |
457 DCHECK(CalledOnValidThread()); | 454 DCHECK(CalledOnValidThread()); |
458 trust_anchor_provider_ = trust_anchor_provider; | 455 trust_anchor_provider_ = trust_anchor_provider; |
459 } | 456 } |
460 | 457 |
461 int MultiThreadedCertVerifier::Verify(X509Certificate* cert, | 458 int MultiThreadedCertVerifier::Verify(X509Certificate* cert, |
462 const std::string& hostname, | 459 const std::string& hostname, |
| 460 const std::string& ocsp_response, |
463 int flags, | 461 int flags, |
464 CRLSet* crl_set, | 462 CRLSet* crl_set, |
465 CertVerifyResult* verify_result, | 463 CertVerifyResult* verify_result, |
466 const CompletionCallback& callback, | 464 const CompletionCallback& callback, |
467 RequestHandle* out_req, | 465 RequestHandle* out_req, |
468 const BoundNetLog& net_log) { | 466 const BoundNetLog& net_log) { |
469 DCHECK(CalledOnValidThread()); | 467 DCHECK(CalledOnValidThread()); |
470 | 468 |
471 if (callback.is_null() || !verify_result || hostname.empty()) { | 469 if (callback.is_null() || !verify_result || hostname.empty()) { |
472 *out_req = NULL; | 470 *out_req = NULL; |
473 return ERR_INVALID_ARGUMENT; | 471 return ERR_INVALID_ARGUMENT; |
474 } | 472 } |
475 | 473 |
476 requests_++; | 474 requests_++; |
477 | 475 |
478 const CertificateList empty_cert_list; | 476 const CertificateList empty_cert_list; |
479 const CertificateList& additional_trust_anchors = | 477 const CertificateList& additional_trust_anchors = |
480 trust_anchor_provider_ ? | 478 trust_anchor_provider_ ? |
481 trust_anchor_provider_->GetAdditionalTrustAnchors() : empty_cert_list; | 479 trust_anchor_provider_->GetAdditionalTrustAnchors() : empty_cert_list; |
482 | 480 |
483 const RequestParams key(cert->fingerprint(), cert->ca_fingerprint(), | 481 const RequestParams key(cert->fingerprint(), cert->ca_fingerprint(), hostname, |
484 hostname, flags, additional_trust_anchors); | 482 ocsp_response, flags, additional_trust_anchors); |
485 const CertVerifierCache::value_type* cached_entry = | 483 const CertVerifierCache::value_type* cached_entry = |
486 cache_.Get(key, CacheValidityPeriod(base::Time::Now())); | 484 cache_.Get(key, CacheValidityPeriod(base::Time::Now())); |
487 if (cached_entry) { | 485 if (cached_entry) { |
488 ++cache_hits_; | 486 ++cache_hits_; |
489 *out_req = NULL; | 487 *out_req = NULL; |
490 *verify_result = cached_entry->result; | 488 *verify_result = cached_entry->result; |
491 return cached_entry->error; | 489 return cached_entry->error; |
492 } | 490 } |
493 | 491 |
494 // No cache hit. See if an identical request is currently in flight. | 492 // No cache hit. See if an identical request is currently in flight. |
495 CertVerifierJob* job; | 493 CertVerifierJob* job; |
496 std::map<RequestParams, CertVerifierJob*>::const_iterator j; | 494 std::map<RequestParams, CertVerifierJob*>::const_iterator j; |
497 j = inflight_.find(key); | 495 j = inflight_.find(key); |
498 if (j != inflight_.end()) { | 496 if (j != inflight_.end()) { |
499 // An identical request is in flight already. We'll just attach our | 497 // An identical request is in flight already. We'll just attach our |
500 // callback. | 498 // callback. |
501 inflight_joins_++; | 499 inflight_joins_++; |
502 job = j->second; | 500 job = j->second; |
503 } else { | 501 } else { |
504 // Need to make a new request. | 502 // Need to make a new request. |
505 CertVerifierWorker* worker = | 503 CertVerifierWorker* worker = new CertVerifierWorker( |
506 new CertVerifierWorker(verify_proc_.get(), | 504 verify_proc_.get(), cert, hostname, ocsp_response, flags, crl_set, |
507 cert, | 505 additional_trust_anchors, this); |
508 hostname, | |
509 flags, | |
510 crl_set, | |
511 additional_trust_anchors, | |
512 this); | |
513 job = new CertVerifierJob( | 506 job = new CertVerifierJob( |
514 worker, | 507 worker, |
515 BoundNetLog::Make(net_log.net_log(), NetLog::SOURCE_CERT_VERIFIER_JOB)); | 508 BoundNetLog::Make(net_log.net_log(), NetLog::SOURCE_CERT_VERIFIER_JOB)); |
516 if (!worker->Start()) { | 509 if (!worker->Start()) { |
517 delete job; | 510 delete job; |
518 delete worker; | 511 delete worker; |
519 *out_req = NULL; | 512 *out_req = NULL; |
520 // TODO(wtc): log to the NetLog. | 513 // TODO(wtc): log to the NetLog. |
521 LOG(ERROR) << "CertVerifierWorker couldn't be started."; | 514 LOG(ERROR) << "CertVerifierWorker couldn't be started."; |
522 return ERR_INSUFFICIENT_RESOURCES; // Just a guess. | 515 return ERR_INSUFFICIENT_RESOURCES; // Just a guess. |
(...skipping 11 matching lines...) Expand all Loading... |
534 *out_req = request; | 527 *out_req = request; |
535 return ERR_IO_PENDING; | 528 return ERR_IO_PENDING; |
536 } | 529 } |
537 | 530 |
538 void MultiThreadedCertVerifier::CancelRequest(RequestHandle req) { | 531 void MultiThreadedCertVerifier::CancelRequest(RequestHandle req) { |
539 DCHECK(CalledOnValidThread()); | 532 DCHECK(CalledOnValidThread()); |
540 CertVerifierRequest* request = reinterpret_cast<CertVerifierRequest*>(req); | 533 CertVerifierRequest* request = reinterpret_cast<CertVerifierRequest*>(req); |
541 request->Cancel(); | 534 request->Cancel(); |
542 } | 535 } |
543 | 536 |
| 537 bool MultiThreadedCertVerifier::SupportsOCSPStapling() { |
| 538 return verify_proc_->SupportsOCSPStapling(); |
| 539 } |
| 540 |
544 MultiThreadedCertVerifier::RequestParams::RequestParams( | 541 MultiThreadedCertVerifier::RequestParams::RequestParams( |
545 const SHA1HashValue& cert_fingerprint_arg, | 542 const SHA1HashValue& cert_fingerprint_arg, |
546 const SHA1HashValue& ca_fingerprint_arg, | 543 const SHA1HashValue& ca_fingerprint_arg, |
547 const std::string& hostname_arg, | 544 const std::string& hostname_arg, |
| 545 const std::string& ocsp_response_arg, |
548 int flags_arg, | 546 int flags_arg, |
549 const CertificateList& additional_trust_anchors) | 547 const CertificateList& additional_trust_anchors) |
550 : hostname(hostname_arg), | 548 : hostname(hostname_arg), flags(flags_arg) { |
551 flags(flags_arg) { | 549 hash_values.reserve(3 + additional_trust_anchors.size()); |
552 hash_values.reserve(2 + additional_trust_anchors.size()); | 550 SHA1HashValue ocsp_hash; |
| 551 base::SHA1HashBytes( |
| 552 reinterpret_cast<const unsigned char*>(ocsp_response_arg.data()), |
| 553 ocsp_response_arg.size(), ocsp_hash.data); |
| 554 hash_values.push_back(ocsp_hash); |
553 hash_values.push_back(cert_fingerprint_arg); | 555 hash_values.push_back(cert_fingerprint_arg); |
554 hash_values.push_back(ca_fingerprint_arg); | 556 hash_values.push_back(ca_fingerprint_arg); |
555 for (size_t i = 0; i < additional_trust_anchors.size(); ++i) | 557 for (size_t i = 0; i < additional_trust_anchors.size(); ++i) |
556 hash_values.push_back(additional_trust_anchors[i]->fingerprint()); | 558 hash_values.push_back(additional_trust_anchors[i]->fingerprint()); |
557 } | 559 } |
558 | 560 |
559 MultiThreadedCertVerifier::RequestParams::~RequestParams() {} | 561 MultiThreadedCertVerifier::RequestParams::~RequestParams() {} |
560 | 562 |
561 bool MultiThreadedCertVerifier::RequestParams::operator<( | 563 bool MultiThreadedCertVerifier::RequestParams::operator<( |
562 const RequestParams& other) const { | 564 const RequestParams& other) const { |
563 // |flags| is compared before |cert_fingerprint|, |ca_fingerprint|, and | 565 // |flags| is compared before |cert_fingerprint|, |ca_fingerprint|, |
564 // |hostname| under assumption that integer comparisons are faster than | 566 // |hostname|, and |ocsp_response|, under assumption that integer comparisons |
565 // memory and string comparisons. | 567 // are faster than memory and string comparisons. |
566 if (flags != other.flags) | 568 if (flags != other.flags) |
567 return flags < other.flags; | 569 return flags < other.flags; |
568 if (hostname != other.hostname) | 570 if (hostname != other.hostname) |
569 return hostname < other.hostname; | 571 return hostname < other.hostname; |
570 return std::lexicographical_compare( | 572 return std::lexicographical_compare( |
571 hash_values.begin(), hash_values.end(), other.hash_values.begin(), | 573 hash_values.begin(), hash_values.end(), other.hash_values.begin(), |
572 other.hash_values.end(), SHA1HashValueLessThan()); | 574 other.hash_values.end(), SHA1HashValueLessThan()); |
573 } | 575 } |
574 | 576 |
575 // HandleResult is called by CertVerifierWorker on the origin message loop. | 577 // HandleResult is called by CertVerifierWorker on the origin message loop. |
576 // It deletes CertVerifierJob. | 578 // It deletes CertVerifierJob. |
577 void MultiThreadedCertVerifier::HandleResult( | 579 void MultiThreadedCertVerifier::HandleResult( |
578 X509Certificate* cert, | 580 X509Certificate* cert, |
579 const std::string& hostname, | 581 const std::string& hostname, |
| 582 const std::string& ocsp_response, |
580 int flags, | 583 int flags, |
581 const CertificateList& additional_trust_anchors, | 584 const CertificateList& additional_trust_anchors, |
582 int error, | 585 int error, |
583 const CertVerifyResult& verify_result) { | 586 const CertVerifyResult& verify_result) { |
584 DCHECK(CalledOnValidThread()); | 587 DCHECK(CalledOnValidThread()); |
585 | 588 |
586 const RequestParams key(cert->fingerprint(), cert->ca_fingerprint(), | 589 const RequestParams key(cert->fingerprint(), cert->ca_fingerprint(), hostname, |
587 hostname, flags, additional_trust_anchors); | 590 ocsp_response, flags, additional_trust_anchors); |
588 | 591 |
589 CachedResult cached_result; | 592 CachedResult cached_result; |
590 cached_result.error = error; | 593 cached_result.error = error; |
591 cached_result.result = verify_result; | 594 cached_result.result = verify_result; |
592 base::Time now = base::Time::Now(); | 595 base::Time now = base::Time::Now(); |
593 cache_.Put( | 596 cache_.Put( |
594 key, cached_result, CacheValidityPeriod(now), | 597 key, cached_result, CacheValidityPeriod(now), |
595 CacheValidityPeriod(now, now + base::TimeDelta::FromSeconds(kTTLSecs))); | 598 CacheValidityPeriod(now, now + base::TimeDelta::FromSeconds(kTTLSecs))); |
596 | 599 |
597 std::map<RequestParams, CertVerifierJob*>::iterator j; | 600 std::map<RequestParams, CertVerifierJob*>::iterator j; |
(...skipping 16 matching lines...) Expand all Loading... |
614 | 617 |
615 void MultiThreadedCertVerifier::OnCACertChanged( | 618 void MultiThreadedCertVerifier::OnCACertChanged( |
616 const X509Certificate* cert) { | 619 const X509Certificate* cert) { |
617 DCHECK(CalledOnValidThread()); | 620 DCHECK(CalledOnValidThread()); |
618 | 621 |
619 ClearCache(); | 622 ClearCache(); |
620 } | 623 } |
621 | 624 |
622 } // namespace net | 625 } // namespace net |
623 | 626 |
OLD | NEW |