policy_cert_verifier_browsertest.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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_);
55    test_server_cert_ = LoadCertificate("ok_cert.pem", net::SERVER_CERT);
56    ASSERT_TRUE(test_server_cert_);
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