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/memory/ref_counted.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/run_loop.h"
     11 #include "chrome/common/pref_names.h"
     12 #include "chrome/test/base/testing_browser_process.h"
     13 #include "chrome/test/base/testing_profile.h"
     14 #include "chrome/test/base/testing_profile_manager.h"
     15 #include "content/public/browser/browser_thread.h"
     16 #include "content/public/test/test_browser_thread.h"
     17 #include "crypto/nss_util.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_proc.h"
     23 #include "net/cert/cert_verify_result.h"
     24 #include "net/cert/nss_cert_database.h"
     25 #include "net/cert/x509_certificate.h"
     26 #include "net/test/cert_test_util.h"
     27 #include "testing/gmock/include/gmock/gmock.h"
     28 #include "testing/gtest/include/gtest/gtest.h"
     29 
     30 using testing::Mock;
     31 using testing::ReturnRef;
     32 
     33 namespace policy {
     34 
     35 namespace {
     36 
     37 class MockCertTrustAnchorProvider : public net::CertTrustAnchorProvider {
     38  public:
     39   MockCertTrustAnchorProvider() {}
     40   virtual ~MockCertTrustAnchorProvider() {}
     41 
     42   MOCK_METHOD0(GetAdditionalTrustAnchors, const net::CertificateList&());
     43 };
     44 
     45 }  // namespace
     46 
     47 // This is actually a unit test, but is linked with browser_tests because
     48 // importing a certificate into the NSS test database persists for the duration
     49 // of a process; since each browser_test runs in a separate process then this
     50 // won't affect subsequent tests.
     51 // This can be moved to the unittests target once the TODO in ~ScopedTestNSSDB
     52 // is fixed.
     53 class PolicyCertVerifierTest : public testing::Test {
     54  public:
     55   PolicyCertVerifierTest()
     56       : cert_db_(NULL),
     57         ui_thread_(content::BrowserThread::UI, &loop_),
     58         io_thread_(content::BrowserThread::IO, &loop_),
     59         profile_manager_(TestingBrowserProcess::GetGlobal()),
     60         profile_(NULL) {}
     61 
     62   virtual ~PolicyCertVerifierTest() {}
     63 
     64   virtual void SetUp() OVERRIDE {
     65     ASSERT_TRUE(test_nssdb_.is_open());
     66     cert_db_ = net::NSSCertDatabase::GetInstance();
     67 
     68     ASSERT_TRUE(profile_manager_.SetUp());
     69     profile_ = profile_manager_.CreateTestingProfile("profile");
     70 
     71     cert_verifier_.reset(new PolicyCertVerifier(profile_, &trust_provider_));
     72   }
     73 
     74   bool SupportsAdditionalTrustAnchors() {
     75     scoped_refptr<net::CertVerifyProc> proc =
     76         net::CertVerifyProc::CreateDefault();
     77     return proc->SupportsAdditionalTrustAnchors();
     78   }
     79 
     80   scoped_refptr<net::X509Certificate> LoadCertificate(const std::string& name,
     81                                                       net::CertType type) {
     82     scoped_refptr<net::X509Certificate> cert =
     83         net::ImportCertFromFile(net::GetTestCertsDirectory(), name);
     84 
     85     // No certificate is trusted right after it's loaded.
     86     net::NSSCertDatabase::TrustBits trust =
     87         cert_db_->GetCertTrust(cert.get(), type);
     88     EXPECT_EQ(net::NSSCertDatabase::TRUST_DEFAULT, trust);
     89 
     90     return cert;
     91   }
     92 
     93  protected:
     94   crypto::ScopedTestNSSDB test_nssdb_;
     95   net::NSSCertDatabase* cert_db_;
     96   base::MessageLoop loop_;
     97   content::TestBrowserThread ui_thread_;
     98   content::TestBrowserThread io_thread_;
     99   TestingProfileManager profile_manager_;
    100   TestingProfile* profile_;
    101   MockCertTrustAnchorProvider trust_provider_;
    102   scoped_ptr<PolicyCertVerifier> cert_verifier_;
    103   const net::CertificateList empty_cert_list_;
    104 };
    105 
    106 TEST_F(PolicyCertVerifierTest, VerifyUntrustedCert) {
    107   scoped_refptr<net::X509Certificate> cert =
    108       LoadCertificate("ok_cert.pem", net::SERVER_CERT);
    109   ASSERT_TRUE(cert.get());
    110 
    111   // |cert| is untrusted, so Verify() fails.
    112   net::CertVerifyResult verify_result;
    113   net::TestCompletionCallback callback;
    114   net::CertVerifier::RequestHandle request_handle;
    115   EXPECT_CALL(trust_provider_, GetAdditionalTrustAnchors())
    116       .WillOnce(ReturnRef(empty_cert_list_));
    117   int error = cert_verifier_->Verify(cert.get(),
    118                                      "127.0.0.1",
    119                                      0,
    120                                      NULL,
    121                                      &verify_result,
    122                                      callback.callback(),
    123                                      &request_handle,
    124                                      net::BoundNetLog());
    125   Mock::VerifyAndClearExpectations(&trust_provider_);
    126   ASSERT_EQ(net::ERR_IO_PENDING, error);
    127   ASSERT_TRUE(request_handle);
    128   error = callback.WaitForResult();
    129   EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error);
    130 
    131   // Issuing the same request again hits the cache. This tests the synchronous
    132   // path.
    133   EXPECT_CALL(trust_provider_, GetAdditionalTrustAnchors())
    134       .WillOnce(ReturnRef(empty_cert_list_));
    135   error = cert_verifier_->Verify(cert.get(),
    136                                  "127.0.0.1",
    137                                  0,
    138                                  NULL,
    139                                  &verify_result,
    140                                  callback.callback(),
    141                                  &request_handle,
    142                                  net::BoundNetLog());
    143   Mock::VerifyAndClearExpectations(&trust_provider_);
    144   EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error);
    145 
    146   // The profile is not tainted.
    147   base::RunLoop().RunUntilIdle();
    148   EXPECT_FALSE(
    149       profile_->GetPrefs()->GetBoolean(prefs::kUsedPolicyCertificatesOnce));
    150 }
    151 
    152 TEST_F(PolicyCertVerifierTest, VerifyTrustedCert) {
    153   // |ca_cert| is the issuer of |cert|.
    154   scoped_refptr<net::X509Certificate> ca_cert =
    155       LoadCertificate("root_ca_cert.pem", net::CA_CERT);
    156   ASSERT_TRUE(ca_cert.get());
    157   scoped_refptr<net::X509Certificate> cert =
    158       LoadCertificate("ok_cert.pem", net::SERVER_CERT);
    159   ASSERT_TRUE(cert.get());
    160 
    161   // Make the database trust |ca_cert|.
    162   net::CertificateList import_list;
    163   import_list.push_back(ca_cert);
    164   net::NSSCertDatabase::ImportCertFailureList failure_list;
    165   ASSERT_TRUE(cert_db_->ImportCACerts(
    166       import_list, net::NSSCertDatabase::TRUSTED_SSL, &failure_list));
    167   ASSERT_TRUE(failure_list.empty());
    168 
    169   // Verify that it is now trusted.
    170   net::NSSCertDatabase::TrustBits trust =
    171       cert_db_->GetCertTrust(ca_cert.get(), net::CA_CERT);
    172   EXPECT_EQ(net::NSSCertDatabase::TRUSTED_SSL, trust);
    173 
    174   // Verify() successfully verifies |cert| after it was imported.
    175   net::CertVerifyResult verify_result;
    176   net::TestCompletionCallback callback;
    177   net::CertVerifier::RequestHandle request_handle;
    178   EXPECT_CALL(trust_provider_, GetAdditionalTrustAnchors())
    179       .WillOnce(ReturnRef(empty_cert_list_));
    180   int error = cert_verifier_->Verify(cert.get(),
    181                                      "127.0.0.1",
    182                                      0,
    183                                      NULL,
    184                                      &verify_result,
    185                                      callback.callback(),
    186                                      &request_handle,
    187                                      net::BoundNetLog());
    188   Mock::VerifyAndClearExpectations(&trust_provider_);
    189   ASSERT_EQ(net::ERR_IO_PENDING, error);
    190   ASSERT_TRUE(request_handle);
    191   error = callback.WaitForResult();
    192   EXPECT_EQ(net::OK, error);
    193 
    194   // The profile is not tainted, since the certificate is trusted from the
    195   // database.
    196   base::RunLoop().RunUntilIdle();
    197   EXPECT_FALSE(
    198       profile_->GetPrefs()->GetBoolean(prefs::kUsedPolicyCertificatesOnce));
    199 }
    200 
    201 TEST_F(PolicyCertVerifierTest, VerifyUsingAdditionalTrustAnchor) {
    202   if (!SupportsAdditionalTrustAnchors()) {
    203     LOG(INFO) << "Test skipped on this platform. NSS >= 3.14.2 required.";
    204     return;
    205   }
    206 
    207   // |ca_cert| is the issuer of |cert|.
    208   scoped_refptr<net::X509Certificate> ca_cert =
    209       LoadCertificate("root_ca_cert.pem", net::CA_CERT);
    210   ASSERT_TRUE(ca_cert.get());
    211   scoped_refptr<net::X509Certificate> cert =
    212       LoadCertificate("ok_cert.pem", net::SERVER_CERT);
    213   ASSERT_TRUE(cert.get());
    214 
    215   net::CertificateList additional_trust_anchors;
    216   additional_trust_anchors.push_back(ca_cert);
    217 
    218   // Verify() successfully verifies |cert|, using |ca_cert| from the list of
    219   // |additional_trust_anchors|.
    220   net::CertVerifyResult verify_result;
    221   net::TestCompletionCallback callback;
    222   net::CertVerifier::RequestHandle request_handle;
    223   EXPECT_CALL(trust_provider_, GetAdditionalTrustAnchors())
    224       .WillOnce(ReturnRef(additional_trust_anchors));
    225   int error = cert_verifier_->Verify(cert.get(),
    226                                      "127.0.0.1",
    227                                      0,
    228                                      NULL,
    229                                      &verify_result,
    230                                      callback.callback(),
    231                                      &request_handle,
    232                                      net::BoundNetLog());
    233   Mock::VerifyAndClearExpectations(&trust_provider_);
    234   ASSERT_EQ(net::ERR_IO_PENDING, error);
    235   ASSERT_TRUE(request_handle);
    236   error = callback.WaitForResult();
    237   EXPECT_EQ(net::OK, error);
    238 
    239   // The profile becomes tainted after using the trust anchors that came from
    240   // the policy configuration.
    241   base::RunLoop().RunUntilIdle();
    242   EXPECT_TRUE(
    243       profile_->GetPrefs()->GetBoolean(prefs::kUsedPolicyCertificatesOnce));
    244 }
    245 
    246 TEST_F(PolicyCertVerifierTest, ProfileRemainsTainted) {
    247   if (!SupportsAdditionalTrustAnchors()) {
    248     LOG(INFO) << "Test skipped on this platform. NSS >= 3.14.2 required.";
    249     return;
    250   }
    251 
    252   // |ca_cert| is the issuer of |cert|.
    253   scoped_refptr<net::X509Certificate> ca_cert =
    254       LoadCertificate("root_ca_cert.pem", net::CA_CERT);
    255   ASSERT_TRUE(ca_cert.get());
    256   scoped_refptr<net::X509Certificate> cert =
    257       LoadCertificate("ok_cert.pem", net::SERVER_CERT);
    258   ASSERT_TRUE(cert.get());
    259 
    260   net::CertificateList additional_trust_anchors;
    261   additional_trust_anchors.push_back(ca_cert);
    262 
    263   // |cert| is untrusted, so Verify() fails.
    264   net::CertVerifyResult verify_result;
    265   net::TestCompletionCallback callback;
    266   net::CertVerifier::RequestHandle request_handle;
    267   EXPECT_CALL(trust_provider_, GetAdditionalTrustAnchors())
    268       .WillOnce(ReturnRef(empty_cert_list_));
    269   int error = cert_verifier_->Verify(cert.get(),
    270                                      "127.0.0.1",
    271                                      0,
    272                                      NULL,
    273                                      &verify_result,
    274                                      callback.callback(),
    275                                      &request_handle,
    276                                      net::BoundNetLog());
    277   Mock::VerifyAndClearExpectations(&trust_provider_);
    278   ASSERT_EQ(net::ERR_IO_PENDING, error);
    279   ASSERT_TRUE(request_handle);
    280   error = callback.WaitForResult();
    281   EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error);
    282 
    283   // The profile is not tainted.
    284   base::RunLoop().RunUntilIdle();
    285   EXPECT_FALSE(
    286       profile_->GetPrefs()->GetBoolean(prefs::kUsedPolicyCertificatesOnce));
    287 
    288   // Verify() again with the additional trust anchors.
    289   EXPECT_CALL(trust_provider_, GetAdditionalTrustAnchors())
    290       .WillOnce(ReturnRef(additional_trust_anchors));
    291   error = cert_verifier_->Verify(cert.get(),
    292                                  "127.0.0.1",
    293                                  0,
    294                                  NULL,
    295                                  &verify_result,
    296                                  callback.callback(),
    297                                  &request_handle,
    298                                  net::BoundNetLog());
    299   Mock::VerifyAndClearExpectations(&trust_provider_);
    300   ASSERT_EQ(net::ERR_IO_PENDING, error);
    301   ASSERT_TRUE(request_handle);
    302   error = callback.WaitForResult();
    303   EXPECT_EQ(net::OK, error);
    304 
    305   // The profile becomes tainted after using the trust anchors that came from
    306   // the policy configuration.
    307   base::RunLoop().RunUntilIdle();
    308   EXPECT_TRUE(
    309       profile_->GetPrefs()->GetBoolean(prefs::kUsedPolicyCertificatesOnce));
    310 
    311   // Verifying after removing the trust anchors should now fail.
    312   EXPECT_CALL(trust_provider_, GetAdditionalTrustAnchors())
    313       .WillOnce(ReturnRef(empty_cert_list_));
    314   error = cert_verifier_->Verify(cert.get(),
    315                                  "127.0.0.1",
    316                                  0,
    317                                  NULL,
    318                                  &verify_result,
    319                                  callback.callback(),
    320                                  &request_handle,
    321                                  net::BoundNetLog());
    322   Mock::VerifyAndClearExpectations(&trust_provider_);
    323   // Note: this hits the cached result from the first Verify() in this test.
    324   EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error);
    325 
    326   // The profile is still tainted.
    327   base::RunLoop().RunUntilIdle();
    328   EXPECT_TRUE(
    329       profile_->GetPrefs()->GetBoolean(prefs::kUsedPolicyCertificatesOnce));
    330 }
    331 
    332 }  // namespace policy
    333