| OLD | NEW |
| 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/cert_verifier.h" | 5 #include "net/base/origin_bound_cert_service.h" |
| 6 |
| 7 #include <limits> |
| 6 | 8 |
| 7 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
| 10 #include "base/logging.h" |
| 11 #include "base/memory/ref_counted.h" |
| 12 #include "base/memory/scoped_ptr.h" |
| 8 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
| 14 #include "base/rand_util.h" |
| 9 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
| 10 #include "base/synchronization/lock.h" | |
| 11 #include "base/threading/worker_pool.h" | 16 #include "base/threading/worker_pool.h" |
| 17 #include "crypto/rsa_private_key.h" |
| 12 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
| 19 #include "net/base/origin_bound_cert_store.h" |
| 13 #include "net/base/x509_certificate.h" | 20 #include "net/base/x509_certificate.h" |
| 14 | 21 |
| 15 #if defined(USE_NSS) | 22 #if defined(USE_NSS) |
| 16 #include <private/pprthred.h> // PR_DetachThread | 23 #include <private/pprthred.h> // PR_DetachThread |
| 17 #endif | 24 #endif |
| 18 | 25 |
| 19 namespace net { | 26 namespace net { |
| 20 | 27 |
| 21 //////////////////////////////////////////////////////////////////////////// | |
| 22 | |
| 23 // Life of a request: | |
| 24 // | |
| 25 // CertVerifier CertVerifierJob CertVerifierWorker Request | |
| 26 // | (origin loop) (worker loop) | |
| 27 // | | |
| 28 // Verify() | |
| 29 // |---->-------------------<creates> | |
| 30 // | | |
| 31 // |---->----<creates> | |
| 32 // | | |
| 33 // |---->---------------------------------------------------<creates> | |
| 34 // | | |
| 35 // |---->--------------------Start | |
| 36 // | | | |
| 37 // | PostTask | |
| 38 // | | |
| 39 // | <starts verifying> | |
| 40 // |---->-----AddRequest | | |
| 41 // | | |
| 42 // | | |
| 43 // | | |
| 44 // Finish | |
| 45 // | | |
| 46 // PostTask | |
| 47 // | |
| 48 // | | |
| 49 // DoReply | |
| 50 // |----<-----------------------| | |
| 51 // HandleResult | |
| 52 // | | |
| 53 // |---->-----HandleResult | |
| 54 // | | |
| 55 // |------>-----------------------------------Post | |
| 56 // | |
| 57 // | |
| 58 // | |
| 59 // On a cache hit, CertVerifier::Verify() returns synchronously without | |
| 60 // posting a task to a worker thread. | |
| 61 | |
| 62 // The number of CachedCertVerifyResult objects that we'll cache. | |
| 63 static const unsigned kMaxCacheEntries = 256; | |
| 64 | |
| 65 // The number of seconds for which we'll cache a cache entry. | |
| 66 static const unsigned kTTLSecs = 1800; // 30 minutes. | |
| 67 | |
| 68 namespace { | 28 namespace { |
| 69 | 29 |
| 70 class DefaultTimeService : public CertVerifier::TimeService { | 30 const int kKeySizeInBits = 1024; |
| 71 public: | 31 const int kValidityPeriodInDays = 365; |
| 72 // CertVerifier::TimeService methods: | |
| 73 virtual base::Time Now() { return base::Time::Now(); } | |
| 74 }; | |
| 75 | 32 |
| 76 } // namespace | 33 } // namespace |
| 77 | 34 |
| 78 CachedCertVerifyResult::CachedCertVerifyResult() : error(ERR_FAILED) { | |
| 79 } | |
| 80 | |
| 81 CachedCertVerifyResult::~CachedCertVerifyResult() {} | |
| 82 | |
| 83 bool CachedCertVerifyResult::HasExpired(const base::Time current_time) const { | |
| 84 return current_time >= expiry; | |
| 85 } | |
| 86 | |
| 87 // Represents the output and result callback of a request. | 35 // Represents the output and result callback of a request. |
| 88 class CertVerifierRequest { | 36 class OriginBoundCertServiceRequest { |
| 89 public: | 37 public: |
| 90 CertVerifierRequest(CompletionCallback* callback, | 38 OriginBoundCertServiceRequest(CompletionCallback* callback, |
| 91 CertVerifyResult* verify_result) | 39 std::string* private_key, |
| 40 std::string* cert) |
| 92 : callback_(callback), | 41 : callback_(callback), |
| 93 verify_result_(verify_result) { | 42 private_key_(private_key), |
| 43 cert_(cert) { |
| 94 } | 44 } |
| 95 | 45 |
| 96 // Ensures that the result callback will never be made. | 46 // Ensures that the result callback will never be made. |
| 97 void Cancel() { | 47 void Cancel() { |
| 98 callback_ = NULL; | 48 callback_ = NULL; |
| 99 verify_result_ = NULL; | 49 private_key_ = NULL; |
| 50 cert_ = NULL; |
| 100 } | 51 } |
| 101 | 52 |
| 102 // Copies the contents of |verify_result| to the caller's | 53 // Copies the contents of |private_key| and |cert| to the caller's fields |
| 103 // CertVerifyResult and calls the callback. | 54 // and calls the callback. |
| 104 void Post(const CachedCertVerifyResult& verify_result) { | 55 void Post(int error, |
| 56 const std::string& private_key, |
| 57 const std::string& cert) { |
| 105 if (callback_) { | 58 if (callback_) { |
| 106 *verify_result_ = verify_result.result; | 59 *private_key_ = private_key; |
| 107 callback_->Run(verify_result.error); | 60 *cert_ = cert; |
| 61 callback_->Run(error); |
| 108 } | 62 } |
| 109 delete this; | 63 delete this; |
| 110 } | 64 } |
| 111 | 65 |
| 112 bool canceled() const { return !callback_; } | 66 bool canceled() const { return !callback_; } |
| 113 | 67 |
| 114 private: | 68 private: |
| 115 CompletionCallback* callback_; | 69 CompletionCallback* callback_; |
| 116 CertVerifyResult* verify_result_; | 70 std::string* private_key_; |
| 71 std::string* cert_; |
| 117 }; | 72 }; |
| 118 | 73 |
| 119 | 74 // OriginBoundCertServiceWorker runs on a worker thread and takes care of the |
| 120 // CertVerifierWorker runs on a worker thread and takes care of the blocking | 75 // blocking process of performing key generation. Deletes itself eventually |
| 121 // process of performing the certificate verification. Deletes itself | 76 // if Start() succeeds. |
| 122 // eventually if Start() succeeds. | 77 class OriginBoundCertServiceWorker { |
| 123 class CertVerifierWorker { | |
| 124 public: | 78 public: |
| 125 CertVerifierWorker(X509Certificate* cert, | 79 OriginBoundCertServiceWorker( |
| 126 const std::string& hostname, | 80 const std::string& origin, |
| 127 int flags, | 81 OriginBoundCertService* origin_bound_cert_service) |
| 128 CertVerifier* cert_verifier) | 82 : origin_(origin), |
| 129 : cert_(cert), | |
| 130 hostname_(hostname), | |
| 131 flags_(flags), | |
| 132 origin_loop_(MessageLoop::current()), | 83 origin_loop_(MessageLoop::current()), |
| 133 cert_verifier_(cert_verifier), | 84 origin_bound_cert_service_(origin_bound_cert_service), |
| 134 canceled_(false), | 85 canceled_(false), |
| 135 error_(ERR_FAILED) { | 86 error_(ERR_FAILED) { |
| 136 } | 87 } |
| 137 | 88 |
| 138 bool Start() { | 89 bool Start() { |
| 139 DCHECK_EQ(MessageLoop::current(), origin_loop_); | 90 DCHECK_EQ(MessageLoop::current(), origin_loop_); |
| 140 | 91 |
| 141 return base::WorkerPool::PostTask( | 92 return base::WorkerPool::PostTask( |
| 142 FROM_HERE, NewRunnableMethod(this, &CertVerifierWorker::Run), | 93 FROM_HERE, |
| 94 NewRunnableMethod(this, &OriginBoundCertServiceWorker::Run), |
| 143 true /* task is slow */); | 95 true /* task is slow */); |
| 144 } | 96 } |
| 145 | 97 |
| 146 // Cancel is called from the origin loop when the CertVerifier is getting | 98 // Cancel is called from the origin loop when the OriginBoundCertService is |
| 147 // deleted. | 99 // getting deleted. |
| 148 void Cancel() { | 100 void Cancel() { |
| 149 DCHECK_EQ(MessageLoop::current(), origin_loop_); | 101 DCHECK_EQ(MessageLoop::current(), origin_loop_); |
| 150 base::AutoLock locked(lock_); | 102 base::AutoLock locked(lock_); |
| 151 canceled_ = true; | 103 canceled_ = true; |
| 152 } | 104 } |
| 153 | 105 |
| 154 private: | 106 private: |
| 155 void Run() { | 107 void Run() { |
| 108 uint32 serial_number = base::RandInt(0, std::numeric_limits<int>::max()); |
| 156 // Runs on a worker thread. | 109 // Runs on a worker thread. |
| 157 error_ = cert_->Verify(hostname_, flags_, &verify_result_); | 110 error_ = origin_bound_cert_service_->GenerateCert(origin_, |
| 111 serial_number, |
| 112 &private_key_, |
| 113 &cert_); |
| 158 #if defined(USE_NSS) | 114 #if defined(USE_NSS) |
| 159 // Detach the thread from NSPR. | 115 // Detach the thread from NSPR. |
| 160 // Calling NSS functions attaches the thread to NSPR, which stores | 116 // Calling NSS functions attaches the thread to NSPR, which stores |
| 161 // the NSPR thread ID in thread-specific data. | 117 // the NSPR thread ID in thread-specific data. |
| 162 // The threads in our thread pool terminate after we have called | 118 // The threads in our thread pool terminate after we have called |
| 163 // PR_Cleanup. Unless we detach them from NSPR, net_unittests gets | 119 // PR_Cleanup. Unless we detach them from NSPR, net_unittests gets |
| 164 // segfaults on shutdown when the threads' thread-specific data | 120 // segfaults on shutdown when the threads' thread-specific data |
| 165 // destructors run. | 121 // destructors run. |
| 166 PR_DetachThread(); | 122 PR_DetachThread(); |
| 167 #endif | 123 #endif |
| 168 Finish(); | 124 Finish(); |
| 169 } | 125 } |
| 170 | 126 |
| 171 // DoReply runs on the origin thread. | 127 // DoReply runs on the origin thread. |
| 172 void DoReply() { | 128 void DoReply() { |
| 173 DCHECK_EQ(MessageLoop::current(), origin_loop_); | 129 DCHECK_EQ(MessageLoop::current(), origin_loop_); |
| 174 { | 130 { |
| 175 // We lock here because the worker thread could still be in Finished, | 131 // We lock here because the worker thread could still be in Finished, |
| 176 // after the PostTask, but before unlocking |lock_|. If we do not lock in | 132 // after the PostTask, but before unlocking |lock_|. If we do not lock in |
| 177 // this case, we will end up deleting a locked Lock, which can lead to | 133 // this case, we will end up deleting a locked Lock, which can lead to |
| 178 // memory leaks or worse errors. | 134 // memory leaks or worse errors. |
| 179 base::AutoLock locked(lock_); | 135 base::AutoLock locked(lock_); |
| 180 if (!canceled_) { | 136 if (!canceled_) { |
| 181 cert_verifier_->HandleResult(cert_, hostname_, flags_, | 137 origin_bound_cert_service_->HandleResult( |
| 182 error_, verify_result_); | 138 origin_, error_, private_key_, cert_); |
| 183 } | 139 } |
| 184 } | 140 } |
| 185 delete this; | 141 delete this; |
| 186 } | 142 } |
| 187 | 143 |
| 188 void Finish() { | 144 void Finish() { |
| 189 // Runs on the worker thread. | 145 // Runs on the worker thread. |
| 190 // We assume that the origin loop outlives the CertVerifier. If the | 146 // We assume that the origin loop outlives the OriginBoundCertService. If |
| 191 // CertVerifier is deleted, it will call Cancel on us. If it does so | 147 // the OriginBoundCertService is deleted, it will call Cancel on us. If it |
| 192 // before the Acquire, we'll delete ourselves and return. If it's trying to | 148 // does so before the Acquire, we'll delete ourselves and return. If it's |
| 193 // do so concurrently, then it'll block on the lock and we'll call PostTask | 149 // trying to do so concurrently, then it'll block on the lock and we'll |
| 194 // while the CertVerifier (and therefore the MessageLoop) is still alive. | 150 // call PostTask while the OriginBoundCertService (and therefore the |
| 195 // If it does so after this function, we assume that the MessageLoop will | 151 // MessageLoop) is still alive. If it does so after this function, we |
| 196 // process pending tasks. In which case we'll notice the |canceled_| flag | 152 // assume that the MessageLoop will process pending tasks. In which case |
| 197 // in DoReply. | 153 // we'll notice the |canceled_| flag in DoReply. |
| 198 | 154 |
| 199 bool canceled; | 155 bool canceled; |
| 200 { | 156 { |
| 201 base::AutoLock locked(lock_); | 157 base::AutoLock locked(lock_); |
| 202 canceled = canceled_; | 158 canceled = canceled_; |
| 203 if (!canceled) { | 159 if (!canceled) { |
| 204 origin_loop_->PostTask( | 160 origin_loop_->PostTask( |
| 205 FROM_HERE, NewRunnableMethod(this, &CertVerifierWorker::DoReply)); | 161 FROM_HERE, |
| 162 NewRunnableMethod(this, &OriginBoundCertServiceWorker::DoReply)); |
| 206 } | 163 } |
| 207 } | 164 } |
| 208 | |
| 209 if (canceled) | 165 if (canceled) |
| 210 delete this; | 166 delete this; |
| 211 } | 167 } |
| 212 | 168 |
| 213 scoped_refptr<X509Certificate> cert_; | 169 const std::string origin_; |
| 214 const std::string hostname_; | |
| 215 const int flags_; | |
| 216 MessageLoop* const origin_loop_; | 170 MessageLoop* const origin_loop_; |
| 217 CertVerifier* const cert_verifier_; | 171 OriginBoundCertService* const origin_bound_cert_service_; |
| 218 | 172 |
| 219 // lock_ protects canceled_. | 173 // lock_ protects canceled_. |
| 220 base::Lock lock_; | 174 base::Lock lock_; |
| 221 | 175 |
| 222 // If canceled_ is true, | 176 // If canceled_ is true, |
| 223 // * origin_loop_ cannot be accessed by the worker thread, | 177 // * origin_loop_ cannot be accessed by the worker thread, |
| 224 // * cert_verifier_ cannot be accessed by any thread. | 178 // * origin_bound_cert_service_ cannot be accessed by any thread. |
| 225 bool canceled_; | 179 bool canceled_; |
| 226 | 180 |
| 227 int error_; | 181 int error_; |
| 228 CertVerifyResult verify_result_; | 182 std::string private_key_; |
| 183 std::string cert_; |
| 229 | 184 |
| 230 DISALLOW_COPY_AND_ASSIGN(CertVerifierWorker); | 185 DISALLOW_COPY_AND_ASSIGN(OriginBoundCertServiceWorker); |
| 231 }; | 186 }; |
| 232 | 187 |
| 233 // A CertVerifierJob is a one-to-one counterpart of a CertVerifierWorker. It | 188 // An OriginBoundCertServiceJob is a one-to-one counterpart of an |
| 234 // lives only on the CertVerifier's origin message loop. | 189 // OriginBoundCertServiceWorker. It lives only on the OriginBoundCertService's |
| 235 class CertVerifierJob { | 190 // origin message loop. |
| 191 class OriginBoundCertServiceJob { |
| 236 public: | 192 public: |
| 237 explicit CertVerifierJob(CertVerifierWorker* worker) : worker_(worker) { | 193 explicit OriginBoundCertServiceJob(OriginBoundCertServiceWorker* worker) |
| 194 : worker_(worker) { |
| 238 } | 195 } |
| 239 | 196 |
| 240 ~CertVerifierJob() { | 197 ~OriginBoundCertServiceJob() { |
| 241 if (worker_) { | 198 if (worker_) { |
| 242 worker_->Cancel(); | 199 worker_->Cancel(); |
| 243 DeleteAllCanceled(); | 200 DeleteAllCanceled(); |
| 244 } | 201 } |
| 245 } | 202 } |
| 246 | 203 |
| 247 void AddRequest(CertVerifierRequest* request) { | 204 void AddRequest(OriginBoundCertServiceRequest* request) { |
| 248 requests_.push_back(request); | 205 requests_.push_back(request); |
| 249 } | 206 } |
| 250 | 207 |
| 251 void HandleResult(const CachedCertVerifyResult& verify_result) { | 208 void HandleResult(int error, |
| 209 const std::string& private_key, |
| 210 const std::string& cert) { |
| 252 worker_ = NULL; | 211 worker_ = NULL; |
| 253 PostAll(verify_result); | 212 PostAll(error, private_key, cert); |
| 254 } | 213 } |
| 255 | 214 |
| 256 private: | 215 private: |
| 257 void PostAll(const CachedCertVerifyResult& verify_result) { | 216 void PostAll(int error, |
| 258 std::vector<CertVerifierRequest*> requests; | 217 const std::string& private_key, |
| 218 const std::string& cert) { |
| 219 std::vector<OriginBoundCertServiceRequest*> requests; |
| 259 requests_.swap(requests); | 220 requests_.swap(requests); |
| 260 | 221 |
| 261 for (std::vector<CertVerifierRequest*>::iterator | 222 for (std::vector<OriginBoundCertServiceRequest*>::iterator |
| 262 i = requests.begin(); i != requests.end(); i++) { | 223 i = requests.begin(); i != requests.end(); i++) { |
| 263 (*i)->Post(verify_result); | 224 (*i)->Post(error, private_key, cert); |
| 264 // Post() causes the CertVerifierRequest to delete itself. | 225 // Post() causes the OriginBoundCertServiceRequest to delete itself. |
| 265 } | 226 } |
| 266 } | 227 } |
| 267 | 228 |
| 268 void DeleteAllCanceled() { | 229 void DeleteAllCanceled() { |
| 269 for (std::vector<CertVerifierRequest*>::iterator | 230 for (std::vector<OriginBoundCertServiceRequest*>::iterator |
| 270 i = requests_.begin(); i != requests_.end(); i++) { | 231 i = requests_.begin(); i != requests_.end(); i++) { |
| 271 if ((*i)->canceled()) { | 232 if ((*i)->canceled()) { |
| 272 delete *i; | 233 delete *i; |
| 273 } else { | 234 } else { |
| 274 LOG(DFATAL) << "CertVerifierRequest leaked!"; | 235 LOG(DFATAL) << "OriginBoundCertServiceRequest leaked!"; |
| 275 } | 236 } |
| 276 } | 237 } |
| 277 } | 238 } |
| 278 | 239 |
| 279 std::vector<CertVerifierRequest*> requests_; | 240 std::vector<OriginBoundCertServiceRequest*> requests_; |
| 280 CertVerifierWorker* worker_; | 241 OriginBoundCertServiceWorker* worker_; |
| 281 }; | 242 }; |
| 282 | 243 |
| 283 | 244 OriginBoundCertService::OriginBoundCertService( |
| 284 CertVerifier::CertVerifier() | 245 OriginBoundCertStore* origin_bound_cert_store) |
| 285 : time_service_(new DefaultTimeService), | 246 : origin_bound_cert_store_(origin_bound_cert_store), |
| 286 requests_(0), | 247 requests_(0), |
| 287 cache_hits_(0), | 248 cache_hits_(0), |
| 288 inflight_joins_(0) { | 249 inflight_joins_(0) {} |
| 289 CertDatabase::AddObserver(this); | 250 |
| 251 OriginBoundCertService::~OriginBoundCertService() { |
| 252 STLDeleteValues(&inflight_); |
| 290 } | 253 } |
| 291 | 254 |
| 292 CertVerifier::CertVerifier(TimeService* time_service) | 255 int OriginBoundCertService::GetOriginBoundCert(const std::string& origin, |
| 293 : time_service_(time_service), | 256 std::string* private_key, |
| 294 requests_(0), | 257 std::string* cert, |
| 295 cache_hits_(0), | 258 CompletionCallback* callback, |
| 296 inflight_joins_(0) { | 259 RequestHandle* out_req) { |
| 297 CertDatabase::AddObserver(this); | |
| 298 } | |
| 299 | 260 |
| 300 CertVerifier::~CertVerifier() { | |
| 301 STLDeleteValues(&inflight_); | |
| 302 | |
| 303 CertDatabase::RemoveObserver(this); | |
| 304 } | |
| 305 | |
| 306 int CertVerifier::Verify(X509Certificate* cert, | |
| 307 const std::string& hostname, | |
| 308 int flags, | |
| 309 CertVerifyResult* verify_result, | |
| 310 CompletionCallback* callback, | |
| 311 RequestHandle* out_req) { | |
| 312 DCHECK(CalledOnValidThread()); | 261 DCHECK(CalledOnValidThread()); |
| 313 | 262 |
| 314 if (!callback || !verify_result || hostname.empty()) { | 263 if (!callback || !private_key || !cert || origin.empty()) { |
| 315 *out_req = NULL; | 264 *out_req = NULL; |
| 316 return ERR_INVALID_ARGUMENT; | 265 return ERR_INVALID_ARGUMENT; |
| 317 } | 266 } |
| 318 | 267 |
| 319 requests_++; | 268 requests_++; |
| 320 | 269 |
| 321 const RequestParams key = {cert->fingerprint(), hostname, flags}; | 270 // Check if an origin bound cert already exists for this origin. |
| 322 // First check the cache. | 271 if (origin_bound_cert_store_->GetOriginBoundCert(origin, |
| 323 std::map<RequestParams, CachedCertVerifyResult>::iterator i; | 272 private_key, |
| 324 i = cache_.find(key); | 273 cert)) { |
| 325 if (i != cache_.end()) { | 274 cache_hits_++; |
| 326 if (!i->second.HasExpired(time_service_->Now())) { | 275 *out_req = NULL; |
| 327 cache_hits_++; | 276 return OK; |
| 328 *out_req = NULL; | |
| 329 *verify_result = i->second.result; | |
| 330 return i->second.error; | |
| 331 } | |
| 332 // Cache entry has expired. | |
| 333 cache_.erase(i); | |
| 334 } | 277 } |
| 335 | 278 |
| 336 // No cache hit. See if an identical request is currently in flight. | 279 // No cache hit. See if an identical request is currently in flight. |
| 337 CertVerifierJob* job; | 280 OriginBoundCertServiceJob* job; |
| 338 std::map<RequestParams, CertVerifierJob*>::const_iterator j; | 281 std::map<std::string, OriginBoundCertServiceJob*>::const_iterator j; |
| 339 j = inflight_.find(key); | 282 j = inflight_.find(origin); |
| 340 if (j != inflight_.end()) { | 283 if (j != inflight_.end()) { |
| 341 // An identical request is in flight already. We'll just attach our | 284 // An identical request is in flight already. We'll just attach our |
| 342 // callback. | 285 // callback. |
| 343 inflight_joins_++; | 286 inflight_joins_++; |
| 344 job = j->second; | 287 job = j->second; |
| 345 } else { | 288 } else { |
| 346 // Need to make a new request. | 289 // Need to make a new request. |
| 347 CertVerifierWorker* worker = new CertVerifierWorker(cert, hostname, flags, | 290 OriginBoundCertServiceWorker* worker = |
| 348 this); | 291 new OriginBoundCertServiceWorker(origin, this); |
| 349 job = new CertVerifierJob(worker); | 292 job = new OriginBoundCertServiceJob(worker); |
| 350 if (!worker->Start()) { | 293 if (!worker->Start()) { |
| 351 delete job; | 294 delete job; |
| 352 delete worker; | 295 delete worker; |
| 353 *out_req = NULL; | 296 *out_req = NULL; |
| 354 // TODO(wtc): log to the NetLog. | 297 // TODO(rkn): Log to the NetLog. |
| 355 LOG(ERROR) << "CertVerifierWorker couldn't be started."; | 298 LOG(ERROR) << "OriginBoundCertServiceWorker couldn't be started."; |
| 356 return ERR_INSUFFICIENT_RESOURCES; // Just a guess. | 299 return ERR_INSUFFICIENT_RESOURCES; // Just a guess. |
| 357 } | 300 } |
| 358 inflight_.insert(std::make_pair(key, job)); | 301 inflight_[origin] = job; |
| 359 } | 302 } |
| 360 | 303 |
| 361 CertVerifierRequest* request = | 304 OriginBoundCertServiceRequest* request = |
| 362 new CertVerifierRequest(callback, verify_result); | 305 new OriginBoundCertServiceRequest(callback, private_key, cert); |
| 363 job->AddRequest(request); | 306 job->AddRequest(request); |
| 364 *out_req = request; | 307 *out_req = request; |
| 365 return ERR_IO_PENDING; | 308 return ERR_IO_PENDING; |
| 366 } | 309 } |
| 367 | 310 |
| 368 void CertVerifier::CancelRequest(RequestHandle req) { | 311 int OriginBoundCertService::GenerateCert(const std::string& origin, |
| 312 uint32 serial_number, |
| 313 std::string* private_key, |
| 314 std::string* cert) { |
| 315 std::string subject = "CN=OBC"; |
| 316 scoped_ptr<crypto::RSAPrivateKey> key( |
| 317 crypto::RSAPrivateKey::Create(kKeySizeInBits)); |
| 318 if (!key.get()) { |
| 319 LOG(WARNING) << "Unable to create key pair for client"; |
| 320 return ERR_FAILED; |
| 321 } |
| 322 |
| 323 scoped_refptr<X509Certificate> x509_cert = X509Certificate::CreateSelfSigned( |
| 324 key.get(), |
| 325 subject, |
| 326 serial_number, |
| 327 base::TimeDelta::FromDays(kValidityPeriodInDays)); |
| 328 if (!x509_cert) { |
| 329 LOG(WARNING) << "Unable to create x509 cert for client"; |
| 330 return ERR_FAILED; |
| 331 } |
| 332 |
| 333 std::vector<uint8> private_key_info; |
| 334 if (!key->ExportPrivateKey(&private_key_info)) { |
| 335 LOG(WARNING) << "Unable to export private key"; |
| 336 return ERR_FAILED; |
| 337 } |
| 338 // TODO(rkn): Perhaps ExportPrivateKey should be changed to output a |
| 339 // std::string* to prevent this copying. |
| 340 std::string key_out(private_key_info.begin(), private_key_info.end()); |
| 341 |
| 342 std::string der_cert; |
| 343 if (!x509_cert->GetDEREncoded(&der_cert)) { |
| 344 LOG(WARNING) << "Unable to get DER-enconded cert"; |
| 345 return ERR_FAILED; |
| 346 } |
| 347 |
| 348 private_key->swap(key_out); |
| 349 cert->swap(der_cert); |
| 350 return OK; |
| 351 } |
| 352 |
| 353 void OriginBoundCertService::CancelRequest(RequestHandle req) { |
| 369 DCHECK(CalledOnValidThread()); | 354 DCHECK(CalledOnValidThread()); |
| 370 CertVerifierRequest* request = reinterpret_cast<CertVerifierRequest*>(req); | 355 OriginBoundCertServiceRequest* request = |
| 356 reinterpret_cast<OriginBoundCertServiceRequest*>(req); |
| 371 request->Cancel(); | 357 request->Cancel(); |
| 372 } | 358 } |
| 373 | 359 |
| 374 void CertVerifier::ClearCache() { | 360 // HandleResult is called by OriginBoundCertServiceWorker on the origin message |
| 361 // loop. It deletes OriginBoundCertServiceJob. |
| 362 void OriginBoundCertService::HandleResult(const std::string& origin, |
| 363 int error, |
| 364 const std::string& private_key, |
| 365 const std::string& cert) { |
| 375 DCHECK(CalledOnValidThread()); | 366 DCHECK(CalledOnValidThread()); |
| 376 | 367 |
| 377 cache_.clear(); | 368 origin_bound_cert_store_->SetOriginBoundCert(origin, private_key, cert); |
| 378 // Leaves inflight_ alone. | |
| 379 } | |
| 380 | 369 |
| 381 size_t CertVerifier::GetCacheSize() const { | 370 std::map<std::string, OriginBoundCertServiceJob*>::iterator j; |
| 382 DCHECK(CalledOnValidThread()); | 371 j = inflight_.find(origin); |
| 383 | |
| 384 return cache_.size(); | |
| 385 } | |
| 386 | |
| 387 // HandleResult is called by CertVerifierWorker on the origin message loop. | |
| 388 // It deletes CertVerifierJob. | |
| 389 void CertVerifier::HandleResult(X509Certificate* cert, | |
| 390 const std::string& hostname, | |
| 391 int flags, | |
| 392 int error, | |
| 393 const CertVerifyResult& verify_result) { | |
| 394 DCHECK(CalledOnValidThread()); | |
| 395 | |
| 396 const base::Time current_time(time_service_->Now()); | |
| 397 | |
| 398 CachedCertVerifyResult cached_result; | |
| 399 cached_result.error = error; | |
| 400 cached_result.result = verify_result; | |
| 401 uint32 ttl = kTTLSecs; | |
| 402 cached_result.expiry = current_time + base::TimeDelta::FromSeconds(ttl); | |
| 403 | |
| 404 const RequestParams key = {cert->fingerprint(), hostname, flags}; | |
| 405 | |
| 406 DCHECK_GE(kMaxCacheEntries, 1u); | |
| 407 DCHECK_LE(cache_.size(), kMaxCacheEntries); | |
| 408 if (cache_.size() == kMaxCacheEntries) { | |
| 409 // Need to remove an element of the cache. | |
| 410 std::map<RequestParams, CachedCertVerifyResult>::iterator i, cur; | |
| 411 for (i = cache_.begin(); i != cache_.end(); ) { | |
| 412 cur = i++; | |
| 413 if (cur->second.HasExpired(current_time)) | |
| 414 cache_.erase(cur); | |
| 415 } | |
| 416 } | |
| 417 if (cache_.size() == kMaxCacheEntries) { | |
| 418 // If we didn't clear out any expired entries, we just remove the first | |
| 419 // element. Crummy but simple. | |
| 420 cache_.erase(cache_.begin()); | |
| 421 } | |
| 422 | |
| 423 cache_.insert(std::make_pair(key, cached_result)); | |
| 424 | |
| 425 std::map<RequestParams, CertVerifierJob*>::iterator j; | |
| 426 j = inflight_.find(key); | |
| 427 if (j == inflight_.end()) { | 372 if (j == inflight_.end()) { |
| 428 NOTREACHED(); | 373 NOTREACHED(); |
| 429 return; | 374 return; |
| 430 } | 375 } |
| 431 CertVerifierJob* job = j->second; | 376 OriginBoundCertServiceJob* job = j->second; |
| 432 inflight_.erase(j); | 377 inflight_.erase(j); |
| 433 | 378 |
| 434 job->HandleResult(cached_result); | 379 job->HandleResult(error, private_key, cert); |
| 435 delete job; | 380 delete job; |
| 436 } | 381 } |
| 437 | 382 |
| 438 void CertVerifier::OnCertTrustChanged(const X509Certificate* cert) { | 383 int OriginBoundCertService::GetCertCount() { |
| 439 DCHECK(CalledOnValidThread()); | 384 return origin_bound_cert_store_->GetCertCount(); |
| 440 | |
| 441 ClearCache(); | |
| 442 } | |
| 443 | |
| 444 ///////////////////////////////////////////////////////////////////// | |
| 445 | |
| 446 SingleRequestCertVerifier::SingleRequestCertVerifier( | |
| 447 CertVerifier* cert_verifier) | |
| 448 : cert_verifier_(cert_verifier), | |
| 449 cur_request_(NULL), | |
| 450 cur_request_callback_(NULL), | |
| 451 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 452 callback_(this, &SingleRequestCertVerifier::OnVerifyCompletion)) { | |
| 453 DCHECK(cert_verifier_ != NULL); | |
| 454 } | |
| 455 | |
| 456 SingleRequestCertVerifier::~SingleRequestCertVerifier() { | |
| 457 if (cur_request_) { | |
| 458 cert_verifier_->CancelRequest(cur_request_); | |
| 459 cur_request_ = NULL; | |
| 460 } | |
| 461 } | |
| 462 | |
| 463 int SingleRequestCertVerifier::Verify(X509Certificate* cert, | |
| 464 const std::string& hostname, | |
| 465 int flags, | |
| 466 CertVerifyResult* verify_result, | |
| 467 CompletionCallback* callback) { | |
| 468 // Should not be already in use. | |
| 469 DCHECK(!cur_request_ && !cur_request_callback_); | |
| 470 | |
| 471 // Do a synchronous verification. | |
| 472 if (!callback) | |
| 473 return cert->Verify(hostname, flags, verify_result); | |
| 474 | |
| 475 CertVerifier::RequestHandle request = NULL; | |
| 476 | |
| 477 // We need to be notified of completion before |callback| is called, so that | |
| 478 // we can clear out |cur_request_*|. | |
| 479 int rv = cert_verifier_->Verify( | |
| 480 cert, hostname, flags, verify_result, &callback_, &request); | |
| 481 | |
| 482 if (rv == ERR_IO_PENDING) { | |
| 483 // Cleared in OnVerifyCompletion(). | |
| 484 cur_request_ = request; | |
| 485 cur_request_callback_ = callback; | |
| 486 } | |
| 487 | |
| 488 return rv; | |
| 489 } | |
| 490 | |
| 491 void SingleRequestCertVerifier::OnVerifyCompletion(int result) { | |
| 492 DCHECK(cur_request_ && cur_request_callback_); | |
| 493 | |
| 494 CompletionCallback* callback = cur_request_callback_; | |
| 495 | |
| 496 // Clear the outstanding request information. | |
| 497 cur_request_ = NULL; | |
| 498 cur_request_callback_ = NULL; | |
| 499 | |
| 500 // Call the user's original callback. | |
| 501 callback->Run(result); | |
| 502 } | 385 } |
| 503 | 386 |
| 504 } // namespace net | 387 } // namespace net |
| 505 | 388 |
| 506 DISABLE_RUNNABLE_METHOD_REFCOUNT(net::CertVerifierWorker); | 389 DISABLE_RUNNABLE_METHOD_REFCOUNT(net::OriginBoundCertServiceWorker); |
| OLD | NEW |