Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(247)

Side by Side Diff: net/base/server_bound_cert_service.cc

Issue 11742037: Make ServerBoundCertStore interface async, move SQLiteServerBoundCertStore load onto DB thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix login_utils_browsertest Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/base/server_bound_cert_service.h ('k') | net/base/server_bound_cert_store.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/base/server_bound_cert_service.h" 5 #include "net/base/server_bound_cert_service.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 27 matching lines...) Expand all
38 const int kValidityPeriodInDays = 365; 38 const int kValidityPeriodInDays = 365;
39 // When we check the system time, we add this many days to the end of the check 39 // When we check the system time, we add this many days to the end of the check
40 // so the result will still hold even after chrome has been running for a 40 // so the result will still hold even after chrome has been running for a
41 // while. 41 // while.
42 const int kSystemTimeValidityBufferInDays = 90; 42 const int kSystemTimeValidityBufferInDays = 90;
43 43
44 bool IsSupportedCertType(uint8 type) { 44 bool IsSupportedCertType(uint8 type) {
45 switch(type) { 45 switch(type) {
46 case CLIENT_CERT_ECDSA_SIGN: 46 case CLIENT_CERT_ECDSA_SIGN:
47 return true; 47 return true;
48 // If we add any more supported types, CertIsValid will need to be updated
49 // to check that the returned type matches one of the requested types.
48 default: 50 default:
49 return false; 51 return false;
50 } 52 }
51 } 53 }
52 54
55 bool CertIsValid(const std::string& domain,
56 SSLClientCertType type,
57 base::Time expiration_time) {
58 if (expiration_time < base::Time::Now()) {
59 DVLOG(1) << "Cert store had expired cert for " << domain;
60 return false;
61 } else if (!IsSupportedCertType(type)) {
62 DVLOG(1) << "Cert store had cert of wrong type " << type << " for "
63 << domain;
64 return false;
65 }
66 return true;
67 }
68
53 // Used by the GetDomainBoundCertResult histogram to record the final 69 // Used by the GetDomainBoundCertResult histogram to record the final
54 // outcome of each GetDomainBoundCert call. Do not re-use values. 70 // outcome of each GetDomainBoundCert call. Do not re-use values.
55 enum GetCertResult { 71 enum GetCertResult {
56 // Synchronously found and returned an existing domain bound cert. 72 // Synchronously found and returned an existing domain bound cert.
57 SYNC_SUCCESS = 0, 73 SYNC_SUCCESS = 0,
58 // Generated and returned a domain bound cert asynchronously. 74 // Retrieved or generated and returned a domain bound cert asynchronously.
59 ASYNC_SUCCESS = 1, 75 ASYNC_SUCCESS = 1,
60 // Generation request was cancelled before the cert generation completed. 76 // Retrieval/generation request was cancelled before the cert generation
77 // completed.
61 ASYNC_CANCELLED = 2, 78 ASYNC_CANCELLED = 2,
62 // Cert generation failed. 79 // Cert generation failed.
63 ASYNC_FAILURE_KEYGEN = 3, 80 ASYNC_FAILURE_KEYGEN = 3,
64 ASYNC_FAILURE_CREATE_CERT = 4, 81 ASYNC_FAILURE_CREATE_CERT = 4,
65 ASYNC_FAILURE_EXPORT_KEY = 5, 82 ASYNC_FAILURE_EXPORT_KEY = 5,
66 ASYNC_FAILURE_UNKNOWN = 6, 83 ASYNC_FAILURE_UNKNOWN = 6,
67 // GetDomainBoundCert was called with invalid arguments. 84 // GetDomainBoundCert was called with invalid arguments.
68 INVALID_ARGUMENT = 7, 85 INVALID_ARGUMENT = 7,
69 // We don't support any of the cert types the server requested. 86 // We don't support any of the cert types the server requested.
70 UNSUPPORTED_TYPE = 8, 87 UNSUPPORTED_TYPE = 8,
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 } 214 }
198 case ERR_KEY_GENERATION_FAILED: 215 case ERR_KEY_GENERATION_FAILED:
199 RecordGetDomainBoundCertResult(ASYNC_FAILURE_KEYGEN); 216 RecordGetDomainBoundCertResult(ASYNC_FAILURE_KEYGEN);
200 break; 217 break;
201 case ERR_ORIGIN_BOUND_CERT_GENERATION_FAILED: 218 case ERR_ORIGIN_BOUND_CERT_GENERATION_FAILED:
202 RecordGetDomainBoundCertResult(ASYNC_FAILURE_CREATE_CERT); 219 RecordGetDomainBoundCertResult(ASYNC_FAILURE_CREATE_CERT);
203 break; 220 break;
204 case ERR_PRIVATE_KEY_EXPORT_FAILED: 221 case ERR_PRIVATE_KEY_EXPORT_FAILED:
205 RecordGetDomainBoundCertResult(ASYNC_FAILURE_EXPORT_KEY); 222 RecordGetDomainBoundCertResult(ASYNC_FAILURE_EXPORT_KEY);
206 break; 223 break;
224 case ERR_INSUFFICIENT_RESOURCES:
225 RecordGetDomainBoundCertResult(WORKER_FAILURE);
226 break;
207 default: 227 default:
208 RecordGetDomainBoundCertResult(ASYNC_FAILURE_UNKNOWN); 228 RecordGetDomainBoundCertResult(ASYNC_FAILURE_UNKNOWN);
209 break; 229 break;
210 } 230 }
211 if (!callback_.is_null()) { 231 if (!callback_.is_null()) {
212 *type_ = type; 232 *type_ = type;
213 *private_key_ = private_key; 233 *private_key_ = private_key;
214 *cert_ = cert; 234 *cert_ = cert;
215 callback_.Run(error); 235 callback_.Run(error);
216 } 236 }
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 WorkerDoneCallback callback_; 308 WorkerDoneCallback callback_;
289 309
290 DISALLOW_COPY_AND_ASSIGN(ServerBoundCertServiceWorker); 310 DISALLOW_COPY_AND_ASSIGN(ServerBoundCertServiceWorker);
291 }; 311 };
292 312
293 // A ServerBoundCertServiceJob is a one-to-one counterpart of an 313 // A ServerBoundCertServiceJob is a one-to-one counterpart of an
294 // ServerBoundCertServiceWorker. It lives only on the ServerBoundCertService's 314 // ServerBoundCertServiceWorker. It lives only on the ServerBoundCertService's
295 // origin message loop. 315 // origin message loop.
296 class ServerBoundCertServiceJob { 316 class ServerBoundCertServiceJob {
297 public: 317 public:
298 ServerBoundCertServiceJob(SSLClientCertType type) : type_(type) { 318 ServerBoundCertServiceJob(SSLClientCertType type)
319 : type_(type) {
299 } 320 }
300 321
301 ~ServerBoundCertServiceJob() { 322 ~ServerBoundCertServiceJob() {
302 if (!requests_.empty()) 323 if (!requests_.empty())
303 DeleteAllCanceled(); 324 DeleteAllCanceled();
304 } 325 }
305 326
306 SSLClientCertType type() const { return type_; } 327 SSLClientCertType type() const { return type_; }
307 328
308 void AddRequest(ServerBoundCertServiceRequest* request) { 329 void AddRequest(ServerBoundCertServiceRequest* request) {
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 } 464 }
444 } 465 }
445 if (preferred_type == CLIENT_CERT_INVALID_TYPE) { 466 if (preferred_type == CLIENT_CERT_INVALID_TYPE) {
446 RecordGetDomainBoundCertResult(UNSUPPORTED_TYPE); 467 RecordGetDomainBoundCertResult(UNSUPPORTED_TYPE);
447 // None of the requested types are supported. 468 // None of the requested types are supported.
448 return ERR_CLIENT_AUTH_CERT_TYPE_UNSUPPORTED; 469 return ERR_CLIENT_AUTH_CERT_TYPE_UNSUPPORTED;
449 } 470 }
450 471
451 requests_++; 472 requests_++;
452 473
453 // Check if a domain bound cert of an acceptable type already exists for this 474 // See if an identical request is currently in flight.
454 // domain, and that it has not expired.
455 base::Time now = base::Time::Now();
456 base::Time creation_time;
457 base::Time expiration_time;
458 if (server_bound_cert_store_->GetServerBoundCert(domain,
459 type,
460 &creation_time,
461 &expiration_time,
462 private_key,
463 cert)) {
464 if (expiration_time < now) {
465 DVLOG(1) << "Cert store had expired cert for " << domain;
466 } else if (!IsSupportedCertType(*type) ||
467 std::find(requested_types.begin(), requested_types.end(),
468 *type) == requested_types.end()) {
469 DVLOG(1) << "Cert store had cert of wrong type " << *type << " for "
470 << domain;
471 } else {
472 DVLOG(1) << "Cert store had valid cert for " << domain
473 << " of type " << *type;
474 cert_store_hits_++;
475 RecordGetDomainBoundCertResult(SYNC_SUCCESS);
476 base::TimeDelta request_time = base::TimeTicks::Now() - request_start;
477 UMA_HISTOGRAM_TIMES("DomainBoundCerts.GetCertTimeSync", request_time);
478 RecordGetCertTime(request_time);
479 return OK;
480 }
481 }
482
483 // |server_bound_cert_store_| has no cert for this domain. See if an
484 // identical request is currently in flight.
485 ServerBoundCertServiceJob* job = NULL; 475 ServerBoundCertServiceJob* job = NULL;
486 std::map<std::string, ServerBoundCertServiceJob*>::const_iterator j; 476 std::map<std::string, ServerBoundCertServiceJob*>::const_iterator j;
487 j = inflight_.find(domain); 477 j = inflight_.find(domain);
488 if (j != inflight_.end()) { 478 if (j != inflight_.end()) {
489 // An identical request is in flight already. We'll just attach our 479 // An identical request is in flight already. We'll just attach our
490 // callback. 480 // callback.
491 job = j->second; 481 job = j->second;
492 // Check that the job is for an acceptable type of cert. 482 // Check that the job is for an acceptable type of cert.
493 if (std::find(requested_types.begin(), requested_types.end(), job->type()) 483 if (std::find(requested_types.begin(), requested_types.end(), job->type())
494 == requested_types.end()) { 484 == requested_types.end()) {
495 DVLOG(1) << "Found inflight job of wrong type " << job->type() 485 DVLOG(1) << "Found inflight job of wrong type " << job->type()
496 << " for " << domain; 486 << " for " << domain;
497 // If we get here, the server is asking for different types of certs in 487 // If we get here, the server is asking for different types of certs in
498 // short succession. This probably means the server is broken or 488 // short succession. This probably means the server is broken or
499 // misconfigured. Since we only store one type of cert per domain, we 489 // misconfigured. Since we only store one type of cert per domain, we
500 // are unable to handle this well. Just return an error and let the first 490 // are unable to handle this well. Just return an error and let the first
501 // job finish. 491 // job finish.
502 RecordGetDomainBoundCertResult(TYPE_MISMATCH); 492 RecordGetDomainBoundCertResult(TYPE_MISMATCH);
503 return ERR_ORIGIN_BOUND_CERT_GENERATION_TYPE_MISMATCH; 493 return ERR_ORIGIN_BOUND_CERT_GENERATION_TYPE_MISMATCH;
504 } 494 }
505 inflight_joins_++; 495 inflight_joins_++;
506 } else { 496
507 // Need to make a new request. 497 ServerBoundCertServiceRequest* request = new ServerBoundCertServiceRequest(
498 request_start,
499 base::Bind(&RequestHandle::OnRequestComplete,
500 base::Unretained(out_req)),
501 type, private_key, cert);
502 job->AddRequest(request);
503 out_req->RequestStarted(this, request, callback);
504 return ERR_IO_PENDING;
505 }
506
507 // Check if a domain bound cert of an acceptable type already exists for this
508 // domain, and that it has not expired.
509 base::Time expiration_time;
510 if (server_bound_cert_store_->GetServerBoundCert(
511 domain,
512 type,
513 &expiration_time,
514 private_key,
515 cert,
516 base::Bind(&ServerBoundCertService::GotServerBoundCert,
517 weak_ptr_factory_.GetWeakPtr()))) {
518 if (*type != CLIENT_CERT_INVALID_TYPE) {
519 // Sync lookup found a cert.
520 if (CertIsValid(domain, *type, expiration_time)) {
521 DVLOG(1) << "Cert store had valid cert for " << domain
522 << " of type " << *type;
523 cert_store_hits_++;
524 RecordGetDomainBoundCertResult(SYNC_SUCCESS);
525 base::TimeDelta request_time = base::TimeTicks::Now() - request_start;
526 UMA_HISTOGRAM_TIMES("DomainBoundCerts.GetCertTimeSync", request_time);
527 RecordGetCertTime(request_time);
528 return OK;
529 }
530 }
531
532 // Sync lookup did not find a cert, or it found an expired one. Start
533 // generating a new one.
508 ServerBoundCertServiceWorker* worker = new ServerBoundCertServiceWorker( 534 ServerBoundCertServiceWorker* worker = new ServerBoundCertServiceWorker(
509 domain, 535 domain,
510 preferred_type, 536 preferred_type,
511 base::Bind(&ServerBoundCertService::HandleResult, 537 base::Bind(&ServerBoundCertService::GeneratedServerBoundCert,
512 weak_ptr_factory_.GetWeakPtr())); 538 weak_ptr_factory_.GetWeakPtr()));
513 if (!worker->Start(task_runner_)) { 539 if (!worker->Start(task_runner_)) {
540 delete worker;
514 // TODO(rkn): Log to the NetLog. 541 // TODO(rkn): Log to the NetLog.
515 LOG(ERROR) << "ServerBoundCertServiceWorker couldn't be started."; 542 LOG(ERROR) << "ServerBoundCertServiceWorker couldn't be started.";
516 RecordGetDomainBoundCertResult(WORKER_FAILURE); 543 RecordGetDomainBoundCertResult(WORKER_FAILURE);
517 return ERR_INSUFFICIENT_RESOURCES; // Just a guess. 544 return ERR_INSUFFICIENT_RESOURCES;
518 } 545 }
519 job = new ServerBoundCertServiceJob(preferred_type);
520 inflight_[domain] = job;
521 } 546 }
522 547
548 // We are either waiting for async DB lookup, or waiting for cert generation.
549 // Create a job & request to track it.
550 job = new ServerBoundCertServiceJob(preferred_type);
551 inflight_[domain] = job;
552
523 ServerBoundCertServiceRequest* request = new ServerBoundCertServiceRequest( 553 ServerBoundCertServiceRequest* request = new ServerBoundCertServiceRequest(
524 request_start, 554 request_start,
525 base::Bind(&RequestHandle::OnRequestComplete, base::Unretained(out_req)), 555 base::Bind(&RequestHandle::OnRequestComplete, base::Unretained(out_req)),
526 type, private_key, cert); 556 type, private_key, cert);
527 job->AddRequest(request); 557 job->AddRequest(request);
528 out_req->RequestStarted(this, request, callback); 558 out_req->RequestStarted(this, request, callback);
529 return ERR_IO_PENDING; 559 return ERR_IO_PENDING;
530 } 560 }
531 561
562 void ServerBoundCertService::GotServerBoundCert(
563 const std::string& server_identifier,
564 SSLClientCertType type,
565 base::Time expiration_time,
566 const std::string& key,
567 const std::string& cert) {
568 DCHECK(CalledOnValidThread());
569
570 std::map<std::string, ServerBoundCertServiceJob*>::iterator j;
571 j = inflight_.find(server_identifier);
572 if (j == inflight_.end()) {
573 NOTREACHED();
574 return;
575 }
576 ServerBoundCertServiceJob* job = j->second;
577
578 if (type != CLIENT_CERT_INVALID_TYPE) {
579 // Async DB lookup found a cert.
580 if (CertIsValid(server_identifier, type, expiration_time)) {
581 DVLOG(1) << "Cert store had valid cert for " << server_identifier
582 << " of type " << type;
583 cert_store_hits_++;
584 // ServerBoundCertServiceRequest::Post will do the histograms and stuff.
585 HandleResult(OK, server_identifier, type, key, cert);
586 return;
587 }
588 }
589
590 // Async lookup did not find a cert, or it found an expired one. Start
591 // generating a new one.
592 ServerBoundCertServiceWorker* worker = new ServerBoundCertServiceWorker(
593 server_identifier,
594 job->type(),
595 base::Bind(&ServerBoundCertService::GeneratedServerBoundCert,
596 weak_ptr_factory_.GetWeakPtr()));
597 if (!worker->Start(task_runner_)) {
598 delete worker;
599 // TODO(rkn): Log to the NetLog.
600 LOG(ERROR) << "ServerBoundCertServiceWorker couldn't be started.";
601 HandleResult(ERR_INSUFFICIENT_RESOURCES, server_identifier,
602 CLIENT_CERT_INVALID_TYPE, "", "");
603 return;
604 }
605 }
606
532 ServerBoundCertStore* ServerBoundCertService::GetCertStore() { 607 ServerBoundCertStore* ServerBoundCertService::GetCertStore() {
533 return server_bound_cert_store_.get(); 608 return server_bound_cert_store_.get();
534 } 609 }
535 610
536 void ServerBoundCertService::CancelRequest(ServerBoundCertServiceRequest* req) { 611 void ServerBoundCertService::CancelRequest(ServerBoundCertServiceRequest* req) {
537 DCHECK(CalledOnValidThread()); 612 DCHECK(CalledOnValidThread());
538 req->Cancel(); 613 req->Cancel();
539 } 614 }
540 615
541 // HandleResult is called by ServerBoundCertServiceWorker on the origin message 616 void ServerBoundCertService::GeneratedServerBoundCert(
542 // loop. It deletes ServerBoundCertServiceJob.
543 void ServerBoundCertService::HandleResult(
544 const std::string& server_identifier, 617 const std::string& server_identifier,
545 int error, 618 int error,
546 scoped_ptr<ServerBoundCertStore::ServerBoundCert> cert) { 619 scoped_ptr<ServerBoundCertStore::ServerBoundCert> cert) {
547 DCHECK(CalledOnValidThread()); 620 DCHECK(CalledOnValidThread());
548 621
549 if (error == OK) { 622 if (error == OK) {
550 // TODO(mattm): we should just Pass() the cert object to 623 // TODO(mattm): we should just Pass() the cert object to
551 // SetServerBoundCert(). 624 // SetServerBoundCert().
552 server_bound_cert_store_->SetServerBoundCert( 625 server_bound_cert_store_->SetServerBoundCert(
553 cert->server_identifier(), cert->type(), cert->creation_time(), 626 cert->server_identifier(), cert->type(), cert->creation_time(),
554 cert->expiration_time(), cert->private_key(), cert->cert()); 627 cert->expiration_time(), cert->private_key(), cert->cert());
628
629 HandleResult(error, server_identifier, cert->type(), cert->private_key(),
630 cert->cert());
631 } else {
632 HandleResult(error, server_identifier, CLIENT_CERT_INVALID_TYPE, "", "");
555 } 633 }
634 }
635
636 void ServerBoundCertService::HandleResult(
637 int error,
638 const std::string& server_identifier,
639 SSLClientCertType type,
640 const std::string& private_key,
641 const std::string& cert) {
642 DCHECK(CalledOnValidThread());
556 643
557 std::map<std::string, ServerBoundCertServiceJob*>::iterator j; 644 std::map<std::string, ServerBoundCertServiceJob*>::iterator j;
558 j = inflight_.find(server_identifier); 645 j = inflight_.find(server_identifier);
559 if (j == inflight_.end()) { 646 if (j == inflight_.end()) {
560 NOTREACHED(); 647 NOTREACHED();
561 return; 648 return;
562 } 649 }
563 ServerBoundCertServiceJob* job = j->second; 650 ServerBoundCertServiceJob* job = j->second;
564 inflight_.erase(j); 651 inflight_.erase(j);
565 652
566 if (cert) 653 job->HandleResult(error, type, private_key, cert);
567 job->HandleResult(error, cert->type(), cert->private_key(), cert->cert());
568 else
569 job->HandleResult(error, CLIENT_CERT_INVALID_TYPE, "", "");
570 delete job; 654 delete job;
571 } 655 }
572 656
573 int ServerBoundCertService::cert_count() { 657 int ServerBoundCertService::cert_count() {
574 return server_bound_cert_store_->GetCertCount(); 658 return server_bound_cert_store_->GetCertCount();
575 } 659 }
576 660
577 } // namespace net 661 } // namespace net
OLDNEW
« no previous file with comments | « net/base/server_bound_cert_service.h ('k') | net/base/server_bound_cert_store.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698