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