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

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

Issue 9617039: Change Origin bound certs -> Domain bound certs. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: explanitory comment Created 8 years, 9 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
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/origin_bound_cert_service.h" 5 #include "net/base/origin_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"
11 #include "base/bind_helpers.h" 11 #include "base/bind_helpers.h"
12 #include "base/compiler_specific.h" 12 #include "base/compiler_specific.h"
13 #include "base/location.h" 13 #include "base/location.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/memory/ref_counted.h" 15 #include "base/memory/ref_counted.h"
16 #include "base/memory/scoped_ptr.h" 16 #include "base/memory/scoped_ptr.h"
17 #include "base/message_loop.h" 17 #include "base/message_loop.h"
18 #include "base/rand_util.h" 18 #include "base/rand_util.h"
19 #include "base/stl_util.h" 19 #include "base/stl_util.h"
20 #include "base/threading/worker_pool.h" 20 #include "base/threading/worker_pool.h"
21 #include "crypto/ec_private_key.h" 21 #include "crypto/ec_private_key.h"
22 #include "googleurl/src/gurl.h"
22 #include "net/base/net_errors.h" 23 #include "net/base/net_errors.h"
23 #include "net/base/origin_bound_cert_store.h" 24 #include "net/base/origin_bound_cert_store.h"
24 #include "net/base/registry_controlled_domain.h" 25 #include "net/base/registry_controlled_domain.h"
25 #include "net/base/x509_certificate.h" 26 #include "net/base/x509_certificate.h"
26 #include "net/base/x509_util.h" 27 #include "net/base/x509_util.h"
27 28
28 #if defined(USE_NSS) 29 #if defined(USE_NSS)
29 #include <private/pprthred.h> // PR_DetachThread 30 #include <private/pprthred.h> // PR_DetachThread
30 #endif 31 #endif
31 32
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 std::string* private_key_; 92 std::string* private_key_;
92 std::string* cert_; 93 std::string* cert_;
93 }; 94 };
94 95
95 // OriginBoundCertServiceWorker runs on a worker thread and takes care of the 96 // OriginBoundCertServiceWorker runs on a worker thread and takes care of the
96 // blocking process of performing key generation. Deletes itself eventually 97 // blocking process of performing key generation. Deletes itself eventually
97 // if Start() succeeds. 98 // if Start() succeeds.
98 class OriginBoundCertServiceWorker { 99 class OriginBoundCertServiceWorker {
99 public: 100 public:
100 OriginBoundCertServiceWorker( 101 OriginBoundCertServiceWorker(
101 const std::string& origin, 102 const std::string& domain,
102 SSLClientCertType type, 103 SSLClientCertType type,
103 OriginBoundCertService* origin_bound_cert_service) 104 OriginBoundCertService* origin_bound_cert_service)
104 : origin_(origin), 105 : domain_(domain),
105 type_(type), 106 type_(type),
106 serial_number_(base::RandInt(0, std::numeric_limits<int>::max())), 107 serial_number_(base::RandInt(0, std::numeric_limits<int>::max())),
107 origin_loop_(MessageLoop::current()), 108 origin_loop_(MessageLoop::current()),
108 origin_bound_cert_service_(origin_bound_cert_service), 109 origin_bound_cert_service_(origin_bound_cert_service),
109 canceled_(false), 110 canceled_(false),
110 error_(ERR_FAILED) { 111 error_(ERR_FAILED) {
111 } 112 }
112 113
113 bool Start() { 114 bool Start() {
114 DCHECK_EQ(MessageLoop::current(), origin_loop_); 115 DCHECK_EQ(MessageLoop::current(), origin_loop_);
115 116
116 return base::WorkerPool::PostTask( 117 return base::WorkerPool::PostTask(
117 FROM_HERE, 118 FROM_HERE,
118 base::Bind(&OriginBoundCertServiceWorker::Run, base::Unretained(this)), 119 base::Bind(&OriginBoundCertServiceWorker::Run, base::Unretained(this)),
119 true /* task is slow */); 120 true /* task is slow */);
120 } 121 }
121 122
122 // Cancel is called from the origin loop when the OriginBoundCertService is 123 // Cancel is called from the origin loop when the OriginBoundCertService is
123 // getting deleted. 124 // getting deleted.
124 void Cancel() { 125 void Cancel() {
125 DCHECK_EQ(MessageLoop::current(), origin_loop_); 126 DCHECK_EQ(MessageLoop::current(), origin_loop_);
126 base::AutoLock locked(lock_); 127 base::AutoLock locked(lock_);
127 canceled_ = true; 128 canceled_ = true;
128 } 129 }
129 130
130 private: 131 private:
131 void Run() { 132 void Run() {
132 // Runs on a worker thread. 133 // Runs on a worker thread.
133 error_ = OriginBoundCertService::GenerateCert(origin_, 134 error_ = OriginBoundCertService::GenerateCert(domain_,
134 type_, 135 type_,
135 serial_number_, 136 serial_number_,
136 &creation_time_, 137 &creation_time_,
137 &expiration_time_, 138 &expiration_time_,
138 &private_key_, 139 &private_key_,
139 &cert_); 140 &cert_);
140 #if defined(USE_NSS) 141 #if defined(USE_NSS)
141 // Detach the thread from NSPR. 142 // Detach the thread from NSPR.
142 // Calling NSS functions attaches the thread to NSPR, which stores 143 // Calling NSS functions attaches the thread to NSPR, which stores
143 // the NSPR thread ID in thread-specific data. 144 // the NSPR thread ID in thread-specific data.
(...skipping 10 matching lines...) Expand all
154 void DoReply() { 155 void DoReply() {
155 DCHECK_EQ(MessageLoop::current(), origin_loop_); 156 DCHECK_EQ(MessageLoop::current(), origin_loop_);
156 { 157 {
157 // We lock here because the worker thread could still be in Finished, 158 // We lock here because the worker thread could still be in Finished,
158 // after the PostTask, but before unlocking |lock_|. If we do not lock in 159 // after the PostTask, but before unlocking |lock_|. If we do not lock in
159 // this case, we will end up deleting a locked Lock, which can lead to 160 // this case, we will end up deleting a locked Lock, which can lead to
160 // memory leaks or worse errors. 161 // memory leaks or worse errors.
161 base::AutoLock locked(lock_); 162 base::AutoLock locked(lock_);
162 if (!canceled_) { 163 if (!canceled_) {
163 origin_bound_cert_service_->HandleResult( 164 origin_bound_cert_service_->HandleResult(
164 origin_, error_, type_, creation_time_, expiration_time_, 165 domain_, error_, type_, creation_time_, expiration_time_,
165 private_key_, cert_); 166 private_key_, cert_);
166 } 167 }
167 } 168 }
168 delete this; 169 delete this;
169 } 170 }
170 171
171 void Finish() { 172 void Finish() {
172 // Runs on the worker thread. 173 // Runs on the worker thread.
173 // We assume that the origin loop outlives the OriginBoundCertService. If 174 // We assume that the origin loop outlives the OriginBoundCertService. If
174 // the OriginBoundCertService is deleted, it will call Cancel on us. If it 175 // the OriginBoundCertService is deleted, it will call Cancel on us. If it
(...skipping 11 matching lines...) Expand all
186 if (!canceled) { 187 if (!canceled) {
187 origin_loop_->PostTask( 188 origin_loop_->PostTask(
188 FROM_HERE, base::Bind(&OriginBoundCertServiceWorker::DoReply, 189 FROM_HERE, base::Bind(&OriginBoundCertServiceWorker::DoReply,
189 base::Unretained(this))); 190 base::Unretained(this)));
190 } 191 }
191 } 192 }
192 if (canceled) 193 if (canceled)
193 delete this; 194 delete this;
194 } 195 }
195 196
196 const std::string origin_; 197 const std::string domain_;
197 const SSLClientCertType type_; 198 const SSLClientCertType type_;
198 // Note that serial_number_ must be initialized on a non-worker thread 199 // Note that serial_number_ must be initialized on a non-worker thread
199 // (see documentation for OriginBoundCertService::GenerateCert). 200 // (see documentation for OriginBoundCertService::GenerateCert).
200 uint32 serial_number_; 201 uint32 serial_number_;
201 MessageLoop* const origin_loop_; 202 MessageLoop* const origin_loop_;
202 OriginBoundCertService* const origin_bound_cert_service_; 203 OriginBoundCertService* const origin_bound_cert_service_;
203 204
204 // lock_ protects canceled_. 205 // lock_ protects canceled_.
205 base::Lock lock_; 206 base::Lock lock_;
206 207
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 RequestHandle* out_req) { 314 RequestHandle* out_req) {
314 DCHECK(CalledOnValidThread()); 315 DCHECK(CalledOnValidThread());
315 316
316 *out_req = NULL; 317 *out_req = NULL;
317 318
318 if (callback.is_null() || !private_key || !cert || origin.empty() || 319 if (callback.is_null() || !private_key || !cert || origin.empty() ||
319 requested_types.empty()) { 320 requested_types.empty()) {
320 return ERR_INVALID_ARGUMENT; 321 return ERR_INVALID_ARGUMENT;
321 } 322 }
322 323
324 std::string domain = GetDomainForHost(GURL(origin).host());
wtc 2012/03/08 02:13:45 Should we also check domain.empty()? See the orig
mattm 2012/03/15 01:48:44 Done.
325
323 SSLClientCertType preferred_type = CLIENT_CERT_INVALID_TYPE; 326 SSLClientCertType preferred_type = CLIENT_CERT_INVALID_TYPE;
324 for (size_t i = 0; i < requested_types.size(); ++i) { 327 for (size_t i = 0; i < requested_types.size(); ++i) {
325 if (IsSupportedCertType(requested_types[i])) { 328 if (IsSupportedCertType(requested_types[i])) {
326 preferred_type = static_cast<SSLClientCertType>(requested_types[i]); 329 preferred_type = static_cast<SSLClientCertType>(requested_types[i]);
327 break; 330 break;
328 } 331 }
329 } 332 }
330 if (preferred_type == CLIENT_CERT_INVALID_TYPE) { 333 if (preferred_type == CLIENT_CERT_INVALID_TYPE) {
331 // None of the requested types are supported. 334 // None of the requested types are supported.
332 return ERR_CLIENT_AUTH_CERT_TYPE_UNSUPPORTED; 335 return ERR_CLIENT_AUTH_CERT_TYPE_UNSUPPORTED;
333 } 336 }
334 337
335 requests_++; 338 requests_++;
336 339
337 // Check if an origin bound cert of an acceptable type already exists for this 340 // Check if a domain bound cert of an acceptable type already exists for this
338 // origin, and that it has not expired. 341 // domain, and that it has not expired.
339 base::Time now = base::Time::Now(); 342 base::Time now = base::Time::Now();
340 base::Time creation_time; 343 base::Time creation_time;
341 base::Time expiration_time; 344 base::Time expiration_time;
342 if (origin_bound_cert_store_->GetOriginBoundCert(origin, 345 if (origin_bound_cert_store_->GetOriginBoundCert(domain,
343 type, 346 type,
344 &creation_time, 347 &creation_time,
345 &expiration_time, 348 &expiration_time,
346 private_key, 349 private_key,
347 cert)) { 350 cert)) {
348 if (expiration_time < now) { 351 if (expiration_time < now) {
349 DVLOG(1) << "Cert store had expired cert for " << origin; 352 DVLOG(1) << "Cert store had expired cert for " << domain;
350 } else if (!IsSupportedCertType(*type) || 353 } else if (!IsSupportedCertType(*type) ||
351 std::find(requested_types.begin(), requested_types.end(), 354 std::find(requested_types.begin(), requested_types.end(),
352 *type) == requested_types.end()) { 355 *type) == requested_types.end()) {
353 DVLOG(1) << "Cert store had cert of wrong type " << *type << " for " 356 DVLOG(1) << "Cert store had cert of wrong type " << *type << " for "
354 << origin; 357 << domain;
355 } else { 358 } else {
356 cert_store_hits_++; 359 cert_store_hits_++;
357 return OK; 360 return OK;
358 } 361 }
359 } 362 }
360 363
361 // |origin_bound_cert_store_| has no cert for this origin. See if an 364 // |origin_bound_cert_store_| has no cert for this domain. See if an
362 // identical request is currently in flight. 365 // identical request is currently in flight.
363 OriginBoundCertServiceJob* job = NULL; 366 OriginBoundCertServiceJob* job = NULL;
364 std::map<std::string, OriginBoundCertServiceJob*>::const_iterator j; 367 std::map<std::string, OriginBoundCertServiceJob*>::const_iterator j;
365 j = inflight_.find(origin); 368 j = inflight_.find(domain);
366 if (j != inflight_.end()) { 369 if (j != inflight_.end()) {
367 // An identical request is in flight already. We'll just attach our 370 // An identical request is in flight already. We'll just attach our
368 // callback. 371 // callback.
369 job = j->second; 372 job = j->second;
370 // Check that the job is for an acceptable type of cert. 373 // Check that the job is for an acceptable type of cert.
371 if (std::find(requested_types.begin(), requested_types.end(), job->type()) 374 if (std::find(requested_types.begin(), requested_types.end(), job->type())
372 == requested_types.end()) { 375 == requested_types.end()) {
373 DVLOG(1) << "Found inflight job of wrong type " << job->type() 376 DVLOG(1) << "Found inflight job of wrong type " << job->type()
374 << " for " << origin; 377 << " for " << domain;
375 // If we get here, the server is asking for different types of certs in 378 // If we get here, the server is asking for different types of certs in
376 // short succession. This probably means the server is broken or 379 // short succession. This probably means the server is broken or
377 // misconfigured. Since we only store one type of cert per origin, we 380 // misconfigured. Since we only store one type of cert per domain, we
378 // are unable to handle this well. Just return an error and let the first 381 // are unable to handle this well. Just return an error and let the first
379 // job finish. 382 // job finish.
380 return ERR_ORIGIN_BOUND_CERT_GENERATION_TYPE_MISMATCH; 383 return ERR_ORIGIN_BOUND_CERT_GENERATION_TYPE_MISMATCH;
381 } 384 }
382 inflight_joins_++; 385 inflight_joins_++;
383 } else { 386 } else {
384 // Need to make a new request. 387 // Need to make a new request.
385 OriginBoundCertServiceWorker* worker = new OriginBoundCertServiceWorker( 388 OriginBoundCertServiceWorker* worker = new OriginBoundCertServiceWorker(
386 origin, 389 domain,
387 preferred_type, 390 preferred_type,
388 this); 391 this);
389 job = new OriginBoundCertServiceJob(worker, preferred_type); 392 job = new OriginBoundCertServiceJob(worker, preferred_type);
390 if (!worker->Start()) { 393 if (!worker->Start()) {
391 delete job; 394 delete job;
392 delete worker; 395 delete worker;
393 // TODO(rkn): Log to the NetLog. 396 // TODO(rkn): Log to the NetLog.
394 LOG(ERROR) << "OriginBoundCertServiceWorker couldn't be started."; 397 LOG(ERROR) << "OriginBoundCertServiceWorker couldn't be started.";
395 return ERR_INSUFFICIENT_RESOURCES; // Just a guess. 398 return ERR_INSUFFICIENT_RESOURCES; // Just a guess.
396 } 399 }
397 inflight_[origin] = job; 400 inflight_[domain] = job;
398 } 401 }
399 402
400 OriginBoundCertServiceRequest* request = 403 OriginBoundCertServiceRequest* request =
401 new OriginBoundCertServiceRequest(callback, type, private_key, cert); 404 new OriginBoundCertServiceRequest(callback, type, private_key, cert);
402 job->AddRequest(request); 405 job->AddRequest(request);
403 *out_req = request; 406 *out_req = request;
404 return ERR_IO_PENDING; 407 return ERR_IO_PENDING;
405 } 408 }
406 409
407 OriginBoundCertStore* OriginBoundCertService::GetCertStore() { 410 OriginBoundCertStore* OriginBoundCertService::GetCertStore() {
408 return origin_bound_cert_store_.get(); 411 return origin_bound_cert_store_.get();
409 } 412 }
410 413
411 // static 414 // static
412 int OriginBoundCertService::GenerateCert(const std::string& origin, 415 int OriginBoundCertService::GenerateCert(const std::string& domain,
413 SSLClientCertType type, 416 SSLClientCertType type,
414 uint32 serial_number, 417 uint32 serial_number,
415 base::Time* creation_time, 418 base::Time* creation_time,
416 base::Time* expiration_time, 419 base::Time* expiration_time,
417 std::string* private_key, 420 std::string* private_key,
418 std::string* cert) { 421 std::string* cert) {
419 base::Time now = base::Time::Now(); 422 base::Time now = base::Time::Now();
420 base::Time not_valid_after = 423 base::Time not_valid_after =
421 now + base::TimeDelta::FromDays(kValidityPeriodInDays); 424 now + base::TimeDelta::FromDays(kValidityPeriodInDays);
422 std::string der_cert; 425 std::string der_cert;
423 std::vector<uint8> private_key_info; 426 std::vector<uint8> private_key_info;
424 switch (type) { 427 switch (type) {
425 case CLIENT_CERT_ECDSA_SIGN: { 428 case CLIENT_CERT_ECDSA_SIGN: {
426 scoped_ptr<crypto::ECPrivateKey> key(crypto::ECPrivateKey::Create()); 429 scoped_ptr<crypto::ECPrivateKey> key(crypto::ECPrivateKey::Create());
427 if (!key.get()) { 430 if (!key.get()) {
428 DLOG(ERROR) << "Unable to create key pair for client"; 431 DLOG(ERROR) << "Unable to create key pair for client";
429 return ERR_KEY_GENERATION_FAILED; 432 return ERR_KEY_GENERATION_FAILED;
430 } 433 }
431 if (!x509_util::CreateOriginBoundCertEC( 434 if (!x509_util::CreateOriginBoundCertEC(
432 key.get(), 435 key.get(),
433 origin, 436 domain,
434 serial_number, 437 serial_number,
435 now, 438 now,
436 not_valid_after, 439 not_valid_after,
437 &der_cert)) { 440 &der_cert)) {
438 DLOG(ERROR) << "Unable to create x509 cert for client"; 441 DLOG(ERROR) << "Unable to create x509 cert for client";
439 return ERR_ORIGIN_BOUND_CERT_GENERATION_FAILED; 442 return ERR_ORIGIN_BOUND_CERT_GENERATION_FAILED;
440 } 443 }
441 444
442 if (!key->ExportEncryptedPrivateKey( 445 if (!key->ExportEncryptedPrivateKey(
443 kEPKIPassword, 1, &private_key_info)) { 446 kEPKIPassword, 1, &private_key_info)) {
(...skipping 20 matching lines...) Expand all
464 467
465 void OriginBoundCertService::CancelRequest(RequestHandle req) { 468 void OriginBoundCertService::CancelRequest(RequestHandle req) {
466 DCHECK(CalledOnValidThread()); 469 DCHECK(CalledOnValidThread());
467 OriginBoundCertServiceRequest* request = 470 OriginBoundCertServiceRequest* request =
468 reinterpret_cast<OriginBoundCertServiceRequest*>(req); 471 reinterpret_cast<OriginBoundCertServiceRequest*>(req);
469 request->Cancel(); 472 request->Cancel();
470 } 473 }
471 474
472 // HandleResult is called by OriginBoundCertServiceWorker on the origin message 475 // HandleResult is called by OriginBoundCertServiceWorker on the origin message
473 // loop. It deletes OriginBoundCertServiceJob. 476 // loop. It deletes OriginBoundCertServiceJob.
474 void OriginBoundCertService::HandleResult(const std::string& origin, 477 void OriginBoundCertService::HandleResult(const std::string& domain,
475 int error, 478 int error,
476 SSLClientCertType type, 479 SSLClientCertType type,
477 base::Time creation_time, 480 base::Time creation_time,
478 base::Time expiration_time, 481 base::Time expiration_time,
479 const std::string& private_key, 482 const std::string& private_key,
480 const std::string& cert) { 483 const std::string& cert) {
481 DCHECK(CalledOnValidThread()); 484 DCHECK(CalledOnValidThread());
482 485
483 origin_bound_cert_store_->SetOriginBoundCert( 486 origin_bound_cert_store_->SetOriginBoundCert(
484 origin, type, creation_time, expiration_time, private_key, cert); 487 domain, type, creation_time, expiration_time, private_key, cert);
485 488
486 std::map<std::string, OriginBoundCertServiceJob*>::iterator j; 489 std::map<std::string, OriginBoundCertServiceJob*>::iterator j;
487 j = inflight_.find(origin); 490 j = inflight_.find(domain);
488 if (j == inflight_.end()) { 491 if (j == inflight_.end()) {
489 NOTREACHED(); 492 NOTREACHED();
490 return; 493 return;
491 } 494 }
492 OriginBoundCertServiceJob* job = j->second; 495 OriginBoundCertServiceJob* job = j->second;
493 inflight_.erase(j); 496 inflight_.erase(j);
494 497
495 job->HandleResult(error, type, private_key, cert); 498 job->HandleResult(error, type, private_key, cert);
496 delete job; 499 delete job;
497 } 500 }
498 501
499 int OriginBoundCertService::cert_count() { 502 int OriginBoundCertService::cert_count() {
500 return origin_bound_cert_store_->GetCertCount(); 503 return origin_bound_cert_store_->GetCertCount();
501 } 504 }
502 505
503 } // namespace net 506 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698