nss_ocsp.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/ocsp/nss_ocsp.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <certt.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <certdb.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ocsp.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <nspr.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <nss.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pthread.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <secerr.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stringprintf.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/condition_variable.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_checker.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/time.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "googleurl/src/gurl.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/host_port_pair.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/load_flags.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_request_headers.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_response_headers.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Protects |g_request_context|.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)pthread_mutex_t g_request_context_lock = PTHREAD_MUTEX_INITIALIZER;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLRequestContext* g_request_context = NULL;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The default timeout for network fetches in NSS is 60 seconds. Choose a
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// saner upper limit for OCSP/CRL/AIA fetches.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kNetworkFetchTimeoutInSecs = 15;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OCSPRequestSession;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OCSPIOLoop {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void StartUsing() {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock autolock(lock_);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    used_ = true;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    io_loop_ = MessageLoopForIO::current();
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(io_loop_);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called on IO loop.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Shutdown();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool used() const {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock autolock(lock_);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return used_;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called from worker thread.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void PostTaskToIOLoop(const tracked_objects::Location& from_here,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const base::Closure& task);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void EnsureIOLoop();
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddRequest(OCSPRequestSession* request);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RemoveRequest(OCSPRequestSession* request);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clears internal state and calls |StartUsing()|. Should be called only in
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the context of testing.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ReuseForTesting() {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::AutoLock autolock(lock_);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(MessageLoopForIO::current());
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thread_checker_.DetachFromThread();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thread_checker_.CalledOnValidThread();
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shutdown_ = false;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      used_ = false;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StartUsing();
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct base::DefaultLazyInstanceTraits<OCSPIOLoop>;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OCSPIOLoop();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~OCSPIOLoop();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CancelAllRequests();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mutable base::Lock lock_;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool shutdown_;  // Protected by |lock_|.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<OCSPRequestSession*> requests_;  // Protected by |lock_|.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool used_;  // Protected by |lock_|.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This should not be modified after |used_|.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MessageLoopForIO* io_loop_;  // Protected by |lock_|.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadChecker thread_checker_;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(OCSPIOLoop);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::LazyInstance<OCSPIOLoop>::Leaky
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_ocsp_io_loop = LAZY_INSTANCE_INITIALIZER;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kRecvBufferSize = 4096;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All OCSP handlers should be called in the context of
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CertVerifier's thread (i.e. worker pool, not on the I/O thread).
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It supports blocking mode only.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPCreateSession(const char* host, PRUint16 portnum,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            SEC_HTTP_SERVER_SESSION* pSession);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session,
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               PRPollDesc **pPollDesc);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPFreeSession(SEC_HTTP_SERVER_SESSION session);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPCreate(SEC_HTTP_SERVER_SESSION session,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const char* http_protocol_variant,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const char* path_and_query_string,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const char* http_request_method,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const PRIntervalTime timeout,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     SEC_HTTP_REQUEST_SESSION* pRequest);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPSetPostData(SEC_HTTP_REQUEST_SESSION request,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const char* http_data,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const PRUint32 http_data_len,
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const char* http_content_type);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPAddHeader(SEC_HTTP_REQUEST_SESSION request,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const char* http_header_name,
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const char* http_header_value);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPTrySendAndReceive(SEC_HTTP_REQUEST_SESSION request,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                PRPollDesc** pPollDesc,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                PRUint16* http_response_code,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const char** http_response_content_type,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const char** http_response_headers,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const char** http_response_data,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                PRUint32* http_response_data_len);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)char* GetAlternateOCSPAIAInfo(CERTCertificate *cert);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OCSPNSSInitialization {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct base::DefaultLazyInstanceTraits<OCSPNSSInitialization>;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OCSPNSSInitialization();
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~OCSPNSSInitialization();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SEC_HttpClientFcn client_fcn_;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(OCSPNSSInitialization);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::LazyInstance<OCSPNSSInitialization> g_ocsp_nss_initialization =
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LAZY_INSTANCE_INITIALIZER;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Concrete class for SEC_HTTP_REQUEST_SESSION.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Public methods except virtual methods of URLRequest::Delegate
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (On* methods) run on certificate verifier thread (worker thread).
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Virtual methods of URLRequest::Delegate and private methods run
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on IO thread.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OCSPRequestSession
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public base::RefCountedThreadSafe<OCSPRequestSession>,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public URLRequest::Delegate {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OCSPRequestSession(const GURL& url,
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const char* http_request_method,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     base::TimeDelta timeout)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : url_(url),
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        http_request_method_(http_request_method),
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        timeout_(timeout),
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request_(NULL),
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        buffer_(new IOBuffer(kRecvBufferSize)),
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        response_code_(-1),
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cv_(&lock_),
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        io_loop_(NULL),
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        finished_(false) {}
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetPostData(const char* http_data, PRUint32 http_data_len,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   const char* http_content_type) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    upload_content_.assign(http_data, http_data_len);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    upload_content_type_.assign(http_content_type);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddHeader(const char* http_header_name, const char* http_header_value) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extra_request_headers_.SetHeader(http_header_name,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     http_header_value);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Start() {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // At this point, it runs on worker thread.
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |io_loop_| was initialized to be NULL in constructor, and
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // set only in StartURLRequest, so no need to lock |lock_| here.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!io_loop_);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_ocsp_io_loop.Get().PostTaskToIOLoop(
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&OCSPRequestSession::StartURLRequest, this));
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Started() const {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return request_ != NULL;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Cancel() {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // IO thread may set |io_loop_| to NULL, so protect by |lock_|.
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock autolock(lock_);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CancelLocked();
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Finished() const {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock autolock(lock_);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return finished_;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Wait() {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta timeout = timeout_;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock autolock(lock_);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (!finished_) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeTicks last_time = base::TimeTicks::Now();
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cv_.TimedWait(timeout);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Check elapsed time
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta elapsed_time = base::TimeTicks::Now() - last_time;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout -= elapsed_time;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (timeout < base::TimeDelta()) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VLOG(1) << "OCSP Timed out";
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!finished_)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          CancelLocked();
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return finished_;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const GURL& url() const {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return url_;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& http_request_method() const {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return http_request_method_;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta timeout() const {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return timeout_;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PRUint16 http_response_code() const {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(finished_);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return response_code_;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& http_response_content_type() const {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(finished_);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return response_content_type_;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& http_response_headers() const {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(finished_);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return response_headers_->raw_headers();
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& http_response_data() const {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(finished_);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return data_;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnReceivedRedirect(URLRequest* request,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const GURL& new_url,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  bool* defer_redirect) OVERRIDE {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(request, request_);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_url.SchemeIs("http")) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Prevent redirects to non-HTTP schemes, including HTTPS. This matches
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the initial check in OCSPServerSession::CreateRequest().
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CancelURLRequest();
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnResponseStarted(URLRequest* request) OVERRIDE {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(request, request_);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int bytes_read = 0;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (request->status().is_success()) {
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response_code_ = request_->GetResponseCode();
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response_headers_ = request_->response_headers();
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response_headers_->GetMimeType(&response_content_type_);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_->Read(buffer_, kRecvBufferSize, &bytes_read);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnReadCompleted(request_, bytes_read);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnReadCompleted(URLRequest* request,
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int bytes_read) OVERRIDE {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(request, request_);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    do {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!request_->status().is_success() || bytes_read <= 0)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data_.append(buffer_->data(), bytes_read);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } while (request_->Read(buffer_, kRecvBufferSize, &bytes_read));
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!request_->status().is_io_pending()) {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete request_;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_ = NULL;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_ocsp_io_loop.Get().RemoveRequest(this);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::AutoLock autolock(lock_);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        finished_ = true;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        io_loop_ = NULL;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cv_.Signal();
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Release();  // Balanced with StartURLRequest().
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Must be called on the IO loop thread.
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CancelURLRequest() {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::AutoLock autolock(lock_);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (io_loop_)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (request_) {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_->Cancel();
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete request_;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_ = NULL;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_ocsp_io_loop.Get().RemoveRequest(this);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::AutoLock autolock(lock_);
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        finished_ = true;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        io_loop_ = NULL;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cv_.Signal();
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Release();  // Balanced with StartURLRequest().
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCountedThreadSafe<OCSPRequestSession>;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~OCSPRequestSession() {
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When this destructor is called, there should be only one thread that has
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a reference to this object, and so that thread doesn't need to lock
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |lock_| here.
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!request_);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!io_loop_);
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Must call this method while holding |lock_|.
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CancelLocked() {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    lock_.AssertAcquired();
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (io_loop_) {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      io_loop_->PostTask(
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&OCSPRequestSession::CancelURLRequest, this));
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Runs on |g_ocsp_io_loop|'s IO loop.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void StartURLRequest() {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!request_);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_mutex_lock(&g_request_context_lock);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLRequestContext* url_request_context = g_request_context;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_mutex_unlock(&g_request_context_lock);
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (url_request_context == NULL)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::AutoLock autolock(lock_);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(!io_loop_);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      io_loop_ = MessageLoopForIO::current();
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_ocsp_io_loop.Get().AddRequest(this);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request_ = new URLRequest(url_, this, url_request_context);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // To meet the privacy requirements of incognito mode.
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request_->set_load_flags(LOAD_DISABLE_CACHE | LOAD_DO_NOT_SAVE_COOKIES |
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             LOAD_DO_NOT_SEND_COOKIES);
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (http_request_method_ == "POST") {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(!upload_content_.empty());
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(!upload_content_type_.empty());
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_->set_method("POST");
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extra_request_headers_.SetHeader(
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          HttpRequestHeaders::kContentType, upload_content_type_);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_->AppendBytesToUpload(upload_content_.data(),
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    static_cast<int>(upload_content_.size()));
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!extra_request_headers_.IsEmpty())
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_->SetExtraRequestHeaders(extra_request_headers_);
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request_->Start();
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddRef();  // Release after |request_| deleted.
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL url_;                      // The URL we eventually wound up at
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string http_request_method_;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta timeout_;       // The timeout for OCSP
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRequest* request_;           // The actual request this wraps
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<IOBuffer> buffer_;  // Read buffer
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpRequestHeaders extra_request_headers_;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string upload_content_;    // HTTP POST payload
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string upload_content_type_;  // MIME type of POST payload
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int response_code_;             // HTTP status code for the request
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string response_content_type_;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<HttpResponseHeaders> response_headers_;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string data_;              // Results of the request
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |lock_| protects |finished_| and |io_loop_|.
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mutable base::Lock lock_;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ConditionVariable cv_;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MessageLoop* io_loop_;          // Message loop of the IO thread
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool finished_;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(OCSPRequestSession);
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Concrete class for SEC_HTTP_SERVER_SESSION.
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OCSPServerSession {
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OCSPServerSession(const char* host, PRUint16 port)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : host_and_port_(host, port) {}
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~OCSPServerSession() {}
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OCSPRequestSession* CreateRequest(const char* http_protocol_variant,
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const char* path_and_query_string,
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const char* http_request_method,
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const PRIntervalTime timeout) {
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We dont' support "https" because we haven't thought about
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // whether it's safe to re-enter this code from talking to an OCSP
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // responder over SSL.
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (strcmp(http_protocol_variant, "http") != 0) {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string url_string(base::StringPrintf(
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "%s://%s%s",
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        http_protocol_variant,
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        host_and_port_.ToString().c_str(),
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        path_and_query_string));
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "URL [" << url_string << "]";
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GURL url(url_string);
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NSS does not expose public functions to adjust the fetch timeout when
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // using libpkix, so hardcode the upper limit for network fetches.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta actual_timeout = std::min(
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromSeconds(kNetworkFetchTimeoutInSecs),
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromMilliseconds(PR_IntervalToMilliseconds(timeout)));
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return new OCSPRequestSession(url, http_request_method, actual_timeout);
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HostPortPair host_and_port_;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(OCSPServerSession);
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OCSPIOLoop::OCSPIOLoop()
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : shutdown_(false),
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      used_(false),
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      io_loop_(NULL) {
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OCSPIOLoop::~OCSPIOLoop() {
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IO thread was already deleted before the singleton is deleted
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in AtExitManager.
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock autolock(lock_);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!io_loop_);
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!used_);
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(shutdown_);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_mutex_lock(&g_request_context_lock);
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!g_request_context);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_mutex_unlock(&g_request_context_lock);
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OCSPIOLoop::Shutdown() {
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Safe to read outside lock since we only write on IO thread anyway.
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Prevent the worker thread from trying to access |io_loop_|.
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock autolock(lock_);
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    io_loop_ = NULL;
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    used_ = false;
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shutdown_ = true;
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelAllRequests();
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_mutex_lock(&g_request_context_lock);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_request_context = NULL;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_mutex_unlock(&g_request_context_lock);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OCSPIOLoop::PostTaskToIOLoop(
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const tracked_objects::Location& from_here, const base::Closure& task) {
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock autolock(lock_);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (io_loop_)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    io_loop_->PostTask(from_here, task);
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OCSPIOLoop::EnsureIOLoop() {
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock autolock(lock_);
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OCSPIOLoop::AddRequest(OCSPRequestSession* request) {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!ContainsKey(requests_, request));
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  requests_.insert(request);
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OCSPIOLoop::RemoveRequest(OCSPRequestSession* request) {
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsKey(requests_, request));
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  requests_.erase(request);
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OCSPIOLoop::CancelAllRequests() {
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CancelURLRequest() always removes the request from the requests_
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // set synchronously.
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!requests_.empty())
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*requests_.begin())->CancelURLRequest();
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OCSPNSSInitialization::OCSPNSSInitialization() {
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NSS calls the functions in the function table to download certificates
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // or CRLs or talk to OCSP responders over HTTP.  These functions must
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // set an NSS/NSPR error code when they fail.  Otherwise NSS will get the
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // residual error code from an earlier failed function call.
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  client_fcn_.version = 1;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1;
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ft->createSessionFcn = OCSPCreateSession;
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ft->keepAliveSessionFcn = OCSPKeepAliveSession;
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ft->freeSessionFcn = OCSPFreeSession;
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ft->createFcn = OCSPCreate;
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ft->setPostDataFcn = OCSPSetPostData;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ft->addHeaderFcn = OCSPAddHeader;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ft->trySendAndReceiveFcn = OCSPTrySendAndReceive;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ft->cancelFcn = NULL;
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ft->freeFcn = OCSPFree;
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus status = SEC_RegisterDefaultHttpClient(&client_fcn_);
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status != SECSuccess) {
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Error initializing OCSP: " << PR_GetError();
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Work around NSS bugs 524013 and 564334.  NSS incorrectly thinks the
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CRLs for Network Solutions Certificate Authority have bad signatures,
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which causes certificates issued by that CA to be reported as revoked.
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // By using OCSP for those certificates, which don't have AIA extensions,
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we can work around these bugs.  See http://crbug.com/41730.
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERT_StringFromCertFcn old_callback = NULL;
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status = CERT_RegisterAlternateOCSPAIAInfoCallBack(
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetAlternateOCSPAIAInfo, &old_callback);
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status == SECSuccess) {
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!old_callback);
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Error initializing OCSP: " << PR_GetError();
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OCSPNSSInitialization::~OCSPNSSInitialization() {
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus status = CERT_RegisterAlternateOCSPAIAInfoCallBack(NULL, NULL);
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status != SECSuccess) {
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Error unregistering OCSP: " << PR_GetError();
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OCSP Http Client functions.
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Our Http Client functions operate in blocking mode.
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPCreateSession(const char* host, PRUint16 portnum,
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            SEC_HTTP_SERVER_SESSION* pSession) {
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "OCSP create session: host=" << host << " port=" << portnum;
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_mutex_lock(&g_request_context_lock);
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLRequestContext* request_context = g_request_context;
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_mutex_unlock(&g_request_context_lock);
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request_context == NULL) {
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "No URLRequestContext for NSS HTTP handler. host: " << host;
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The application failed to call SetURLRequestContextForNSSHttpIO or
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // has already called ShutdownNSSHttpIO, so we can't create and use
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // URLRequest.  PR_NOT_IMPLEMENTED_ERROR is not an accurate error
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // code for these error conditions, but is close enough.
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SECFailure;
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pSession = new OCSPServerSession(host, portnum);
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SECSuccess;
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session,
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               PRPollDesc **pPollDesc) {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "OCSP keep alive";
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pPollDesc)
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *pPollDesc = NULL;
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SECSuccess;
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPFreeSession(SEC_HTTP_SERVER_SESSION session) {
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "OCSP free session";
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete reinterpret_cast<OCSPServerSession*>(session);
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SECSuccess;
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPCreate(SEC_HTTP_SERVER_SESSION session,
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const char* http_protocol_variant,
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const char* path_and_query_string,
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const char* http_request_method,
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const PRIntervalTime timeout,
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     SEC_HTTP_REQUEST_SESSION* pRequest) {
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "OCSP create protocol=" << http_protocol_variant
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << " path_and_query=" << path_and_query_string
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << " http_request_method=" << http_request_method
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << " timeout=" << timeout;
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OCSPServerSession* ocsp_session =
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<OCSPServerSession*>(session);
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OCSPRequestSession* req = ocsp_session->CreateRequest(http_protocol_variant,
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                        path_and_query_string,
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                        http_request_method,
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                        timeout);
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = SECFailure;
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (req) {
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    req->AddRef();  // Release in OCSPFree().
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = SECSuccess;
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pRequest = req;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPSetPostData(SEC_HTTP_REQUEST_SESSION request,
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const char* http_data,
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const PRUint32 http_data_len,
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const char* http_content_type) {
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "OCSP set post data len=" << http_data_len;
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request);
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  req->SetPostData(http_data, http_data_len, http_content_type);
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SECSuccess;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPAddHeader(SEC_HTTP_REQUEST_SESSION request,
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const char* http_header_name,
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const char* http_header_value) {
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "OCSP add header name=" << http_header_name
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << " value=" << http_header_value;
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  req->AddHeader(http_header_name, http_header_value);
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SECSuccess;
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sets response of |req| in the output parameters.
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It is helper routine for OCSP trySendAndReceiveFcn.
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |http_response_data_len| could be used as input parameter.  If it has
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// non-zero value, it is considered as maximum size of |http_response_data|.
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPSetResponse(OCSPRequestSession* req,
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          PRUint16* http_response_code,
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const char** http_response_content_type,
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const char** http_response_headers,
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const char** http_response_data,
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          PRUint32* http_response_data_len) {
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(req->Finished());
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& data = req->http_response_data();
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (http_response_data_len && *http_response_data_len) {
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (*http_response_data_len < data.size()) {
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "response body too large: " << *http_response_data_len
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " < " << data.size();
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *http_response_data_len = data.size();
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PORT_SetError(SEC_ERROR_BAD_HTTP_RESPONSE);
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return SECFailure;
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "OCSP response "
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << " response_code=" << req->http_response_code()
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << " content_type=" << req->http_response_content_type()
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << " header=" << req->http_response_headers()
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << " data_len=" << data.size();
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (http_response_code)
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *http_response_code = req->http_response_code();
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (http_response_content_type)
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *http_response_content_type = req->http_response_content_type().c_str();
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (http_response_headers)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *http_response_headers = req->http_response_headers().c_str();
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (http_response_data)
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *http_response_data = data.data();
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (http_response_data_len)
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *http_response_data_len = data.size();
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SECSuccess;
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPTrySendAndReceive(SEC_HTTP_REQUEST_SESSION request,
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                PRPollDesc** pPollDesc,
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                PRUint16* http_response_code,
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const char** http_response_content_type,
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const char** http_response_headers,
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const char** http_response_data,
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                PRUint32* http_response_data_len) {
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (http_response_data_len) {
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We must always set an output value, even on failure.  The output value 0
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // means the failure was unrelated to the acceptable response data length.
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *http_response_data_len = 0;
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "OCSP try send and receive";
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request);
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We support blocking mode only.
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pPollDesc)
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *pPollDesc = NULL;
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (req->Started() || req->Finished()) {
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We support blocking mode only, so this function shouldn't be called
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // again when req has stareted or finished.
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PORT_SetError(SEC_ERROR_BAD_HTTP_RESPONSE);  // Simple approximation.
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SECFailure;
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::Time start_time = base::Time::Now();
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool request_ok = true;
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  req->Start();
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!req->Wait() || req->http_response_code() == static_cast<PRUint16>(-1)) {
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the response code is -1, the request failed and there is no response.
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request_ok = false;
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::TimeDelta duration = base::Time::Now() - start_time;
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For metrics, we want to know if the request was 'successful' or not.
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |request_ok| determines if we'll pass the response back to NSS and |ok|
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // keep track of if we think the response was good.
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = true;
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!request_ok ||
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (req->http_response_code() >= 400 && req->http_response_code() < 600) ||
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      req->http_response_data().size() == 0 ||
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // 0x30 is the ASN.1 DER encoding of a SEQUENCE. All valid OCSP/CRL/CRT
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // responses must start with this. If we didn't check for this then a
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // captive portal could provide an HTML reply that we would count as a
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // 'success' (although it wouldn't count in NSS, of course).
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      req->http_response_data().data()[0] != 0x30) {
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok = false;
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We want to know if this was:
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   1) An OCSP request
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   2) A CRL request
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   3) A request for a missing intermediate certificate
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There's no sure way to do this, so we use heuristics like MIME type and
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // URL.
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* mime_type = "";
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ok)
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mime_type = req->http_response_content_type().c_str();
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_ocsp =
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      strcasecmp(mime_type, "application/ocsp-response") == 0;
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_crl = strcasecmp(mime_type, "application/x-pkcs7-crl") == 0 ||
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                strcasecmp(mime_type, "application/x-x509-crl") == 0 ||
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                strcasecmp(mime_type, "application/pkix-crl") == 0;
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_cert =
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      strcasecmp(mime_type, "application/x-x509-ca-cert") == 0 ||
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      strcasecmp(mime_type, "application/x-x509-server-cert") == 0 ||
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      strcasecmp(mime_type, "application/pkix-cert") == 0 ||
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      strcasecmp(mime_type, "application/pkcs7-mime") == 0;
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_cert && !is_crl && !is_ocsp) {
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We didn't get a hint from the MIME type, so do the best that we can.
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string path = req->url().path();
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string host = req->url().host();
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_crl = strcasestr(path.c_str(), ".crl") != NULL;
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_cert = strcasestr(path.c_str(), ".crt") != NULL ||
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              strcasestr(path.c_str(), ".p7c") != NULL ||
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              strcasestr(path.c_str(), ".cer") != NULL;
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_ocsp = strcasestr(host.c_str(), "ocsp") != NULL ||
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              req->http_request_method() == "POST";
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_ocsp) {
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ok) {
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_TIMES("Net.OCSPRequestTimeMs", duration);
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("Net.OCSPRequestSuccess", true);
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_TIMES("Net.OCSPRequestFailedTimeMs", duration);
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("Net.OCSPRequestSuccess", false);
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (is_crl) {
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ok) {
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_TIMES("Net.CRLRequestTimeMs", duration);
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("Net.CRLRequestSuccess", true);
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_TIMES("Net.CRLRequestFailedTimeMs", duration);
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("Net.CRLRequestSuccess", false);
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (is_cert) {
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ok)
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_TIMES("Net.CRTRequestTimeMs", duration);
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ok)
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_TIMES("Net.UnknownTypeRequestTimeMs", duration);
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!request_ok) {
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PORT_SetError(SEC_ERROR_BAD_HTTP_RESPONSE);  // Simple approximation.
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SECFailure;
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return OCSPSetResponse(
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      req, http_response_code,
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      http_response_content_type,
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      http_response_headers,
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      http_response_data,
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      http_response_data_len);
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request) {
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "OCSP free";
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request);
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  req->Cancel();
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  req->Release();
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SECSuccess;
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Data for GetAlternateOCSPAIAInfo.
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CN=Network Solutions Certificate Authority,O=Network Solutions L.L.C.,C=US
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// There are two CAs with this name.  Their key IDs are listed next.
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const unsigned char network_solutions_ca_name[] = {
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x30, 0x62, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x21, 0x30, 0x1f, 0x06,
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x4e, 0x65, 0x74, 0x77,
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69,
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x6f, 0x6e, 0x73, 0x20, 0x4c, 0x2e, 0x4c, 0x2e, 0x43, 0x2e,
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x27, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53,
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43,
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const unsigned int network_solutions_ca_name_len = 100;
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This CA is an intermediate CA, subordinate to UTN-USERFirst-Hardware.
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const unsigned char network_solutions_ca_key_id[] = {
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x3c, 0x41, 0xe2, 0x8f, 0x08, 0x08, 0xa9, 0x4c, 0x25, 0x89,
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x8d, 0x6d, 0xc5, 0x38, 0xd0, 0xfc, 0x85, 0x8c, 0x62, 0x17
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const unsigned int network_solutions_ca_key_id_len = 20;
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This CA is a root CA.  It is also cross-certified by
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// UTN-USERFirst-Hardware.
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const unsigned char network_solutions_ca_key_id2[] = {
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x21, 0x30, 0xc9, 0xfb, 0x00, 0xd7, 0x4e, 0x98, 0xda, 0x87,
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0xaa, 0x2a, 0xd0, 0xa7, 0x2e, 0xb1, 0x40, 0x31, 0xa7, 0x4c
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const unsigned int network_solutions_ca_key_id2_len = 20;
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// An entry in our OCSP responder table.  |issuer| and |issuer_key_id| are
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the key.  |ocsp_url| is the value.
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct OCSPResponderTableEntry {
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem issuer;
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem issuer_key_id;
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *ocsp_url;
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const OCSPResponderTableEntry g_ocsp_responder_table[] = {
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      siBuffer,
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const_cast<unsigned char*>(network_solutions_ca_name),
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      network_solutions_ca_name_len
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      siBuffer,
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const_cast<unsigned char*>(network_solutions_ca_key_id),
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      network_solutions_ca_key_id_len
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "http://ocsp.netsolssl.com"
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  },
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      siBuffer,
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const_cast<unsigned char*>(network_solutions_ca_name),
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      network_solutions_ca_name_len
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      siBuffer,
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const_cast<unsigned char*>(network_solutions_ca_key_id2),
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      network_solutions_ca_key_id2_len
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "http://ocsp.netsolssl.com"
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)char* GetAlternateOCSPAIAInfo(CERTCertificate *cert) {
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cert && !cert->isRoot && cert->authKeyID) {
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (unsigned int i=0; i < arraysize(g_ocsp_responder_table); i++) {
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (SECITEM_CompareItem(&g_ocsp_responder_table[i].issuer,
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &cert->derIssuer) == SECEqual &&
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          SECITEM_CompareItem(&g_ocsp_responder_table[i].issuer_key_id,
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &cert->authKeyID->keyID) == SECEqual) {
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return PORT_Strdup(g_ocsp_responder_table[i].ocsp_url);
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // anonymous namespace
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetMessageLoopForNSSHttpIO() {
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Must have a MessageLoopForIO.
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(MessageLoopForIO::current());
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool used = g_ocsp_io_loop.Get().used();
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Should not be called when g_ocsp_io_loop has already been used.
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!used);
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnsureNSSHttpIOInit() {
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_ocsp_io_loop.Get().StartUsing();
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_ocsp_nss_initialization.Get();
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ShutdownNSSHttpIO() {
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_ocsp_io_loop.Get().Shutdown();
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ResetNSSHttpIOForTesting() {
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_ocsp_io_loop.Get().ReuseForTesting();
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function would be called before NSS initialization.
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetURLRequestContextForNSSHttpIO(URLRequestContext* request_context) {
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_mutex_lock(&g_request_context_lock);
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request_context) {
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!g_request_context);
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_request_context = request_context;
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_mutex_unlock(&g_request_context_lock);
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
966