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