policy_cert_verifier_browsertest.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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 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 106TEST_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 152TEST_F(PolicyCertVerifierTest, VerifyTrustedCert) { 153 // |ca_cert| is the issuer of |cert|. 154 scoped_refptr<net::X509Certificate> ca_cert = 155 LoadCertificate("root_ca_cert.crt", 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 201TEST_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.crt", 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 246TEST_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.crt", 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