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

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

Powered by Google App Engine
This is Rietveld 408576698