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