Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Side by Side Diff: net/cert/internal/trust_store_nss_unittest.cc

Issue 2126803004: WIP: NSS trust store integration for path builder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cert-command-line-path-builder-add_certpathbuilder
Patch Set: . Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/cert/internal/trust_store_nss.cc ('k') | net/cert/internal/trust_store_static.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 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 "net/cert/internal/trust_store_nss.h"
6
7 #include <cert.h>
8 #include <certdb.h>
9
10 #include "base/bind.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/run_loop.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #include "crypto/scoped_test_nss_db.h"
16 #include "net/cert/internal/test_helpers.h"
17 #include "net/cert/internal/trust_store_test_helpers.h"
18 #include "net/cert/scoped_nss_types.h"
19 #include "net/cert/x509_certificate.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace net {
23
24 namespace {
25
26 class TrustStoreNSSTest : public testing::Test {
27 public:
28 void SetUp() override {
29 ASSERT_TRUE(test_nssdb_.is_open());
30
31 ParsedCertificateList chain;
32 ParsedCertificateList roots;
33 bool unused_verify_result;
34 der::GeneralizedTime unused_time;
35
36 ReadCertChainTestFromFile(
37 "net/data/verify_certificate_chain_unittest/key-rollover-oldchain.pem",
38 &chain, &roots, &unused_time, &unused_verify_result);
39 ASSERT_EQ(2U, chain.size());
40 ASSERT_EQ(1U, roots.size());
41 target_ = chain[0];
42 oldintermediate_ = chain[1];
43 oldroot_ = roots[0];
44 ASSERT_TRUE(target_);
45 ASSERT_TRUE(oldintermediate_);
46 ASSERT_TRUE(oldroot_);
47
48 ReadCertChainTestFromFile(
49 "net/data/verify_certificate_chain_unittest/"
50 "key-rollover-longrolloverchain.pem",
51 &chain, &roots, &unused_time, &unused_verify_result);
52 ASSERT_EQ(4U, chain.size());
53 newintermediate_ = chain[1];
54 newroot_ = chain[2];
55 newrootrollover_ = chain[3];
56 ASSERT_TRUE(newintermediate_);
57 ASSERT_TRUE(newroot_);
58 ASSERT_TRUE(newrootrollover_);
59
60 trust_store_nss_.reset(
61 new TrustStoreNSS(base::ThreadTaskRunnerHandle::Get()));
62 }
63
64 std::string GetUniqueNickname() {
65 return "trust_store_nss_unittest" + base::UintToString(nickname_counter_++);
66 }
67
68 void AddCertToNSS(const ParsedCertificate* cert) {
69 std::string nickname = GetUniqueNickname();
70 ScopedCERTCertificate nss_cert(
71 X509Certificate::CreateOSCertHandleFromBytesWithNickname(
72 cert->der_cert().AsStringPiece().data(), cert->der_cert().Length(),
73 nickname.c_str()));
74 ASSERT_TRUE(nss_cert);
75 SECStatus srv =
76 PK11_ImportCert(test_nssdb_.slot(), nss_cert.get(), CK_INVALID_HANDLE,
77 nickname.c_str(), PR_FALSE /* includeTrust (unused) */);
78 ASSERT_EQ(SECSuccess, srv);
79 }
80
81 void AddCertsToNSS() {
82 AddCertToNSS(target_.get());
83 AddCertToNSS(oldintermediate_.get());
84 AddCertToNSS(newintermediate_.get());
85 AddCertToNSS(oldroot_.get());
86 AddCertToNSS(newroot_.get());
87 AddCertToNSS(newrootrollover_.get());
88 }
89
90 // Trusts |cert|. Assumes the cert was already imported into NSS.
91 void TrustCert(const ParsedCertificate* cert) {
92 SECItem der_cert;
93 der_cert.data = const_cast<uint8_t*>(cert->der_cert().UnsafeData());
94 der_cert.len = base::checked_cast<unsigned>(cert->der_cert().Length());
95 der_cert.type = siDERCertBuffer;
96
97 // XXX Is this an acceptable way to get the cert for checking trust? Should it
98 // use CERT_NewTempCertificate instead? Or is there a way to get a trust val ue
99 // directly without going through CERT_GetCertTrust?
100 ScopedCERTCertificate nss_cert(
101 CERT_FindCertByDERCert(CERT_GetDefaultCertDB(), &der_cert));
102 ASSERT_TRUE(nss_cert);
103
104 CERTCertTrust trust = {0};
105 trust.sslFlags =
106 CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA | CERTDB_VALID_CA;
107 SECStatus srv =
108 CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nss_cert.get(), &trust);
109 ASSERT_EQ(SECSuccess, srv);
110 }
111
112 bool IsTrusted(scoped_refptr<ParsedCertificate> cert) {
113 bool unused_trusted = false;
114 TrustResultRecorder trust_results;
115 std::unique_ptr<TrustStore::Request> trust_req;
116 trust_store_nss_->IsTrustedCertificate(std::move(cert), trust_results.Callba ck(),
117 &unused_trusted, &trust_req);
118 EXPECT_FALSE(unused_trusted);
119 if (!trust_req) {
120 ADD_FAILURE() << "!trust_req";
121 return false;
122 }
123 trust_results.Run();
124 if (trust_results.results().size() != 1U) {
125 ADD_FAILURE() << "trust_results.results().size() == "
126 << trust_results.results().size();
127 return false;
128 }
129 return trust_results.results()[0];
130 }
131
132 protected:
133 scoped_refptr<ParsedCertificate> target_;
134 scoped_refptr<ParsedCertificate> oldintermediate_;
135 scoped_refptr<ParsedCertificate> newintermediate_;
136 scoped_refptr<ParsedCertificate> oldroot_;
137 scoped_refptr<ParsedCertificate> newroot_;
138 scoped_refptr<ParsedCertificate> newrootrollover_;
139 crypto::ScopedTestNSSDB test_nssdb_;
140 std::unique_ptr<TrustStoreNSS> trust_store_nss_;
141 unsigned nickname_counter_ = 0;
142 };
143
144 class IssuerResultRecorder {
145 public:
146 IssuerResultRecorder() {
147 run_loops_.push_back(base::WrapUnique(new base::RunLoop()));
148 }
149
150 void HandleResult(CertIssuerSource::Request* req) {
151 results_.push_back(req);
152 run_loops_.back()->Quit();
153 run_loops_.push_back(base::WrapUnique(new base::RunLoop()));
154 }
155
156 const std::vector<CertIssuerSource::Request*>& results() { return results_; }
157
158 CertIssuerSource::Request* Run() {
159 run_loops_[cur_]->Run();
160 return results_[cur_++];
161 }
162
163 CertIssuerSource::IssuerCallback Callback() {
164 return base::Bind(&IssuerResultRecorder::HandleResult, base::Unretained(this ));
165 }
166
167 private:
168 std::vector<CertIssuerSource::Request*> results_;
169 std::vector<std::unique_ptr<base::RunLoop>> run_loops_;
170 size_t cur_ = 0;
171 };
172
173 void IssuerRequestDeleter(std::unique_ptr<CertIssuerSource::Request>* req_owner,
174 base::Closure done_callback,
175 CertIssuerSource::Request* req) {
176 ASSERT_EQ(req, req_owner->get());
177 req_owner->reset();
178 done_callback.Run();
179 }
180
181 // Without adding the test certs to the NSS DB, should get no issuer results and
182 // none of the certs should be trusted.
183 TEST_F(TrustStoreNSSTest, CertsNotPresent) {
184 ParsedCertificateList issuers;
185 trust_store_nss_->SyncGetIssuersOf(target_.get(), &issuers);
186 EXPECT_TRUE(issuers.empty());
187
188 IssuerResultRecorder issuer_results;
189 std::unique_ptr<CertIssuerSource::Request> req;
190 trust_store_nss_->AsyncGetIssuersOf(target_,
191 issuer_results.Callback(), &req);
192 ASSERT_TRUE(req);
193 CertIssuerSource::Request* done_req = issuer_results.Run();
194 EXPECT_EQ(done_req, req.get());
195 scoped_refptr<ParsedCertificate> result_cert;
196 EXPECT_EQ(CompletionStatus::SYNC, req->GetNext(&result_cert));
197 EXPECT_FALSE(result_cert);
198
199 EXPECT_FALSE(IsTrusted(oldroot_));
200 EXPECT_FALSE(IsTrusted(newrootrollover_));
201 EXPECT_FALSE(IsTrusted(newroot_));
202 EXPECT_FALSE(IsTrusted(oldintermediate_));
203 EXPECT_FALSE(IsTrusted(newintermediate_));
204 EXPECT_FALSE(IsTrusted(target_));
205 }
206
207 // Certs added to the NSS DB, but not trusted. Should get issuer matches, but
208 // nothing should be marked trusted.
209 TEST_F(TrustStoreNSSTest, UntrustedIntermediates) {
210 AddCertsToNSS();
211
212 // Request issuers of the target cert. TrustStoreNSS never returns results
213 // synchronously.
214 ParsedCertificateList issuers;
215 trust_store_nss_->SyncGetIssuersOf(target_.get(), &issuers);
216 EXPECT_TRUE(issuers.empty());
217
218 // Async get should return both issuers, even though they aren't trusted they
219 // can be used for path building.
220 IssuerResultRecorder issuer_results;
221 std::unique_ptr<CertIssuerSource::Request> issuer_req;
222 trust_store_nss_->AsyncGetIssuersOf(target_,
223 issuer_results.Callback(), &issuer_req);
224 ASSERT_TRUE(issuer_req);
225 CertIssuerSource::Request* done_issuer_req = issuer_results.Run();
226 EXPECT_EQ(done_issuer_req, issuer_req.get());
227 scoped_refptr<ParsedCertificate> result_cert1;
228 ASSERT_EQ(CompletionStatus::SYNC, issuer_req->GetNext(&result_cert1));
229 ASSERT_TRUE(result_cert1);
230 scoped_refptr<ParsedCertificate> result_cert2;
231 ASSERT_EQ(CompletionStatus::SYNC, issuer_req->GetNext(&result_cert2));
232 ASSERT_TRUE(result_cert2);
233 scoped_refptr<ParsedCertificate> result_cert3;
234 EXPECT_EQ(CompletionStatus::SYNC, issuer_req->GetNext(&result_cert3));
235 EXPECT_FALSE(result_cert3);
236
237 if (result_cert1->der_cert() == oldintermediate_->der_cert()) {
238 EXPECT_EQ(result_cert2->der_cert(), newintermediate_->der_cert());
239 } else {
240 EXPECT_EQ(result_cert1->der_cert(), newintermediate_->der_cert());
241 EXPECT_EQ(result_cert2->der_cert(), oldintermediate_->der_cert());
242 }
243
244 // None of the certs are trusted.
245 EXPECT_FALSE(IsTrusted(oldroot_));
246 EXPECT_FALSE(IsTrusted(newrootrollover_));
247 EXPECT_FALSE(IsTrusted(newroot_));
248 EXPECT_FALSE(IsTrusted(oldintermediate_));
249 EXPECT_FALSE(IsTrusted(newintermediate_));
250 EXPECT_FALSE(IsTrusted(target_));
251 }
252
253 // Certs added to the NSS DB, and one of the CA certs trusted.
254 // Should get issuer matches, and that one cert should return as trusted.
255 TEST_F(TrustStoreNSSTest, TrustedCA) {
256 AddCertsToNSS();
257 TrustCert(newroot_.get());
258 ParsedCertificateList issuers;
259
260 // Getting issuers of the intermediate should return all the matching roots in
261 // NSS DB, regardless if they were trusted.
262 IssuerResultRecorder issuer_results;
263 std::unique_ptr<CertIssuerSource::Request> req;
264 trust_store_nss_->AsyncGetIssuersOf(oldintermediate_,
265 issuer_results.Callback(), &req);
266 ASSERT_TRUE(req);
267 CertIssuerSource::Request* done_req = issuer_results.Run();
268 EXPECT_EQ(done_req, req.get());
269 scoped_refptr<ParsedCertificate> result_cert1;
270 ASSERT_EQ(CompletionStatus::SYNC, req->GetNext(&result_cert1));
271 ASSERT_TRUE(result_cert1);
272 scoped_refptr<ParsedCertificate> result_cert2;
273 ASSERT_EQ(CompletionStatus::SYNC, req->GetNext(&result_cert2));
274 ASSERT_TRUE(result_cert2);
275 scoped_refptr<ParsedCertificate> result_cert3;
276 ASSERT_EQ(CompletionStatus::SYNC, req->GetNext(&result_cert3));
277 ASSERT_TRUE(result_cert3);
278 scoped_refptr<ParsedCertificate> result_cert4;
279 EXPECT_EQ(CompletionStatus::SYNC, req->GetNext(&result_cert4));
280 EXPECT_FALSE(result_cert4);
281
282 std::vector<base::StringPiece> expected_issuers = {
283 oldroot_->der_cert().AsStringPiece(),
284 newroot_->der_cert().AsStringPiece(),
285 newrootrollover_->der_cert().AsStringPiece(),
286 };
287 std::vector<base::StringPiece> got_issuers = {
288 result_cert1->der_cert().AsStringPiece(),
289 result_cert2->der_cert().AsStringPiece(),
290 result_cert3->der_cert().AsStringPiece(),
291 };
292 std::sort(expected_issuers.begin(), expected_issuers.end());
293 std::sort(got_issuers.begin(), got_issuers.end());
294 EXPECT_EQ(got_issuers, expected_issuers);
295
296 // Only newroot is trusted.
297 EXPECT_FALSE(IsTrusted(oldroot_));
298 EXPECT_FALSE(IsTrusted(newrootrollover_));
299 EXPECT_TRUE(IsTrusted(newroot_));
300 EXPECT_FALSE(IsTrusted(oldintermediate_));
301 EXPECT_FALSE(IsTrusted(newintermediate_));
302 EXPECT_FALSE(IsTrusted(target_));
303 }
304
305 // Cancel a AsyncGetIssuersOf request before it has returned any results.
306 // Callback should not be called.
307 TEST_F(TrustStoreNSSTest, CancelIssuerRequest) {
308 IssuerResultRecorder issuer_results;
309 std::unique_ptr<CertIssuerSource::Request> req;
310 trust_store_nss_->AsyncGetIssuersOf(target_,
311 issuer_results.Callback(), &req);
312 ASSERT_TRUE(req);
313 req.reset();
314 base::RunLoop().RunUntilIdle();
315 EXPECT_TRUE(issuer_results.results().empty());
316 }
317
318 // Cancel a AsyncGetIssuersOf request after the callback was called, but during
319 // the middle of retrieving the results with GetNext. Mostly just tests that
320 // nothing crashes.
321 TEST_F(TrustStoreNSSTest, CancelIssuerRequestDuringResults) {
322 AddCertsToNSS();
323
324 IssuerResultRecorder issuer_results;
325 std::unique_ptr<CertIssuerSource::Request> issuer_req;
326 trust_store_nss_->AsyncGetIssuersOf(target_,
327 issuer_results.Callback(), &issuer_req);
328 ASSERT_TRUE(issuer_req);
329 CertIssuerSource::Request* done_issuer_req = issuer_results.Run();
330 EXPECT_EQ(done_issuer_req, issuer_req.get());
331 scoped_refptr<ParsedCertificate> result_cert1;
332 ASSERT_EQ(CompletionStatus::SYNC, issuer_req->GetNext(&result_cert1));
333 ASSERT_TRUE(result_cert1);
334
335 issuer_req.reset();
336 base::RunLoop().RunUntilIdle();
337 }
338
339 // Cancel a AsyncGetIssuersOf request during the callback. Should not crash.
340 TEST_F(TrustStoreNSSTest, CancelIssuerRequestDuringCallback) {
341 AddCertsToNSS();
342
343 base::RunLoop run_loop;
344 std::unique_ptr<CertIssuerSource::Request> issuer_req;
345 trust_store_nss_->AsyncGetIssuersOf(
346 target_,
347 base::Bind(&IssuerRequestDeleter, &issuer_req, run_loop.QuitClosure()),
348 &issuer_req);
349 ASSERT_TRUE(issuer_req);
350 run_loop.Run();
351 ASSERT_FALSE(issuer_req);
352 base::RunLoop().RunUntilIdle();
353 }
354
355 // Cancel a IsTrustedCertificate request before it has returned any results.
356 // Callback should not be called.
357 TEST_F(TrustStoreNSSTest, CancelTrustRequest) {
358 bool unused_trusted = false;
359 std::unique_ptr<TrustStore::Request> trust_req;
360 TrustResultRecorder trust_results;
361 trust_store_nss_->IsTrustedCertificate(newroot_, trust_results.Callback(),
362 &unused_trusted, &trust_req);
363 ASSERT_TRUE(trust_req);
364 trust_req.reset();
365 base::RunLoop().RunUntilIdle();
366 EXPECT_TRUE(trust_results.results().empty());
367 }
368
369 // Cancel a IsTrustedCertificate request during the callback. Should not crash.
370 TEST_F(TrustStoreNSSTest, CancelTrustRequestDuringCallback) {
371 bool unused_trusted = false;
372 base::RunLoop run_loop;
373 std::unique_ptr<TrustStore::Request> trust_req;
374 trust_store_nss_->IsTrustedCertificate(
375 newroot_,
376 base::Bind(&TrustRequestDeleter, &trust_req, run_loop.QuitClosure()),
377 &unused_trusted, &trust_req);
378 ASSERT_TRUE(trust_req);
379 run_loop.Run();
380 ASSERT_FALSE(trust_req);
381 base::RunLoop().RunUntilIdle();
382 }
383
384
385 // XXX this test fails
386 TEST_F(TrustStoreNSSTest, Normalziatison) {
387 ParsedCertificateList chain;
388 ParsedCertificateList roots;
389 bool unused_verify_result;
390 der::GeneralizedTime unused_time;
391
392 ReadCertChainTestFromFile(
393 "net/data/verify_certificate_chain_unittest/"
394 "issuer-and-subject-not-byte-for-byte-equal-anchor.pem",
395 &chain, &roots, &unused_time, &unused_verify_result);
396 ASSERT_EQ(2U, chain.size());
397 ASSERT_EQ(1U, roots.size());
398 scoped_refptr<ParsedCertificate> target = chain[0];
399 scoped_refptr<ParsedCertificate> intermediate = chain[1];
400 scoped_refptr<ParsedCertificate> root = roots[0];
401 ASSERT_TRUE(target);
402 ASSERT_TRUE(intermediate);
403 ASSERT_TRUE(root);
404
405 EXPECT_NE(intermediate->tbs().issuer_tlv, root->tbs().subject_tlv);
406 EXPECT_EQ(intermediate->normalized_issuer(), root->normalized_subject());
407
408 AddCertToNSS(root.get());
409
410 // Async get should return both issuers, even though they aren't trusted they
411 // can be used for path building.
412 IssuerResultRecorder issuer_results;
413 std::unique_ptr<CertIssuerSource::Request> issuer_req;
414 trust_store_nss_->AsyncGetIssuersOf(intermediate, issuer_results.Callback(),
415 &issuer_req);
416 ASSERT_TRUE(issuer_req);
417 CertIssuerSource::Request* done_issuer_req = issuer_results.Run();
418 EXPECT_EQ(done_issuer_req, issuer_req.get());
419 scoped_refptr<ParsedCertificate> result_cert1;
420 ASSERT_EQ(CompletionStatus::SYNC, issuer_req->GetNext(&result_cert1));
421 ASSERT_TRUE(result_cert1);
422 scoped_refptr<ParsedCertificate> result_cert2;
423 EXPECT_EQ(CompletionStatus::SYNC, issuer_req->GetNext(&result_cert2));
424 EXPECT_FALSE(result_cert2);
425
426 EXPECT_EQ(result_cert1->der_cert(), root->der_cert());
427 }
428
429 } // namespace
430
431 } // namespace net
OLDNEW
« no previous file with comments | « net/cert/internal/trust_store_nss.cc ('k') | net/cert/internal/trust_store_static.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698