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 3 // found in the LICENSE file. 4 5 #include "net/ocsp/nss_ocsp.h" 6 7 #include <certt.h> 8 #include <certdb.h> 9 #include <ocsp.h> 10 #include <nspr.h> 11 #include <nss.h> 12 #include <pthread.h> 13 #include <secerr.h> 14 15 #include <algorithm> 16 #include <string> 17 18 #include "base/basictypes.h" 19 #include "base/callback.h" 20 #include "base/compiler_specific.h" 21 #include "base/lazy_instance.h" 22 #include "base/logging.h" 23 #include "base/message_loop/message_loop.h" 24 #include "base/metrics/histogram.h" 25 #include "base/stl_util.h" 26 #include "base/strings/string_util.h" 27 #include "base/strings/stringprintf.h" 28 #include "base/synchronization/condition_variable.h" 29 #include "base/synchronization/lock.h" 30 #include "base/threading/thread_checker.h" 31 #include "base/time/time.h" 32 #include "net/base/host_port_pair.h" 33 #include "net/base/io_buffer.h" 34 #include "net/base/load_flags.h" 35 #include "net/base/request_priority.h" 36 #include "net/base/upload_bytes_element_reader.h" 37 #include "net/base/upload_data_stream.h" 38 #include "net/http/http_request_headers.h" 39 #include "net/http/http_response_headers.h" 40 #include "net/url_request/url_request.h" 41 #include "net/url_request/url_request_context.h" 42 #include "url/gurl.h" 43 44 namespace net { 45 46 namespace { 47 48 // Protects |g_request_context|. 49 pthread_mutex_t g_request_context_lock = PTHREAD_MUTEX_INITIALIZER; 50 URLRequestContext* g_request_context = NULL; 51 52 // The default timeout for network fetches in NSS is 60 seconds. Choose a 53 // saner upper limit for OCSP/CRL/AIA fetches. 54 const int kNetworkFetchTimeoutInSecs = 15; 55 56 class OCSPRequestSession; 57 58 class OCSPIOLoop { 59 public: 60 void StartUsing() { 61 base::AutoLock autolock(lock_); 62 used_ = true; 63 io_loop_ = base::MessageLoopForIO::current(); 64 DCHECK(io_loop_); 65 } 66 67 // Called on IO loop. 68 void Shutdown(); 69 70 bool used() const { 71 base::AutoLock autolock(lock_); 72 return used_; 73 } 74 75 // Called from worker thread. 76 void PostTaskToIOLoop(const tracked_objects::Location& from_here, 77 const base::Closure& task); 78 79 void EnsureIOLoop(); 80 81 void AddRequest(OCSPRequestSession* request); 82 void RemoveRequest(OCSPRequestSession* request); 83 84 // Clears internal state and calls |StartUsing()|. Should be called only in 85 // the context of testing. 86 void ReuseForTesting() { 87 { 88 base::AutoLock autolock(lock_); 89 DCHECK(base::MessageLoopForIO::current()); 90 thread_checker_.DetachFromThread(); 91 92 // CalledOnValidThread is the only available API to reassociate 93 // thread_checker_ with the current thread. Result ignored intentionally. 94 ignore_result(thread_checker_.CalledOnValidThread()); 95 shutdown_ = false; 96 used_ = false; 97 } 98 StartUsing(); 99 } 100 101 private: 102 friend struct base::DefaultLazyInstanceTraits<OCSPIOLoop>; 103 104 OCSPIOLoop(); 105 ~OCSPIOLoop(); 106 107 void CancelAllRequests(); 108 109 mutable base::Lock lock_; 110 bool shutdown_; // Protected by |lock_|. 111 std::set<OCSPRequestSession*> requests_; // Protected by |lock_|. 112 bool used_; // Protected by |lock_|. 113 // This should not be modified after |used_|. 114 base::MessageLoopForIO* io_loop_; // Protected by |lock_|. 115 base::ThreadChecker thread_checker_; 116 117 DISALLOW_COPY_AND_ASSIGN(OCSPIOLoop); 118 }; 119 120 base::LazyInstance<OCSPIOLoop>::Leaky 121 g_ocsp_io_loop = LAZY_INSTANCE_INITIALIZER; 122 123 const int kRecvBufferSize = 4096; 124 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). 127 // It supports blocking mode only. 128 129 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum, 130 SEC_HTTP_SERVER_SESSION* pSession); 131 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session, 132 PRPollDesc **pPollDesc); 133 SECStatus OCSPFreeSession(SEC_HTTP_SERVER_SESSION session); 134 135 SECStatus OCSPCreate(SEC_HTTP_SERVER_SESSION session, 136 const char* http_protocol_variant, 137 const char* path_and_query_string, 138 const char* http_request_method, 139 const PRIntervalTime timeout, 140 SEC_HTTP_REQUEST_SESSION* pRequest); 141 SECStatus OCSPSetPostData(SEC_HTTP_REQUEST_SESSION request, 142 const char* http_data, 143 const PRUint32 http_data_len, 144 const char* http_content_type); 145 SECStatus OCSPAddHeader(SEC_HTTP_REQUEST_SESSION request, 146 const char* http_header_name, 147 const char* http_header_value); 148 SECStatus OCSPTrySendAndReceive(SEC_HTTP_REQUEST_SESSION request, 149 PRPollDesc** pPollDesc, 150 PRUint16* http_response_code, 151 const char** http_response_content_type, 152 const char** http_response_headers, 153 const char** http_response_data, 154 PRUint32* http_response_data_len); 155 SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request); 156 157 char* GetAlternateOCSPAIAInfo(CERTCertificate *cert); 158 159 class OCSPNSSInitialization { 160 private: 161 friend struct base::DefaultLazyInstanceTraits<OCSPNSSInitialization>; 162 163 OCSPNSSInitialization(); 164 ~OCSPNSSInitialization(); 165 166 SEC_HttpClientFcn client_fcn_; 167 168 DISALLOW_COPY_AND_ASSIGN(OCSPNSSInitialization); 169 }; 170 171 base::LazyInstance<OCSPNSSInitialization> g_ocsp_nss_initialization = 172 LAZY_INSTANCE_INITIALIZER; 173 174 // Concrete class for SEC_HTTP_REQUEST_SESSION. 175 // Public methods except virtual methods of URLRequest::Delegate 176 // (On* methods) run on certificate verifier thread (worker thread). 177 // Virtual methods of URLRequest::Delegate and private methods run 178 // on IO thread. 179 class OCSPRequestSession 180 : public base::RefCountedThreadSafe<OCSPRequestSession>, 181 public URLRequest::Delegate { 182 public: 183 OCSPRequestSession(const GURL& url, 184 const char* http_request_method, 185 base::TimeDelta timeout) 186 : url_(url), 187 http_request_method_(http_request_method), 188 timeout_(timeout), 189 request_(NULL), 190 buffer_(new IOBuffer(kRecvBufferSize)), 191 response_code_(-1), 192 cv_(&lock_), 193 io_loop_(NULL), 194 finished_(false) {} 195 196 void SetPostData(const char* http_data, PRUint32 http_data_len, 197 const char* http_content_type) { 198 // |upload_content_| should not be modified if |request_| is active. 199 DCHECK(!request_); 200 upload_content_.assign(http_data, http_data_len); 201 upload_content_type_.assign(http_content_type); 202 } 203 204 void AddHeader(const char* http_header_name, const char* http_header_value) { 205 extra_request_headers_.SetHeader(http_header_name, 206 http_header_value); 207 } 208 209 void Start() { 210 // At this point, it runs on worker thread. 211 // |io_loop_| was initialized to be NULL in constructor, and 212 // set only in StartURLRequest, so no need to lock |lock_| here. 213 DCHECK(!io_loop_); 214 g_ocsp_io_loop.Get().PostTaskToIOLoop( 215 FROM_HERE, 216 base::Bind(&OCSPRequestSession::StartURLRequest, this)); 217 } 218 219 bool Started() const { 220 return request_ != NULL; 221 } 222 223 void Cancel() { 224 // IO thread may set |io_loop_| to NULL, so protect by |lock_|. 225 base::AutoLock autolock(lock_); 226 CancelLocked(); 227 } 228 229 bool Finished() const { 230 base::AutoLock autolock(lock_); 231 return finished_; 232 } 233 234 bool Wait() { 235 base::TimeDelta timeout = timeout_; 236 base::AutoLock autolock(lock_); 237 while (!finished_) { 238 base::TimeTicks last_time = base::TimeTicks::Now(); 239 cv_.TimedWait(timeout); 240 // Check elapsed time 241 base::TimeDelta elapsed_time = base::TimeTicks::Now() - last_time; 242 timeout -= elapsed_time; 243 if (timeout < base::TimeDelta()) { 244 VLOG(1) << "OCSP Timed out"; 245 if (!finished_) 246 CancelLocked(); 247 break; 248 } 249 } 250 return finished_; 251 } 252 253 const GURL& url() const { 254 return url_; 255 } 256 257 const std::string& http_request_method() const { 258 return http_request_method_; 259 } 260 261 base::TimeDelta timeout() const { 262 return timeout_; 263 } 264 265 PRUint16 http_response_code() const { 266 DCHECK(finished_); 267 return response_code_; 268 } 269 270 const std::string& http_response_content_type() const { 271 DCHECK(finished_); 272 return response_content_type_; 273 } 274 275 const std::string& http_response_headers() const { 276 DCHECK(finished_); 277 return response_headers_->raw_headers(); 278 } 279 280 const std::string& http_response_data() const { 281 DCHECK(finished_); 282 return data_; 283 } 284 285 virtual void OnReceivedRedirect(URLRequest* request, 286 const GURL& new_url, 287 bool* defer_redirect) OVERRIDE { 288 DCHECK_EQ(request, request_); 289 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); 290 291 if (!new_url.SchemeIs("http")) { 292 // Prevent redirects to non-HTTP schemes, including HTTPS. This matches 293 // the initial check in OCSPServerSession::CreateRequest(). 294 CancelURLRequest(); 295 } 296 } 297 298 virtual void OnResponseStarted(URLRequest* request) OVERRIDE { 299 DCHECK_EQ(request, request_); 300 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); 301 302 int bytes_read = 0; 303 if (request->status().is_success()) { 304 response_code_ = request_->GetResponseCode(); 305 response_headers_ = request_->response_headers(); 306 response_headers_->GetMimeType(&response_content_type_); 307 request_->Read(buffer_.get(), kRecvBufferSize, &bytes_read); 308 } 309 OnReadCompleted(request_, bytes_read); 310 } 311 312 virtual void OnReadCompleted(URLRequest* request, 313 int bytes_read) OVERRIDE { 314 DCHECK_EQ(request, request_); 315 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); 316 317 do { 318 if (!request_->status().is_success() || bytes_read <= 0) 319 break; 320 data_.append(buffer_->data(), bytes_read); 321 } while (request_->Read(buffer_.get(), kRecvBufferSize, &bytes_read)); 322 323 if (!request_->status().is_io_pending()) { 324 delete request_; 325 request_ = NULL; 326 g_ocsp_io_loop.Get().RemoveRequest(this); 327 { 328 base::AutoLock autolock(lock_); 329 finished_ = true; 330 io_loop_ = NULL; 331 } 332 cv_.Signal(); 333 Release(); // Balanced with StartURLRequest(). 334 } 335 } 336 337 // Must be called on the IO loop thread. 338 void CancelURLRequest() { 339 #ifndef NDEBUG 340 { 341 base::AutoLock autolock(lock_); 342 if (io_loop_) 343 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); 344 } 345 #endif 346 if (request_) { 347 request_->Cancel(); 348 delete request_; 349 request_ = NULL; 350 g_ocsp_io_loop.Get().RemoveRequest(this); 351 { 352 base::AutoLock autolock(lock_); 353 finished_ = true; 354 io_loop_ = NULL; 355 } 356 cv_.Signal(); 357 Release(); // Balanced with StartURLRequest(). 358 } 359 } 360 361 private: 362 friend class base::RefCountedThreadSafe<OCSPRequestSession>; 363 364 virtual ~OCSPRequestSession() { 365 // When this destructor is called, there should be only one thread that has 366 // a reference to this object, and so that thread doesn't need to lock 367 // |lock_| here. 368 DCHECK(!request_); 369 DCHECK(!io_loop_); 370 } 371 372 // Must call this method while holding |lock_|. 373 void CancelLocked() { 374 lock_.AssertAcquired(); 375 if (io_loop_) { 376 io_loop_->PostTask( 377 FROM_HERE, 378 base::Bind(&OCSPRequestSession::CancelURLRequest, this)); 379 } 380 } 381 382 // Runs on |g_ocsp_io_loop|'s IO loop. 383 void StartURLRequest() { 384 DCHECK(!request_); 385 386 pthread_mutex_lock(&g_request_context_lock); 387 URLRequestContext* url_request_context = g_request_context; 388 pthread_mutex_unlock(&g_request_context_lock); 389 390 if (url_request_context == NULL) 391 return; 392 393 { 394 base::AutoLock autolock(lock_); 395 DCHECK(!io_loop_); 396 io_loop_ = base::MessageLoopForIO::current(); 397 g_ocsp_io_loop.Get().AddRequest(this); 398 } 399 400 request_ = 401 new URLRequest(url_, DEFAULT_PRIORITY, this, url_request_context); 402 // To meet the privacy requirements of incognito mode. 403 request_->SetLoadFlags(LOAD_DISABLE_CACHE | LOAD_DO_NOT_SAVE_COOKIES | 404 LOAD_DO_NOT_SEND_COOKIES); 405 406 if (http_request_method_ == "POST") { 407 DCHECK(!upload_content_.empty()); 408 DCHECK(!upload_content_type_.empty()); 409 410 request_->set_method("POST"); 411 extra_request_headers_.SetHeader( 412 HttpRequestHeaders::kContentType, upload_content_type_); 413 414 scoped_ptr<UploadElementReader> reader(new UploadBytesElementReader( 415 upload_content_.data(), upload_content_.size())); 416 request_->set_upload(make_scoped_ptr( 417 UploadDataStream::CreateWithReader(reader.Pass(), 0))); 418 } 419 if (!extra_request_headers_.IsEmpty()) 420 request_->SetExtraRequestHeaders(extra_request_headers_); 421 422 request_->Start(); 423 AddRef(); // Release after |request_| deleted. 424 } 425 426 GURL url_; // The URL we eventually wound up at 427 std::string http_request_method_; 428 base::TimeDelta timeout_; // The timeout for OCSP 429 URLRequest* request_; // The actual request this wraps 430 scoped_refptr<IOBuffer> buffer_; // Read buffer 431 HttpRequestHeaders extra_request_headers_; 432 433 // HTTP POST payload. |request_| reads bytes from this. 434 std::string upload_content_; 435 std::string upload_content_type_; // MIME type of POST payload 436 437 int response_code_; // HTTP status code for the request 438 std::string response_content_type_; 439 scoped_refptr<HttpResponseHeaders> response_headers_; 440 std::string data_; // Results of the request 441 442 // |lock_| protects |finished_| and |io_loop_|. 443 mutable base::Lock lock_; 444 base::ConditionVariable cv_; 445 446 base::MessageLoop* io_loop_; // Message loop of the IO thread 447 bool finished_; 448 449 DISALLOW_COPY_AND_ASSIGN(OCSPRequestSession); 450 }; 451 452 // Concrete class for SEC_HTTP_SERVER_SESSION. 453 class OCSPServerSession { 454 public: 455 OCSPServerSession(const char* host, PRUint16 port) 456 : host_and_port_(host, port) {} 457 ~OCSPServerSession() {} 458 459 OCSPRequestSession* CreateRequest(const char* http_protocol_variant, 460 const char* path_and_query_string, 461 const char* http_request_method, 462 const PRIntervalTime timeout) { 463 // 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 465 // responder over SSL. 466 if (strcmp(http_protocol_variant, "http") != 0) { 467 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 468 return NULL; 469 } 470 471 std::string url_string(base::StringPrintf( 472 "%s://%s%s", 473 http_protocol_variant, 474 host_and_port_.ToString().c_str(), 475 path_and_query_string)); 476 VLOG(1) << "URL [" << url_string << "]"; 477 GURL url(url_string); 478 479 // NSS does not expose public functions to adjust the fetch timeout when 480 // using libpkix, so hardcode the upper limit for network fetches. 481 base::TimeDelta actual_timeout = std::min( 482 base::TimeDelta::FromSeconds(kNetworkFetchTimeoutInSecs), 483 base::TimeDelta::FromMilliseconds(PR_IntervalToMilliseconds(timeout))); 484 485 return new OCSPRequestSession(url, http_request_method, actual_timeout); 486 } 487 488 489 private: 490 HostPortPair host_and_port_; 491 492 DISALLOW_COPY_AND_ASSIGN(OCSPServerSession); 493 }; 494 495 OCSPIOLoop::OCSPIOLoop() 496 : shutdown_(false), 497 used_(false), 498 io_loop_(NULL) { 499 } 500 501 OCSPIOLoop::~OCSPIOLoop() { 502 // IO thread was already deleted before the singleton is deleted 503 // in AtExitManager. 504 { 505 base::AutoLock autolock(lock_); 506 DCHECK(!io_loop_); 507 DCHECK(!used_); 508 DCHECK(shutdown_); 509 } 510 511 pthread_mutex_lock(&g_request_context_lock); 512 DCHECK(!g_request_context); 513 pthread_mutex_unlock(&g_request_context_lock); 514 } 515 516 void OCSPIOLoop::Shutdown() { 517 // Safe to read outside lock since we only write on IO thread anyway. 518 DCHECK(thread_checker_.CalledOnValidThread()); 519 520 // Prevent the worker thread from trying to access |io_loop_|. 521 { 522 base::AutoLock autolock(lock_); 523 io_loop_ = NULL; 524 used_ = false; 525 shutdown_ = true; 526 } 527 528 CancelAllRequests(); 529 530 pthread_mutex_lock(&g_request_context_lock); 531 g_request_context = NULL; 532 pthread_mutex_unlock(&g_request_context_lock); 533 } 534 535 void OCSPIOLoop::PostTaskToIOLoop( 536 const tracked_objects::Location& from_here, const base::Closure& task) { 537 base::AutoLock autolock(lock_); 538 if (io_loop_) 539 io_loop_->PostTask(from_here, task); 540 } 541 542 void OCSPIOLoop::EnsureIOLoop() { 543 base::AutoLock autolock(lock_); 544 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); 545 } 546 547 void OCSPIOLoop::AddRequest(OCSPRequestSession* request) { 548 DCHECK(!ContainsKey(requests_, request)); 549 requests_.insert(request); 550 } 551 552 void OCSPIOLoop::RemoveRequest(OCSPRequestSession* request) { 553 DCHECK(ContainsKey(requests_, request)); 554 requests_.erase(request); 555 } 556 557 void OCSPIOLoop::CancelAllRequests() { 558 // CancelURLRequest() always removes the request from the requests_ 559 // set synchronously. 560 while (!requests_.empty()) 561 (*requests_.begin())->CancelURLRequest(); 562 } 563 564 OCSPNSSInitialization::OCSPNSSInitialization() { 565 // NSS calls the functions in the function table to download certificates 566 // 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 568 // residual error code from an earlier failed function call. 569 client_fcn_.version = 1; 570 SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1; 571 ft->createSessionFcn = OCSPCreateSession; 572 ft->keepAliveSessionFcn = OCSPKeepAliveSession; 573 ft->freeSessionFcn = OCSPFreeSession; 574 ft->createFcn = OCSPCreate; 575 ft->setPostDataFcn = OCSPSetPostData; 576 ft->addHeaderFcn = OCSPAddHeader; 577 ft->trySendAndReceiveFcn = OCSPTrySendAndReceive; 578 ft->cancelFcn = NULL; 579 ft->freeFcn = OCSPFree; 580 SECStatus status = SEC_RegisterDefaultHttpClient(&client_fcn_); 581 if (status != SECSuccess) { 582 NOTREACHED() << "Error initializing OCSP: " << PR_GetError(); 583 } 584 585 // Work around NSS bugs 524013 and 564334. NSS incorrectly thinks the 586 // CRLs for Network Solutions Certificate Authority have bad signatures, 587 // 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, 589 // we can work around these bugs. See http://crbug.com/41730. 590 CERT_StringFromCertFcn old_callback = NULL; 591 status = CERT_RegisterAlternateOCSPAIAInfoCallBack( 592 GetAlternateOCSPAIAInfo, &old_callback); 593 if (status == SECSuccess) { 594 DCHECK(!old_callback); 595 } else { 596 NOTREACHED() << "Error initializing OCSP: " << PR_GetError(); 597 } 598 } 599 600 OCSPNSSInitialization::~OCSPNSSInitialization() { 601 SECStatus status = CERT_RegisterAlternateOCSPAIAInfoCallBack(NULL, NULL); 602 if (status != SECSuccess) { 603 LOG(ERROR) << "Error unregistering OCSP: " << PR_GetError(); 604 } 605 } 606 607 608 // OCSP Http Client functions. 609 // Our Http Client functions operate in blocking mode. 610 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum, 611 SEC_HTTP_SERVER_SESSION* pSession) { 612 VLOG(1) << "OCSP create session: host=" << host << " port=" << portnum; 613 pthread_mutex_lock(&g_request_context_lock); 614 URLRequestContext* request_context = g_request_context; 615 pthread_mutex_unlock(&g_request_context_lock); 616 if (request_context == NULL) { 617 LOG(ERROR) << "No URLRequestContext for NSS HTTP handler. host: " << host; 618 // The application failed to call SetURLRequestContextForNSSHttpIO or 619 // has already called ShutdownNSSHttpIO, so we can't create and use 620 // URLRequest. PR_NOT_IMPLEMENTED_ERROR is not an accurate error 621 // code for these error conditions, but is close enough. 622 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 623 return SECFailure; 624 } 625 *pSession = new OCSPServerSession(host, portnum); 626 return SECSuccess; 627 } 628 629 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session, 630 PRPollDesc **pPollDesc) { 631 VLOG(1) << "OCSP keep alive"; 632 if (pPollDesc) 633 *pPollDesc = NULL; 634 return SECSuccess; 635 } 636 637 SECStatus OCSPFreeSession(SEC_HTTP_SERVER_SESSION session) { 638 VLOG(1) << "OCSP free session"; 639 delete reinterpret_cast<OCSPServerSession*>(session); 640 return SECSuccess; 641 } 642 643 SECStatus OCSPCreate(SEC_HTTP_SERVER_SESSION session, 644 const char* http_protocol_variant, 645 const char* path_and_query_string, 646 const char* http_request_method, 647 const PRIntervalTime timeout, 648 SEC_HTTP_REQUEST_SESSION* pRequest) { 649 VLOG(1) << "OCSP create protocol=" << http_protocol_variant 650 << " path_and_query=" << path_and_query_string 651 << " http_request_method=" << http_request_method 652 << " timeout=" << timeout; 653 OCSPServerSession* ocsp_session = 654 reinterpret_cast<OCSPServerSession*>(session); 655 656 OCSPRequestSession* req = ocsp_session->CreateRequest(http_protocol_variant, 657 path_and_query_string, 658 http_request_method, 659 timeout); 660 SECStatus rv = SECFailure; 661 if (req) { 662 req->AddRef(); // Release in OCSPFree(). 663 rv = SECSuccess; 664 } 665 *pRequest = req; 666 return rv; 667 } 668 669 SECStatus OCSPSetPostData(SEC_HTTP_REQUEST_SESSION request, 670 const char* http_data, 671 const PRUint32 http_data_len, 672 const char* http_content_type) { 673 VLOG(1) << "OCSP set post data len=" << http_data_len; 674 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); 675 676 req->SetPostData(http_data, http_data_len, http_content_type); 677 return SECSuccess; 678 } 679 680 SECStatus OCSPAddHeader(SEC_HTTP_REQUEST_SESSION request, 681 const char* http_header_name, 682 const char* http_header_value) { 683 VLOG(1) << "OCSP add header name=" << http_header_name 684 << " value=" << http_header_value; 685 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); 686 687 req->AddHeader(http_header_name, http_header_value); 688 return SECSuccess; 689 } 690 691 // Sets response of |req| in the output parameters. 692 // It is helper routine for OCSP trySendAndReceiveFcn. 693 // |http_response_data_len| could be used as input parameter. If it has 694 // non-zero value, it is considered as maximum size of |http_response_data|. 695 SECStatus OCSPSetResponse(OCSPRequestSession* req, 696 PRUint16* http_response_code, 697 const char** http_response_content_type, 698 const char** http_response_headers, 699 const char** http_response_data, 700 PRUint32* http_response_data_len) { 701 DCHECK(req->Finished()); 702 const std::string& data = req->http_response_data(); 703 if (http_response_data_len && *http_response_data_len) { 704 if (*http_response_data_len < data.size()) { 705 LOG(ERROR) << "response body too large: " << *http_response_data_len 706 << " < " << data.size(); 707 *http_response_data_len = data.size(); 708 PORT_SetError(SEC_ERROR_BAD_HTTP_RESPONSE); 709 return SECFailure; 710 } 711 } 712 VLOG(1) << "OCSP response " 713 << " response_code=" << req->http_response_code() 714 << " content_type=" << req->http_response_content_type() 715 << " header=" << req->http_response_headers() 716 << " data_len=" << data.size(); 717 if (http_response_code) 718 *http_response_code = req->http_response_code(); 719 if (http_response_content_type) 720 *http_response_content_type = req->http_response_content_type().c_str(); 721 if (http_response_headers) 722 *http_response_headers = req->http_response_headers().c_str(); 723 if (http_response_data) 724 *http_response_data = data.data(); 725 if (http_response_data_len) 726 *http_response_data_len = data.size(); 727 return SECSuccess; 728 } 729 730 SECStatus OCSPTrySendAndReceive(SEC_HTTP_REQUEST_SESSION request, 731 PRPollDesc** pPollDesc, 732 PRUint16* http_response_code, 733 const char** http_response_content_type, 734 const char** http_response_headers, 735 const char** http_response_data, 736 PRUint32* http_response_data_len) { 737 if (http_response_data_len) { 738 // We must always set an output value, even on failure. The output value 0 739 // means the failure was unrelated to the acceptable response data length. 740 *http_response_data_len = 0; 741 } 742 743 VLOG(1) << "OCSP try send and receive"; 744 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); 745 // We support blocking mode only. 746 if (pPollDesc) 747 *pPollDesc = NULL; 748 749 if (req->Started() || req->Finished()) { 750 // We support blocking mode only, so this function shouldn't be called 751 // again when req has stareted or finished. 752 NOTREACHED(); 753 PORT_SetError(SEC_ERROR_BAD_HTTP_RESPONSE); // Simple approximation. 754 return SECFailure; 755 } 756 757 const base::Time start_time = base::Time::Now(); 758 bool request_ok = true; 759 req->Start(); 760 if (!req->Wait() || req->http_response_code() == static_cast<PRUint16>(-1)) { 761 // If the response code is -1, the request failed and there is no response. 762 request_ok = false; 763 } 764 const base::TimeDelta duration = base::Time::Now() - start_time; 765 766 // For metrics, we want to know if the request was 'successful' or not. 767 // |request_ok| determines if we'll pass the response back to NSS and |ok| 768 // keep track of if we think the response was good. 769 bool ok = true; 770 if (!request_ok || 771 (req->http_response_code() >= 400 && req->http_response_code() < 600) || 772 req->http_response_data().size() == 0 || 773 // 0x30 is the ASN.1 DER encoding of a SEQUENCE. All valid OCSP/CRL/CRT 774 // responses must start with this. If we didn't check for this then a 775 // captive portal could provide an HTML reply that we would count as a 776 // 'success' (although it wouldn't count in NSS, of course). 777 req->http_response_data().data()[0] != 0x30) { 778 ok = false; 779 } 780 781 // We want to know if this was: 782 // 1) An OCSP request 783 // 2) A CRL request 784 // 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 786 // URL. 787 const char* mime_type = ""; 788 if (ok) 789 mime_type = req->http_response_content_type().c_str(); 790 bool is_ocsp = 791 strcasecmp(mime_type, "application/ocsp-response") == 0; 792 bool is_crl = strcasecmp(mime_type, "application/x-pkcs7-crl") == 0 || 793 strcasecmp(mime_type, "application/x-x509-crl") == 0 || 794 strcasecmp(mime_type, "application/pkix-crl") == 0; 795 bool is_cert = 796 strcasecmp(mime_type, "application/x-x509-ca-cert") == 0 || 797 strcasecmp(mime_type, "application/x-x509-server-cert") == 0 || 798 strcasecmp(mime_type, "application/pkix-cert") == 0 || 799 strcasecmp(mime_type, "application/pkcs7-mime") == 0; 800 801 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. 803 const std::string path = req->url().path(); 804 const std::string host = req->url().host(); 805 is_crl = strcasestr(path.c_str(), ".crl") != NULL; 806 is_cert = strcasestr(path.c_str(), ".crt") != NULL || 807 strcasestr(path.c_str(), ".p7c") != NULL || 808 strcasestr(path.c_str(), ".cer") != NULL; 809 is_ocsp = strcasestr(host.c_str(), "ocsp") != NULL || 810 req->http_request_method() == "POST"; 811 } 812 813 if (is_ocsp) { 814 if (ok) { 815 UMA_HISTOGRAM_TIMES("Net.OCSPRequestTimeMs", duration); 816 UMA_HISTOGRAM_BOOLEAN("Net.OCSPRequestSuccess", true); 817 } else { 818 UMA_HISTOGRAM_TIMES("Net.OCSPRequestFailedTimeMs", duration); 819 UMA_HISTOGRAM_BOOLEAN("Net.OCSPRequestSuccess", false); 820 } 821 } else if (is_crl) { 822 if (ok) { 823 UMA_HISTOGRAM_TIMES("Net.CRLRequestTimeMs", duration); 824 UMA_HISTOGRAM_BOOLEAN("Net.CRLRequestSuccess", true); 825 } else { 826 UMA_HISTOGRAM_TIMES("Net.CRLRequestFailedTimeMs", duration); 827 UMA_HISTOGRAM_BOOLEAN("Net.CRLRequestSuccess", false); 828 } 829 } else if (is_cert) { 830 if (ok) 831 UMA_HISTOGRAM_TIMES("Net.CRTRequestTimeMs", duration); 832 } else { 833 if (ok) 834 UMA_HISTOGRAM_TIMES("Net.UnknownTypeRequestTimeMs", duration); 835 } 836 837 if (!request_ok) { 838 PORT_SetError(SEC_ERROR_BAD_HTTP_RESPONSE); // Simple approximation. 839 return SECFailure; 840 } 841 842 return OCSPSetResponse( 843 req, http_response_code, 844 http_response_content_type, 845 http_response_headers, 846 http_response_data, 847 http_response_data_len); 848 } 849 850 SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request) { 851 VLOG(1) << "OCSP free"; 852 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); 853 req->Cancel(); 854 req->Release(); 855 return SECSuccess; 856 } 857 858 // Data for GetAlternateOCSPAIAInfo. 859 860 // CN=Network Solutions Certificate Authority,O=Network Solutions L.L.C.,C=US 861 // 862 // There are two CAs with this name. Their key IDs are listed next. 863 const unsigned char network_solutions_ca_name[] = { 864 0x30, 0x62, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 865 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x21, 0x30, 0x1f, 0x06, 866 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x4e, 0x65, 0x74, 0x77, 867 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 868 0x6f, 0x6e, 0x73, 0x20, 0x4c, 0x2e, 0x4c, 0x2e, 0x43, 0x2e, 869 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 870 0x27, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53, 871 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 872 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 873 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79 874 }; 875 const unsigned int network_solutions_ca_name_len = 100; 876 877 // This CA is an intermediate CA, subordinate to UTN-USERFirst-Hardware. 878 const unsigned char network_solutions_ca_key_id[] = { 879 0x3c, 0x41, 0xe2, 0x8f, 0x08, 0x08, 0xa9, 0x4c, 0x25, 0x89, 880 0x8d, 0x6d, 0xc5, 0x38, 0xd0, 0xfc, 0x85, 0x8c, 0x62, 0x17 881 }; 882 const unsigned int network_solutions_ca_key_id_len = 20; 883 884 // This CA is a root CA. It is also cross-certified by 885 // UTN-USERFirst-Hardware. 886 const unsigned char network_solutions_ca_key_id2[] = { 887 0x21, 0x30, 0xc9, 0xfb, 0x00, 0xd7, 0x4e, 0x98, 0xda, 0x87, 888 0xaa, 0x2a, 0xd0, 0xa7, 0x2e, 0xb1, 0x40, 0x31, 0xa7, 0x4c 889 }; 890 const unsigned int network_solutions_ca_key_id2_len = 20; 891 892 // An entry in our OCSP responder table. |issuer| and |issuer_key_id| are 893 // the key. |ocsp_url| is the value. 894 struct OCSPResponderTableEntry { 895 SECItem issuer; 896 SECItem issuer_key_id; 897 const char *ocsp_url; 898 }; 899 900 const OCSPResponderTableEntry g_ocsp_responder_table[] = { 901 { 902 { 903 siBuffer, 904 const_cast<unsigned char*>(network_solutions_ca_name), 905 network_solutions_ca_name_len 906 }, 907 { 908 siBuffer, 909 const_cast<unsigned char*>(network_solutions_ca_key_id), 910 network_solutions_ca_key_id_len 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 929 char* GetAlternateOCSPAIAInfo(CERTCertificate *cert) { 930 if (cert && !cert->isRoot && cert->authKeyID) { 931 for (unsigned int i=0; i < arraysize(g_ocsp_responder_table); i++) { 932 if (SECITEM_CompareItem(&g_ocsp_responder_table[i].issuer, 933 &cert->derIssuer) == SECEqual && 934 SECITEM_CompareItem(&g_ocsp_responder_table[i].issuer_key_id, 935 &cert->authKeyID->keyID) == SECEqual) { 936 return PORT_Strdup(g_ocsp_responder_table[i].ocsp_url); 937 } 938 } 939 } 940 941 return NULL; 942 } 943 944 } // anonymous namespace 945 946 void SetMessageLoopForNSSHttpIO() { 947 // Must have a MessageLoopForIO. 948 DCHECK(base::MessageLoopForIO::current()); 949 950 bool used = g_ocsp_io_loop.Get().used(); 951 952 // Should not be called when g_ocsp_io_loop has already been used. 953 DCHECK(!used); 954 } 955 956 void EnsureNSSHttpIOInit() { 957 g_ocsp_io_loop.Get().StartUsing(); 958 g_ocsp_nss_initialization.Get(); 959 } 960 961 void ShutdownNSSHttpIO() { 962 g_ocsp_io_loop.Get().Shutdown(); 963 } 964 965 void ResetNSSHttpIOForTesting() { 966 g_ocsp_io_loop.Get().ReuseForTesting(); 967 } 968 969 // This function would be called before NSS initialization. 970 void SetURLRequestContextForNSSHttpIO(URLRequestContext* request_context) { 971 pthread_mutex_lock(&g_request_context_lock); 972 if (request_context) { 973 DCHECK(!g_request_context); 974 } 975 g_request_context = request_context; 976 pthread_mutex_unlock(&g_request_context_lock); 977 } 978 979 } // namespace net 980