| 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 #include <memory> | 8 #include <memory> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 // PR_Cleanup. Unless we detach them from NSPR, net_unittests gets | 249 // PR_Cleanup. Unless we detach them from NSPR, net_unittests gets |
| 250 // segfaults on shutdown when the threads' thread-specific data | 250 // segfaults on shutdown when the threads' thread-specific data |
| 251 // destructors run. | 251 // destructors run. |
| 252 PR_DetachThread(); | 252 PR_DetachThread(); |
| 253 #endif | 253 #endif |
| 254 } | 254 } |
| 255 | 255 |
| 256 // CertVerifierJob lives only on the verifier's origin message loop. | 256 // CertVerifierJob lives only on the verifier's origin message loop. |
| 257 class CertVerifierJob { | 257 class CertVerifierJob { |
| 258 public: | 258 public: |
| 259 CertVerifierJob(const MultiThreadedCertVerifier::RequestParams& key, | 259 CertVerifierJob(const CertVerifier::RequestParams& key, |
| 260 NetLog* net_log, | 260 NetLog* net_log, |
| 261 X509Certificate* cert, | 261 X509Certificate* cert, |
| 262 MultiThreadedCertVerifier* cert_verifier) | 262 MultiThreadedCertVerifier* cert_verifier) |
| 263 : key_(key), | 263 : key_(key), |
| 264 start_time_(base::TimeTicks::Now()), | 264 start_time_(base::TimeTicks::Now()), |
| 265 wall_start_time_(base::Time::Now()), |
| 265 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_CERT_VERIFIER_JOB)), | 266 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_CERT_VERIFIER_JOB)), |
| 266 cert_verifier_(cert_verifier), | 267 cert_verifier_(cert_verifier), |
| 267 is_first_job_(false), | 268 is_first_job_(false), |
| 268 weak_ptr_factory_(this) { | 269 weak_ptr_factory_(this) { |
| 269 net_log_.BeginEvent( | 270 net_log_.BeginEvent( |
| 270 NetLog::TYPE_CERT_VERIFIER_JOB, | 271 NetLog::TYPE_CERT_VERIFIER_JOB, |
| 271 base::Bind(&NetLogX509CertificateCallback, base::Unretained(cert))); | 272 base::Bind(&NetLogX509CertificateCallback, base::Unretained(cert))); |
| 272 } | 273 } |
| 273 | 274 |
| 274 // Indicates whether this was the first job started by the CertVerifier. This | 275 // Indicates whether this was the first job started by the CertVerifier. This |
| 275 // is only used for logging certain UMA stats. | 276 // is only used for logging certain UMA stats. |
| 276 void set_is_first_job(bool is_first_job) { is_first_job_ = is_first_job; } | 277 void set_is_first_job(bool is_first_job) { is_first_job_ = is_first_job; } |
| 277 | 278 |
| 278 const MultiThreadedCertVerifier::RequestParams& key() const { return key_; } | 279 const CertVerifier::RequestParams& key() const { return key_; } |
| 279 | 280 |
| 280 // Posts a task to the worker pool to do the verification. Once the | 281 // Posts a task to the worker pool to do the verification. Once the |
| 281 // verification has completed on the worker thread, it will call | 282 // verification has completed on the worker thread, it will call |
| 282 // OnJobCompleted() on the origin thread. | 283 // OnJobCompleted() on the origin thread. |
| 283 bool Start(const scoped_refptr<CertVerifyProc>& verify_proc, | 284 bool Start(const scoped_refptr<CertVerifyProc>& verify_proc, |
| 284 const scoped_refptr<X509Certificate>& cert, | 285 const scoped_refptr<X509Certificate>& cert, |
| 285 const std::string& hostname, | 286 const std::string& hostname, |
| 286 const std::string& ocsp_response, | 287 const std::string& ocsp_response, |
| 287 int flags, | 288 int flags, |
| 288 const scoped_refptr<CRLSet>& crl_set, | 289 const scoped_refptr<CRLSet>& crl_set, |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 } | 362 } |
| 362 } | 363 } |
| 363 | 364 |
| 364 void OnJobCompleted( | 365 void OnJobCompleted( |
| 365 std::unique_ptr<MultiThreadedCertVerifier::CachedResult> verify_result) { | 366 std::unique_ptr<MultiThreadedCertVerifier::CachedResult> verify_result) { |
| 366 TRACE_EVENT0("net", "CertVerifierJob::OnJobCompleted"); | 367 TRACE_EVENT0("net", "CertVerifierJob::OnJobCompleted"); |
| 367 std::unique_ptr<CertVerifierJob> keep_alive = | 368 std::unique_ptr<CertVerifierJob> keep_alive = |
| 368 cert_verifier_->RemoveJob(this); | 369 cert_verifier_->RemoveJob(this); |
| 369 | 370 |
| 370 LogMetrics(*verify_result); | 371 LogMetrics(*verify_result); |
| 371 cert_verifier_->SaveResultToCache(key_, *verify_result); | 372 cert_verifier_->SaveResultToCache(key_, wall_start_time_, *verify_result); |
| 372 cert_verifier_ = nullptr; | 373 cert_verifier_ = nullptr; |
| 373 | 374 |
| 374 // TODO(eroman): If the cert_verifier_ is deleted from within one of the | 375 // TODO(eroman): If the cert_verifier_ is deleted from within one of the |
| 375 // callbacks, any remaining requests for that job should be cancelled. Right | 376 // callbacks, any remaining requests for that job should be cancelled. Right |
| 376 // now they will be called. | 377 // now they will be called. |
| 377 while (!requests_.empty()) { | 378 while (!requests_.empty()) { |
| 378 base::LinkNode<CertVerifierRequest>* request = requests_.head(); | 379 base::LinkNode<CertVerifierRequest>* request = requests_.head(); |
| 379 request->RemoveFromList(); | 380 request->RemoveFromList(); |
| 380 request->value()->Post(*verify_result); | 381 request->value()->Post(*verify_result); |
| 381 } | 382 } |
| 382 } | 383 } |
| 383 | 384 |
| 384 const MultiThreadedCertVerifier::RequestParams key_; | 385 const CertVerifier::RequestParams key_; |
| 386 // The tick count of when the job started. This is used to measure how long |
| 387 // the job actually took to complete. |
| 385 const base::TimeTicks start_time_; | 388 const base::TimeTicks start_time_; |
| 386 | 389 |
| 390 // The wall time of when the job started. This is to account for situations |
| 391 // where the system clock may have changed after the Job had started, which |
| 392 // could otherwise result in caching the wrong data. |
| 393 const base::Time wall_start_time_; |
| 394 |
| 387 RequestList requests_; // Non-owned. | 395 RequestList requests_; // Non-owned. |
| 388 | 396 |
| 389 const BoundNetLog net_log_; | 397 const BoundNetLog net_log_; |
| 390 MultiThreadedCertVerifier* cert_verifier_; // Non-owned. | 398 MultiThreadedCertVerifier* cert_verifier_; // Non-owned. |
| 391 | 399 |
| 392 bool is_first_job_; | 400 bool is_first_job_; |
| 393 base::WeakPtrFactory<CertVerifierJob> weak_ptr_factory_; | 401 base::WeakPtrFactory<CertVerifierJob> weak_ptr_factory_; |
| 394 }; | 402 }; |
| 395 | 403 |
| 396 MultiThreadedCertVerifier::MultiThreadedCertVerifier( | 404 MultiThreadedCertVerifier::MultiThreadedCertVerifier( |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 431 if (callback.is_null() || !verify_result || hostname.empty()) | 439 if (callback.is_null() || !verify_result || hostname.empty()) |
| 432 return ERR_INVALID_ARGUMENT; | 440 return ERR_INVALID_ARGUMENT; |
| 433 | 441 |
| 434 requests_++; | 442 requests_++; |
| 435 | 443 |
| 436 const CertificateList empty_cert_list; | 444 const CertificateList empty_cert_list; |
| 437 const CertificateList& additional_trust_anchors = | 445 const CertificateList& additional_trust_anchors = |
| 438 trust_anchor_provider_ ? | 446 trust_anchor_provider_ ? |
| 439 trust_anchor_provider_->GetAdditionalTrustAnchors() : empty_cert_list; | 447 trust_anchor_provider_->GetAdditionalTrustAnchors() : empty_cert_list; |
| 440 | 448 |
| 441 const RequestParams key(cert->fingerprint(), cert->ca_fingerprint(), hostname, | 449 const CertVerifier::RequestParams key(cert, hostname, flags, ocsp_response, |
| 442 ocsp_response, flags, additional_trust_anchors); | 450 additional_trust_anchors); |
| 443 const CertVerifierCache::value_type* cached_entry = | 451 const CertVerifierCache::value_type* cached_entry = |
| 444 cache_.Get(key, CacheValidityPeriod(base::Time::Now())); | 452 cache_.Get(key, CacheValidityPeriod(base::Time::Now())); |
| 445 if (cached_entry) { | 453 if (cached_entry) { |
| 446 ++cache_hits_; | 454 ++cache_hits_; |
| 447 *verify_result = cached_entry->result; | 455 *verify_result = cached_entry->result; |
| 448 return cached_entry->error; | 456 return cached_entry->error; |
| 449 } | 457 } |
| 450 | 458 |
| 451 // No cache hit. See if an identical request is currently in flight. | 459 // No cache hit. See if an identical request is currently in flight. |
| 452 CertVerifierJob* job = FindJob(key); | 460 CertVerifierJob* job = FindJob(key); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 476 std::unique_ptr<CertVerifierRequest> request = | 484 std::unique_ptr<CertVerifierRequest> request = |
| 477 job->CreateRequest(callback, verify_result, net_log); | 485 job->CreateRequest(callback, verify_result, net_log); |
| 478 *out_req = std::move(request); | 486 *out_req = std::move(request); |
| 479 return ERR_IO_PENDING; | 487 return ERR_IO_PENDING; |
| 480 } | 488 } |
| 481 | 489 |
| 482 bool MultiThreadedCertVerifier::SupportsOCSPStapling() { | 490 bool MultiThreadedCertVerifier::SupportsOCSPStapling() { |
| 483 return verify_proc_->SupportsOCSPStapling(); | 491 return verify_proc_->SupportsOCSPStapling(); |
| 484 } | 492 } |
| 485 | 493 |
| 486 MultiThreadedCertVerifier::RequestParams::RequestParams( | |
| 487 const SHA1HashValue& cert_fingerprint_arg, | |
| 488 const SHA1HashValue& ca_fingerprint_arg, | |
| 489 const std::string& hostname_arg, | |
| 490 const std::string& ocsp_response_arg, | |
| 491 int flags_arg, | |
| 492 const CertificateList& additional_trust_anchors) | |
| 493 : hostname(hostname_arg), flags(flags_arg), start_time(base::Time::Now()) { | |
| 494 hash_values.reserve(3 + additional_trust_anchors.size()); | |
| 495 SHA1HashValue ocsp_hash; | |
| 496 base::SHA1HashBytes( | |
| 497 reinterpret_cast<const unsigned char*>(ocsp_response_arg.data()), | |
| 498 ocsp_response_arg.size(), ocsp_hash.data); | |
| 499 hash_values.push_back(ocsp_hash); | |
| 500 hash_values.push_back(cert_fingerprint_arg); | |
| 501 hash_values.push_back(ca_fingerprint_arg); | |
| 502 for (size_t i = 0; i < additional_trust_anchors.size(); ++i) | |
| 503 hash_values.push_back(additional_trust_anchors[i]->fingerprint()); | |
| 504 } | |
| 505 | |
| 506 MultiThreadedCertVerifier::RequestParams::RequestParams( | |
| 507 const RequestParams& other) = default; | |
| 508 | |
| 509 MultiThreadedCertVerifier::RequestParams::~RequestParams() {} | |
| 510 | |
| 511 bool MultiThreadedCertVerifier::RequestParams::operator<( | |
| 512 const RequestParams& other) const { | |
| 513 // |flags| is compared before |cert_fingerprint|, |ca_fingerprint|, | |
| 514 // |hostname|, and |ocsp_response|, under assumption that integer comparisons | |
| 515 // are faster than memory and string comparisons. | |
| 516 if (flags != other.flags) | |
| 517 return flags < other.flags; | |
| 518 if (hostname != other.hostname) | |
| 519 return hostname < other.hostname; | |
| 520 return std::lexicographical_compare( | |
| 521 hash_values.begin(), hash_values.end(), other.hash_values.begin(), | |
| 522 other.hash_values.end(), SHA1HashValueLessThan()); | |
| 523 } | |
| 524 | |
| 525 bool MultiThreadedCertVerifier::JobComparator::operator()( | 494 bool MultiThreadedCertVerifier::JobComparator::operator()( |
| 526 const CertVerifierJob* job1, | 495 const CertVerifierJob* job1, |
| 527 const CertVerifierJob* job2) const { | 496 const CertVerifierJob* job2) const { |
| 528 return job1->key() < job2->key(); | 497 return job1->key() < job2->key(); |
| 529 } | 498 } |
| 530 | 499 |
| 531 void MultiThreadedCertVerifier::SaveResultToCache(const RequestParams& key, | 500 void MultiThreadedCertVerifier::SaveResultToCache( |
| 532 const CachedResult& result) { | 501 const CertVerifier::RequestParams& key, |
| 502 const base::Time& start_time, |
| 503 const CachedResult& result) { |
| 533 DCHECK(CalledOnValidThread()); | 504 DCHECK(CalledOnValidThread()); |
| 534 | 505 |
| 535 // When caching, this uses the time that validation started as the | 506 // When caching, this uses the time that validation started as the |
| 536 // beginning of the validity, rather than the time that it ended (aka | 507 // beginning of the validity, rather than the time that it ended (aka |
| 537 // base::Time::Now()), to account for the fact that during validation, | 508 // base::Time::Now()), to account for the fact that during validation, |
| 538 // the clock may have changed. | 509 // the clock may have changed. |
| 539 // | 510 // |
| 540 // If the clock has changed significantly, then this result will ideally | 511 // If the clock has changed significantly, then this result will ideally |
| 541 // be evicted and the next time the certificate is encountered, it will | 512 // be evicted and the next time the certificate is encountered, it will |
| 542 // be revalidated. | 513 // be revalidated. |
| 543 // | 514 // |
| 544 // Because of this, it's possible for situations to arise where the | 515 // Because of this, it's possible for situations to arise where the |
| 545 // clock was correct at the start of validation, changed to an | 516 // clock was correct at the start of validation, changed to an |
| 546 // incorrect time during validation (such as too far in the past or | 517 // incorrect time during validation (such as too far in the past or |
| 547 // future), and then was reset to the correct time. If this happens, | 518 // future), and then was reset to the correct time. If this happens, |
| 548 // it's likely that the result will not be a valid/correct result, | 519 // it's likely that the result will not be a valid/correct result, |
| 549 // but will still be used from the cache because the clock was reset | 520 // but will still be used from the cache because the clock was reset |
| 550 // to the correct time after the (bad) validation result completed. | 521 // to the correct time after the (bad) validation result completed. |
| 551 // | 522 // |
| 552 // However, this solution optimizes for the case where the clock is | 523 // However, this solution optimizes for the case where the clock is |
| 553 // bad at the start of validation, and subsequently is corrected. In | 524 // bad at the start of validation, and subsequently is corrected. In |
| 554 // that situation, the result is also incorrect, but because the clock | 525 // that situation, the result is also incorrect, but because the clock |
| 555 // was corrected after validation, if the cache validity period was | 526 // was corrected after validation, if the cache validity period was |
| 556 // computed at the end of validation, it would continue to serve an | 527 // computed at the end of validation, it would continue to serve an |
| 557 // invalid result for kTTLSecs. | 528 // invalid result for kTTLSecs. |
| 558 const base::Time start_time = key.start_time; | |
| 559 cache_.Put( | 529 cache_.Put( |
| 560 key, result, CacheValidityPeriod(start_time), | 530 key, result, CacheValidityPeriod(start_time), |
| 561 CacheValidityPeriod(start_time, | 531 CacheValidityPeriod(start_time, |
| 562 start_time + base::TimeDelta::FromSeconds(kTTLSecs))); | 532 start_time + base::TimeDelta::FromSeconds(kTTLSecs))); |
| 563 } | 533 } |
| 564 | 534 |
| 565 std::unique_ptr<CertVerifierJob> MultiThreadedCertVerifier::RemoveJob( | 535 std::unique_ptr<CertVerifierJob> MultiThreadedCertVerifier::RemoveJob( |
| 566 CertVerifierJob* job) { | 536 CertVerifierJob* job) { |
| 567 DCHECK(CalledOnValidThread()); | 537 DCHECK(CalledOnValidThread()); |
| 568 bool erased_job = inflight_.erase(job) == 1; | 538 bool erased_job = inflight_.erase(job) == 1; |
| 569 DCHECK(erased_job); | 539 DCHECK(erased_job); |
| 570 return base::WrapUnique(job); | 540 return base::WrapUnique(job); |
| 571 } | 541 } |
| 572 | 542 |
| 573 void MultiThreadedCertVerifier::OnCACertChanged( | 543 void MultiThreadedCertVerifier::OnCACertChanged( |
| 574 const X509Certificate* cert) { | 544 const X509Certificate* cert) { |
| 575 DCHECK(CalledOnValidThread()); | 545 DCHECK(CalledOnValidThread()); |
| 576 | 546 |
| 577 ClearCache(); | 547 ClearCache(); |
| 578 } | 548 } |
| 579 | 549 |
| 580 struct MultiThreadedCertVerifier::JobToRequestParamsComparator { | 550 struct MultiThreadedCertVerifier::JobToRequestParamsComparator { |
| 581 bool operator()(const CertVerifierJob* job, | 551 bool operator()(const CertVerifierJob* job, |
| 582 const MultiThreadedCertVerifier::RequestParams& value) const { | 552 const CertVerifier::RequestParams& value) const { |
| 583 return job->key() < value; | 553 return job->key() < value; |
| 584 } | 554 } |
| 585 }; | 555 }; |
| 586 | 556 |
| 587 CertVerifierJob* MultiThreadedCertVerifier::FindJob(const RequestParams& key) { | 557 CertVerifierJob* MultiThreadedCertVerifier::FindJob( |
| 558 const CertVerifier::RequestParams& key) { |
| 588 DCHECK(CalledOnValidThread()); | 559 DCHECK(CalledOnValidThread()); |
| 589 | 560 |
| 590 // The JobSet is kept in sorted order so items can be found using binary | 561 // The JobSet is kept in sorted order so items can be found using binary |
| 591 // search. | 562 // search. |
| 592 auto it = std::lower_bound(inflight_.begin(), inflight_.end(), key, | 563 auto it = std::lower_bound(inflight_.begin(), inflight_.end(), key, |
| 593 JobToRequestParamsComparator()); | 564 JobToRequestParamsComparator()); |
| 594 if (it != inflight_.end() && !(key < (*it)->key())) | 565 if (it != inflight_.end() && !(key < (*it)->key())) |
| 595 return *it; | 566 return *it; |
| 596 return nullptr; | 567 return nullptr; |
| 597 } | 568 } |
| 598 | 569 |
| 599 } // namespace net | 570 } // namespace net |
| OLD | NEW |