1// Copyright 2014 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_internal.h" 17#include "crypto/scoped_test_nss_chromeos_user.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_chromeos.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 28namespace policy { 29 30class PolicyCertVerifierTest : public testing::Test { 31 public: 32 PolicyCertVerifierTest() 33 : trust_anchor_used_(false), test_nss_user_("user1") {} 34 35 virtual ~PolicyCertVerifierTest() {} 36 37 virtual void SetUp() OVERRIDE { 38 ASSERT_TRUE(test_nss_user_.constructed_successfully()); 39 test_nss_user_.FinishInit(); 40 41 test_cert_db_.reset(new net::NSSCertDatabaseChromeOS( 42 crypto::GetPublicSlotForChromeOSUser(test_nss_user_.username_hash()), 43 crypto::GetPrivateSlotForChromeOSUser( 44 test_nss_user_.username_hash(), 45 base::Callback<void(crypto::ScopedPK11Slot)>()))); 46 test_cert_db_->SetSlowTaskRunnerForTest(base::MessageLoopProxy::current()); 47 48 cert_verifier_.reset(new PolicyCertVerifier(base::Bind( 49 &PolicyCertVerifierTest::OnTrustAnchorUsed, base::Unretained(this)))); 50 cert_verifier_->InitializeOnIOThread(new chromeos::CertVerifyProcChromeOS( 51 crypto::GetPublicSlotForChromeOSUser(test_nss_user_.username_hash()))); 52 53 test_ca_cert_ = LoadCertificate("root_ca_cert.pem", net::CA_CERT); 54 ASSERT_TRUE(test_ca_cert_.get()); 55 test_server_cert_ = LoadCertificate("ok_cert.pem", net::SERVER_CERT); 56 ASSERT_TRUE(test_server_cert_.get()); 57 test_ca_cert_list_.push_back(test_ca_cert_); 58 } 59 60 virtual void TearDown() OVERRIDE { 61 // Destroy |cert_verifier_| before destroying the ThreadBundle, otherwise 62 // BrowserThread::CurrentlyOn checks fail. 63 cert_verifier_.reset(); 64 } 65 66 protected: 67 int VerifyTestServerCert(const net::TestCompletionCallback& test_callback, 68 net::CertVerifyResult* verify_result, 69 net::CertVerifier::RequestHandle* request_handle) { 70 return cert_verifier_->Verify(test_server_cert_.get(), 71 "127.0.0.1", 72 0, 73 NULL, 74 verify_result, 75 test_callback.callback(), 76 request_handle, 77 net::BoundNetLog()); 78 } 79 80 bool SupportsAdditionalTrustAnchors() { 81 scoped_refptr<net::CertVerifyProc> proc = 82 net::CertVerifyProc::CreateDefault(); 83 return proc->SupportsAdditionalTrustAnchors(); 84 } 85 86 // Returns whether |cert_verifier| signalled usage of one of the additional 87 // trust anchors (i.e. of |test_ca_cert_|) for the first time or since the 88 // last call of this function. 89 bool WasTrustAnchorUsedAndReset() { 90 base::RunLoop().RunUntilIdle(); 91 bool result = trust_anchor_used_; 92 trust_anchor_used_ = false; 93 return result; 94 } 95 96 // |test_ca_cert_| is the issuer of |test_server_cert_|. 97 scoped_refptr<net::X509Certificate> test_ca_cert_; 98 scoped_refptr<net::X509Certificate> test_server_cert_; 99 net::CertificateList test_ca_cert_list_; 100 scoped_ptr<net::NSSCertDatabaseChromeOS> test_cert_db_; 101 scoped_ptr<PolicyCertVerifier> cert_verifier_; 102 103 private: 104 void OnTrustAnchorUsed() { 105 trust_anchor_used_ = true; 106 } 107 108 scoped_refptr<net::X509Certificate> LoadCertificate(const std::string& name, 109 net::CertType type) { 110 scoped_refptr<net::X509Certificate> cert = 111 net::ImportCertFromFile(net::GetTestCertsDirectory(), name); 112 113 // No certificate is trusted right after it's loaded. 114 net::NSSCertDatabase::TrustBits trust = 115 test_cert_db_->GetCertTrust(cert.get(), type); 116 EXPECT_EQ(net::NSSCertDatabase::TRUST_DEFAULT, trust); 117 118 return cert; 119 } 120 121 bool trust_anchor_used_; 122 crypto::ScopedTestNSSChromeOSUser test_nss_user_; 123 content::TestBrowserThreadBundle thread_bundle_; 124}; 125 126TEST_F(PolicyCertVerifierTest, VerifyUntrustedCert) { 127 // |test_server_cert_| is untrusted, so Verify() fails. 128 { 129 net::CertVerifyResult verify_result; 130 net::TestCompletionCallback callback; 131 net::CertVerifier::RequestHandle request_handle = NULL; 132 int error = VerifyTestServerCert(callback, &verify_result, &request_handle); 133 ASSERT_EQ(net::ERR_IO_PENDING, error); 134 EXPECT_TRUE(request_handle); 135 error = callback.WaitForResult(); 136 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error); 137 } 138 139 // Issuing the same request again hits the cache. This tests the synchronous 140 // path. 141 { 142 net::CertVerifyResult verify_result; 143 net::TestCompletionCallback callback; 144 net::CertVerifier::RequestHandle request_handle = NULL; 145 int error = VerifyTestServerCert(callback, &verify_result, &request_handle); 146 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error); 147 } 148 149 EXPECT_FALSE(WasTrustAnchorUsedAndReset()); 150} 151 152TEST_F(PolicyCertVerifierTest, VerifyTrustedCert) { 153 // Make the database trust |test_ca_cert_|. 154 net::NSSCertDatabase::ImportCertFailureList failure_list; 155 ASSERT_TRUE(test_cert_db_->ImportCACerts( 156 test_ca_cert_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 test_cert_db_->GetCertTrust(test_ca_cert_.get(), net::CA_CERT); 162 EXPECT_EQ(net::NSSCertDatabase::TRUSTED_SSL, trust); 163 164 // Verify() successfully verifies |test_server_cert_| after it was imported. 165 net::CertVerifyResult verify_result; 166 net::TestCompletionCallback callback; 167 net::CertVerifier::RequestHandle request_handle = NULL; 168 int error = VerifyTestServerCert(callback, &verify_result, &request_handle); 169 ASSERT_EQ(net::ERR_IO_PENDING, error); 170 EXPECT_TRUE(request_handle); 171 error = callback.WaitForResult(); 172 EXPECT_EQ(net::OK, error); 173 174 // The additional trust anchors were not used, since the certificate is 175 // trusted from the database. 176 EXPECT_FALSE(WasTrustAnchorUsedAndReset()); 177} 178 179TEST_F(PolicyCertVerifierTest, VerifyUsingAdditionalTrustAnchor) { 180 ASSERT_TRUE(SupportsAdditionalTrustAnchors()); 181 182 // |test_server_cert_| is untrusted, so Verify() fails. 183 { 184 net::CertVerifyResult verify_result; 185 net::TestCompletionCallback callback; 186 net::CertVerifier::RequestHandle request_handle = NULL; 187 int error = VerifyTestServerCert(callback, &verify_result, &request_handle); 188 ASSERT_EQ(net::ERR_IO_PENDING, error); 189 EXPECT_TRUE(request_handle); 190 error = callback.WaitForResult(); 191 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error); 192 } 193 EXPECT_FALSE(WasTrustAnchorUsedAndReset()); 194 195 // Verify() again with the additional trust anchors. 196 cert_verifier_->SetTrustAnchors(test_ca_cert_list_); 197 { 198 net::CertVerifyResult verify_result; 199 net::TestCompletionCallback callback; 200 net::CertVerifier::RequestHandle request_handle = NULL; 201 int error = VerifyTestServerCert(callback, &verify_result, &request_handle); 202 ASSERT_EQ(net::ERR_IO_PENDING, error); 203 EXPECT_TRUE(request_handle); 204 error = callback.WaitForResult(); 205 EXPECT_EQ(net::OK, error); 206 } 207 EXPECT_TRUE(WasTrustAnchorUsedAndReset()); 208 209 // Verify() again with the additional trust anchors will hit the cache. 210 cert_verifier_->SetTrustAnchors(test_ca_cert_list_); 211 { 212 net::CertVerifyResult verify_result; 213 net::TestCompletionCallback callback; 214 net::CertVerifier::RequestHandle request_handle = NULL; 215 int error = VerifyTestServerCert(callback, &verify_result, &request_handle); 216 EXPECT_EQ(net::OK, error); 217 } 218 EXPECT_TRUE(WasTrustAnchorUsedAndReset()); 219 220 // Verifying after removing the trust anchors should now fail. 221 cert_verifier_->SetTrustAnchors(net::CertificateList()); 222 { 223 net::CertVerifyResult verify_result; 224 net::TestCompletionCallback callback; 225 net::CertVerifier::RequestHandle request_handle = NULL; 226 int error = VerifyTestServerCert(callback, &verify_result, &request_handle); 227 // Note: this hits the cached result from the first Verify() in this test. 228 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error); 229 } 230 // The additional trust anchors were reset, thus |cert_verifier_| should not 231 // signal it's usage anymore. 232 EXPECT_FALSE(WasTrustAnchorUsedAndReset()); 233} 234 235} // namespace policy 236