| 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(), | 573 hash_values.begin(), hash_values.end(), |
| 572 other.hash_values.begin(), other.hash_values.end(), | 574 other.hash_values.begin(), other.hash_values.end(), |
| 573 net::SHA1HashValueLessThan()); | 575 net::SHA1HashValueLessThan()); |
| 574 } | 576 } |
| 575 | 577 |
| 576 // HandleResult is called by CertVerifierWorker on the origin message loop. | 578 // HandleResult is called by CertVerifierWorker on the origin message loop. |
| 577 // It deletes CertVerifierJob. | 579 // It deletes CertVerifierJob. |
| 578 void MultiThreadedCertVerifier::HandleResult( | 580 void MultiThreadedCertVerifier::HandleResult( |
| 579 X509Certificate* cert, | 581 X509Certificate* cert, |
| 580 const std::string& hostname, | 582 const std::string& hostname, |
| 583 const std::string& ocsp_response, |
| 581 int flags, | 584 int flags, |
| 582 const CertificateList& additional_trust_anchors, | 585 const CertificateList& additional_trust_anchors, |
| 583 int error, | 586 int error, |
| 584 const CertVerifyResult& verify_result) { | 587 const CertVerifyResult& verify_result) { |
| 585 DCHECK(CalledOnValidThread()); | 588 DCHECK(CalledOnValidThread()); |
| 586 | 589 |
| 587 const RequestParams key(cert->fingerprint(), cert->ca_fingerprint(), | 590 const RequestParams key(cert->fingerprint(), cert->ca_fingerprint(), hostname, |
| 588 hostname, flags, additional_trust_anchors); | 591 ocsp_response, flags, additional_trust_anchors); |
| 589 | 592 |
| 590 CachedResult cached_result; | 593 CachedResult cached_result; |
| 591 cached_result.error = error; | 594 cached_result.error = error; |
| 592 cached_result.result = verify_result; | 595 cached_result.result = verify_result; |
| 593 base::Time now = base::Time::Now(); | 596 base::Time now = base::Time::Now(); |
| 594 cache_.Put( | 597 cache_.Put( |
| 595 key, cached_result, CacheValidityPeriod(now), | 598 key, cached_result, CacheValidityPeriod(now), |
| 596 CacheValidityPeriod(now, now + base::TimeDelta::FromSeconds(kTTLSecs))); | 599 CacheValidityPeriod(now, now + base::TimeDelta::FromSeconds(kTTLSecs))); |
| 597 | 600 |
| 598 std::map<RequestParams, CertVerifierJob*>::iterator j; | 601 std::map<RequestParams, CertVerifierJob*>::iterator j; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 615 | 618 |
| 616 void MultiThreadedCertVerifier::OnCACertChanged( | 619 void MultiThreadedCertVerifier::OnCACertChanged( |
| 617 const X509Certificate* cert) { | 620 const X509Certificate* cert) { |
| 618 DCHECK(CalledOnValidThread()); | 621 DCHECK(CalledOnValidThread()); |
| 619 | 622 |
| 620 ClearCache(); | 623 ClearCache(); |
| 621 } | 624 } |
| 622 | 625 |
| 623 } // namespace net | 626 } // namespace net |
| 624 | 627 |
| OLD | NEW |