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.
5 #include "chrome/browser/chromeos/policy/policy_cert_verifier.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 "content/public/browser/browser_thread.h"
14 #include "content/public/test/test_browser_thread_bundle.h"
15 #include "crypto/nss_util.h"
16 #include "net/base/net_log.h"
17 #include "net/base/test_completion_callback.h"
18 #include "net/base/test_data_directory.h"
19 #include "net/cert/cert_trust_anchor_provider.h"
20 #include "net/cert/cert_verify_proc.h"
21 #include "net/cert/cert_verify_result.h"
22 #include "net/cert/nss_cert_database.h"
23 #include "net/cert/x509_certificate.h"
24 #include "net/test/cert_test_util.h"
25 #include "testing/gtest/include/gtest/gtest.h"
29 // This is actually a unit test, but is linked with browser_tests because
30 // importing a certificate into the NSS test database persists for the duration
31 // of a process; since each browser_test runs in a separate process then this
32 // won't affect subsequent tests.
33 // This can be moved to the unittests target once the TODO in ~ScopedTestNSSDB
35 class PolicyCertVerifierTest
: public testing::Test
{
37 PolicyCertVerifierTest() : cert_db_(NULL
), trust_anchor_used_(false) {}
39 virtual ~PolicyCertVerifierTest() {}
41 virtual void SetUp() OVERRIDE
{
42 ASSERT_TRUE(test_nssdb_
.is_open());
43 cert_db_
= net::NSSCertDatabase::GetInstance();
45 cert_verifier_
.reset(new PolicyCertVerifier(base::Bind(
46 &PolicyCertVerifierTest::OnTrustAnchorUsed
, base::Unretained(this))));
47 cert_verifier_
->InitializeOnIOThread();
49 test_ca_cert_
= LoadCertificate("root_ca_cert.pem", net::CA_CERT
);
50 ASSERT_TRUE(test_ca_cert_
);
51 test_server_cert_
= LoadCertificate("ok_cert.pem", net::SERVER_CERT
);
52 ASSERT_TRUE(test_server_cert_
);
53 test_ca_cert_list_
.push_back(test_ca_cert_
);
56 virtual void TearDown() OVERRIDE
{
57 // Destroy |cert_verifier_| before destroying the ThreadBundle, otherwise
58 // BrowserThread::CurrentlyOn checks fail.
59 cert_verifier_
.reset();
63 int VerifyTestServerCert(const net::TestCompletionCallback
& test_callback
,
64 net::CertVerifyResult
* verify_result
,
65 net::CertVerifier::RequestHandle
* request_handle
) {
66 return cert_verifier_
->Verify(test_server_cert_
.get(),
71 test_callback
.callback(),
76 bool SupportsAdditionalTrustAnchors() {
77 scoped_refptr
<net::CertVerifyProc
> proc
=
78 net::CertVerifyProc::CreateDefault();
79 return proc
->SupportsAdditionalTrustAnchors();
82 // Returns whether |cert_verifier| signalled usage of one of the additional
83 // trust anchors (i.e. of |test_ca_cert_|) for the first time or since the
84 // last call of this function.
85 bool WasTrustAnchorUsedAndReset() {
86 base::RunLoop().RunUntilIdle();
87 bool result
= trust_anchor_used_
;
88 trust_anchor_used_
= false;
92 // |test_ca_cert_| is the issuer of |test_server_cert_|.
93 scoped_refptr
<net::X509Certificate
> test_ca_cert_
;
94 scoped_refptr
<net::X509Certificate
> test_server_cert_
;
95 net::CertificateList test_ca_cert_list_
;
96 net::NSSCertDatabase
* cert_db_
;
97 scoped_ptr
<PolicyCertVerifier
> cert_verifier_
;
100 void OnTrustAnchorUsed() {
101 trust_anchor_used_
= true;
104 scoped_refptr
<net::X509Certificate
> LoadCertificate(const std::string
& name
,
105 net::CertType type
) {
106 scoped_refptr
<net::X509Certificate
> cert
=
107 net::ImportCertFromFile(net::GetTestCertsDirectory(), name
);
109 // No certificate is trusted right after it's loaded.
110 net::NSSCertDatabase::TrustBits trust
=
111 cert_db_
->GetCertTrust(cert
.get(), type
);
112 EXPECT_EQ(net::NSSCertDatabase::TRUST_DEFAULT
, trust
);
117 bool trust_anchor_used_
;
118 crypto::ScopedTestNSSDB test_nssdb_
;
119 content::TestBrowserThreadBundle thread_bundle_
;
122 TEST_F(PolicyCertVerifierTest
, VerifyUntrustedCert
) {
123 // |test_server_cert_| is untrusted, so Verify() fails.
125 net::CertVerifyResult verify_result
;
126 net::TestCompletionCallback callback
;
127 net::CertVerifier::RequestHandle request_handle
= NULL
;
128 int error
= VerifyTestServerCert(callback
, &verify_result
, &request_handle
);
129 ASSERT_EQ(net::ERR_IO_PENDING
, error
);
130 EXPECT_TRUE(request_handle
);
131 error
= callback
.WaitForResult();
132 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID
, error
);
135 // Issuing the same request again hits the cache. This tests the synchronous
138 net::CertVerifyResult verify_result
;
139 net::TestCompletionCallback callback
;
140 net::CertVerifier::RequestHandle request_handle
= NULL
;
141 int error
= VerifyTestServerCert(callback
, &verify_result
, &request_handle
);
142 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID
, error
);
145 EXPECT_FALSE(WasTrustAnchorUsedAndReset());
148 TEST_F(PolicyCertVerifierTest
, VerifyTrustedCert
) {
149 // Make the database trust |test_ca_cert_|.
150 net::NSSCertDatabase::ImportCertFailureList failure_list
;
151 ASSERT_TRUE(cert_db_
->ImportCACerts(
152 test_ca_cert_list_
, net::NSSCertDatabase::TRUSTED_SSL
, &failure_list
));
153 ASSERT_TRUE(failure_list
.empty());
155 // Verify that it is now trusted.
156 net::NSSCertDatabase::TrustBits trust
=
157 cert_db_
->GetCertTrust(test_ca_cert_
.get(), net::CA_CERT
);
158 EXPECT_EQ(net::NSSCertDatabase::TRUSTED_SSL
, trust
);
160 // Verify() successfully verifies |test_server_cert_| after it was imported.
161 net::CertVerifyResult verify_result
;
162 net::TestCompletionCallback callback
;
163 net::CertVerifier::RequestHandle request_handle
= NULL
;
164 int error
= VerifyTestServerCert(callback
, &verify_result
, &request_handle
);
165 ASSERT_EQ(net::ERR_IO_PENDING
, error
);
166 EXPECT_TRUE(request_handle
);
167 error
= callback
.WaitForResult();
168 EXPECT_EQ(net::OK
, error
);
170 // The additional trust anchors were not used, since the certificate is
171 // trusted from the database.
172 EXPECT_FALSE(WasTrustAnchorUsedAndReset());
175 TEST_F(PolicyCertVerifierTest
, VerifyUsingAdditionalTrustAnchor
) {
176 ASSERT_TRUE(SupportsAdditionalTrustAnchors());
178 // |test_server_cert_| is untrusted, so Verify() fails.
180 net::CertVerifyResult verify_result
;
181 net::TestCompletionCallback callback
;
182 net::CertVerifier::RequestHandle request_handle
= NULL
;
183 int error
= VerifyTestServerCert(callback
, &verify_result
, &request_handle
);
184 ASSERT_EQ(net::ERR_IO_PENDING
, error
);
185 EXPECT_TRUE(request_handle
);
186 error
= callback
.WaitForResult();
187 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID
, error
);
189 EXPECT_FALSE(WasTrustAnchorUsedAndReset());
191 // Verify() again with the additional trust anchors.
192 cert_verifier_
->SetTrustAnchors(test_ca_cert_list_
);
194 net::CertVerifyResult verify_result
;
195 net::TestCompletionCallback callback
;
196 net::CertVerifier::RequestHandle request_handle
= NULL
;
197 int error
= VerifyTestServerCert(callback
, &verify_result
, &request_handle
);
198 ASSERT_EQ(net::ERR_IO_PENDING
, error
);
199 EXPECT_TRUE(request_handle
);
200 error
= callback
.WaitForResult();
201 EXPECT_EQ(net::OK
, error
);
203 EXPECT_TRUE(WasTrustAnchorUsedAndReset());
205 // Verify() again with the additional trust anchors will hit the cache.
206 cert_verifier_
->SetTrustAnchors(test_ca_cert_list_
);
208 net::CertVerifyResult verify_result
;
209 net::TestCompletionCallback callback
;
210 net::CertVerifier::RequestHandle request_handle
= NULL
;
211 int error
= VerifyTestServerCert(callback
, &verify_result
, &request_handle
);
212 EXPECT_EQ(net::OK
, error
);
214 EXPECT_TRUE(WasTrustAnchorUsedAndReset());
216 // Verifying after removing the trust anchors should now fail.
217 cert_verifier_
->SetTrustAnchors(net::CertificateList());
219 net::CertVerifyResult verify_result
;
220 net::TestCompletionCallback callback
;
221 net::CertVerifier::RequestHandle request_handle
= NULL
;
222 int error
= VerifyTestServerCert(callback
, &verify_result
, &request_handle
);
223 // Note: this hits the cached result from the first Verify() in this test.
224 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID
, error
);
226 // The additional trust anchors were reset, thus |cert_verifier_| should not
227 // signal it's usage anymore.
228 EXPECT_FALSE(WasTrustAnchorUsedAndReset());
231 } // namespace policy