OLD | NEW |
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/ocsp/nss_ocsp.h" | 5 #include "net/ocsp/nss_ocsp.h" |
6 | 6 |
7 #include <certt.h> | 7 #include <certt.h> |
8 #include <certdb.h> | 8 #include <certdb.h> |
9 #include <ocsp.h> | 9 #include <ocsp.h> |
10 #include <nspr.h> | 10 #include <nspr.h> |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 | 100 |
101 private: | 101 private: |
102 friend struct base::DefaultLazyInstanceTraits<OCSPIOLoop>; | 102 friend struct base::DefaultLazyInstanceTraits<OCSPIOLoop>; |
103 | 103 |
104 OCSPIOLoop(); | 104 OCSPIOLoop(); |
105 ~OCSPIOLoop(); | 105 ~OCSPIOLoop(); |
106 | 106 |
107 void CancelAllRequests(); | 107 void CancelAllRequests(); |
108 | 108 |
109 mutable base::Lock lock_; | 109 mutable base::Lock lock_; |
110 bool shutdown_; // Protected by |lock_|. | 110 bool shutdown_; // Protected by |lock_|. |
111 std::set<OCSPRequestSession*> requests_; // Protected by |lock_|. | 111 std::set<OCSPRequestSession*> requests_; // Protected by |lock_|. |
112 bool used_; // Protected by |lock_|. | 112 bool used_; // Protected by |lock_|. |
113 // This should not be modified after |used_|. | 113 // This should not be modified after |used_|. |
114 base::MessageLoopForIO* io_loop_; // Protected by |lock_|. | 114 base::MessageLoopForIO* io_loop_; // Protected by |lock_|. |
115 base::ThreadChecker thread_checker_; | 115 base::ThreadChecker thread_checker_; |
116 | 116 |
117 DISALLOW_COPY_AND_ASSIGN(OCSPIOLoop); | 117 DISALLOW_COPY_AND_ASSIGN(OCSPIOLoop); |
118 }; | 118 }; |
119 | 119 |
120 base::LazyInstance<OCSPIOLoop>::Leaky | 120 base::LazyInstance<OCSPIOLoop>::Leaky g_ocsp_io_loop = |
121 g_ocsp_io_loop = LAZY_INSTANCE_INITIALIZER; | 121 LAZY_INSTANCE_INITIALIZER; |
122 | 122 |
123 const int kRecvBufferSize = 4096; | 123 const int kRecvBufferSize = 4096; |
124 | 124 |
125 // All OCSP handlers should be called in the context of | 125 // All OCSP handlers should be called in the context of |
126 // CertVerifier's thread (i.e. worker pool, not on the I/O thread). | 126 // CertVerifier's thread (i.e. worker pool, not on the I/O thread). |
127 // It supports blocking mode only. | 127 // It supports blocking mode only. |
128 | 128 |
129 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum, | 129 SECStatus OCSPCreateSession(const char* host, |
| 130 PRUint16 portnum, |
130 SEC_HTTP_SERVER_SESSION* pSession); | 131 SEC_HTTP_SERVER_SESSION* pSession); |
131 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session, | 132 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session, |
132 PRPollDesc **pPollDesc); | 133 PRPollDesc** pPollDesc); |
133 SECStatus OCSPFreeSession(SEC_HTTP_SERVER_SESSION session); | 134 SECStatus OCSPFreeSession(SEC_HTTP_SERVER_SESSION session); |
134 | 135 |
135 SECStatus OCSPCreate(SEC_HTTP_SERVER_SESSION session, | 136 SECStatus OCSPCreate(SEC_HTTP_SERVER_SESSION session, |
136 const char* http_protocol_variant, | 137 const char* http_protocol_variant, |
137 const char* path_and_query_string, | 138 const char* path_and_query_string, |
138 const char* http_request_method, | 139 const char* http_request_method, |
139 const PRIntervalTime timeout, | 140 const PRIntervalTime timeout, |
140 SEC_HTTP_REQUEST_SESSION* pRequest); | 141 SEC_HTTP_REQUEST_SESSION* pRequest); |
141 SECStatus OCSPSetPostData(SEC_HTTP_REQUEST_SESSION request, | 142 SECStatus OCSPSetPostData(SEC_HTTP_REQUEST_SESSION request, |
142 const char* http_data, | 143 const char* http_data, |
143 const PRUint32 http_data_len, | 144 const PRUint32 http_data_len, |
144 const char* http_content_type); | 145 const char* http_content_type); |
145 SECStatus OCSPAddHeader(SEC_HTTP_REQUEST_SESSION request, | 146 SECStatus OCSPAddHeader(SEC_HTTP_REQUEST_SESSION request, |
146 const char* http_header_name, | 147 const char* http_header_name, |
147 const char* http_header_value); | 148 const char* http_header_value); |
148 SECStatus OCSPTrySendAndReceive(SEC_HTTP_REQUEST_SESSION request, | 149 SECStatus OCSPTrySendAndReceive(SEC_HTTP_REQUEST_SESSION request, |
149 PRPollDesc** pPollDesc, | 150 PRPollDesc** pPollDesc, |
150 PRUint16* http_response_code, | 151 PRUint16* http_response_code, |
151 const char** http_response_content_type, | 152 const char** http_response_content_type, |
152 const char** http_response_headers, | 153 const char** http_response_headers, |
153 const char** http_response_data, | 154 const char** http_response_data, |
154 PRUint32* http_response_data_len); | 155 PRUint32* http_response_data_len); |
155 SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request); | 156 SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request); |
156 | 157 |
157 char* GetAlternateOCSPAIAInfo(CERTCertificate *cert); | 158 char* GetAlternateOCSPAIAInfo(CERTCertificate* cert); |
158 | 159 |
159 class OCSPNSSInitialization { | 160 class OCSPNSSInitialization { |
160 private: | 161 private: |
161 friend struct base::DefaultLazyInstanceTraits<OCSPNSSInitialization>; | 162 friend struct base::DefaultLazyInstanceTraits<OCSPNSSInitialization>; |
162 | 163 |
163 OCSPNSSInitialization(); | 164 OCSPNSSInitialization(); |
164 ~OCSPNSSInitialization(); | 165 ~OCSPNSSInitialization(); |
165 | 166 |
166 SEC_HttpClientFcn client_fcn_; | 167 SEC_HttpClientFcn client_fcn_; |
167 | 168 |
(...skipping 18 matching lines...) Expand all Loading... |
186 : url_(url), | 187 : url_(url), |
187 http_request_method_(http_request_method), | 188 http_request_method_(http_request_method), |
188 timeout_(timeout), | 189 timeout_(timeout), |
189 request_(NULL), | 190 request_(NULL), |
190 buffer_(new IOBuffer(kRecvBufferSize)), | 191 buffer_(new IOBuffer(kRecvBufferSize)), |
191 response_code_(-1), | 192 response_code_(-1), |
192 cv_(&lock_), | 193 cv_(&lock_), |
193 io_loop_(NULL), | 194 io_loop_(NULL), |
194 finished_(false) {} | 195 finished_(false) {} |
195 | 196 |
196 void SetPostData(const char* http_data, PRUint32 http_data_len, | 197 void SetPostData(const char* http_data, |
| 198 PRUint32 http_data_len, |
197 const char* http_content_type) { | 199 const char* http_content_type) { |
198 // |upload_content_| should not be modified if |request_| is active. | 200 // |upload_content_| should not be modified if |request_| is active. |
199 DCHECK(!request_); | 201 DCHECK(!request_); |
200 upload_content_.assign(http_data, http_data_len); | 202 upload_content_.assign(http_data, http_data_len); |
201 upload_content_type_.assign(http_content_type); | 203 upload_content_type_.assign(http_content_type); |
202 } | 204 } |
203 | 205 |
204 void AddHeader(const char* http_header_name, const char* http_header_value) { | 206 void AddHeader(const char* http_header_name, const char* http_header_value) { |
205 extra_request_headers_.SetHeader(http_header_name, | 207 extra_request_headers_.SetHeader(http_header_name, http_header_value); |
206 http_header_value); | |
207 } | 208 } |
208 | 209 |
209 void Start() { | 210 void Start() { |
210 // At this point, it runs on worker thread. | 211 // At this point, it runs on worker thread. |
211 // |io_loop_| was initialized to be NULL in constructor, and | 212 // |io_loop_| was initialized to be NULL in constructor, and |
212 // set only in StartURLRequest, so no need to lock |lock_| here. | 213 // set only in StartURLRequest, so no need to lock |lock_| here. |
213 DCHECK(!io_loop_); | 214 DCHECK(!io_loop_); |
214 g_ocsp_io_loop.Get().PostTaskToIOLoop( | 215 g_ocsp_io_loop.Get().PostTaskToIOLoop( |
215 FROM_HERE, | 216 FROM_HERE, base::Bind(&OCSPRequestSession::StartURLRequest, this)); |
216 base::Bind(&OCSPRequestSession::StartURLRequest, this)); | |
217 } | 217 } |
218 | 218 |
219 bool Started() const { | 219 bool Started() const { return request_ != NULL; } |
220 return request_ != NULL; | |
221 } | |
222 | 220 |
223 void Cancel() { | 221 void Cancel() { |
224 // IO thread may set |io_loop_| to NULL, so protect by |lock_|. | 222 // IO thread may set |io_loop_| to NULL, so protect by |lock_|. |
225 base::AutoLock autolock(lock_); | 223 base::AutoLock autolock(lock_); |
226 CancelLocked(); | 224 CancelLocked(); |
227 } | 225 } |
228 | 226 |
229 bool Finished() const { | 227 bool Finished() const { |
230 base::AutoLock autolock(lock_); | 228 base::AutoLock autolock(lock_); |
231 return finished_; | 229 return finished_; |
(...skipping 11 matching lines...) Expand all Loading... |
243 if (timeout < base::TimeDelta()) { | 241 if (timeout < base::TimeDelta()) { |
244 VLOG(1) << "OCSP Timed out"; | 242 VLOG(1) << "OCSP Timed out"; |
245 if (!finished_) | 243 if (!finished_) |
246 CancelLocked(); | 244 CancelLocked(); |
247 break; | 245 break; |
248 } | 246 } |
249 } | 247 } |
250 return finished_; | 248 return finished_; |
251 } | 249 } |
252 | 250 |
253 const GURL& url() const { | 251 const GURL& url() const { return url_; } |
254 return url_; | |
255 } | |
256 | 252 |
257 const std::string& http_request_method() const { | 253 const std::string& http_request_method() const { |
258 return http_request_method_; | 254 return http_request_method_; |
259 } | 255 } |
260 | 256 |
261 base::TimeDelta timeout() const { | 257 base::TimeDelta timeout() const { return timeout_; } |
262 return timeout_; | |
263 } | |
264 | 258 |
265 PRUint16 http_response_code() const { | 259 PRUint16 http_response_code() const { |
266 DCHECK(finished_); | 260 DCHECK(finished_); |
267 return response_code_; | 261 return response_code_; |
268 } | 262 } |
269 | 263 |
270 const std::string& http_response_content_type() const { | 264 const std::string& http_response_content_type() const { |
271 DCHECK(finished_); | 265 DCHECK(finished_); |
272 return response_content_type_; | 266 return response_content_type_; |
273 } | 267 } |
(...skipping 28 matching lines...) Expand all Loading... |
302 int bytes_read = 0; | 296 int bytes_read = 0; |
303 if (request->status().is_success()) { | 297 if (request->status().is_success()) { |
304 response_code_ = request_->GetResponseCode(); | 298 response_code_ = request_->GetResponseCode(); |
305 response_headers_ = request_->response_headers(); | 299 response_headers_ = request_->response_headers(); |
306 response_headers_->GetMimeType(&response_content_type_); | 300 response_headers_->GetMimeType(&response_content_type_); |
307 request_->Read(buffer_.get(), kRecvBufferSize, &bytes_read); | 301 request_->Read(buffer_.get(), kRecvBufferSize, &bytes_read); |
308 } | 302 } |
309 OnReadCompleted(request_, bytes_read); | 303 OnReadCompleted(request_, bytes_read); |
310 } | 304 } |
311 | 305 |
312 virtual void OnReadCompleted(URLRequest* request, | 306 virtual void OnReadCompleted(URLRequest* request, int bytes_read) OVERRIDE { |
313 int bytes_read) OVERRIDE { | |
314 DCHECK_EQ(request, request_); | 307 DCHECK_EQ(request, request_); |
315 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); | 308 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); |
316 | 309 |
317 do { | 310 do { |
318 if (!request_->status().is_success() || bytes_read <= 0) | 311 if (!request_->status().is_success() || bytes_read <= 0) |
319 break; | 312 break; |
320 data_.append(buffer_->data(), bytes_read); | 313 data_.append(buffer_->data(), bytes_read); |
321 } while (request_->Read(buffer_.get(), kRecvBufferSize, &bytes_read)); | 314 } while (request_->Read(buffer_.get(), kRecvBufferSize, &bytes_read)); |
322 | 315 |
323 if (!request_->status().is_io_pending()) { | 316 if (!request_->status().is_io_pending()) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 // |lock_| here. | 360 // |lock_| here. |
368 DCHECK(!request_); | 361 DCHECK(!request_); |
369 DCHECK(!io_loop_); | 362 DCHECK(!io_loop_); |
370 } | 363 } |
371 | 364 |
372 // Must call this method while holding |lock_|. | 365 // Must call this method while holding |lock_|. |
373 void CancelLocked() { | 366 void CancelLocked() { |
374 lock_.AssertAcquired(); | 367 lock_.AssertAcquired(); |
375 if (io_loop_) { | 368 if (io_loop_) { |
376 io_loop_->PostTask( | 369 io_loop_->PostTask( |
377 FROM_HERE, | 370 FROM_HERE, base::Bind(&OCSPRequestSession::CancelURLRequest, this)); |
378 base::Bind(&OCSPRequestSession::CancelURLRequest, this)); | |
379 } | 371 } |
380 } | 372 } |
381 | 373 |
382 // Runs on |g_ocsp_io_loop|'s IO loop. | 374 // Runs on |g_ocsp_io_loop|'s IO loop. |
383 void StartURLRequest() { | 375 void StartURLRequest() { |
384 DCHECK(!request_); | 376 DCHECK(!request_); |
385 | 377 |
386 pthread_mutex_lock(&g_request_context_lock); | 378 pthread_mutex_lock(&g_request_context_lock); |
387 URLRequestContext* url_request_context = g_request_context; | 379 URLRequestContext* url_request_context = g_request_context; |
388 pthread_mutex_unlock(&g_request_context_lock); | 380 pthread_mutex_unlock(&g_request_context_lock); |
(...skipping 12 matching lines...) Expand all Loading... |
401 new URLRequest(url_, DEFAULT_PRIORITY, this, url_request_context); | 393 new URLRequest(url_, DEFAULT_PRIORITY, this, url_request_context); |
402 // To meet the privacy requirements of incognito mode. | 394 // To meet the privacy requirements of incognito mode. |
403 request_->SetLoadFlags(LOAD_DISABLE_CACHE | LOAD_DO_NOT_SAVE_COOKIES | | 395 request_->SetLoadFlags(LOAD_DISABLE_CACHE | LOAD_DO_NOT_SAVE_COOKIES | |
404 LOAD_DO_NOT_SEND_COOKIES); | 396 LOAD_DO_NOT_SEND_COOKIES); |
405 | 397 |
406 if (http_request_method_ == "POST") { | 398 if (http_request_method_ == "POST") { |
407 DCHECK(!upload_content_.empty()); | 399 DCHECK(!upload_content_.empty()); |
408 DCHECK(!upload_content_type_.empty()); | 400 DCHECK(!upload_content_type_.empty()); |
409 | 401 |
410 request_->set_method("POST"); | 402 request_->set_method("POST"); |
411 extra_request_headers_.SetHeader( | 403 extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType, |
412 HttpRequestHeaders::kContentType, upload_content_type_); | 404 upload_content_type_); |
413 | 405 |
414 scoped_ptr<UploadElementReader> reader(new UploadBytesElementReader( | 406 scoped_ptr<UploadElementReader> reader(new UploadBytesElementReader( |
415 upload_content_.data(), upload_content_.size())); | 407 upload_content_.data(), upload_content_.size())); |
416 request_->set_upload(make_scoped_ptr( | 408 request_->set_upload(make_scoped_ptr( |
417 UploadDataStream::CreateWithReader(reader.Pass(), 0))); | 409 UploadDataStream::CreateWithReader(reader.Pass(), 0))); |
418 } | 410 } |
419 if (!extra_request_headers_.IsEmpty()) | 411 if (!extra_request_headers_.IsEmpty()) |
420 request_->SetExtraRequestHeaders(extra_request_headers_); | 412 request_->SetExtraRequestHeaders(extra_request_headers_); |
421 | 413 |
422 request_->Start(); | 414 request_->Start(); |
423 AddRef(); // Release after |request_| deleted. | 415 AddRef(); // Release after |request_| deleted. |
424 } | 416 } |
425 | 417 |
426 GURL url_; // The URL we eventually wound up at | 418 GURL url_; // The URL we eventually wound up at |
427 std::string http_request_method_; | 419 std::string http_request_method_; |
428 base::TimeDelta timeout_; // The timeout for OCSP | 420 base::TimeDelta timeout_; // The timeout for OCSP |
429 URLRequest* request_; // The actual request this wraps | 421 URLRequest* request_; // The actual request this wraps |
430 scoped_refptr<IOBuffer> buffer_; // Read buffer | 422 scoped_refptr<IOBuffer> buffer_; // Read buffer |
431 HttpRequestHeaders extra_request_headers_; | 423 HttpRequestHeaders extra_request_headers_; |
432 | 424 |
433 // HTTP POST payload. |request_| reads bytes from this. | 425 // HTTP POST payload. |request_| reads bytes from this. |
434 std::string upload_content_; | 426 std::string upload_content_; |
435 std::string upload_content_type_; // MIME type of POST payload | 427 std::string upload_content_type_; // MIME type of POST payload |
436 | 428 |
437 int response_code_; // HTTP status code for the request | 429 int response_code_; // HTTP status code for the request |
438 std::string response_content_type_; | 430 std::string response_content_type_; |
439 scoped_refptr<HttpResponseHeaders> response_headers_; | 431 scoped_refptr<HttpResponseHeaders> response_headers_; |
440 std::string data_; // Results of the request | 432 std::string data_; // Results of the request |
441 | 433 |
442 // |lock_| protects |finished_| and |io_loop_|. | 434 // |lock_| protects |finished_| and |io_loop_|. |
443 mutable base::Lock lock_; | 435 mutable base::Lock lock_; |
444 base::ConditionVariable cv_; | 436 base::ConditionVariable cv_; |
445 | 437 |
446 base::MessageLoop* io_loop_; // Message loop of the IO thread | 438 base::MessageLoop* io_loop_; // Message loop of the IO thread |
447 bool finished_; | 439 bool finished_; |
448 | 440 |
449 DISALLOW_COPY_AND_ASSIGN(OCSPRequestSession); | 441 DISALLOW_COPY_AND_ASSIGN(OCSPRequestSession); |
450 }; | 442 }; |
(...skipping 10 matching lines...) Expand all Loading... |
461 const char* http_request_method, | 453 const char* http_request_method, |
462 const PRIntervalTime timeout) { | 454 const PRIntervalTime timeout) { |
463 // We dont' support "https" because we haven't thought about | 455 // We dont' support "https" because we haven't thought about |
464 // whether it's safe to re-enter this code from talking to an OCSP | 456 // whether it's safe to re-enter this code from talking to an OCSP |
465 // responder over SSL. | 457 // responder over SSL. |
466 if (strcmp(http_protocol_variant, "http") != 0) { | 458 if (strcmp(http_protocol_variant, "http") != 0) { |
467 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); | 459 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); |
468 return NULL; | 460 return NULL; |
469 } | 461 } |
470 | 462 |
471 std::string url_string(base::StringPrintf( | 463 std::string url_string(base::StringPrintf("%s://%s%s", |
472 "%s://%s%s", | 464 http_protocol_variant, |
473 http_protocol_variant, | 465 host_and_port_.ToString().c_str(), |
474 host_and_port_.ToString().c_str(), | 466 path_and_query_string)); |
475 path_and_query_string)); | |
476 VLOG(1) << "URL [" << url_string << "]"; | 467 VLOG(1) << "URL [" << url_string << "]"; |
477 GURL url(url_string); | 468 GURL url(url_string); |
478 | 469 |
479 // NSS does not expose public functions to adjust the fetch timeout when | 470 // NSS does not expose public functions to adjust the fetch timeout when |
480 // using libpkix, so hardcode the upper limit for network fetches. | 471 // using libpkix, so hardcode the upper limit for network fetches. |
481 base::TimeDelta actual_timeout = std::min( | 472 base::TimeDelta actual_timeout = std::min( |
482 base::TimeDelta::FromSeconds(kNetworkFetchTimeoutInSecs), | 473 base::TimeDelta::FromSeconds(kNetworkFetchTimeoutInSecs), |
483 base::TimeDelta::FromMilliseconds(PR_IntervalToMilliseconds(timeout))); | 474 base::TimeDelta::FromMilliseconds(PR_IntervalToMilliseconds(timeout))); |
484 | 475 |
485 return new OCSPRequestSession(url, http_request_method, actual_timeout); | 476 return new OCSPRequestSession(url, http_request_method, actual_timeout); |
486 } | 477 } |
487 | 478 |
488 | |
489 private: | 479 private: |
490 HostPortPair host_and_port_; | 480 HostPortPair host_and_port_; |
491 | 481 |
492 DISALLOW_COPY_AND_ASSIGN(OCSPServerSession); | 482 DISALLOW_COPY_AND_ASSIGN(OCSPServerSession); |
493 }; | 483 }; |
494 | 484 |
495 OCSPIOLoop::OCSPIOLoop() | 485 OCSPIOLoop::OCSPIOLoop() : shutdown_(false), used_(false), io_loop_(NULL) { |
496 : shutdown_(false), | |
497 used_(false), | |
498 io_loop_(NULL) { | |
499 } | 486 } |
500 | 487 |
501 OCSPIOLoop::~OCSPIOLoop() { | 488 OCSPIOLoop::~OCSPIOLoop() { |
502 // IO thread was already deleted before the singleton is deleted | 489 // IO thread was already deleted before the singleton is deleted |
503 // in AtExitManager. | 490 // in AtExitManager. |
504 { | 491 { |
505 base::AutoLock autolock(lock_); | 492 base::AutoLock autolock(lock_); |
506 DCHECK(!io_loop_); | 493 DCHECK(!io_loop_); |
507 DCHECK(!used_); | 494 DCHECK(!used_); |
508 DCHECK(shutdown_); | 495 DCHECK(shutdown_); |
(...skipping 16 matching lines...) Expand all Loading... |
525 shutdown_ = true; | 512 shutdown_ = true; |
526 } | 513 } |
527 | 514 |
528 CancelAllRequests(); | 515 CancelAllRequests(); |
529 | 516 |
530 pthread_mutex_lock(&g_request_context_lock); | 517 pthread_mutex_lock(&g_request_context_lock); |
531 g_request_context = NULL; | 518 g_request_context = NULL; |
532 pthread_mutex_unlock(&g_request_context_lock); | 519 pthread_mutex_unlock(&g_request_context_lock); |
533 } | 520 } |
534 | 521 |
535 void OCSPIOLoop::PostTaskToIOLoop( | 522 void OCSPIOLoop::PostTaskToIOLoop(const tracked_objects::Location& from_here, |
536 const tracked_objects::Location& from_here, const base::Closure& task) { | 523 const base::Closure& task) { |
537 base::AutoLock autolock(lock_); | 524 base::AutoLock autolock(lock_); |
538 if (io_loop_) | 525 if (io_loop_) |
539 io_loop_->PostTask(from_here, task); | 526 io_loop_->PostTask(from_here, task); |
540 } | 527 } |
541 | 528 |
542 void OCSPIOLoop::EnsureIOLoop() { | 529 void OCSPIOLoop::EnsureIOLoop() { |
543 base::AutoLock autolock(lock_); | 530 base::AutoLock autolock(lock_); |
544 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); | 531 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); |
545 } | 532 } |
546 | 533 |
(...skipping 13 matching lines...) Expand all Loading... |
560 while (!requests_.empty()) | 547 while (!requests_.empty()) |
561 (*requests_.begin())->CancelURLRequest(); | 548 (*requests_.begin())->CancelURLRequest(); |
562 } | 549 } |
563 | 550 |
564 OCSPNSSInitialization::OCSPNSSInitialization() { | 551 OCSPNSSInitialization::OCSPNSSInitialization() { |
565 // NSS calls the functions in the function table to download certificates | 552 // NSS calls the functions in the function table to download certificates |
566 // or CRLs or talk to OCSP responders over HTTP. These functions must | 553 // or CRLs or talk to OCSP responders over HTTP. These functions must |
567 // set an NSS/NSPR error code when they fail. Otherwise NSS will get the | 554 // set an NSS/NSPR error code when they fail. Otherwise NSS will get the |
568 // residual error code from an earlier failed function call. | 555 // residual error code from an earlier failed function call. |
569 client_fcn_.version = 1; | 556 client_fcn_.version = 1; |
570 SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1; | 557 SEC_HttpClientFcnV1Struct* ft = &client_fcn_.fcnTable.ftable1; |
571 ft->createSessionFcn = OCSPCreateSession; | 558 ft->createSessionFcn = OCSPCreateSession; |
572 ft->keepAliveSessionFcn = OCSPKeepAliveSession; | 559 ft->keepAliveSessionFcn = OCSPKeepAliveSession; |
573 ft->freeSessionFcn = OCSPFreeSession; | 560 ft->freeSessionFcn = OCSPFreeSession; |
574 ft->createFcn = OCSPCreate; | 561 ft->createFcn = OCSPCreate; |
575 ft->setPostDataFcn = OCSPSetPostData; | 562 ft->setPostDataFcn = OCSPSetPostData; |
576 ft->addHeaderFcn = OCSPAddHeader; | 563 ft->addHeaderFcn = OCSPAddHeader; |
577 ft->trySendAndReceiveFcn = OCSPTrySendAndReceive; | 564 ft->trySendAndReceiveFcn = OCSPTrySendAndReceive; |
578 ft->cancelFcn = NULL; | 565 ft->cancelFcn = NULL; |
579 ft->freeFcn = OCSPFree; | 566 ft->freeFcn = OCSPFree; |
580 SECStatus status = SEC_RegisterDefaultHttpClient(&client_fcn_); | 567 SECStatus status = SEC_RegisterDefaultHttpClient(&client_fcn_); |
581 if (status != SECSuccess) { | 568 if (status != SECSuccess) { |
582 NOTREACHED() << "Error initializing OCSP: " << PR_GetError(); | 569 NOTREACHED() << "Error initializing OCSP: " << PR_GetError(); |
583 } | 570 } |
584 | 571 |
585 // Work around NSS bugs 524013 and 564334. NSS incorrectly thinks the | 572 // Work around NSS bugs 524013 and 564334. NSS incorrectly thinks the |
586 // CRLs for Network Solutions Certificate Authority have bad signatures, | 573 // CRLs for Network Solutions Certificate Authority have bad signatures, |
587 // which causes certificates issued by that CA to be reported as revoked. | 574 // which causes certificates issued by that CA to be reported as revoked. |
588 // By using OCSP for those certificates, which don't have AIA extensions, | 575 // By using OCSP for those certificates, which don't have AIA extensions, |
589 // we can work around these bugs. See http://crbug.com/41730. | 576 // we can work around these bugs. See http://crbug.com/41730. |
590 CERT_StringFromCertFcn old_callback = NULL; | 577 CERT_StringFromCertFcn old_callback = NULL; |
591 status = CERT_RegisterAlternateOCSPAIAInfoCallBack( | 578 status = CERT_RegisterAlternateOCSPAIAInfoCallBack(GetAlternateOCSPAIAInfo, |
592 GetAlternateOCSPAIAInfo, &old_callback); | 579 &old_callback); |
593 if (status == SECSuccess) { | 580 if (status == SECSuccess) { |
594 DCHECK(!old_callback); | 581 DCHECK(!old_callback); |
595 } else { | 582 } else { |
596 NOTREACHED() << "Error initializing OCSP: " << PR_GetError(); | 583 NOTREACHED() << "Error initializing OCSP: " << PR_GetError(); |
597 } | 584 } |
598 } | 585 } |
599 | 586 |
600 OCSPNSSInitialization::~OCSPNSSInitialization() { | 587 OCSPNSSInitialization::~OCSPNSSInitialization() { |
601 SECStatus status = CERT_RegisterAlternateOCSPAIAInfoCallBack(NULL, NULL); | 588 SECStatus status = CERT_RegisterAlternateOCSPAIAInfoCallBack(NULL, NULL); |
602 if (status != SECSuccess) { | 589 if (status != SECSuccess) { |
603 LOG(ERROR) << "Error unregistering OCSP: " << PR_GetError(); | 590 LOG(ERROR) << "Error unregistering OCSP: " << PR_GetError(); |
604 } | 591 } |
605 } | 592 } |
606 | 593 |
607 | |
608 // OCSP Http Client functions. | 594 // OCSP Http Client functions. |
609 // Our Http Client functions operate in blocking mode. | 595 // Our Http Client functions operate in blocking mode. |
610 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum, | 596 SECStatus OCSPCreateSession(const char* host, |
| 597 PRUint16 portnum, |
611 SEC_HTTP_SERVER_SESSION* pSession) { | 598 SEC_HTTP_SERVER_SESSION* pSession) { |
612 VLOG(1) << "OCSP create session: host=" << host << " port=" << portnum; | 599 VLOG(1) << "OCSP create session: host=" << host << " port=" << portnum; |
613 pthread_mutex_lock(&g_request_context_lock); | 600 pthread_mutex_lock(&g_request_context_lock); |
614 URLRequestContext* request_context = g_request_context; | 601 URLRequestContext* request_context = g_request_context; |
615 pthread_mutex_unlock(&g_request_context_lock); | 602 pthread_mutex_unlock(&g_request_context_lock); |
616 if (request_context == NULL) { | 603 if (request_context == NULL) { |
617 LOG(ERROR) << "No URLRequestContext for NSS HTTP handler. host: " << host; | 604 LOG(ERROR) << "No URLRequestContext for NSS HTTP handler. host: " << host; |
618 // The application failed to call SetURLRequestContextForNSSHttpIO or | 605 // The application failed to call SetURLRequestContextForNSSHttpIO or |
619 // has already called ShutdownNSSHttpIO, so we can't create and use | 606 // has already called ShutdownNSSHttpIO, so we can't create and use |
620 // URLRequest. PR_NOT_IMPLEMENTED_ERROR is not an accurate error | 607 // URLRequest. PR_NOT_IMPLEMENTED_ERROR is not an accurate error |
621 // code for these error conditions, but is close enough. | 608 // code for these error conditions, but is close enough. |
622 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); | 609 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); |
623 return SECFailure; | 610 return SECFailure; |
624 } | 611 } |
625 *pSession = new OCSPServerSession(host, portnum); | 612 *pSession = new OCSPServerSession(host, portnum); |
626 return SECSuccess; | 613 return SECSuccess; |
627 } | 614 } |
628 | 615 |
629 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session, | 616 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session, |
630 PRPollDesc **pPollDesc) { | 617 PRPollDesc** pPollDesc) { |
631 VLOG(1) << "OCSP keep alive"; | 618 VLOG(1) << "OCSP keep alive"; |
632 if (pPollDesc) | 619 if (pPollDesc) |
633 *pPollDesc = NULL; | 620 *pPollDesc = NULL; |
634 return SECSuccess; | 621 return SECSuccess; |
635 } | 622 } |
636 | 623 |
637 SECStatus OCSPFreeSession(SEC_HTTP_SERVER_SESSION session) { | 624 SECStatus OCSPFreeSession(SEC_HTTP_SERVER_SESSION session) { |
638 VLOG(1) << "OCSP free session"; | 625 VLOG(1) << "OCSP free session"; |
639 delete reinterpret_cast<OCSPServerSession*>(session); | 626 delete reinterpret_cast<OCSPServerSession*>(session); |
640 return SECSuccess; | 627 return SECSuccess; |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
780 | 767 |
781 // We want to know if this was: | 768 // We want to know if this was: |
782 // 1) An OCSP request | 769 // 1) An OCSP request |
783 // 2) A CRL request | 770 // 2) A CRL request |
784 // 3) A request for a missing intermediate certificate | 771 // 3) A request for a missing intermediate certificate |
785 // There's no sure way to do this, so we use heuristics like MIME type and | 772 // There's no sure way to do this, so we use heuristics like MIME type and |
786 // URL. | 773 // URL. |
787 const char* mime_type = ""; | 774 const char* mime_type = ""; |
788 if (ok) | 775 if (ok) |
789 mime_type = req->http_response_content_type().c_str(); | 776 mime_type = req->http_response_content_type().c_str(); |
790 bool is_ocsp = | 777 bool is_ocsp = strcasecmp(mime_type, "application/ocsp-response") == 0; |
791 strcasecmp(mime_type, "application/ocsp-response") == 0; | |
792 bool is_crl = strcasecmp(mime_type, "application/x-pkcs7-crl") == 0 || | 778 bool is_crl = strcasecmp(mime_type, "application/x-pkcs7-crl") == 0 || |
793 strcasecmp(mime_type, "application/x-x509-crl") == 0 || | 779 strcasecmp(mime_type, "application/x-x509-crl") == 0 || |
794 strcasecmp(mime_type, "application/pkix-crl") == 0; | 780 strcasecmp(mime_type, "application/pkix-crl") == 0; |
795 bool is_cert = | 781 bool is_cert = strcasecmp(mime_type, "application/x-x509-ca-cert") == 0 || |
796 strcasecmp(mime_type, "application/x-x509-ca-cert") == 0 || | 782 strcasecmp(mime_type, "application/x-x509-server-cert") == 0 || |
797 strcasecmp(mime_type, "application/x-x509-server-cert") == 0 || | 783 strcasecmp(mime_type, "application/pkix-cert") == 0 || |
798 strcasecmp(mime_type, "application/pkix-cert") == 0 || | 784 strcasecmp(mime_type, "application/pkcs7-mime") == 0; |
799 strcasecmp(mime_type, "application/pkcs7-mime") == 0; | |
800 | 785 |
801 if (!is_cert && !is_crl && !is_ocsp) { | 786 if (!is_cert && !is_crl && !is_ocsp) { |
802 // We didn't get a hint from the MIME type, so do the best that we can. | 787 // We didn't get a hint from the MIME type, so do the best that we can. |
803 const std::string path = req->url().path(); | 788 const std::string path = req->url().path(); |
804 const std::string host = req->url().host(); | 789 const std::string host = req->url().host(); |
805 is_crl = strcasestr(path.c_str(), ".crl") != NULL; | 790 is_crl = strcasestr(path.c_str(), ".crl") != NULL; |
806 is_cert = strcasestr(path.c_str(), ".crt") != NULL || | 791 is_cert = strcasestr(path.c_str(), ".crt") != NULL || |
807 strcasestr(path.c_str(), ".p7c") != NULL || | 792 strcasestr(path.c_str(), ".p7c") != NULL || |
808 strcasestr(path.c_str(), ".cer") != NULL; | 793 strcasestr(path.c_str(), ".cer") != NULL; |
809 is_ocsp = strcasestr(host.c_str(), "ocsp") != NULL || | 794 is_ocsp = strcasestr(host.c_str(), "ocsp") != NULL || |
(...skipping 22 matching lines...) Expand all Loading... |
832 } else { | 817 } else { |
833 if (ok) | 818 if (ok) |
834 UMA_HISTOGRAM_TIMES("Net.UnknownTypeRequestTimeMs", duration); | 819 UMA_HISTOGRAM_TIMES("Net.UnknownTypeRequestTimeMs", duration); |
835 } | 820 } |
836 | 821 |
837 if (!request_ok) { | 822 if (!request_ok) { |
838 PORT_SetError(SEC_ERROR_BAD_HTTP_RESPONSE); // Simple approximation. | 823 PORT_SetError(SEC_ERROR_BAD_HTTP_RESPONSE); // Simple approximation. |
839 return SECFailure; | 824 return SECFailure; |
840 } | 825 } |
841 | 826 |
842 return OCSPSetResponse( | 827 return OCSPSetResponse(req, |
843 req, http_response_code, | 828 http_response_code, |
844 http_response_content_type, | 829 http_response_content_type, |
845 http_response_headers, | 830 http_response_headers, |
846 http_response_data, | 831 http_response_data, |
847 http_response_data_len); | 832 http_response_data_len); |
848 } | 833 } |
849 | 834 |
850 SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request) { | 835 SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request) { |
851 VLOG(1) << "OCSP free"; | 836 VLOG(1) << "OCSP free"; |
852 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); | 837 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); |
853 req->Cancel(); | 838 req->Cancel(); |
854 req->Release(); | 839 req->Release(); |
855 return SECSuccess; | 840 return SECSuccess; |
856 } | 841 } |
857 | 842 |
858 // Data for GetAlternateOCSPAIAInfo. | 843 // Data for GetAlternateOCSPAIAInfo. |
859 | 844 |
860 // CN=Network Solutions Certificate Authority,O=Network Solutions L.L.C.,C=US | 845 // CN=Network Solutions Certificate Authority,O=Network Solutions L.L.C.,C=US |
861 // | 846 // |
862 // There are two CAs with this name. Their key IDs are listed next. | 847 // There are two CAs with this name. Their key IDs are listed next. |
863 const unsigned char network_solutions_ca_name[] = { | 848 const unsigned char network_solutions_ca_name[] = { |
864 0x30, 0x62, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, | 849 0x30, 0x62, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, |
865 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x21, 0x30, 0x1f, 0x06, | 850 0x02, 0x55, 0x53, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, |
866 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x4e, 0x65, 0x74, 0x77, | 851 0x13, 0x18, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, |
867 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, | 852 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x4c, 0x2e, 0x4c, 0x2e, |
868 0x6f, 0x6e, 0x73, 0x20, 0x4c, 0x2e, 0x4c, 0x2e, 0x43, 0x2e, | 853 0x43, 0x2e, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, |
869 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, | 854 0x27, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, 0x6c, |
870 0x27, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53, | 855 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, |
871 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, | 856 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, |
872 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, | 857 0x72, 0x69, 0x74, 0x79}; |
873 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79 | |
874 }; | |
875 const unsigned int network_solutions_ca_name_len = 100; | 858 const unsigned int network_solutions_ca_name_len = 100; |
876 | 859 |
877 // This CA is an intermediate CA, subordinate to UTN-USERFirst-Hardware. | 860 // This CA is an intermediate CA, subordinate to UTN-USERFirst-Hardware. |
878 const unsigned char network_solutions_ca_key_id[] = { | 861 const unsigned char network_solutions_ca_key_id[] = { |
879 0x3c, 0x41, 0xe2, 0x8f, 0x08, 0x08, 0xa9, 0x4c, 0x25, 0x89, | 862 0x3c, 0x41, 0xe2, 0x8f, 0x08, 0x08, 0xa9, 0x4c, 0x25, 0x89, |
880 0x8d, 0x6d, 0xc5, 0x38, 0xd0, 0xfc, 0x85, 0x8c, 0x62, 0x17 | 863 0x8d, 0x6d, 0xc5, 0x38, 0xd0, 0xfc, 0x85, 0x8c, 0x62, 0x17}; |
881 }; | |
882 const unsigned int network_solutions_ca_key_id_len = 20; | 864 const unsigned int network_solutions_ca_key_id_len = 20; |
883 | 865 |
884 // This CA is a root CA. It is also cross-certified by | 866 // This CA is a root CA. It is also cross-certified by |
885 // UTN-USERFirst-Hardware. | 867 // UTN-USERFirst-Hardware. |
886 const unsigned char network_solutions_ca_key_id2[] = { | 868 const unsigned char network_solutions_ca_key_id2[] = { |
887 0x21, 0x30, 0xc9, 0xfb, 0x00, 0xd7, 0x4e, 0x98, 0xda, 0x87, | 869 0x21, 0x30, 0xc9, 0xfb, 0x00, 0xd7, 0x4e, 0x98, 0xda, 0x87, |
888 0xaa, 0x2a, 0xd0, 0xa7, 0x2e, 0xb1, 0x40, 0x31, 0xa7, 0x4c | 870 0xaa, 0x2a, 0xd0, 0xa7, 0x2e, 0xb1, 0x40, 0x31, 0xa7, 0x4c}; |
889 }; | |
890 const unsigned int network_solutions_ca_key_id2_len = 20; | 871 const unsigned int network_solutions_ca_key_id2_len = 20; |
891 | 872 |
892 // An entry in our OCSP responder table. |issuer| and |issuer_key_id| are | 873 // An entry in our OCSP responder table. |issuer| and |issuer_key_id| are |
893 // the key. |ocsp_url| is the value. | 874 // the key. |ocsp_url| is the value. |
894 struct OCSPResponderTableEntry { | 875 struct OCSPResponderTableEntry { |
895 SECItem issuer; | 876 SECItem issuer; |
896 SECItem issuer_key_id; | 877 SECItem issuer_key_id; |
897 const char *ocsp_url; | 878 const char* ocsp_url; |
898 }; | 879 }; |
899 | 880 |
900 const OCSPResponderTableEntry g_ocsp_responder_table[] = { | 881 const OCSPResponderTableEntry g_ocsp_responder_table[] = { |
901 { | 882 {{siBuffer, const_cast<unsigned char*>(network_solutions_ca_name), |
902 { | 883 network_solutions_ca_name_len}, |
903 siBuffer, | 884 {siBuffer, const_cast<unsigned char*>(network_solutions_ca_key_id), |
904 const_cast<unsigned char*>(network_solutions_ca_name), | 885 network_solutions_ca_key_id_len}, |
905 network_solutions_ca_name_len | 886 "http://ocsp.netsolssl.com"}, |
906 }, | 887 {{siBuffer, const_cast<unsigned char*>(network_solutions_ca_name), |
907 { | 888 network_solutions_ca_name_len}, |
908 siBuffer, | 889 {siBuffer, const_cast<unsigned char*>(network_solutions_ca_key_id2), |
909 const_cast<unsigned char*>(network_solutions_ca_key_id), | 890 network_solutions_ca_key_id2_len}, |
910 network_solutions_ca_key_id_len | 891 "http://ocsp.netsolssl.com"}}; |
911 }, | |
912 "http://ocsp.netsolssl.com" | |
913 }, | |
914 { | |
915 { | |
916 siBuffer, | |
917 const_cast<unsigned char*>(network_solutions_ca_name), | |
918 network_solutions_ca_name_len | |
919 }, | |
920 { | |
921 siBuffer, | |
922 const_cast<unsigned char*>(network_solutions_ca_key_id2), | |
923 network_solutions_ca_key_id2_len | |
924 }, | |
925 "http://ocsp.netsolssl.com" | |
926 } | |
927 }; | |
928 | 892 |
929 char* GetAlternateOCSPAIAInfo(CERTCertificate *cert) { | 893 char* GetAlternateOCSPAIAInfo(CERTCertificate* cert) { |
930 if (cert && !cert->isRoot && cert->authKeyID) { | 894 if (cert && !cert->isRoot && cert->authKeyID) { |
931 for (unsigned int i=0; i < arraysize(g_ocsp_responder_table); i++) { | 895 for (unsigned int i = 0; i < arraysize(g_ocsp_responder_table); i++) { |
932 if (SECITEM_CompareItem(&g_ocsp_responder_table[i].issuer, | 896 if (SECITEM_CompareItem(&g_ocsp_responder_table[i].issuer, |
933 &cert->derIssuer) == SECEqual && | 897 &cert->derIssuer) == SECEqual && |
934 SECITEM_CompareItem(&g_ocsp_responder_table[i].issuer_key_id, | 898 SECITEM_CompareItem(&g_ocsp_responder_table[i].issuer_key_id, |
935 &cert->authKeyID->keyID) == SECEqual) { | 899 &cert->authKeyID->keyID) == SECEqual) { |
936 return PORT_Strdup(g_ocsp_responder_table[i].ocsp_url); | 900 return PORT_Strdup(g_ocsp_responder_table[i].ocsp_url); |
937 } | 901 } |
938 } | 902 } |
939 } | 903 } |
940 | 904 |
941 return NULL; | 905 return NULL; |
(...skipping 28 matching lines...) Expand all Loading... |
970 void SetURLRequestContextForNSSHttpIO(URLRequestContext* request_context) { | 934 void SetURLRequestContextForNSSHttpIO(URLRequestContext* request_context) { |
971 pthread_mutex_lock(&g_request_context_lock); | 935 pthread_mutex_lock(&g_request_context_lock); |
972 if (request_context) { | 936 if (request_context) { |
973 DCHECK(!g_request_context); | 937 DCHECK(!g_request_context); |
974 } | 938 } |
975 g_request_context = request_context; | 939 g_request_context = request_context; |
976 pthread_mutex_unlock(&g_request_context_lock); | 940 pthread_mutex_unlock(&g_request_context_lock); |
977 } | 941 } |
978 | 942 |
979 } // namespace net | 943 } // namespace net |
OLD | NEW |