policy_cert_verifier_browsertest.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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.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 30using testing::Mock; 31using testing::ReturnRef; 32 33namespace policy { 34 35namespace { 36 37class 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. 53class 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 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 106TEST_F(PolicyCertVerifierTest, VerifyUntrustedCert) { 107 scoped_refptr<net::X509Certificate> cert = 108 LoadCertificate("ok_cert.pem", net::SERVER_CERT); 109 ASSERT_TRUE(cert); 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, "127.0.0.1", 0, NULL, 118 &verify_result, callback.callback(), 119 &request_handle, net::BoundNetLog()); 120 Mock::VerifyAndClearExpectations(&trust_provider_); 121 ASSERT_EQ(net::ERR_IO_PENDING, error); 122 ASSERT_TRUE(request_handle); 123 error = callback.WaitForResult(); 124 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error); 125 126 // Issuing the same request again hits the cache. This tests the synchronous 127 // path. 128 EXPECT_CALL(trust_provider_, GetAdditionalTrustAnchors()) 129 .WillOnce(ReturnRef(empty_cert_list_)); 130 error = cert_verifier_->Verify(cert, "127.0.0.1", 0, NULL, 131 &verify_result, callback.callback(), 132 &request_handle, net::BoundNetLog()); 133 Mock::VerifyAndClearExpectations(&trust_provider_); 134 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error); 135 136 // The profile is not tainted. 137 base::RunLoop().RunUntilIdle(); 138 EXPECT_FALSE( 139 profile_->GetPrefs()->GetBoolean(prefs::kUsedPolicyCertificatesOnce)); 140} 141 142TEST_F(PolicyCertVerifierTest, VerifyTrustedCert) { 143 // |ca_cert| is the issuer of |cert|. 144 scoped_refptr<net::X509Certificate> ca_cert = 145 LoadCertificate("root_ca_cert.crt", net::CA_CERT); 146 ASSERT_TRUE(ca_cert); 147 scoped_refptr<net::X509Certificate> cert = 148 LoadCertificate("ok_cert.pem", net::SERVER_CERT); 149 ASSERT_TRUE(cert); 150 151 // Make the database trust |ca_cert|. 152 net::CertificateList import_list; 153 import_list.push_back(ca_cert); 154 net::NSSCertDatabase::ImportCertFailureList failure_list; 155 ASSERT_TRUE(cert_db_->ImportCACerts( 156 import_list, net::NSSCertDatabase::TRUSTED_SSL, &failure_list)); 157 ASSERT_TRUE(failure_list.empty()); 158 159 // Verify that it is now trusted. 160 net::NSSCertDatabase::TrustBits trust = 161 cert_db_->GetCertTrust(ca_cert.get(), net::CA_CERT); 162 EXPECT_EQ(net::NSSCertDatabase::TRUSTED_SSL, trust); 163 164 // Verify() successfully verifies |cert| after it was imported. 165 net::CertVerifyResult verify_result; 166 net::TestCompletionCallback callback; 167 net::CertVerifier::RequestHandle request_handle; 168 EXPECT_CALL(trust_provider_, GetAdditionalTrustAnchors()) 169 .WillOnce(ReturnRef(empty_cert_list_)); 170 int error = cert_verifier_->Verify(cert, "127.0.0.1", 0, NULL, 171 &verify_result, callback.callback(), 172 &request_handle, net::BoundNetLog()); 173 Mock::VerifyAndClearExpectations(&trust_provider_); 174 ASSERT_EQ(net::ERR_IO_PENDING, error); 175 ASSERT_TRUE(request_handle); 176 error = callback.WaitForResult(); 177 EXPECT_EQ(net::OK, error); 178 179 // The profile is not tainted, since the certificate is trusted from the 180 // database. 181 base::RunLoop().RunUntilIdle(); 182 EXPECT_FALSE( 183 profile_->GetPrefs()->GetBoolean(prefs::kUsedPolicyCertificatesOnce)); 184} 185 186TEST_F(PolicyCertVerifierTest, VerifyUsingAdditionalTrustAnchor) { 187 if (!SupportsAdditionalTrustAnchors()) { 188 LOG(INFO) << "Test skipped on this platform. NSS >= 3.14.2 required."; 189 return; 190 } 191 192 // |ca_cert| is the issuer of |cert|. 193 scoped_refptr<net::X509Certificate> ca_cert = 194 LoadCertificate("root_ca_cert.crt", net::CA_CERT); 195 ASSERT_TRUE(ca_cert); 196 scoped_refptr<net::X509Certificate> cert = 197 LoadCertificate("ok_cert.pem", net::SERVER_CERT); 198 ASSERT_TRUE(cert); 199 200 net::CertificateList additional_trust_anchors; 201 additional_trust_anchors.push_back(ca_cert); 202 203 // Verify() successfully verifies |cert|, using |ca_cert| from the list of 204 // |additional_trust_anchors|. 205 net::CertVerifyResult verify_result; 206 net::TestCompletionCallback callback; 207 net::CertVerifier::RequestHandle request_handle; 208 EXPECT_CALL(trust_provider_, GetAdditionalTrustAnchors()) 209 .WillOnce(ReturnRef(additional_trust_anchors)); 210 int error = cert_verifier_->Verify(cert, "127.0.0.1", 0, NULL, 211 &verify_result, callback.callback(), 212 &request_handle, net::BoundNetLog()); 213 Mock::VerifyAndClearExpectations(&trust_provider_); 214 ASSERT_EQ(net::ERR_IO_PENDING, error); 215 ASSERT_TRUE(request_handle); 216 error = callback.WaitForResult(); 217 EXPECT_EQ(net::OK, error); 218 219 // The profile becomes tainted after using the trust anchors that came from 220 // the policy configuration. 221 base::RunLoop().RunUntilIdle(); 222 EXPECT_TRUE( 223 profile_->GetPrefs()->GetBoolean(prefs::kUsedPolicyCertificatesOnce)); 224} 225 226TEST_F(PolicyCertVerifierTest, ProfileRemainsTainted) { 227 if (!SupportsAdditionalTrustAnchors()) { 228 LOG(INFO) << "Test skipped on this platform. NSS >= 3.14.2 required."; 229 return; 230 } 231 232 // |ca_cert| is the issuer of |cert|. 233 scoped_refptr<net::X509Certificate> ca_cert = 234 LoadCertificate("root_ca_cert.crt", net::CA_CERT); 235 ASSERT_TRUE(ca_cert); 236 scoped_refptr<net::X509Certificate> cert = 237 LoadCertificate("ok_cert.pem", net::SERVER_CERT); 238 ASSERT_TRUE(cert); 239 240 net::CertificateList additional_trust_anchors; 241 additional_trust_anchors.push_back(ca_cert); 242 243 // |cert| is untrusted, so Verify() fails. 244 net::CertVerifyResult verify_result; 245 net::TestCompletionCallback callback; 246 net::CertVerifier::RequestHandle request_handle; 247 EXPECT_CALL(trust_provider_, GetAdditionalTrustAnchors()) 248 .WillOnce(ReturnRef(empty_cert_list_)); 249 int error = cert_verifier_->Verify(cert, "127.0.0.1", 0, NULL, 250 &verify_result, callback.callback(), 251 &request_handle, net::BoundNetLog()); 252 Mock::VerifyAndClearExpectations(&trust_provider_); 253 ASSERT_EQ(net::ERR_IO_PENDING, error); 254 ASSERT_TRUE(request_handle); 255 error = callback.WaitForResult(); 256 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error); 257 258 // The profile is not tainted. 259 base::RunLoop().RunUntilIdle(); 260 EXPECT_FALSE( 261 profile_->GetPrefs()->GetBoolean(prefs::kUsedPolicyCertificatesOnce)); 262 263 // Verify() again with the additional trust anchors. 264 EXPECT_CALL(trust_provider_, GetAdditionalTrustAnchors()) 265 .WillOnce(ReturnRef(additional_trust_anchors)); 266 error = cert_verifier_->Verify(cert, "127.0.0.1", 0, NULL, 267 &verify_result, callback.callback(), 268 &request_handle, net::BoundNetLog()); 269 Mock::VerifyAndClearExpectations(&trust_provider_); 270 ASSERT_EQ(net::ERR_IO_PENDING, error); 271 ASSERT_TRUE(request_handle); 272 error = callback.WaitForResult(); 273 EXPECT_EQ(net::OK, error); 274 275 // The profile becomes tainted after using the trust anchors that came from 276 // the policy configuration. 277 base::RunLoop().RunUntilIdle(); 278 EXPECT_TRUE( 279 profile_->GetPrefs()->GetBoolean(prefs::kUsedPolicyCertificatesOnce)); 280 281 // Verifying after removing the trust anchors should now fail. 282 EXPECT_CALL(trust_provider_, GetAdditionalTrustAnchors()) 283 .WillOnce(ReturnRef(empty_cert_list_)); 284 error = cert_verifier_->Verify(cert, "127.0.0.1", 0, NULL, 285 &verify_result, callback.callback(), 286 &request_handle, net::BoundNetLog()); 287 Mock::VerifyAndClearExpectations(&trust_provider_); 288 // Note: this hits the cached result from the first Verify() in this test. 289 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error); 290 291 // The profile is still tainted. 292 base::RunLoop().RunUntilIdle(); 293 EXPECT_TRUE( 294 profile_->GetPrefs()->GetBoolean(prefs::kUsedPolicyCertificatesOnce)); 295} 296 297} // namespace policy 298