| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/ssl/channel_id_service.h" | 5 #include "net/ssl/channel_id_service.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <utility> |
| 9 | 10 |
| 10 #include "base/bind.h" | 11 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
| 12 #include "base/callback_helpers.h" | 13 #include "base/callback_helpers.h" |
| 13 #include "base/compiler_specific.h" | 14 #include "base/compiler_specific.h" |
| 14 #include "base/location.h" | 15 #include "base/location.h" |
| 15 #include "base/logging.h" | 16 #include "base/logging.h" |
| 16 #include "base/macros.h" | 17 #include "base/macros.h" |
| 17 #include "base/memory/ref_counted.h" | 18 #include "base/memory/ref_counted.h" |
| 18 #include "base/memory/scoped_ptr.h" | 19 #include "base/memory/scoped_ptr.h" |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 int* error) { | 88 int* error) { |
| 88 scoped_ptr<ChannelIDStore::ChannelID> result; | 89 scoped_ptr<ChannelIDStore::ChannelID> result; |
| 89 | 90 |
| 90 base::TimeTicks start = base::TimeTicks::Now(); | 91 base::TimeTicks start = base::TimeTicks::Now(); |
| 91 base::Time creation_time = base::Time::Now(); | 92 base::Time creation_time = base::Time::Now(); |
| 92 scoped_ptr<crypto::ECPrivateKey> key(crypto::ECPrivateKey::Create()); | 93 scoped_ptr<crypto::ECPrivateKey> key(crypto::ECPrivateKey::Create()); |
| 93 | 94 |
| 94 if (!key) { | 95 if (!key) { |
| 95 DLOG(ERROR) << "Unable to create channel ID key pair"; | 96 DLOG(ERROR) << "Unable to create channel ID key pair"; |
| 96 *error = ERR_KEY_GENERATION_FAILED; | 97 *error = ERR_KEY_GENERATION_FAILED; |
| 97 return result.Pass(); | 98 return result; |
| 98 } | 99 } |
| 99 | 100 |
| 100 result.reset(new ChannelIDStore::ChannelID(server_identifier, creation_time, | 101 result.reset(new ChannelIDStore::ChannelID(server_identifier, creation_time, |
| 101 key.Pass())); | 102 std::move(key))); |
| 102 UMA_HISTOGRAM_CUSTOM_TIMES("DomainBoundCerts.GenerateCertTime", | 103 UMA_HISTOGRAM_CUSTOM_TIMES("DomainBoundCerts.GenerateCertTime", |
| 103 base::TimeTicks::Now() - start, | 104 base::TimeTicks::Now() - start, |
| 104 base::TimeDelta::FromMilliseconds(1), | 105 base::TimeDelta::FromMilliseconds(1), |
| 105 base::TimeDelta::FromMinutes(5), | 106 base::TimeDelta::FromMinutes(5), |
| 106 50); | 107 50); |
| 107 *error = OK; | 108 *error = OK; |
| 108 return result.Pass(); | 109 return result; |
| 109 } | 110 } |
| 110 | 111 |
| 111 } // namespace | 112 } // namespace |
| 112 | 113 |
| 113 // ChannelIDServiceWorker runs on a worker thread and takes care of the | 114 // ChannelIDServiceWorker runs on a worker thread and takes care of the |
| 114 // blocking process of performing key generation. Will take care of deleting | 115 // blocking process of performing key generation. Will take care of deleting |
| 115 // itself once Start() is called. | 116 // itself once Start() is called. |
| 116 class ChannelIDServiceWorker { | 117 class ChannelIDServiceWorker { |
| 117 public: | 118 public: |
| 118 typedef base::Callback<void( | 119 typedef base::Callback<void( |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 | 177 |
| 177 ~ChannelIDServiceJob() { DCHECK(requests_.empty()); } | 178 ~ChannelIDServiceJob() { DCHECK(requests_.empty()); } |
| 178 | 179 |
| 179 void AddRequest(ChannelIDService::Request* request, | 180 void AddRequest(ChannelIDService::Request* request, |
| 180 bool create_if_missing = false) { | 181 bool create_if_missing = false) { |
| 181 create_if_missing_ |= create_if_missing; | 182 create_if_missing_ |= create_if_missing; |
| 182 requests_.push_back(request); | 183 requests_.push_back(request); |
| 183 } | 184 } |
| 184 | 185 |
| 185 void HandleResult(int error, scoped_ptr<crypto::ECPrivateKey> key) { | 186 void HandleResult(int error, scoped_ptr<crypto::ECPrivateKey> key) { |
| 186 PostAll(error, key.Pass()); | 187 PostAll(error, std::move(key)); |
| 187 } | 188 } |
| 188 | 189 |
| 189 bool CreateIfMissing() const { return create_if_missing_; } | 190 bool CreateIfMissing() const { return create_if_missing_; } |
| 190 | 191 |
| 191 void CancelRequest(ChannelIDService::Request* req) { | 192 void CancelRequest(ChannelIDService::Request* req) { |
| 192 auto it = std::find(requests_.begin(), requests_.end(), req); | 193 auto it = std::find(requests_.begin(), requests_.end(), req); |
| 193 if (it != requests_.end()) | 194 if (it != requests_.end()) |
| 194 requests_.erase(it); | 195 requests_.erase(it); |
| 195 } | 196 } |
| 196 | 197 |
| 197 private: | 198 private: |
| 198 void PostAll(int error, scoped_ptr<crypto::ECPrivateKey> key) { | 199 void PostAll(int error, scoped_ptr<crypto::ECPrivateKey> key) { |
| 199 std::vector<ChannelIDService::Request*> requests; | 200 std::vector<ChannelIDService::Request*> requests; |
| 200 requests_.swap(requests); | 201 requests_.swap(requests); |
| 201 | 202 |
| 202 for (std::vector<ChannelIDService::Request*>::iterator i = requests.begin(); | 203 for (std::vector<ChannelIDService::Request*>::iterator i = requests.begin(); |
| 203 i != requests.end(); i++) { | 204 i != requests.end(); i++) { |
| 204 scoped_ptr<crypto::ECPrivateKey> key_copy; | 205 scoped_ptr<crypto::ECPrivateKey> key_copy; |
| 205 if (key) | 206 if (key) |
| 206 key_copy.reset(key->Copy()); | 207 key_copy.reset(key->Copy()); |
| 207 (*i)->Post(error, key_copy.Pass()); | 208 (*i)->Post(error, std::move(key_copy)); |
| 208 } | 209 } |
| 209 } | 210 } |
| 210 | 211 |
| 211 std::vector<ChannelIDService::Request*> requests_; | 212 std::vector<ChannelIDService::Request*> requests_; |
| 212 bool create_if_missing_; | 213 bool create_if_missing_; |
| 213 }; | 214 }; |
| 214 | 215 |
| 215 // static | 216 // static |
| 216 const char ChannelIDService::kEPKIPassword[] = ""; | 217 const char ChannelIDService::kEPKIPassword[] = ""; |
| 217 | 218 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 case ERR_INSUFFICIENT_RESOURCES: | 269 case ERR_INSUFFICIENT_RESOURCES: |
| 269 RecordGetChannelIDResult(WORKER_FAILURE); | 270 RecordGetChannelIDResult(WORKER_FAILURE); |
| 270 break; | 271 break; |
| 271 default: | 272 default: |
| 272 RecordGetChannelIDResult(ASYNC_FAILURE_UNKNOWN); | 273 RecordGetChannelIDResult(ASYNC_FAILURE_UNKNOWN); |
| 273 break; | 274 break; |
| 274 } | 275 } |
| 275 service_ = NULL; | 276 service_ = NULL; |
| 276 DCHECK(!callback_.is_null()); | 277 DCHECK(!callback_.is_null()); |
| 277 if (key) | 278 if (key) |
| 278 *key_ = key.Pass(); | 279 *key_ = std::move(key); |
| 279 // Running the callback might delete |this| (e.g. the callback cleans up | 280 // Running the callback might delete |this| (e.g. the callback cleans up |
| 280 // resources created for the request), so we can't touch any of our | 281 // resources created for the request), so we can't touch any of our |
| 281 // members afterwards. Reset callback_ first. | 282 // members afterwards. Reset callback_ first. |
| 282 base::ResetAndReturn(&callback_).Run(error); | 283 base::ResetAndReturn(&callback_).Run(error); |
| 283 } | 284 } |
| 284 | 285 |
| 285 ChannelIDService::ChannelIDService( | 286 ChannelIDService::ChannelIDService( |
| 286 ChannelIDStore* channel_id_store, | 287 ChannelIDStore* channel_id_store, |
| 287 const scoped_refptr<base::TaskRunner>& task_runner) | 288 const scoped_refptr<base::TaskRunner>& task_runner) |
| 288 : channel_id_store_(channel_id_store), | 289 : channel_id_store_(channel_id_store), |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 406 j = inflight_.find(server_identifier); | 407 j = inflight_.find(server_identifier); |
| 407 if (j == inflight_.end()) { | 408 if (j == inflight_.end()) { |
| 408 NOTREACHED(); | 409 NOTREACHED(); |
| 409 return; | 410 return; |
| 410 } | 411 } |
| 411 | 412 |
| 412 if (err == OK) { | 413 if (err == OK) { |
| 413 // Async DB lookup found a valid channel ID. | 414 // Async DB lookup found a valid channel ID. |
| 414 key_store_hits_++; | 415 key_store_hits_++; |
| 415 // ChannelIDService::Request::Post will do the histograms and stuff. | 416 // ChannelIDService::Request::Post will do the histograms and stuff. |
| 416 HandleResult(OK, server_identifier, key.Pass()); | 417 HandleResult(OK, server_identifier, std::move(key)); |
| 417 return; | 418 return; |
| 418 } | 419 } |
| 419 // Async lookup failed or the channel ID was missing. Return the error | 420 // Async lookup failed or the channel ID was missing. Return the error |
| 420 // directly, unless the channel ID was missing and a request asked to create | 421 // directly, unless the channel ID was missing and a request asked to create |
| 421 // one. | 422 // one. |
| 422 if (err != ERR_FILE_NOT_FOUND || !j->second->CreateIfMissing()) { | 423 if (err != ERR_FILE_NOT_FOUND || !j->second->CreateIfMissing()) { |
| 423 HandleResult(err, server_identifier, key.Pass()); | 424 HandleResult(err, server_identifier, std::move(key)); |
| 424 return; | 425 return; |
| 425 } | 426 } |
| 426 // At least one request asked to create a channel ID => start generating a new | 427 // At least one request asked to create a channel ID => start generating a new |
| 427 // one. | 428 // one. |
| 428 workers_created_++; | 429 workers_created_++; |
| 429 ChannelIDServiceWorker* worker = new ChannelIDServiceWorker( | 430 ChannelIDServiceWorker* worker = new ChannelIDServiceWorker( |
| 430 server_identifier, | 431 server_identifier, |
| 431 base::Bind(&ChannelIDService::GeneratedChannelID, | 432 base::Bind(&ChannelIDService::GeneratedChannelID, |
| 432 weak_ptr_factory_.GetWeakPtr())); | 433 weak_ptr_factory_.GetWeakPtr())); |
| 433 if (!worker->Start(task_runner_)) { | 434 if (!worker->Start(task_runner_)) { |
| 434 // TODO(rkn): Log to the NetLog. | 435 // TODO(rkn): Log to the NetLog. |
| 435 LOG(ERROR) << "ChannelIDServiceWorker couldn't be started."; | 436 LOG(ERROR) << "ChannelIDServiceWorker couldn't be started."; |
| 436 HandleResult(ERR_INSUFFICIENT_RESOURCES, server_identifier, nullptr); | 437 HandleResult(ERR_INSUFFICIENT_RESOURCES, server_identifier, nullptr); |
| 437 } | 438 } |
| 438 } | 439 } |
| 439 | 440 |
| 440 ChannelIDStore* ChannelIDService::GetChannelIDStore() { | 441 ChannelIDStore* ChannelIDService::GetChannelIDStore() { |
| 441 return channel_id_store_.get(); | 442 return channel_id_store_.get(); |
| 442 } | 443 } |
| 443 | 444 |
| 444 void ChannelIDService::GeneratedChannelID( | 445 void ChannelIDService::GeneratedChannelID( |
| 445 const std::string& server_identifier, | 446 const std::string& server_identifier, |
| 446 int error, | 447 int error, |
| 447 scoped_ptr<ChannelIDStore::ChannelID> channel_id) { | 448 scoped_ptr<ChannelIDStore::ChannelID> channel_id) { |
| 448 DCHECK(CalledOnValidThread()); | 449 DCHECK(CalledOnValidThread()); |
| 449 | 450 |
| 450 scoped_ptr<crypto::ECPrivateKey> key; | 451 scoped_ptr<crypto::ECPrivateKey> key; |
| 451 if (error == OK) { | 452 if (error == OK) { |
| 452 key.reset(channel_id->key()->Copy()); | 453 key.reset(channel_id->key()->Copy()); |
| 453 channel_id_store_->SetChannelID(channel_id.Pass()); | 454 channel_id_store_->SetChannelID(std::move(channel_id)); |
| 454 } | 455 } |
| 455 HandleResult(error, server_identifier, key.Pass()); | 456 HandleResult(error, server_identifier, std::move(key)); |
| 456 } | 457 } |
| 457 | 458 |
| 458 void ChannelIDService::HandleResult(int error, | 459 void ChannelIDService::HandleResult(int error, |
| 459 const std::string& server_identifier, | 460 const std::string& server_identifier, |
| 460 scoped_ptr<crypto::ECPrivateKey> key) { | 461 scoped_ptr<crypto::ECPrivateKey> key) { |
| 461 DCHECK(CalledOnValidThread()); | 462 DCHECK(CalledOnValidThread()); |
| 462 | 463 |
| 463 std::map<std::string, ChannelIDServiceJob*>::iterator j; | 464 std::map<std::string, ChannelIDServiceJob*>::iterator j; |
| 464 j = inflight_.find(server_identifier); | 465 j = inflight_.find(server_identifier); |
| 465 if (j == inflight_.end()) { | 466 if (j == inflight_.end()) { |
| 466 NOTREACHED(); | 467 NOTREACHED(); |
| 467 return; | 468 return; |
| 468 } | 469 } |
| 469 ChannelIDServiceJob* job = j->second; | 470 ChannelIDServiceJob* job = j->second; |
| 470 inflight_.erase(j); | 471 inflight_.erase(j); |
| 471 | 472 |
| 472 job->HandleResult(error, key.Pass()); | 473 job->HandleResult(error, std::move(key)); |
| 473 delete job; | 474 delete job; |
| 474 } | 475 } |
| 475 | 476 |
| 476 bool ChannelIDService::JoinToInFlightRequest( | 477 bool ChannelIDService::JoinToInFlightRequest( |
| 477 const base::TimeTicks& request_start, | 478 const base::TimeTicks& request_start, |
| 478 const std::string& domain, | 479 const std::string& domain, |
| 479 scoped_ptr<crypto::ECPrivateKey>* key, | 480 scoped_ptr<crypto::ECPrivateKey>* key, |
| 480 bool create_if_missing, | 481 bool create_if_missing, |
| 481 const CompletionCallback& callback, | 482 const CompletionCallback& callback, |
| 482 Request* out_req) { | 483 Request* out_req) { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 } | 531 } |
| 531 | 532 |
| 532 return err; | 533 return err; |
| 533 } | 534 } |
| 534 | 535 |
| 535 int ChannelIDService::channel_id_count() { | 536 int ChannelIDService::channel_id_count() { |
| 536 return channel_id_store_->GetChannelIDCount(); | 537 return channel_id_store_->GetChannelIDCount(); |
| 537 } | 538 } |
| 538 | 539 |
| 539 } // namespace net | 540 } // namespace net |
| OLD | NEW |