nss_ocsp.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
1179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// Use of this source code is governed by a BSD-style license that can be 3179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// found in the LICENSE file. 4179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 5179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "net/ocsp/nss_ocsp.h" 6179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 7179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <certt.h> 813daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com#include <certdb.h> 9179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <ocsp.h> 10179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <nspr.h> 11179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <nss.h> 12179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <pthread.h> 13fbd97aa4c5325eace57d24b89845b9581bac9324jorlow@chromium.org#include <secerr.h> 14fbd97aa4c5325eace57d24b89845b9581bac9324jorlow@chromium.org 15179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include <algorithm> 1629c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org#include <string> 17179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 18179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/basictypes.h" 19179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/callback.h" 20179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/compiler_specific.h" 21179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/lazy_instance.h" 22179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/logging.h" 23179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/message_loop.h" 24179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/metrics/histogram.h" 25179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/stl_util.h" 26179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/strings/string_util.h" 27179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/strings/stringprintf.h" 28179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/synchronization/condition_variable.h" 29179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/synchronization/lock.h" 30179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/threading/thread_checker.h" 31179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "base/time/time.h" 32179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "googleurl/src/gurl.h" 33179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "net/base/host_port_pair.h" 34179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "net/base/io_buffer.h" 35179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "net/base/load_flags.h" 36179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "net/base/upload_bytes_element_reader.h" 37179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "net/base/upload_data_stream.h" 38179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "net/http/http_request_headers.h" 39179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "net/http/http_response_headers.h" 40179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org#include "net/url_request/url_request.h" 4195e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org#include "net/url_request/url_request_context.h" 42179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 435fb21ed7ac9e91010d473ac77e132ae68f348d6agabor@google.comnamespace net { 44179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 45179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgnamespace { 46179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 475fb21ed7ac9e91010d473ac77e132ae68f348d6agabor@google.com// Protects |g_request_context|. 485fb21ed7ac9e91010d473ac77e132ae68f348d6agabor@google.compthread_mutex_t g_request_context_lock = PTHREAD_MUTEX_INITIALIZER; 49179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgURLRequestContext* g_request_context = NULL; 50179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 51179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// The default timeout for network fetches in NSS is 60 seconds. Choose a 52179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// saner upper limit for OCSP/CRL/AIA fetches. 53179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgconst int kNetworkFetchTimeoutInSecs = 15; 54179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 55179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgclass OCSPRequestSession; 56179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 57179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgclass OCSPIOLoop { 58b887f640bae906abfb77fdf418be63350b4c5e1fjorlow@chromium.org public: 59b887f640bae906abfb77fdf418be63350b4c5e1fjorlow@chromium.org void StartUsing() { 6007f3bcfb9764be2a339cc02cf0a0d6edb151defbjorlow@chromium.org base::AutoLock autolock(lock_); 61b887f640bae906abfb77fdf418be63350b4c5e1fjorlow@chromium.org used_ = true; 6208595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org io_loop_ = base::MessageLoopForIO::current(); 6308595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org DCHECK(io_loop_); 6408595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org } 6508595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org 6608595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org // Called on IO loop. 67179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org void Shutdown(); 68179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 6913daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com bool used() const { 7013daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com base::AutoLock autolock(lock_); 71179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org return used_; 72179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org } 7308595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org 7408595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org // Called from worker thread. 75179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org void PostTaskToIOLoop(const tracked_objects::Location& from_here, 76179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org const base::Closure& task); 77179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 78179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org void EnsureIOLoop(); 79179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 80179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org void AddRequest(OCSPRequestSession* request); 8129c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org void RemoveRequest(OCSPRequestSession* request); 82179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 83179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org // Clears internal state and calls |StartUsing()|. Should be called only in 84179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org // the context of testing. 85179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org void ReuseForTesting() { 86179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org { 87179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org base::AutoLock autolock(lock_); 88179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org DCHECK(base::MessageLoopForIO::current()); 89179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org thread_checker_.DetachFromThread(); 904935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org thread_checker_.CalledOnValidThread(); 914935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org shutdown_ = false; 92179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org used_ = false; 93179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org } 94179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org StartUsing(); 9529c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org } 9629c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org 97179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org private: 9829c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org friend struct base::DefaultLazyInstanceTraits<OCSPIOLoop>; 9929c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org 100179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org OCSPIOLoop(); 10129c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org ~OCSPIOLoop(); 10229c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org 10313daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com void CancelAllRequests(); 104179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 1054935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org mutable base::Lock lock_; 1064935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org bool shutdown_; // Protected by |lock_|. 10729c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org std::set<OCSPRequestSession*> requests_; // Protected by |lock_|. 108179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org bool used_; // Protected by |lock_|. 109179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org // This should not be modified after |used_|. 1104935bf087b28aa308c0a820720b85ef695e236aedgrogan@chromium.org base::MessageLoopForIO* io_loop_; // Protected by |lock_|. 11129c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org base::ThreadChecker thread_checker_; 11229c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org 11329c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org DISALLOW_COPY_AND_ASSIGN(OCSPIOLoop); 11429c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org}; 115179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 116179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgbase::LazyInstance<OCSPIOLoop>::Leaky 117179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org g_ocsp_io_loop = LAZY_INSTANCE_INITIALIZER; 11829c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.org 11929c68f16466b1704dc7a663cf51bf9c5579830c3dgrogan@chromium.orgconst int kRecvBufferSize = 4096; 120179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 121179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// All OCSP handlers should be called in the context of 122179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// CertVerifier's thread (i.e. worker pool, not on the I/O thread). 123179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// It supports blocking mode only. 12499a7585544fc162a5f8dd39a6add00776a981efesanjay@google.com 125179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgSECStatus OCSPCreateSession(const char* host, PRUint16 portnum, 126179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org SEC_HTTP_SERVER_SESSION* pSession); 12795e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.orgSECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session, 128179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org PRPollDesc **pPollDesc); 129179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgSECStatus OCSPFreeSession(SEC_HTTP_SERVER_SESSION session); 130179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 131179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgSECStatus OCSPCreate(SEC_HTTP_SERVER_SESSION session, 132179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org const char* http_protocol_variant, 133179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org const char* path_and_query_string, 134179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org const char* http_request_method, 135179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org const PRIntervalTime timeout, 136179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org SEC_HTTP_REQUEST_SESSION* pRequest); 137179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgSECStatus OCSPSetPostData(SEC_HTTP_REQUEST_SESSION request, 138179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org const char* http_data, 1396635e49a8999ab5e411d5227146a3db17fac2944hans@chromium.org const PRUint32 http_data_len, 140179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org const char* http_content_type); 14195e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.orgSECStatus OCSPAddHeader(SEC_HTTP_REQUEST_SESSION request, 14295e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org const char* http_header_name, 143179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org const char* http_header_value); 1448cd4ab8303620197cf24282ae8639060efbb326egabor@google.comSECStatus OCSPTrySendAndReceive(SEC_HTTP_REQUEST_SESSION request, 145179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org PRPollDesc** pPollDesc, 14608595b9e51ded54851b7664bd38affad63a67838dgrogan@chromium.org PRUint16* http_response_code, 14713daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com const char** http_response_content_type, 14813daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com const char** http_response_headers, 14913daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com const char** http_response_data, 15013daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.com PRUint32* http_response_data_len); 15113daa9f29c999ee40a257ee0775abee2c78a0ad9sanjay@google.comSECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request); 152179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 153179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgchar* GetAlternateOCSPAIAInfo(CERTCertificate *cert); 154179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 155179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgclass OCSPNSSInitialization { 156179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org private: 157179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org friend struct base::DefaultLazyInstanceTraits<OCSPNSSInitialization>; 158179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 159179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org OCSPNSSInitialization(); 160179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org ~OCSPNSSInitialization(); 1616635e49a8999ab5e411d5227146a3db17fac2944hans@chromium.org 1626635e49a8999ab5e411d5227146a3db17fac2944hans@chromium.org SEC_HttpClientFcn client_fcn_; 1636635e49a8999ab5e411d5227146a3db17fac2944hans@chromium.org 1645fb21ed7ac9e91010d473ac77e132ae68f348d6agabor@google.com DISALLOW_COPY_AND_ASSIGN(OCSPNSSInitialization); 1655fb21ed7ac9e91010d473ac77e132ae68f348d6agabor@google.com}; 1665fb21ed7ac9e91010d473ac77e132ae68f348d6agabor@google.com 1675fb21ed7ac9e91010d473ac77e132ae68f348d6agabor@google.combase::LazyInstance<OCSPNSSInitialization> g_ocsp_nss_initialization = 1686635e49a8999ab5e411d5227146a3db17fac2944hans@chromium.org LAZY_INSTANCE_INITIALIZER; 1696635e49a8999ab5e411d5227146a3db17fac2944hans@chromium.org 170179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// Concrete class for SEC_HTTP_REQUEST_SESSION. 171179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// Public methods except virtual methods of URLRequest::Delegate 172179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// (On* methods) run on certificate verifier thread (worker thread). 173179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// Virtual methods of URLRequest::Delegate and private methods run 174179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org// on IO thread. 175179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.orgclass OCSPRequestSession 17695e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org : public base::RefCountedThreadSafe<OCSPRequestSession>, 17795e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org public URLRequest::Delegate { 17895e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org public: 17995e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org OCSPRequestSession(const GURL& url, 18095e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org const char* http_request_method, 18195e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org base::TimeDelta timeout) 18295e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org : url_(url), 18395e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org http_request_method_(http_request_method), 18495e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org timeout_(timeout), 18595e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org request_(NULL), 18695e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org buffer_(new IOBuffer(kRecvBufferSize)), 18795e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org response_code_(-1), 18895e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org cv_(&lock_), 18995e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org io_loop_(NULL), 19095e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org finished_(false) {} 19195e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org 19295e21f32367748825123e382172ecbfd492ddb23dgrogan@chromium.org void SetPostData(const char* http_data, PRUint32 http_data_len, 193179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org const char* http_content_type) { 194179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org // |upload_content_| should not be modified if |request_| is active. 195179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org DCHECK(!request_); 196179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org upload_content_.assign(http_data, http_data_len); 197179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org upload_content_type_.assign(http_content_type); 198179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org } 199179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 200179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org void AddHeader(const char* http_header_name, const char* http_header_value) { 201179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org extra_request_headers_.SetHeader(http_header_name, 202179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org http_header_value); 203179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org } 204179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org 205179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org void Start() { 20699a7585544fc162a5f8dd39a6add00776a981efesanjay@google.com // At this point, it runs on worker thread. 207179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org // |io_loop_| was initialized to be NULL in constructor, and 208179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org // set only in StartURLRequest, so no need to lock |lock_| here. 20945b9940be332834440bd5299419f396e38085ebehans@chromium.org DCHECK(!io_loop_); 210179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org g_ocsp_io_loop.Get().PostTaskToIOLoop( 211179be588c25dccaa963df9c9c104fc6229435483jorlow@chromium.org FROM_HERE, 212 base::Bind(&OCSPRequestSession::StartURLRequest, this)); 213 } 214 215 bool Started() const { 216 return request_ != NULL; 217 } 218 219 void Cancel() { 220 // IO thread may set |io_loop_| to NULL, so protect by |lock_|. 221 base::AutoLock autolock(lock_); 222 CancelLocked(); 223 } 224 225 bool Finished() const { 226 base::AutoLock autolock(lock_); 227 return finished_; 228 } 229 230 bool Wait() { 231 base::TimeDelta timeout = timeout_; 232 base::AutoLock autolock(lock_); 233 while (!finished_) { 234 base::TimeTicks last_time = base::TimeTicks::Now(); 235 cv_.TimedWait(timeout); 236 // Check elapsed time 237 base::TimeDelta elapsed_time = base::TimeTicks::Now() - last_time; 238 timeout -= elapsed_time; 239 if (timeout < base::TimeDelta()) { 240 VLOG(1) << "OCSP Timed out"; 241 if (!finished_) 242 CancelLocked(); 243 break; 244 } 245 } 246 return finished_; 247 } 248 249 const GURL& url() const { 250 return url_; 251 } 252 253 const std::string& http_request_method() const { 254 return http_request_method_; 255 } 256 257 base::TimeDelta timeout() const { 258 return timeout_; 259 } 260 261 PRUint16 http_response_code() const { 262 DCHECK(finished_); 263 return response_code_; 264 } 265 266 const std::string& http_response_content_type() const { 267 DCHECK(finished_); 268 return response_content_type_; 269 } 270 271 const std::string& http_response_headers() const { 272 DCHECK(finished_); 273 return response_headers_->raw_headers(); 274 } 275 276 const std::string& http_response_data() const { 277 DCHECK(finished_); 278 return data_; 279 } 280 281 virtual void OnReceivedRedirect(URLRequest* request, 282 const GURL& new_url, 283 bool* defer_redirect) OVERRIDE { 284 DCHECK_EQ(request, request_); 285 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); 286 287 if (!new_url.SchemeIs("http")) { 288 // Prevent redirects to non-HTTP schemes, including HTTPS. This matches 289 // the initial check in OCSPServerSession::CreateRequest(). 290 CancelURLRequest(); 291 } 292 } 293 294 virtual void OnResponseStarted(URLRequest* request) OVERRIDE { 295 DCHECK_EQ(request, request_); 296 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); 297 298 int bytes_read = 0; 299 if (request->status().is_success()) { 300 response_code_ = request_->GetResponseCode(); 301 response_headers_ = request_->response_headers(); 302 response_headers_->GetMimeType(&response_content_type_); 303 request_->Read(buffer_.get(), kRecvBufferSize, &bytes_read); 304 } 305 OnReadCompleted(request_, bytes_read); 306 } 307 308 virtual void OnReadCompleted(URLRequest* request, 309 int bytes_read) OVERRIDE { 310 DCHECK_EQ(request, request_); 311 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); 312 313 do { 314 if (!request_->status().is_success() || bytes_read <= 0) 315 break; 316 data_.append(buffer_->data(), bytes_read); 317 } while (request_->Read(buffer_.get(), kRecvBufferSize, &bytes_read)); 318 319 if (!request_->status().is_io_pending()) { 320 delete request_; 321 request_ = NULL; 322 g_ocsp_io_loop.Get().RemoveRequest(this); 323 { 324 base::AutoLock autolock(lock_); 325 finished_ = true; 326 io_loop_ = NULL; 327 } 328 cv_.Signal(); 329 Release(); // Balanced with StartURLRequest(). 330 } 331 } 332 333 // Must be called on the IO loop thread. 334 void CancelURLRequest() { 335#ifndef NDEBUG 336 { 337 base::AutoLock autolock(lock_); 338 if (io_loop_) 339 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); 340 } 341#endif 342 if (request_) { 343 request_->Cancel(); 344 delete request_; 345 request_ = NULL; 346 g_ocsp_io_loop.Get().RemoveRequest(this); 347 { 348 base::AutoLock autolock(lock_); 349 finished_ = true; 350 io_loop_ = NULL; 351 } 352 cv_.Signal(); 353 Release(); // Balanced with StartURLRequest(). 354 } 355 } 356 357 private: 358 friend class base::RefCountedThreadSafe<OCSPRequestSession>; 359 360 virtual ~OCSPRequestSession() { 361 // When this destructor is called, there should be only one thread that has 362 // a reference to this object, and so that thread doesn't need to lock 363 // |lock_| here. 364 DCHECK(!request_); 365 DCHECK(!io_loop_); 366 } 367 368 // Must call this method while holding |lock_|. 369 void CancelLocked() { 370 lock_.AssertAcquired(); 371 if (io_loop_) { 372 io_loop_->PostTask( 373 FROM_HERE, 374 base::Bind(&OCSPRequestSession::CancelURLRequest, this)); 375 } 376 } 377 378 // Runs on |g_ocsp_io_loop|'s IO loop. 379 void StartURLRequest() { 380 DCHECK(!request_); 381 382 pthread_mutex_lock(&g_request_context_lock); 383 URLRequestContext* url_request_context = g_request_context; 384 pthread_mutex_unlock(&g_request_context_lock); 385 386 if (url_request_context == NULL) 387 return; 388 389 { 390 base::AutoLock autolock(lock_); 391 DCHECK(!io_loop_); 392 io_loop_ = base::MessageLoopForIO::current(); 393 g_ocsp_io_loop.Get().AddRequest(this); 394 } 395 396 request_ = new URLRequest(url_, this, url_request_context); 397 // To meet the privacy requirements of incognito mode. 398 request_->set_load_flags(LOAD_DISABLE_CACHE | LOAD_DO_NOT_SAVE_COOKIES | 399 LOAD_DO_NOT_SEND_COOKIES); 400 401 if (http_request_method_ == "POST") { 402 DCHECK(!upload_content_.empty()); 403 DCHECK(!upload_content_type_.empty()); 404 405 request_->set_method("POST"); 406 extra_request_headers_.SetHeader( 407 HttpRequestHeaders::kContentType, upload_content_type_); 408 409 scoped_ptr<UploadElementReader> reader(new UploadBytesElementReader( 410 upload_content_.data(), upload_content_.size())); 411 request_->set_upload(make_scoped_ptr( 412 UploadDataStream::CreateWithReader(reader.Pass(), 0))); 413 } 414 if (!extra_request_headers_.IsEmpty()) 415 request_->SetExtraRequestHeaders(extra_request_headers_); 416 417 request_->Start(); 418 AddRef(); // Release after |request_| deleted. 419 } 420 421 GURL url_; // The URL we eventually wound up at 422 std::string http_request_method_; 423 base::TimeDelta timeout_; // The timeout for OCSP 424 URLRequest* request_; // The actual request this wraps 425 scoped_refptr<IOBuffer> buffer_; // Read buffer 426 HttpRequestHeaders extra_request_headers_; 427 428 // HTTP POST payload. |request_| reads bytes from this. 429 std::string upload_content_; 430 std::string upload_content_type_; // MIME type of POST payload 431 432 int response_code_; // HTTP status code for the request 433 std::string response_content_type_; 434 scoped_refptr<HttpResponseHeaders> response_headers_; 435 std::string data_; // Results of the request 436 437 // |lock_| protects |finished_| and |io_loop_|. 438 mutable base::Lock lock_; 439 base::ConditionVariable cv_; 440 441 base::MessageLoop* io_loop_; // Message loop of the IO thread 442 bool finished_; 443 444 DISALLOW_COPY_AND_ASSIGN(OCSPRequestSession); 445}; 446 447// Concrete class for SEC_HTTP_SERVER_SESSION. 448class OCSPServerSession { 449 public: 450 OCSPServerSession(const char* host, PRUint16 port) 451 : host_and_port_(host, port) {} 452 ~OCSPServerSession() {} 453 454 OCSPRequestSession* CreateRequest(const char* http_protocol_variant, 455 const char* path_and_query_string, 456 const char* http_request_method, 457 const PRIntervalTime timeout) { 458 // We dont' support "https" because we haven't thought about 459 // whether it's safe to re-enter this code from talking to an OCSP 460 // responder over SSL. 461 if (strcmp(http_protocol_variant, "http") != 0) { 462 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 463 return NULL; 464 } 465 466 std::string url_string(base::StringPrintf( 467 "%s://%s%s", 468 http_protocol_variant, 469 host_and_port_.ToString().c_str(), 470 path_and_query_string)); 471 VLOG(1) << "URL [" << url_string << "]"; 472 GURL url(url_string); 473 474 // NSS does not expose public functions to adjust the fetch timeout when 475 // using libpkix, so hardcode the upper limit for network fetches. 476 base::TimeDelta actual_timeout = std::min( 477 base::TimeDelta::FromSeconds(kNetworkFetchTimeoutInSecs), 478 base::TimeDelta::FromMilliseconds(PR_IntervalToMilliseconds(timeout))); 479 480 return new OCSPRequestSession(url, http_request_method, actual_timeout); 481 } 482 483 484 private: 485 HostPortPair host_and_port_; 486 487 DISALLOW_COPY_AND_ASSIGN(OCSPServerSession); 488}; 489 490OCSPIOLoop::OCSPIOLoop() 491 : shutdown_(false), 492 used_(false), 493 io_loop_(NULL) { 494} 495 496OCSPIOLoop::~OCSPIOLoop() { 497 // IO thread was already deleted before the singleton is deleted 498 // in AtExitManager. 499 { 500 base::AutoLock autolock(lock_); 501 DCHECK(!io_loop_); 502 DCHECK(!used_); 503 DCHECK(shutdown_); 504 } 505 506 pthread_mutex_lock(&g_request_context_lock); 507 DCHECK(!g_request_context); 508 pthread_mutex_unlock(&g_request_context_lock); 509} 510 511void OCSPIOLoop::Shutdown() { 512 // Safe to read outside lock since we only write on IO thread anyway. 513 DCHECK(thread_checker_.CalledOnValidThread()); 514 515 // Prevent the worker thread from trying to access |io_loop_|. 516 { 517 base::AutoLock autolock(lock_); 518 io_loop_ = NULL; 519 used_ = false; 520 shutdown_ = true; 521 } 522 523 CancelAllRequests(); 524 525 pthread_mutex_lock(&g_request_context_lock); 526 g_request_context = NULL; 527 pthread_mutex_unlock(&g_request_context_lock); 528} 529 530void OCSPIOLoop::PostTaskToIOLoop( 531 const tracked_objects::Location& from_here, const base::Closure& task) { 532 base::AutoLock autolock(lock_); 533 if (io_loop_) 534 io_loop_->PostTask(from_here, task); 535} 536 537void OCSPIOLoop::EnsureIOLoop() { 538 base::AutoLock autolock(lock_); 539 DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_); 540} 541 542void OCSPIOLoop::AddRequest(OCSPRequestSession* request) { 543 DCHECK(!ContainsKey(requests_, request)); 544 requests_.insert(request); 545} 546 547void OCSPIOLoop::RemoveRequest(OCSPRequestSession* request) { 548 DCHECK(ContainsKey(requests_, request)); 549 requests_.erase(request); 550} 551 552void OCSPIOLoop::CancelAllRequests() { 553 // CancelURLRequest() always removes the request from the requests_ 554 // set synchronously. 555 while (!requests_.empty()) 556 (*requests_.begin())->CancelURLRequest(); 557} 558 559OCSPNSSInitialization::OCSPNSSInitialization() { 560 // NSS calls the functions in the function table to download certificates 561 // or CRLs or talk to OCSP responders over HTTP. These functions must 562 // set an NSS/NSPR error code when they fail. Otherwise NSS will get the 563 // residual error code from an earlier failed function call. 564 client_fcn_.version = 1; 565 SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1; 566 ft->createSessionFcn = OCSPCreateSession; 567 ft->keepAliveSessionFcn = OCSPKeepAliveSession; 568 ft->freeSessionFcn = OCSPFreeSession; 569 ft->createFcn = OCSPCreate; 570 ft->setPostDataFcn = OCSPSetPostData; 571 ft->addHeaderFcn = OCSPAddHeader; 572 ft->trySendAndReceiveFcn = OCSPTrySendAndReceive; 573 ft->cancelFcn = NULL; 574 ft->freeFcn = OCSPFree; 575 SECStatus status = SEC_RegisterDefaultHttpClient(&client_fcn_); 576 if (status != SECSuccess) { 577 NOTREACHED() << "Error initializing OCSP: " << PR_GetError(); 578 } 579 580 // Work around NSS bugs 524013 and 564334. NSS incorrectly thinks the 581 // CRLs for Network Solutions Certificate Authority have bad signatures, 582 // which causes certificates issued by that CA to be reported as revoked. 583 // By using OCSP for those certificates, which don't have AIA extensions, 584 // we can work around these bugs. See http://crbug.com/41730. 585 CERT_StringFromCertFcn old_callback = NULL; 586 status = CERT_RegisterAlternateOCSPAIAInfoCallBack( 587 GetAlternateOCSPAIAInfo, &old_callback); 588 if (status == SECSuccess) { 589 DCHECK(!old_callback); 590 } else { 591 NOTREACHED() << "Error initializing OCSP: " << PR_GetError(); 592 } 593} 594 595OCSPNSSInitialization::~OCSPNSSInitialization() { 596 SECStatus status = CERT_RegisterAlternateOCSPAIAInfoCallBack(NULL, NULL); 597 if (status != SECSuccess) { 598 LOG(ERROR) << "Error unregistering OCSP: " << PR_GetError(); 599 } 600} 601 602 603// OCSP Http Client functions. 604// Our Http Client functions operate in blocking mode. 605SECStatus OCSPCreateSession(const char* host, PRUint16 portnum, 606 SEC_HTTP_SERVER_SESSION* pSession) { 607 VLOG(1) << "OCSP create session: host=" << host << " port=" << portnum; 608 pthread_mutex_lock(&g_request_context_lock); 609 URLRequestContext* request_context = g_request_context; 610 pthread_mutex_unlock(&g_request_context_lock); 611 if (request_context == NULL) { 612 LOG(ERROR) << "No URLRequestContext for NSS HTTP handler. host: " << host; 613 // The application failed to call SetURLRequestContextForNSSHttpIO or 614 // has already called ShutdownNSSHttpIO, so we can't create and use 615 // URLRequest. PR_NOT_IMPLEMENTED_ERROR is not an accurate error 616 // code for these error conditions, but is close enough. 617 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 618 return SECFailure; 619 } 620 *pSession = new OCSPServerSession(host, portnum); 621 return SECSuccess; 622} 623 624SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session, 625 PRPollDesc **pPollDesc) { 626 VLOG(1) << "OCSP keep alive"; 627 if (pPollDesc) 628 *pPollDesc = NULL; 629 return SECSuccess; 630} 631 632SECStatus OCSPFreeSession(SEC_HTTP_SERVER_SESSION session) { 633 VLOG(1) << "OCSP free session"; 634 delete reinterpret_cast<OCSPServerSession*>(session); 635 return SECSuccess; 636} 637 638SECStatus OCSPCreate(SEC_HTTP_SERVER_SESSION session, 639 const char* http_protocol_variant, 640 const char* path_and_query_string, 641 const char* http_request_method, 642 const PRIntervalTime timeout, 643 SEC_HTTP_REQUEST_SESSION* pRequest) { 644 VLOG(1) << "OCSP create protocol=" << http_protocol_variant 645 << " path_and_query=" << path_and_query_string 646 << " http_request_method=" << http_request_method 647 << " timeout=" << timeout; 648 OCSPServerSession* ocsp_session = 649 reinterpret_cast<OCSPServerSession*>(session); 650 651 OCSPRequestSession* req = ocsp_session->CreateRequest(http_protocol_variant, 652 path_and_query_string, 653 http_request_method, 654 timeout); 655 SECStatus rv = SECFailure; 656 if (req) { 657 req->AddRef(); // Release in OCSPFree(). 658 rv = SECSuccess; 659 } 660 *pRequest = req; 661 return rv; 662} 663 664SECStatus OCSPSetPostData(SEC_HTTP_REQUEST_SESSION request, 665 const char* http_data, 666 const PRUint32 http_data_len, 667 const char* http_content_type) { 668 VLOG(1) << "OCSP set post data len=" << http_data_len; 669 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); 670 671 req->SetPostData(http_data, http_data_len, http_content_type); 672 return SECSuccess; 673} 674 675SECStatus OCSPAddHeader(SEC_HTTP_REQUEST_SESSION request, 676 const char* http_header_name, 677 const char* http_header_value) { 678 VLOG(1) << "OCSP add header name=" << http_header_name 679 << " value=" << http_header_value; 680 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); 681 682 req->AddHeader(http_header_name, http_header_value); 683 return SECSuccess; 684} 685 686// Sets response of |req| in the output parameters. 687// It is helper routine for OCSP trySendAndReceiveFcn. 688// |http_response_data_len| could be used as input parameter. If it has 689// non-zero value, it is considered as maximum size of |http_response_data|. 690SECStatus OCSPSetResponse(OCSPRequestSession* req, 691 PRUint16* http_response_code, 692 const char** http_response_content_type, 693 const char** http_response_headers, 694 const char** http_response_data, 695 PRUint32* http_response_data_len) { 696 DCHECK(req->Finished()); 697 const std::string& data = req->http_response_data(); 698 if (http_response_data_len && *http_response_data_len) { 699 if (*http_response_data_len < data.size()) { 700 LOG(ERROR) << "response body too large: " << *http_response_data_len 701 << " < " << data.size(); 702 *http_response_data_len = data.size(); 703 PORT_SetError(SEC_ERROR_BAD_HTTP_RESPONSE); 704 return SECFailure; 705 } 706 } 707 VLOG(1) << "OCSP response " 708 << " response_code=" << req->http_response_code() 709 << " content_type=" << req->http_response_content_type() 710 << " header=" << req->http_response_headers() 711 << " data_len=" << data.size(); 712 if (http_response_code) 713 *http_response_code = req->http_response_code(); 714 if (http_response_content_type) 715 *http_response_content_type = req->http_response_content_type().c_str(); 716 if (http_response_headers) 717 *http_response_headers = req->http_response_headers().c_str(); 718 if (http_response_data) 719 *http_response_data = data.data(); 720 if (http_response_data_len) 721 *http_response_data_len = data.size(); 722 return SECSuccess; 723} 724 725SECStatus OCSPTrySendAndReceive(SEC_HTTP_REQUEST_SESSION request, 726 PRPollDesc** pPollDesc, 727 PRUint16* http_response_code, 728 const char** http_response_content_type, 729 const char** http_response_headers, 730 const char** http_response_data, 731 PRUint32* http_response_data_len) { 732 if (http_response_data_len) { 733 // We must always set an output value, even on failure. The output value 0 734 // means the failure was unrelated to the acceptable response data length. 735 *http_response_data_len = 0; 736 } 737 738 VLOG(1) << "OCSP try send and receive"; 739 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); 740 // We support blocking mode only. 741 if (pPollDesc) 742 *pPollDesc = NULL; 743 744 if (req->Started() || req->Finished()) { 745 // We support blocking mode only, so this function shouldn't be called 746 // again when req has stareted or finished. 747 NOTREACHED(); 748 PORT_SetError(SEC_ERROR_BAD_HTTP_RESPONSE); // Simple approximation. 749 return SECFailure; 750 } 751 752 const base::Time start_time = base::Time::Now(); 753 bool request_ok = true; 754 req->Start(); 755 if (!req->Wait() || req->http_response_code() == static_cast<PRUint16>(-1)) { 756 // If the response code is -1, the request failed and there is no response. 757 request_ok = false; 758 } 759 const base::TimeDelta duration = base::Time::Now() - start_time; 760 761 // For metrics, we want to know if the request was 'successful' or not. 762 // |request_ok| determines if we'll pass the response back to NSS and |ok| 763 // keep track of if we think the response was good. 764 bool ok = true; 765 if (!request_ok || 766 (req->http_response_code() >= 400 && req->http_response_code() < 600) || 767 req->http_response_data().size() == 0 || 768 // 0x30 is the ASN.1 DER encoding of a SEQUENCE. All valid OCSP/CRL/CRT 769 // responses must start with this. If we didn't check for this then a 770 // captive portal could provide an HTML reply that we would count as a 771 // 'success' (although it wouldn't count in NSS, of course). 772 req->http_response_data().data()[0] != 0x30) { 773 ok = false; 774 } 775 776 // We want to know if this was: 777 // 1) An OCSP request 778 // 2) A CRL request 779 // 3) A request for a missing intermediate certificate 780 // There's no sure way to do this, so we use heuristics like MIME type and 781 // URL. 782 const char* mime_type = ""; 783 if (ok) 784 mime_type = req->http_response_content_type().c_str(); 785 bool is_ocsp = 786 strcasecmp(mime_type, "application/ocsp-response") == 0; 787 bool is_crl = strcasecmp(mime_type, "application/x-pkcs7-crl") == 0 || 788 strcasecmp(mime_type, "application/x-x509-crl") == 0 || 789 strcasecmp(mime_type, "application/pkix-crl") == 0; 790 bool is_cert = 791 strcasecmp(mime_type, "application/x-x509-ca-cert") == 0 || 792 strcasecmp(mime_type, "application/x-x509-server-cert") == 0 || 793 strcasecmp(mime_type, "application/pkix-cert") == 0 || 794 strcasecmp(mime_type, "application/pkcs7-mime") == 0; 795 796 if (!is_cert && !is_crl && !is_ocsp) { 797 // We didn't get a hint from the MIME type, so do the best that we can. 798 const std::string path = req->url().path(); 799 const std::string host = req->url().host(); 800 is_crl = strcasestr(path.c_str(), ".crl") != NULL; 801 is_cert = strcasestr(path.c_str(), ".crt") != NULL || 802 strcasestr(path.c_str(), ".p7c") != NULL || 803 strcasestr(path.c_str(), ".cer") != NULL; 804 is_ocsp = strcasestr(host.c_str(), "ocsp") != NULL || 805 req->http_request_method() == "POST"; 806 } 807 808 if (is_ocsp) { 809 if (ok) { 810 UMA_HISTOGRAM_TIMES("Net.OCSPRequestTimeMs", duration); 811 UMA_HISTOGRAM_BOOLEAN("Net.OCSPRequestSuccess", true); 812 } else { 813 UMA_HISTOGRAM_TIMES("Net.OCSPRequestFailedTimeMs", duration); 814 UMA_HISTOGRAM_BOOLEAN("Net.OCSPRequestSuccess", false); 815 } 816 } else if (is_crl) { 817 if (ok) { 818 UMA_HISTOGRAM_TIMES("Net.CRLRequestTimeMs", duration); 819 UMA_HISTOGRAM_BOOLEAN("Net.CRLRequestSuccess", true); 820 } else { 821 UMA_HISTOGRAM_TIMES("Net.CRLRequestFailedTimeMs", duration); 822 UMA_HISTOGRAM_BOOLEAN("Net.CRLRequestSuccess", false); 823 } 824 } else if (is_cert) { 825 if (ok) 826 UMA_HISTOGRAM_TIMES("Net.CRTRequestTimeMs", duration); 827 } else { 828 if (ok) 829 UMA_HISTOGRAM_TIMES("Net.UnknownTypeRequestTimeMs", duration); 830 } 831 832 if (!request_ok) { 833 PORT_SetError(SEC_ERROR_BAD_HTTP_RESPONSE); // Simple approximation. 834 return SECFailure; 835 } 836 837 return OCSPSetResponse( 838 req, http_response_code, 839 http_response_content_type, 840 http_response_headers, 841 http_response_data, 842 http_response_data_len); 843} 844 845SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request) { 846 VLOG(1) << "OCSP free"; 847 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); 848 req->Cancel(); 849 req->Release(); 850 return SECSuccess; 851} 852 853// Data for GetAlternateOCSPAIAInfo. 854 855// CN=Network Solutions Certificate Authority,O=Network Solutions L.L.C.,C=US 856// 857// There are two CAs with this name. Their key IDs are listed next. 858const unsigned char network_solutions_ca_name[] = { 859 0x30, 0x62, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 860 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x21, 0x30, 0x1f, 0x06, 861 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x4e, 0x65, 0x74, 0x77, 862 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 863 0x6f, 0x6e, 0x73, 0x20, 0x4c, 0x2e, 0x4c, 0x2e, 0x43, 0x2e, 864 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 865 0x27, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53, 866 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 867 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 868 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79 869}; 870const unsigned int network_solutions_ca_name_len = 100; 871 872// This CA is an intermediate CA, subordinate to UTN-USERFirst-Hardware. 873const unsigned char network_solutions_ca_key_id[] = { 874 0x3c, 0x41, 0xe2, 0x8f, 0x08, 0x08, 0xa9, 0x4c, 0x25, 0x89, 875 0x8d, 0x6d, 0xc5, 0x38, 0xd0, 0xfc, 0x85, 0x8c, 0x62, 0x17 876}; 877const unsigned int network_solutions_ca_key_id_len = 20; 878 879// This CA is a root CA. It is also cross-certified by 880// UTN-USERFirst-Hardware. 881const unsigned char network_solutions_ca_key_id2[] = { 882 0x21, 0x30, 0xc9, 0xfb, 0x00, 0xd7, 0x4e, 0x98, 0xda, 0x87, 883 0xaa, 0x2a, 0xd0, 0xa7, 0x2e, 0xb1, 0x40, 0x31, 0xa7, 0x4c 884}; 885const unsigned int network_solutions_ca_key_id2_len = 20; 886 887// An entry in our OCSP responder table. |issuer| and |issuer_key_id| are 888// the key. |ocsp_url| is the value. 889struct OCSPResponderTableEntry { 890 SECItem issuer; 891 SECItem issuer_key_id; 892 const char *ocsp_url; 893}; 894 895const OCSPResponderTableEntry g_ocsp_responder_table[] = { 896 { 897 { 898 siBuffer, 899 const_cast<unsigned char*>(network_solutions_ca_name), 900 network_solutions_ca_name_len 901 }, 902 { 903 siBuffer, 904 const_cast<unsigned char*>(network_solutions_ca_key_id), 905 network_solutions_ca_key_id_len 906 }, 907 "http://ocsp.netsolssl.com" 908 }, 909 { 910 { 911 siBuffer, 912 const_cast<unsigned char*>(network_solutions_ca_name), 913 network_solutions_ca_name_len 914 }, 915 { 916 siBuffer, 917 const_cast<unsigned char*>(network_solutions_ca_key_id2), 918 network_solutions_ca_key_id2_len 919 }, 920 "http://ocsp.netsolssl.com" 921 } 922}; 923 924char* GetAlternateOCSPAIAInfo(CERTCertificate *cert) { 925 if (cert && !cert->isRoot && cert->authKeyID) { 926 for (unsigned int i=0; i < arraysize(g_ocsp_responder_table); i++) { 927 if (SECITEM_CompareItem(&g_ocsp_responder_table[i].issuer, 928 &cert->derIssuer) == SECEqual && 929 SECITEM_CompareItem(&g_ocsp_responder_table[i].issuer_key_id, 930 &cert->authKeyID->keyID) == SECEqual) { 931 return PORT_Strdup(g_ocsp_responder_table[i].ocsp_url); 932 } 933 } 934 } 935 936 return NULL; 937} 938 939} // anonymous namespace 940 941void SetMessageLoopForNSSHttpIO() { 942 // Must have a MessageLoopForIO. 943 DCHECK(base::MessageLoopForIO::current()); 944 945 bool used = g_ocsp_io_loop.Get().used(); 946 947 // Should not be called when g_ocsp_io_loop has already been used. 948 DCHECK(!used); 949} 950 951void EnsureNSSHttpIOInit() { 952 g_ocsp_io_loop.Get().StartUsing(); 953 g_ocsp_nss_initialization.Get(); 954} 955 956void ShutdownNSSHttpIO() { 957 g_ocsp_io_loop.Get().Shutdown(); 958} 959 960void ResetNSSHttpIOForTesting() { 961 g_ocsp_io_loop.Get().ReuseForTesting(); 962} 963 964// This function would be called before NSS initialization. 965void SetURLRequestContextForNSSHttpIO(URLRequestContext* request_context) { 966 pthread_mutex_lock(&g_request_context_lock); 967 if (request_context) { 968 DCHECK(!g_request_context); 969 } 970 g_request_context = request_context; 971 pthread_mutex_unlock(&g_request_context_lock); 972} 973 974} // namespace net 975