Home | History | Annotate | Download | only in ocsp
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/ocsp/nss_ocsp.h"
      6 
      7 #include <string>
      8 
      9 #include "base/file_util.h"
     10 #include "base/files/file_path.h"
     11 #include "base/logging.h"
     12 #include "base/memory/ref_counted.h"
     13 #include "net/base/net_errors.h"
     14 #include "net/base/test_completion_callback.h"
     15 #include "net/base/test_data_directory.h"
     16 #include "net/cert/cert_status_flags.h"
     17 #include "net/cert/cert_verifier.h"
     18 #include "net/cert/cert_verify_proc.h"
     19 #include "net/cert/cert_verify_proc_nss.h"
     20 #include "net/cert/cert_verify_result.h"
     21 #include "net/cert/multi_threaded_cert_verifier.h"
     22 #include "net/cert/test_root_certs.h"
     23 #include "net/cert/x509_certificate.h"
     24 #include "net/test/cert_test_util.h"
     25 #include "net/url_request/url_request_filter.h"
     26 #include "net/url_request/url_request_test_job.h"
     27 #include "net/url_request/url_request_test_util.h"
     28 #include "testing/gtest/include/gtest/gtest.h"
     29 
     30 namespace net {
     31 
     32 namespace {
     33 
     34 // Matches the caIssuers hostname from the generated certificate.
     35 const char kAiaHost[] = "aia-test.invalid";
     36 // Returning a single DER-encoded cert, so the mime-type must be
     37 // application/pkix-cert per RFC 5280.
     38 const char kAiaHeaders[] = "HTTP/1.1 200 OK\0"
     39                            "Content-type: application/pkix-cert\0"
     40                            "\0";
     41 
     42 class AiaResponseHandler : public net::URLRequestJobFactory::ProtocolHandler {
     43  public:
     44   AiaResponseHandler(const std::string& headers, const std::string& cert_data)
     45       : headers_(headers), cert_data_(cert_data), request_count_(0) {}
     46   virtual ~AiaResponseHandler() {}
     47 
     48   // net::URLRequestJobFactory::ProtocolHandler implementation:
     49   virtual net::URLRequestJob* MaybeCreateJob(
     50       net::URLRequest* request,
     51       net::NetworkDelegate* network_delegate) const OVERRIDE {
     52     ++const_cast<AiaResponseHandler*>(this)->request_count_;
     53 
     54     return new net::URLRequestTestJob(
     55         request, network_delegate, headers_, cert_data_, true);
     56   }
     57 
     58   int request_count() const { return request_count_; }
     59 
     60  private:
     61   std::string headers_;
     62   std::string cert_data_;
     63   int request_count_;
     64 
     65   DISALLOW_COPY_AND_ASSIGN(AiaResponseHandler);
     66 };
     67 
     68 }  // namespace
     69 
     70 class NssHttpTest : public ::testing::Test {
     71  public:
     72   NssHttpTest()
     73       : context_(false),
     74         handler_(NULL),
     75         verify_proc_(new CertVerifyProcNSS),
     76         verifier_(new MultiThreadedCertVerifier(verify_proc_.get())) {}
     77   virtual ~NssHttpTest() {}
     78 
     79   virtual void SetUp() {
     80     std::string file_contents;
     81     ASSERT_TRUE(file_util::ReadFileToString(
     82         GetTestCertsDirectory().AppendASCII("aia-intermediate.der"),
     83         &file_contents));
     84     ASSERT_FALSE(file_contents.empty());
     85 
     86     // Ownership of |handler| is transferred to the URLRequestFilter, but
     87     // hold onto the original pointer in order to access |request_count()|.
     88     scoped_ptr<AiaResponseHandler> handler(
     89         new AiaResponseHandler(kAiaHeaders, file_contents));
     90     handler_ = handler.get();
     91 
     92     URLRequestFilter::GetInstance()->AddHostnameProtocolHandler(
     93         "http",
     94         kAiaHost,
     95         handler.PassAs<URLRequestJobFactory::ProtocolHandler>());
     96 
     97     SetURLRequestContextForNSSHttpIO(&context_);
     98     EnsureNSSHttpIOInit();
     99   }
    100 
    101   virtual void TearDown() {
    102     ShutdownNSSHttpIO();
    103 
    104     if (handler_)
    105       URLRequestFilter::GetInstance()->RemoveHostnameHandler("http", kAiaHost);
    106   }
    107 
    108   CertVerifier* verifier() const {
    109     return verifier_.get();
    110   }
    111 
    112   int request_count() const {
    113     return handler_->request_count();
    114   }
    115 
    116  protected:
    117   const CertificateList empty_cert_list_;
    118 
    119  private:
    120   TestURLRequestContext context_;
    121   AiaResponseHandler* handler_;
    122   scoped_refptr<CertVerifyProc> verify_proc_;
    123   scoped_ptr<CertVerifier> verifier_;
    124 };
    125 
    126 // Tests that when using NSS to verify certificates, and IO is enabled,
    127 // that a request to fetch missing intermediate certificates is
    128 // made successfully.
    129 TEST_F(NssHttpTest, TestAia) {
    130   scoped_refptr<X509Certificate> test_cert(
    131       ImportCertFromFile(GetTestCertsDirectory(), "aia-cert.pem"));
    132   ASSERT_TRUE(test_cert.get());
    133 
    134   scoped_refptr<X509Certificate> test_root(
    135       ImportCertFromFile(GetTestCertsDirectory(), "aia-root.pem"));
    136   ASSERT_TRUE(test_root.get());
    137 
    138   ScopedTestRoot scoped_root(test_root.get());
    139 
    140   CertVerifyResult verify_result;
    141   TestCompletionCallback test_callback;
    142   CertVerifier::RequestHandle request_handle;
    143 
    144   int flags = CertVerifier::VERIFY_CERT_IO_ENABLED;
    145   int error = verifier()->Verify(test_cert.get(),
    146                                  "aia-host.invalid",
    147                                  flags,
    148                                  NULL,
    149                                  &verify_result,
    150                                  test_callback.callback(),
    151                                  &request_handle,
    152                                  BoundNetLog());
    153   ASSERT_EQ(ERR_IO_PENDING, error);
    154 
    155   error = test_callback.WaitForResult();
    156 
    157   EXPECT_EQ(OK, error);
    158 
    159   // Ensure that NSS made an AIA request for the missing intermediate.
    160   EXPECT_LT(0, request_count());
    161 }
    162 
    163 }  // namespace net
    164