Home | History | Annotate | Download | only in policy
      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 "chrome/browser/chromeos/policy/policy_cert_verifier.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/callback.h"
     10 #include "base/memory/ref_counted.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/run_loop.h"
     13 #include "chrome/browser/chromeos/net/cert_verify_proc_chromeos.h"
     14 #include "content/public/browser/browser_thread.h"
     15 #include "content/public/test/test_browser_thread_bundle.h"
     16 #include "crypto/nss_util.h"
     17 #include "crypto/nss_util_internal.h"
     18 #include "net/base/net_log.h"
     19 #include "net/base/test_completion_callback.h"
     20 #include "net/base/test_data_directory.h"
     21 #include "net/cert/cert_trust_anchor_provider.h"
     22 #include "net/cert/cert_verify_result.h"
     23 #include "net/cert/nss_cert_database.h"
     24 #include "net/cert/x509_certificate.h"
     25 #include "net/test/cert_test_util.h"
     26 #include "testing/gtest/include/gtest/gtest.h"
     27 
     28 namespace policy {
     29 
     30 // This is actually a unit test, but is linked with browser_tests because
     31 // importing a certificate into the NSS test database persists for the duration
     32 // of a process; since each browser_test runs in a separate process then this
     33 // won't affect subsequent tests.
     34 // This can be moved to the unittests target once the TODO in ~ScopedTestNSSDB
     35 // is fixed.
     36 class PolicyCertVerifierTest : public testing::Test {
     37  public:
     38   PolicyCertVerifierTest() : cert_db_(NULL), trust_anchor_used_(false) {}
     39 
     40   virtual ~PolicyCertVerifierTest() {}
     41 
     42   virtual void SetUp() OVERRIDE {
     43     ASSERT_TRUE(test_nssdb_.is_open());
     44     cert_db_ = net::NSSCertDatabase::GetInstance();
     45 
     46     cert_verifier_.reset(new PolicyCertVerifier(base::Bind(
     47         &PolicyCertVerifierTest::OnTrustAnchorUsed, base::Unretained(this))));
     48     cert_verifier_->InitializeOnIOThread(new chromeos::CertVerifyProcChromeOS(
     49         crypto::ScopedPK11Slot(crypto::GetPublicNSSKeySlot())));
     50 
     51     test_ca_cert_ = LoadCertificate("root_ca_cert.pem", net::CA_CERT);
     52     ASSERT_TRUE(test_ca_cert_);
     53     test_server_cert_ = LoadCertificate("ok_cert.pem", net::SERVER_CERT);
     54     ASSERT_TRUE(test_server_cert_);
     55     test_ca_cert_list_.push_back(test_ca_cert_);
     56   }
     57 
     58   virtual void TearDown() OVERRIDE {
     59     // Destroy |cert_verifier_| before destroying the ThreadBundle, otherwise
     60     // BrowserThread::CurrentlyOn checks fail.
     61     cert_verifier_.reset();
     62   }
     63 
     64  protected:
     65   int VerifyTestServerCert(const net::TestCompletionCallback& test_callback,
     66                            net::CertVerifyResult* verify_result,
     67                            net::CertVerifier::RequestHandle* request_handle) {
     68     return cert_verifier_->Verify(test_server_cert_.get(),
     69                                   "127.0.0.1",
     70                                   0,
     71                                   NULL,
     72                                   verify_result,
     73                                   test_callback.callback(),
     74                                   request_handle,
     75                                   net::BoundNetLog());
     76   }
     77 
     78   bool SupportsAdditionalTrustAnchors() {
     79     scoped_refptr<net::CertVerifyProc> proc =
     80         net::CertVerifyProc::CreateDefault();
     81     return proc->SupportsAdditionalTrustAnchors();
     82   }
     83 
     84   // Returns whether |cert_verifier| signalled usage of one of the additional
     85   // trust anchors (i.e. of |test_ca_cert_|) for the first time or since the
     86   // last call of this function.
     87   bool WasTrustAnchorUsedAndReset() {
     88     base::RunLoop().RunUntilIdle();
     89     bool result = trust_anchor_used_;
     90     trust_anchor_used_ = false;
     91     return result;
     92   }
     93 
     94   // |test_ca_cert_| is the issuer of |test_server_cert_|.
     95   scoped_refptr<net::X509Certificate> test_ca_cert_;
     96   scoped_refptr<net::X509Certificate> test_server_cert_;
     97   net::CertificateList test_ca_cert_list_;
     98   net::NSSCertDatabase* cert_db_;
     99   scoped_ptr<PolicyCertVerifier> cert_verifier_;
    100 
    101  private:
    102   void OnTrustAnchorUsed() {
    103     trust_anchor_used_ = true;
    104   }
    105 
    106   scoped_refptr<net::X509Certificate> LoadCertificate(const std::string& name,
    107                                                       net::CertType type) {
    108     scoped_refptr<net::X509Certificate> cert =
    109         net::ImportCertFromFile(net::GetTestCertsDirectory(), name);
    110 
    111     // No certificate is trusted right after it's loaded.
    112     net::NSSCertDatabase::TrustBits trust =
    113         cert_db_->GetCertTrust(cert.get(), type);
    114     EXPECT_EQ(net::NSSCertDatabase::TRUST_DEFAULT, trust);
    115 
    116     return cert;
    117   }
    118 
    119   bool trust_anchor_used_;
    120   crypto::ScopedTestNSSDB test_nssdb_;
    121   content::TestBrowserThreadBundle thread_bundle_;
    122 };
    123 
    124 TEST_F(PolicyCertVerifierTest, VerifyUntrustedCert) {
    125   // |test_server_cert_| is untrusted, so Verify() fails.
    126   {
    127     net::CertVerifyResult verify_result;
    128     net::TestCompletionCallback callback;
    129     net::CertVerifier::RequestHandle request_handle = NULL;
    130     int error = VerifyTestServerCert(callback, &verify_result, &request_handle);
    131     ASSERT_EQ(net::ERR_IO_PENDING, error);
    132     EXPECT_TRUE(request_handle);
    133     error = callback.WaitForResult();
    134     EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error);
    135   }
    136 
    137   // Issuing the same request again hits the cache. This tests the synchronous
    138   // path.
    139   {
    140     net::CertVerifyResult verify_result;
    141     net::TestCompletionCallback callback;
    142     net::CertVerifier::RequestHandle request_handle = NULL;
    143     int error = VerifyTestServerCert(callback, &verify_result, &request_handle);
    144     EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error);
    145   }
    146 
    147   EXPECT_FALSE(WasTrustAnchorUsedAndReset());
    148 }
    149 
    150 TEST_F(PolicyCertVerifierTest, VerifyTrustedCert) {
    151   // Make the database trust |test_ca_cert_|.
    152   net::NSSCertDatabase::ImportCertFailureList failure_list;
    153   ASSERT_TRUE(cert_db_->ImportCACerts(
    154       test_ca_cert_list_, net::NSSCertDatabase::TRUSTED_SSL, &failure_list));
    155   ASSERT_TRUE(failure_list.empty());
    156 
    157   // Verify that it is now trusted.
    158   net::NSSCertDatabase::TrustBits trust =
    159       cert_db_->GetCertTrust(test_ca_cert_.get(), net::CA_CERT);
    160   EXPECT_EQ(net::NSSCertDatabase::TRUSTED_SSL, trust);
    161 
    162   // Verify() successfully verifies |test_server_cert_| after it was imported.
    163   net::CertVerifyResult verify_result;
    164   net::TestCompletionCallback callback;
    165   net::CertVerifier::RequestHandle request_handle = NULL;
    166   int error = VerifyTestServerCert(callback, &verify_result, &request_handle);
    167   ASSERT_EQ(net::ERR_IO_PENDING, error);
    168   EXPECT_TRUE(request_handle);
    169   error = callback.WaitForResult();
    170   EXPECT_EQ(net::OK, error);
    171 
    172   // The additional trust anchors were not used, since the certificate is
    173   // trusted from the database.
    174   EXPECT_FALSE(WasTrustAnchorUsedAndReset());
    175 }
    176 
    177 TEST_F(PolicyCertVerifierTest, VerifyUsingAdditionalTrustAnchor) {
    178   ASSERT_TRUE(SupportsAdditionalTrustAnchors());
    179 
    180   // |test_server_cert_| is untrusted, so Verify() fails.
    181   {
    182     net::CertVerifyResult verify_result;
    183     net::TestCompletionCallback callback;
    184     net::CertVerifier::RequestHandle request_handle = NULL;
    185     int error = VerifyTestServerCert(callback, &verify_result, &request_handle);
    186     ASSERT_EQ(net::ERR_IO_PENDING, error);
    187     EXPECT_TRUE(request_handle);
    188     error = callback.WaitForResult();
    189     EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error);
    190   }
    191   EXPECT_FALSE(WasTrustAnchorUsedAndReset());
    192 
    193   // Verify() again with the additional trust anchors.
    194   cert_verifier_->SetTrustAnchors(test_ca_cert_list_);
    195   {
    196     net::CertVerifyResult verify_result;
    197     net::TestCompletionCallback callback;
    198     net::CertVerifier::RequestHandle request_handle = NULL;
    199     int error = VerifyTestServerCert(callback, &verify_result, &request_handle);
    200     ASSERT_EQ(net::ERR_IO_PENDING, error);
    201     EXPECT_TRUE(request_handle);
    202     error = callback.WaitForResult();
    203     EXPECT_EQ(net::OK, error);
    204   }
    205   EXPECT_TRUE(WasTrustAnchorUsedAndReset());
    206 
    207   // Verify() again with the additional trust anchors will hit the cache.
    208   cert_verifier_->SetTrustAnchors(test_ca_cert_list_);
    209   {
    210     net::CertVerifyResult verify_result;
    211     net::TestCompletionCallback callback;
    212     net::CertVerifier::RequestHandle request_handle = NULL;
    213     int error = VerifyTestServerCert(callback, &verify_result, &request_handle);
    214     EXPECT_EQ(net::OK, error);
    215   }
    216   EXPECT_TRUE(WasTrustAnchorUsedAndReset());
    217 
    218   // Verifying after removing the trust anchors should now fail.
    219   cert_verifier_->SetTrustAnchors(net::CertificateList());
    220   {
    221     net::CertVerifyResult verify_result;
    222     net::TestCompletionCallback callback;
    223     net::CertVerifier::RequestHandle request_handle = NULL;
    224     int error = VerifyTestServerCert(callback, &verify_result, &request_handle);
    225     // Note: this hits the cached result from the first Verify() in this test.
    226     EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error);
    227   }
    228   // The additional trust anchors were reset, thus |cert_verifier_| should not
    229   // signal it's usage anymore.
    230   EXPECT_FALSE(WasTrustAnchorUsedAndReset());
    231 }
    232 
    233 }  // namespace policy
    234