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