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

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

Issue 8890073: Handle Origin Bound Certificate expiration. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: review changes Created 9 years 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/origin_bound_cert_service.h ('k') | net/base/origin_bound_cert_service_unittest.cc » ('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) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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"
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 base::AutoLock locked(lock_); 127 base::AutoLock locked(lock_);
128 canceled_ = true; 128 canceled_ = true;
129 } 129 }
130 130
131 private: 131 private:
132 void Run() { 132 void Run() {
133 // Runs on a worker thread. 133 // Runs on a worker thread.
134 error_ = OriginBoundCertService::GenerateCert(origin_, 134 error_ = OriginBoundCertService::GenerateCert(origin_,
135 type_, 135 type_,
136 serial_number_, 136 serial_number_,
137 &expiration_time_,
137 &private_key_, 138 &private_key_,
138 &cert_); 139 &cert_);
139 #if defined(USE_NSS) 140 #if defined(USE_NSS)
140 // Detach the thread from NSPR. 141 // Detach the thread from NSPR.
141 // Calling NSS functions attaches the thread to NSPR, which stores 142 // Calling NSS functions attaches the thread to NSPR, which stores
142 // the NSPR thread ID in thread-specific data. 143 // the NSPR thread ID in thread-specific data.
143 // The threads in our thread pool terminate after we have called 144 // The threads in our thread pool terminate after we have called
144 // PR_Cleanup. Unless we detach them from NSPR, net_unittests gets 145 // PR_Cleanup. Unless we detach them from NSPR, net_unittests gets
145 // segfaults on shutdown when the threads' thread-specific data 146 // segfaults on shutdown when the threads' thread-specific data
146 // destructors run. 147 // destructors run.
147 PR_DetachThread(); 148 PR_DetachThread();
148 #endif 149 #endif
149 Finish(); 150 Finish();
150 } 151 }
151 152
152 // DoReply runs on the origin thread. 153 // DoReply runs on the origin thread.
153 void DoReply() { 154 void DoReply() {
154 DCHECK_EQ(MessageLoop::current(), origin_loop_); 155 DCHECK_EQ(MessageLoop::current(), origin_loop_);
155 { 156 {
156 // We lock here because the worker thread could still be in Finished, 157 // We lock here because the worker thread could still be in Finished,
157 // after the PostTask, but before unlocking |lock_|. If we do not lock in 158 // after the PostTask, but before unlocking |lock_|. If we do not lock in
158 // this case, we will end up deleting a locked Lock, which can lead to 159 // this case, we will end up deleting a locked Lock, which can lead to
159 // memory leaks or worse errors. 160 // memory leaks or worse errors.
160 base::AutoLock locked(lock_); 161 base::AutoLock locked(lock_);
161 if (!canceled_) { 162 if (!canceled_) {
162 origin_bound_cert_service_->HandleResult(origin_, error_, type_, 163 origin_bound_cert_service_->HandleResult(
163 private_key_, cert_); 164 origin_, error_, type_, expiration_time_, private_key_, cert_);
164 } 165 }
165 } 166 }
166 delete this; 167 delete this;
167 } 168 }
168 169
169 void Finish() { 170 void Finish() {
170 // Runs on the worker thread. 171 // Runs on the worker thread.
171 // We assume that the origin loop outlives the OriginBoundCertService. If 172 // We assume that the origin loop outlives the OriginBoundCertService. If
172 // the OriginBoundCertService is deleted, it will call Cancel on us. If it 173 // the OriginBoundCertService is deleted, it will call Cancel on us. If it
173 // does so before the Acquire, we'll delete ourselves and return. If it's 174 // does so before the Acquire, we'll delete ourselves and return. If it's
(...skipping 27 matching lines...) Expand all
201 202
202 // lock_ protects canceled_. 203 // lock_ protects canceled_.
203 base::Lock lock_; 204 base::Lock lock_;
204 205
205 // If canceled_ is true, 206 // If canceled_ is true,
206 // * origin_loop_ cannot be accessed by the worker thread, 207 // * origin_loop_ cannot be accessed by the worker thread,
207 // * origin_bound_cert_service_ cannot be accessed by any thread. 208 // * origin_bound_cert_service_ cannot be accessed by any thread.
208 bool canceled_; 209 bool canceled_;
209 210
210 int error_; 211 int error_;
212 base::Time expiration_time_;
211 std::string private_key_; 213 std::string private_key_;
212 std::string cert_; 214 std::string cert_;
213 215
214 DISALLOW_COPY_AND_ASSIGN(OriginBoundCertServiceWorker); 216 DISALLOW_COPY_AND_ASSIGN(OriginBoundCertServiceWorker);
215 }; 217 };
216 218
217 // An OriginBoundCertServiceJob is a one-to-one counterpart of an 219 // An OriginBoundCertServiceJob is a one-to-one counterpart of an
218 // OriginBoundCertServiceWorker. It lives only on the OriginBoundCertService's 220 // OriginBoundCertServiceWorker. It lives only on the OriginBoundCertService's
219 // origin message loop. 221 // origin message loop.
220 class OriginBoundCertServiceJob { 222 class OriginBoundCertServiceJob {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 } 317 }
316 if (preferred_type == CLIENT_CERT_INVALID_TYPE) { 318 if (preferred_type == CLIENT_CERT_INVALID_TYPE) {
317 // None of the requested types are supported. 319 // None of the requested types are supported.
318 *out_req = NULL; 320 *out_req = NULL;
319 return ERR_CLIENT_AUTH_CERT_TYPE_UNSUPPORTED; 321 return ERR_CLIENT_AUTH_CERT_TYPE_UNSUPPORTED;
320 } 322 }
321 323
322 requests_++; 324 requests_++;
323 325
324 // Check if an origin bound cert of an acceptable type already exists for this 326 // Check if an origin bound cert of an acceptable type already exists for this
325 // origin. 327 // origin, and that it has not expired.
328 base::Time now = base::Time::Now();
329 base::Time expiration_time;
326 if (origin_bound_cert_store_->GetOriginBoundCert(origin, 330 if (origin_bound_cert_store_->GetOriginBoundCert(origin,
327 type, 331 type,
332 &expiration_time,
328 private_key, 333 private_key,
329 cert)) { 334 cert)) {
330 if (IsSupportedCertType(*type) && 335 if (expiration_time < now) {
331 std::find(requested_types.begin(), requested_types.end(), *type) != 336 DVLOG(1) << "Cert store had expired cert for " << origin;
332 requested_types.end()) { 337 } else if (!IsSupportedCertType(*type) ||
338 std::find(requested_types.begin(), requested_types.end(),
339 *type) == requested_types.end()) {
340 DVLOG(1) << "Cert store had cert of wrong type " << *type << " for "
341 << origin;
342 } else {
333 cert_store_hits_++; 343 cert_store_hits_++;
334 *out_req = NULL; 344 *out_req = NULL;
335 return OK; 345 return OK;
336 } 346 }
337 DVLOG(1) << "Cert store had cert of wrong type " << *type << " for "
338 << origin;
339 } 347 }
340 348
341 // |origin_bound_cert_store_| has no cert for this origin. See if an 349 // |origin_bound_cert_store_| has no cert for this origin. See if an
342 // identical request is currently in flight. 350 // identical request is currently in flight.
343 OriginBoundCertServiceJob* job = NULL; 351 OriginBoundCertServiceJob* job = NULL;
344 std::map<std::string, OriginBoundCertServiceJob*>::const_iterator j; 352 std::map<std::string, OriginBoundCertServiceJob*>::const_iterator j;
345 j = inflight_.find(origin); 353 j = inflight_.find(origin);
346 if (j != inflight_.end()) { 354 if (j != inflight_.end()) {
347 // An identical request is in flight already. We'll just attach our 355 // An identical request is in flight already. We'll just attach our
348 // callback. 356 // callback.
349 job = j->second; 357 job = j->second;
350 // Check that the job is for an acceptable type of cert. 358 // Check that the job is for an acceptable type of cert.
351 if (std::find(requested_types.begin(), requested_types.end(), job->type()) 359 if (std::find(requested_types.begin(), requested_types.end(), job->type())
352 == requested_types.end()) { 360 == requested_types.end()) {
353 DVLOG(1) << "Found inflight job of wrong type " << job->type() 361 DVLOG(1) << "Found inflight job of wrong type " << job->type()
354 << " for " << origin; 362 << " for " << origin;
355 *out_req = NULL; 363 *out_req = NULL;
356 // If we get here, the server is asking for different types of certs in 364 // If we get here, the server is asking for different types of certs in
357 // short succession. This probably means the server is broken or 365 // short succession. This probably means the server is broken or
358 // misconfigured. Since we only store one type of cert per origin, we 366 // misconfigured. Since we only store one type of cert per origin, we
359 // are unable to handle this well. Just return an error and let the first 367 // are unable to handle this well. Just return an error and let the first
360 // job finish. 368 // job finish.
361 return ERR_ORIGIN_BOUND_CERT_GENERATION_TYPE_MISMATCH; 369 return ERR_ORIGIN_BOUND_CERT_GENERATION_TYPE_MISMATCH;
362 } 370 }
363 inflight_joins_++; 371 inflight_joins_++;
364 } else { 372 } else {
365 // Need to make a new request. 373 // Need to make a new request.
366 OriginBoundCertServiceWorker* worker = 374 OriginBoundCertServiceWorker* worker = new OriginBoundCertServiceWorker(
367 new OriginBoundCertServiceWorker(origin, preferred_type, this); 375 origin,
376 preferred_type,
377 this);
368 job = new OriginBoundCertServiceJob(worker, preferred_type); 378 job = new OriginBoundCertServiceJob(worker, preferred_type);
369 if (!worker->Start()) { 379 if (!worker->Start()) {
370 delete job; 380 delete job;
371 delete worker; 381 delete worker;
372 *out_req = NULL; 382 *out_req = NULL;
373 // TODO(rkn): Log to the NetLog. 383 // TODO(rkn): Log to the NetLog.
374 LOG(ERROR) << "OriginBoundCertServiceWorker couldn't be started."; 384 LOG(ERROR) << "OriginBoundCertServiceWorker couldn't be started.";
375 return ERR_INSUFFICIENT_RESOURCES; // Just a guess. 385 return ERR_INSUFFICIENT_RESOURCES; // Just a guess.
376 } 386 }
377 inflight_[origin] = job; 387 inflight_[origin] = job;
378 } 388 }
379 389
380 OriginBoundCertServiceRequest* request = 390 OriginBoundCertServiceRequest* request =
381 new OriginBoundCertServiceRequest(callback, type, private_key, cert); 391 new OriginBoundCertServiceRequest(callback, type, private_key, cert);
382 job->AddRequest(request); 392 job->AddRequest(request);
383 *out_req = request; 393 *out_req = request;
384 return ERR_IO_PENDING; 394 return ERR_IO_PENDING;
385 } 395 }
386 396
387 // static 397 // static
388 int OriginBoundCertService::GenerateCert(const std::string& origin, 398 int OriginBoundCertService::GenerateCert(const std::string& origin,
389 SSLClientCertType type, 399 SSLClientCertType type,
390 uint32 serial_number, 400 uint32 serial_number,
401 base::Time* expiration_time,
391 std::string* private_key, 402 std::string* private_key,
392 std::string* cert) { 403 std::string* cert) {
404 base::Time now = base::Time::Now();
405 base::Time not_valid_after =
406 now + base::TimeDelta::FromDays(kValidityPeriodInDays);
393 std::string der_cert; 407 std::string der_cert;
394 std::vector<uint8> private_key_info; 408 std::vector<uint8> private_key_info;
395 switch (type) { 409 switch (type) {
396 case CLIENT_CERT_RSA_SIGN: { 410 case CLIENT_CERT_RSA_SIGN: {
397 scoped_ptr<crypto::RSAPrivateKey> key( 411 scoped_ptr<crypto::RSAPrivateKey> key(
398 crypto::RSAPrivateKey::Create(kKeySizeInBits)); 412 crypto::RSAPrivateKey::Create(kKeySizeInBits));
399 if (!key.get()) { 413 if (!key.get()) {
400 DLOG(ERROR) << "Unable to create key pair for client"; 414 DLOG(ERROR) << "Unable to create key pair for client";
401 return ERR_KEY_GENERATION_FAILED; 415 return ERR_KEY_GENERATION_FAILED;
402 } 416 }
403 if (!x509_util::CreateOriginBoundCertRSA( 417 if (!x509_util::CreateOriginBoundCertRSA(
404 key.get(), 418 key.get(),
405 origin, 419 origin,
406 serial_number, 420 serial_number,
407 base::TimeDelta::FromDays(kValidityPeriodInDays), 421 now,
422 not_valid_after,
408 &der_cert)) { 423 &der_cert)) {
409 DLOG(ERROR) << "Unable to create x509 cert for client"; 424 DLOG(ERROR) << "Unable to create x509 cert for client";
410 return ERR_ORIGIN_BOUND_CERT_GENERATION_FAILED; 425 return ERR_ORIGIN_BOUND_CERT_GENERATION_FAILED;
411 } 426 }
412 427
413 if (!key->ExportPrivateKey(&private_key_info)) { 428 if (!key->ExportPrivateKey(&private_key_info)) {
414 DLOG(ERROR) << "Unable to export private key"; 429 DLOG(ERROR) << "Unable to export private key";
415 return ERR_PRIVATE_KEY_EXPORT_FAILED; 430 return ERR_PRIVATE_KEY_EXPORT_FAILED;
416 } 431 }
417 break; 432 break;
418 } 433 }
419 case CLIENT_CERT_ECDSA_SIGN: { 434 case CLIENT_CERT_ECDSA_SIGN: {
420 scoped_ptr<crypto::ECPrivateKey> key(crypto::ECPrivateKey::Create()); 435 scoped_ptr<crypto::ECPrivateKey> key(crypto::ECPrivateKey::Create());
421 if (!key.get()) { 436 if (!key.get()) {
422 DLOG(ERROR) << "Unable to create key pair for client"; 437 DLOG(ERROR) << "Unable to create key pair for client";
423 return ERR_KEY_GENERATION_FAILED; 438 return ERR_KEY_GENERATION_FAILED;
424 } 439 }
425 if (!x509_util::CreateOriginBoundCertEC( 440 if (!x509_util::CreateOriginBoundCertEC(
426 key.get(), 441 key.get(),
427 origin, 442 origin,
428 serial_number, 443 serial_number,
429 base::TimeDelta::FromDays(kValidityPeriodInDays), 444 now,
445 not_valid_after,
430 &der_cert)) { 446 &der_cert)) {
431 DLOG(ERROR) << "Unable to create x509 cert for client"; 447 DLOG(ERROR) << "Unable to create x509 cert for client";
432 return ERR_ORIGIN_BOUND_CERT_GENERATION_FAILED; 448 return ERR_ORIGIN_BOUND_CERT_GENERATION_FAILED;
433 } 449 }
434 450
435 if (!key->ExportEncryptedPrivateKey( 451 if (!key->ExportEncryptedPrivateKey(
436 kEPKIPassword, 1, &private_key_info)) { 452 kEPKIPassword, 1, &private_key_info)) {
437 DLOG(ERROR) << "Unable to export private key"; 453 DLOG(ERROR) << "Unable to export private key";
438 return ERR_PRIVATE_KEY_EXPORT_FAILED; 454 return ERR_PRIVATE_KEY_EXPORT_FAILED;
439 } 455 }
440 break; 456 break;
441 } 457 }
442 default: 458 default:
443 NOTREACHED(); 459 NOTREACHED();
444 return ERR_INVALID_ARGUMENT; 460 return ERR_INVALID_ARGUMENT;
445 } 461 }
446 462
447 // TODO(rkn): Perhaps ExportPrivateKey should be changed to output a 463 // TODO(rkn): Perhaps ExportPrivateKey should be changed to output a
448 // std::string* to prevent this copying. 464 // std::string* to prevent this copying.
449 std::string key_out(private_key_info.begin(), private_key_info.end()); 465 std::string key_out(private_key_info.begin(), private_key_info.end());
450 466
451 private_key->swap(key_out); 467 private_key->swap(key_out);
452 cert->swap(der_cert); 468 cert->swap(der_cert);
469 *expiration_time = not_valid_after;
453 return OK; 470 return OK;
454 } 471 }
455 472
456 void OriginBoundCertService::CancelRequest(RequestHandle req) { 473 void OriginBoundCertService::CancelRequest(RequestHandle req) {
457 DCHECK(CalledOnValidThread()); 474 DCHECK(CalledOnValidThread());
458 OriginBoundCertServiceRequest* request = 475 OriginBoundCertServiceRequest* request =
459 reinterpret_cast<OriginBoundCertServiceRequest*>(req); 476 reinterpret_cast<OriginBoundCertServiceRequest*>(req);
460 request->Cancel(); 477 request->Cancel();
461 } 478 }
462 479
463 // HandleResult is called by OriginBoundCertServiceWorker on the origin message 480 // HandleResult is called by OriginBoundCertServiceWorker on the origin message
464 // loop. It deletes OriginBoundCertServiceJob. 481 // loop. It deletes OriginBoundCertServiceJob.
465 void OriginBoundCertService::HandleResult(const std::string& origin, 482 void OriginBoundCertService::HandleResult(const std::string& origin,
466 int error, 483 int error,
467 SSLClientCertType type, 484 SSLClientCertType type,
485 base::Time expiration_time,
468 const std::string& private_key, 486 const std::string& private_key,
469 const std::string& cert) { 487 const std::string& cert) {
470 DCHECK(CalledOnValidThread()); 488 DCHECK(CalledOnValidThread());
471 489
472 origin_bound_cert_store_->SetOriginBoundCert(origin, type, private_key, cert); 490 origin_bound_cert_store_->SetOriginBoundCert(
491 origin, type, expiration_time, private_key, cert);
473 492
474 std::map<std::string, OriginBoundCertServiceJob*>::iterator j; 493 std::map<std::string, OriginBoundCertServiceJob*>::iterator j;
475 j = inflight_.find(origin); 494 j = inflight_.find(origin);
476 if (j == inflight_.end()) { 495 if (j == inflight_.end()) {
477 NOTREACHED(); 496 NOTREACHED();
478 return; 497 return;
479 } 498 }
480 OriginBoundCertServiceJob* job = j->second; 499 OriginBoundCertServiceJob* job = j->second;
481 inflight_.erase(j); 500 inflight_.erase(j);
482 501
483 job->HandleResult(error, type, private_key, cert); 502 job->HandleResult(error, type, private_key, cert);
484 delete job; 503 delete job;
485 } 504 }
486 505
487 int OriginBoundCertService::cert_count() { 506 int OriginBoundCertService::cert_count() {
488 return origin_bound_cert_store_->GetCertCount(); 507 return origin_bound_cert_store_->GetCertCount();
489 } 508 }
490 509
491 } // namespace net 510 } // namespace net
OLDNEW
« no previous file with comments | « net/base/origin_bound_cert_service.h ('k') | net/base/origin_bound_cert_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698