OLD | NEW |
---|---|
(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/path_builder.h" | |
6 | |
7 #include "base/base_paths.h" | |
8 #include "base/cancelable_callback.h" | |
9 #include "base/files/file_util.h" | |
10 #include "base/location.h" | |
11 #include "base/path_service.h" | |
12 #include "base/threading/thread_task_runner_handle.h" | |
13 #include "net/base/net_errors.h" | |
14 #include "net/base/test_completion_callback.h" | |
15 #include "net/cert/internal/cert_issuer_source_static.h" | |
16 #include "net/cert/internal/parsed_certificate.h" | |
17 #include "net/cert/internal/signature_policy.h" | |
18 #include "net/cert/internal/test_helpers.h" | |
19 #include "net/cert/internal/trust_store.h" | |
20 #include "net/cert/internal/verify_certificate_chain.h" | |
21 #include "net/cert/pem_tokenizer.h" | |
22 #include "net/der/input.h" | |
23 #include "net/test/cert_test_util.h" | |
24 #include "net/test/test_certificate_data.h" | |
25 #include "testing/gmock/include/gmock/gmock.h" | |
26 #include "testing/gtest/include/gtest/gtest.h" | |
27 | |
28 namespace net { | |
29 | |
30 namespace { | |
31 | |
32 using ::testing::_; | |
33 using ::testing::Invoke; | |
34 using ::testing::SaveArg; | |
35 using ::testing::StrictMock; | |
36 using ::testing::SetArgPointee; | |
37 using ::testing::Return; | |
38 | |
39 // AsyncCertIssuerSourceStatic always returns its certs asynchronously. | |
40 class AsyncCertIssuerSourceStatic : public CertIssuerSource { | |
41 public: | |
42 class StaticAsyncRequest : public Request { | |
43 public: | |
44 StaticAsyncRequest(const IssuerCallback& issuers_callback, | |
45 ParsedCertificateList&& issuers) | |
eroman
2016/07/01 23:49:29
side-comment: Seems legit, although not sure if st
mattm
2016/07/02 02:21:51
seems to be: https://chromium-cpp.appspot.com/ (R
| |
46 : cancelable_closure_(base::Bind(&StaticAsyncRequest::RunCallback, | |
47 base::Unretained(this))), | |
48 issuers_callback_(issuers_callback) { | |
49 issuers_.swap(issuers); | |
50 issuers_iter_ = issuers_.begin(); | |
51 } | |
52 ~StaticAsyncRequest() override {} | |
53 | |
54 CompletionStatus GetNext( | |
55 scoped_refptr<ParsedCertificate>* out_cert) override { | |
56 if (issuers_iter_ == issuers_.end()) | |
57 *out_cert = nullptr; | |
58 else | |
59 *out_cert = std::move(*issuers_iter_++); | |
60 return CompletionStatus::SYNC; | |
61 } | |
62 | |
63 base::Closure callback() { return cancelable_closure_.callback(); } | |
64 | |
65 private: | |
66 void RunCallback() { issuers_callback_.Run(this); } | |
67 | |
68 base::CancelableClosure cancelable_closure_; | |
69 IssuerCallback issuers_callback_; | |
70 ParsedCertificateList issuers_; | |
71 ParsedCertificateList::iterator issuers_iter_; | |
72 | |
73 DISALLOW_COPY_AND_ASSIGN(StaticAsyncRequest); | |
74 }; | |
75 | |
76 ~AsyncCertIssuerSourceStatic() override {} | |
77 | |
78 void AddCert(scoped_refptr<ParsedCertificate> cert) { | |
79 static_cert_issuer_source_.AddCert(std::move(cert)); | |
80 } | |
81 | |
82 void SyncGetIssuersOf(const ParsedCertificate* cert, | |
83 ParsedCertificateList* issuers) override {} | |
84 void AsyncGetIssuersOf(const ParsedCertificate* cert, | |
85 const IssuerCallback& issuers_callback, | |
86 std::unique_ptr<Request>* out_req) override { | |
87 num_async_gets_++; | |
88 ParsedCertificateList issuers; | |
89 static_cert_issuer_source_.SyncGetIssuersOf(cert, &issuers); | |
90 std::unique_ptr<StaticAsyncRequest> req( | |
91 new StaticAsyncRequest(issuers_callback, std::move(issuers))); | |
92 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, req->callback()); | |
93 *out_req = std::move(req); | |
94 } | |
95 int num_async_gets() const { return num_async_gets_; } | |
96 | |
97 private: | |
98 CertIssuerSourceStatic static_cert_issuer_source_; | |
99 | |
100 int num_async_gets_ = 0; | |
101 }; | |
102 | |
103 // Reads a data file from the unit-test data. | |
104 std::string ReadTestFileToString(const std::string& file_name) { | |
105 // Compute the full path, relative to the src/ directory. | |
106 base::FilePath src_root; | |
107 PathService::Get(base::DIR_SOURCE_ROOT, &src_root); | |
108 base::FilePath filepath = src_root.AppendASCII(file_name); | |
109 | |
110 // Read the full contents of the file. | |
111 std::string file_data; | |
112 if (!base::ReadFileToString(filepath, &file_data)) { | |
113 ADD_FAILURE() << "Couldn't read file: " << filepath.value(); | |
114 return std::string(); | |
115 } | |
116 | |
117 return file_data; | |
118 } | |
119 | |
120 // Reads a verify_certificate_chain_unittest-style test case from |file_name|. | |
121 // Test cases are comprised of a certificate chain, trust store, a timestamp to | |
122 // validate at, and the expected result of verification (though the expected | |
123 // result is ignored here). | |
124 void ReadVerifyCertChainTestFromFile(const std::string& file_name, | |
125 std::vector<std::string>* chain, | |
eroman
2016/07/01 23:49:29
Should we randomize the order of the intermediates
mattm
2016/07/02 02:21:51
Probably not actual randomization (since even if i
| |
126 scoped_refptr<ParsedCertificate>* root, | |
127 der::GeneralizedTime* time) { | |
128 chain->clear(); | |
129 | |
130 std::string file_data = ReadTestFileToString(file_name); | |
131 | |
132 std::vector<std::string> pem_headers; | |
133 | |
134 const char kCertificateHeader[] = "CERTIFICATE"; | |
135 const char kTrustedCertificateHeader[] = "TRUSTED_CERTIFICATE"; | |
136 const char kTimeHeader[] = "TIME"; | |
137 | |
138 pem_headers.push_back(kCertificateHeader); | |
139 pem_headers.push_back(kTrustedCertificateHeader); | |
140 pem_headers.push_back(kTimeHeader); | |
141 | |
142 bool has_time = false; | |
143 | |
144 PEMTokenizer pem_tokenizer(file_data, pem_headers); | |
145 while (pem_tokenizer.GetNext()) { | |
146 const std::string& block_type = pem_tokenizer.block_type(); | |
147 const std::string& block_data = pem_tokenizer.data(); | |
148 | |
149 if (block_type == kCertificateHeader) { | |
150 chain->push_back(block_data); | |
151 } else if (block_type == kTrustedCertificateHeader) { | |
152 *root = ParsedCertificate::CreateFromCertificateCopy(block_data, {}); | |
153 ASSERT_TRUE(*root); | |
154 } else if (block_type == kTimeHeader) { | |
155 ASSERT_FALSE(has_time) << "Duplicate " << kTimeHeader; | |
156 has_time = true; | |
157 ASSERT_TRUE(der::ParseUTCTime(der::Input(&block_data), time)); | |
158 } | |
159 } | |
160 | |
161 ASSERT_TRUE(has_time); | |
162 } | |
163 | |
164 ::testing::AssertionResult ReadTestPem(const std::string& file_name, | |
165 const std::string& block_name, | |
166 std::string* result) { | |
167 const PemBlockMapping mappings[] = { | |
168 {block_name.c_str(), result}, | |
169 }; | |
170 | |
171 return ReadTestDataFromPemFile(file_name, mappings); | |
172 } | |
173 | |
174 ::testing::AssertionResult ReadTestCert( | |
175 const std::string& file_name, | |
176 scoped_refptr<ParsedCertificate>* result) { | |
177 std::string der; | |
178 ::testing::AssertionResult r = ReadTestPem( | |
179 "net/data/ssl/certificates/" + file_name, "CERTIFICATE", &der); | |
180 if (!r) | |
181 return r; | |
182 *result = ParsedCertificate::CreateFromCertificateCopy(der, {}); | |
183 if (!*result) | |
184 return ::testing::AssertionFailure() << "CreateFromCertificateCopy failed"; | |
185 return ::testing::AssertionSuccess(); | |
186 } | |
187 | |
188 // Run the path builder, and wait for async completion if necessary. The return | |
189 // value signifies whether the path builder completed synchronously or | |
190 // asynchronously, not that RunPathBuilder itself is asynchronous. | |
191 CompletionStatus RunPathBuilder(CertPathBuilder* path_builder) { | |
192 TestClosure callback; | |
193 CompletionStatus rv = path_builder->Run(callback.closure()); | |
194 | |
195 if (rv == CompletionStatus::ASYNC) { | |
196 DVLOG(1) << "waiting for async completion..."; | |
197 callback.WaitForResult(); | |
198 DVLOG(1) << "async completed."; | |
199 } | |
200 return rv; | |
201 } | |
202 | |
203 class PathBuilderMultiRootTest : public ::testing::Test { | |
204 public: | |
205 PathBuilderMultiRootTest() : signature_policy_(1024) {} | |
206 | |
207 void SetUp() override { | |
208 ASSERT_TRUE(ReadTestCert("multi-root-A-by-B.pem", &a_by_b_)); | |
209 ASSERT_TRUE(ReadTestCert("multi-root-B-by-C.pem", &b_by_c_)); | |
210 ASSERT_TRUE(ReadTestCert("multi-root-B-by-F.pem", &b_by_f_)); | |
211 ASSERT_TRUE(ReadTestCert("multi-root-C-by-D.pem", &c_by_d_)); | |
212 ASSERT_TRUE(ReadTestCert("multi-root-C-by-E.pem", &c_by_e_)); | |
213 ASSERT_TRUE(ReadTestCert("multi-root-D-by-D.pem", &d_by_d_)); | |
214 ASSERT_TRUE(ReadTestCert("multi-root-E-by-E.pem", &e_by_e_)); | |
215 ASSERT_TRUE(ReadTestCert("multi-root-F-by-E.pem", &f_by_e_)); | |
216 } | |
217 | |
218 protected: | |
219 scoped_refptr<ParsedCertificate> a_by_b_, b_by_c_, b_by_f_, c_by_d_, c_by_e_, | |
220 d_by_d_, e_by_e_, f_by_e_; | |
221 | |
222 SimpleSignaturePolicy signature_policy_; | |
223 der::GeneralizedTime time_ = {2016, 4, 11, 0, 0, 0}; | |
224 }; | |
225 | |
226 // If the target cert is a trust anchor, it should verify and should not include | |
227 // anything else in the path. | |
228 TEST_F(PathBuilderMultiRootTest, TargetIsTrustAnchor) { | |
229 TrustStore trust_store; | |
230 trust_store.AddTrustedCertificate(a_by_b_); | |
231 trust_store.AddTrustedCertificate(b_by_f_); | |
232 | |
233 CertPathBuilder::Result result; | |
234 CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_, | |
235 &result); | |
236 | |
237 EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); | |
238 | |
239 EXPECT_EQ(OK, result.error()); | |
240 EXPECT_EQ(1U, result.paths[result.best_result_index]->path.size()); | |
241 EXPECT_EQ(a_by_b_, result.paths[result.best_result_index]->path[0]); | |
242 } | |
243 | |
244 // If the target cert is directly issued by a trust anchor, it should verify | |
245 // without any intermediate certs being provided. | |
246 TEST_F(PathBuilderMultiRootTest, TargetDirectlySignedByTrustAnchor) { | |
247 TrustStore trust_store; | |
248 trust_store.AddTrustedCertificate(b_by_f_); | |
249 | |
250 CertPathBuilder::Result result; | |
251 CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_, | |
252 &result); | |
253 | |
254 EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); | |
255 | |
256 EXPECT_EQ(OK, result.error()); | |
257 EXPECT_EQ(2U, result.paths[result.best_result_index]->path.size()); | |
258 EXPECT_EQ(a_by_b_, result.paths[result.best_result_index]->path[0]); | |
259 EXPECT_EQ(b_by_f_, result.paths[result.best_result_index]->path[1]); | |
260 } | |
261 | |
262 // Test that async cert queries are not made if the path can be successfully | |
263 // built with synchronously available certs. | |
264 TEST_F(PathBuilderMultiRootTest, TriesSyncFirst) { | |
265 TrustStore trust_store; | |
266 trust_store.AddTrustedCertificate(e_by_e_); | |
267 | |
268 CertIssuerSourceStatic sync_certs; | |
269 sync_certs.AddCert(a_by_b_); | |
eroman
2016/07/01 23:49:29
Does this have an effect on path building, or just
mattm
2016/07/02 02:21:51
No effect. I don't remember if that was on purpose
| |
270 sync_certs.AddCert(b_by_f_); | |
271 sync_certs.AddCert(f_by_e_); | |
272 | |
273 AsyncCertIssuerSourceStatic async_certs; | |
274 async_certs.AddCert(b_by_c_); | |
eroman
2016/07/01 23:49:29
What would happen if b_by_c were returned synchron
mattm
2016/07/02 02:21:51
Yes.
| |
275 async_certs.AddCert(c_by_e_); | |
276 | |
277 CertPathBuilder::Result result; | |
278 CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_, | |
279 &result); | |
280 path_builder.AddCertIssuerSource(&async_certs); | |
281 path_builder.AddCertIssuerSource(&sync_certs); | |
282 | |
283 EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); | |
284 | |
285 EXPECT_EQ(OK, result.error()); | |
286 EXPECT_EQ(0, async_certs.num_async_gets()); | |
287 } | |
288 | |
289 // Test that async cert queries are not made if no callback is provided. | |
290 TEST_F(PathBuilderMultiRootTest, SychronousOnlyMode) { | |
291 TrustStore trust_store; | |
292 trust_store.AddTrustedCertificate(e_by_e_); | |
293 | |
294 CertIssuerSourceStatic sync_certs; | |
295 sync_certs.AddCert(f_by_e_); | |
296 | |
297 AsyncCertIssuerSourceStatic async_certs; | |
298 async_certs.AddCert(b_by_f_); | |
299 | |
300 CertPathBuilder::Result result; | |
301 CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_, | |
302 &result); | |
303 path_builder.AddCertIssuerSource(&async_certs); | |
304 path_builder.AddCertIssuerSource(&sync_certs); | |
305 | |
306 EXPECT_EQ(CompletionStatus::SYNC, path_builder.Run(base::Closure())); | |
307 | |
308 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.error()); | |
309 EXPECT_EQ(0, async_certs.num_async_gets()); | |
310 } | |
311 | |
312 // If async queries are needed, all async sources will be queried | |
313 // simultaneously. | |
314 TEST_F(PathBuilderMultiRootTest, TestAsyncSimultaneous) { | |
315 TrustStore trust_store; | |
316 trust_store.AddTrustedCertificate(e_by_e_); | |
317 | |
318 CertIssuerSourceStatic sync_certs; | |
319 sync_certs.AddCert(a_by_b_); | |
320 sync_certs.AddCert(b_by_c_); | |
321 sync_certs.AddCert(b_by_f_); | |
322 | |
323 AsyncCertIssuerSourceStatic async_certs1; | |
324 async_certs1.AddCert(c_by_e_); | |
325 | |
326 AsyncCertIssuerSourceStatic async_certs2; | |
327 async_certs2.AddCert(f_by_e_); | |
328 | |
329 CertPathBuilder::Result result; | |
330 CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_, | |
331 &result); | |
332 path_builder.AddCertIssuerSource(&async_certs1); | |
333 path_builder.AddCertIssuerSource(&async_certs2); | |
334 path_builder.AddCertIssuerSource(&sync_certs); | |
335 | |
336 EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); | |
337 | |
338 EXPECT_EQ(OK, result.error()); | |
339 EXPECT_EQ(1, async_certs1.num_async_gets()); | |
340 EXPECT_EQ(1, async_certs2.num_async_gets()); | |
341 } | |
342 | |
343 // Test that PathBuilder does not generate longer paths than necessary if one of | |
344 // the supplied certs is itself a trust anchor. | |
345 TEST_F(PathBuilderMultiRootTest, TestLongChain) { | |
346 // Both D(D) and C(D) are trusted roots. | |
347 TrustStore trust_store; | |
348 trust_store.AddTrustedCertificate(d_by_d_); | |
349 trust_store.AddTrustedCertificate(c_by_d_); | |
350 | |
351 // Certs A(B), B(C), and C(D) are all supplied. | |
352 CertIssuerSourceStatic sync_certs; | |
353 sync_certs.AddCert(a_by_b_); | |
354 sync_certs.AddCert(b_by_c_); | |
355 sync_certs.AddCert(c_by_d_); | |
356 | |
357 CertPathBuilder::Result result; | |
358 CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_, | |
359 &result); | |
360 path_builder.AddCertIssuerSource(&sync_certs); | |
361 | |
362 EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); | |
363 | |
364 EXPECT_EQ(OK, result.error()); | |
365 | |
366 // The result path should be A(B) <- B(C) <- C(D) | |
367 // not the longer but also valid A(B) <- B(C) <- C(D) <- D(D) | |
368 EXPECT_EQ(3U, result.paths[result.best_result_index]->path.size()); | |
369 } | |
370 | |
371 // Test that PathBuilder will backtrack and try a different path if the first | |
372 // one doesn't work out. | |
373 TEST_F(PathBuilderMultiRootTest, TestBacktracking) { | |
374 // Only D(D) is a trusted root. | |
375 TrustStore trust_store; | |
376 trust_store.AddTrustedCertificate(d_by_d_); | |
377 | |
378 // Certs A(B), B(F), and F(E) are supplied synchronously, thus the path | |
379 // A(B) <- B(F) <- F(E) should be built first, though it won't verify. | |
380 CertIssuerSourceStatic sync_certs; | |
381 sync_certs.AddCert(a_by_b_); | |
382 sync_certs.AddCert(b_by_f_); | |
383 sync_certs.AddCert(f_by_e_); | |
384 | |
385 // Certs B(C), and C(D) are supplied asynchronously, so the path | |
386 // A(B) <- B(C) <- C(D) <- D(D) should be tried second. | |
387 AsyncCertIssuerSourceStatic async_certs; | |
388 async_certs.AddCert(b_by_c_); | |
389 async_certs.AddCert(c_by_d_); | |
390 | |
391 CertPathBuilder::Result result; | |
392 CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_, | |
393 &result); | |
394 path_builder.AddCertIssuerSource(&sync_certs); | |
395 path_builder.AddCertIssuerSource(&async_certs); | |
396 | |
397 EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); | |
398 | |
399 EXPECT_EQ(OK, result.error()); | |
400 | |
401 // The result path should be A(B) <- B(C) <- C(D) <- D(D) | |
402 ASSERT_EQ(4U, result.paths[result.best_result_index]->path.size()); | |
403 EXPECT_EQ(a_by_b_, result.paths[result.best_result_index]->path[0]); | |
404 EXPECT_EQ(b_by_c_, result.paths[result.best_result_index]->path[1]); | |
405 EXPECT_EQ(c_by_d_, result.paths[result.best_result_index]->path[2]); | |
406 EXPECT_EQ(d_by_d_, result.paths[result.best_result_index]->path[3]); | |
407 } | |
408 | |
409 class PathBuilderKeyRolloverTest : public ::testing::Test { | |
410 public: | |
411 PathBuilderKeyRolloverTest() : signature_policy_(1024) {} | |
412 | |
413 void SetUp() override { | |
414 std::vector<std::string> path; | |
415 | |
416 ReadVerifyCertChainTestFromFile( | |
417 "net/data/verify_certificate_chain_unittest/key-rollover-oldchain.pem", | |
418 &path, &oldroot_, &time_); | |
419 ASSERT_EQ(2U, path.size()); | |
420 target_ = ParsedCertificate::CreateFromCertificateCopy(path[0], {}); | |
421 oldintermediary_ = | |
422 ParsedCertificate::CreateFromCertificateCopy(path[1], {}); | |
423 ASSERT_TRUE(target_); | |
424 ASSERT_TRUE(oldintermediary_); | |
425 | |
426 ReadVerifyCertChainTestFromFile( | |
427 "net/data/verify_certificate_chain_unittest/" | |
428 "key-rollover-longrolloverchain.pem", | |
429 &path, &oldroot_, &time_); | |
430 ASSERT_EQ(4U, path.size()); | |
431 newintermediary_ = | |
432 ParsedCertificate::CreateFromCertificateCopy(path[1], {}); | |
433 newroot_ = ParsedCertificate::CreateFromCertificateCopy(path[2], {}); | |
434 newrootrollover_ = | |
435 ParsedCertificate::CreateFromCertificateCopy(path[3], {}); | |
436 ASSERT_TRUE(newintermediary_); | |
437 ASSERT_TRUE(newroot_); | |
438 ASSERT_TRUE(newrootrollover_); | |
439 } | |
440 | |
441 protected: | |
442 // oldroot-------->newrootrollover newroot | |
443 // | | | | |
444 // v v v | |
445 // oldintermediary newintermediary | |
446 // | | | |
447 // +------------+-------------+ | |
448 // | | |
449 // v | |
450 // target | |
451 scoped_refptr<ParsedCertificate> target_, oldintermediary_, newintermediary_, | |
eroman
2016/07/01 23:49:29
nit: one per line
mattm
2016/07/02 02:21:51
Done.
| |
452 oldroot_, newroot_, newrootrollover_; | |
453 | |
454 SimpleSignaturePolicy signature_policy_; | |
455 der::GeneralizedTime time_; | |
456 }; | |
457 | |
458 // Tests that if only the old root cert is trusted, the path builder can build a | |
459 // path through the new intermediate and rollover cert to the old root. | |
460 TEST_F(PathBuilderKeyRolloverTest, TestRolloverOnlyOldRootTrusted) { | |
461 // Only oldroot is trusted. | |
462 TrustStore trust_store; | |
463 trust_store.AddTrustedCertificate(oldroot_); | |
464 | |
465 // Old intermediary cert is not provided, so the pathbuilder will need to go | |
eroman
2016/07/01 23:49:29
Not sure if one is more correct than another,
but
mattm
2016/07/02 02:21:51
Done.
| |
466 // through the rollover cert. | |
467 CertIssuerSourceStatic sync_certs; | |
468 sync_certs.AddCert(newintermediary_); | |
469 sync_certs.AddCert(newrootrollover_); | |
470 | |
471 CertPathBuilder::Result result; | |
472 CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, | |
473 &result); | |
474 path_builder.AddCertIssuerSource(&sync_certs); | |
475 | |
476 EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); | |
477 | |
478 EXPECT_EQ(OK, result.error()); | |
479 | |
480 // Path builder will first attempt: target <- newintermediary <- oldroot | |
481 // but it will fail since newintermediary is signed by newroot. | |
482 ASSERT_EQ(2U, result.paths.size()); | |
483 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error); | |
484 ASSERT_EQ(3U, result.paths[0]->path.size()); | |
485 EXPECT_EQ(target_, result.paths[0]->path[0]); | |
486 EXPECT_EQ(newintermediary_, result.paths[0]->path[1]); | |
487 EXPECT_EQ(oldroot_, result.paths[0]->path[2]); | |
488 | |
489 // Path builder will next attempt: | |
490 // target <- newintermediary <- newrootrollover <- oldroot | |
491 // which will succeed. | |
492 EXPECT_EQ(1U, result.best_result_index); | |
493 EXPECT_EQ(OK, result.paths[1]->error); | |
494 ASSERT_EQ(4U, result.paths[1]->path.size()); | |
495 EXPECT_EQ(target_, result.paths[1]->path[0]); | |
496 EXPECT_EQ(newintermediary_, result.paths[1]->path[1]); | |
497 EXPECT_EQ(newrootrollover_, result.paths[1]->path[2]); | |
498 EXPECT_EQ(oldroot_, result.paths[1]->path[3]); | |
499 } | |
500 | |
501 // Tests that if both old and new roots are trusted it can build a path through | |
502 // either. | |
503 // TODO(mattm): Once prioritization is implemented, it should test that it | |
504 // always builds the path through the new intermediary and new root. | |
505 TEST_F(PathBuilderKeyRolloverTest, TestRolloverBothRootsTrusted) { | |
506 // Both oldroot and newroot are trusted. | |
507 TrustStore trust_store; | |
508 trust_store.AddTrustedCertificate(oldroot_); | |
509 trust_store.AddTrustedCertificate(newroot_); | |
510 | |
511 // Both old and new intermediates + rollover cert are provided. | |
512 CertIssuerSourceStatic sync_certs; | |
513 sync_certs.AddCert(oldintermediary_); | |
514 sync_certs.AddCert(newintermediary_); | |
515 sync_certs.AddCert(newrootrollover_); | |
516 | |
517 CertPathBuilder::Result result; | |
518 CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, | |
519 &result); | |
520 path_builder.AddCertIssuerSource(&sync_certs); | |
521 | |
522 EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); | |
523 | |
524 EXPECT_EQ(OK, result.error()); | |
525 | |
526 // Path builder willattempt one of: | |
527 // target <- oldintermediary <- oldroot | |
528 // target <- newintermediary <- newroot | |
529 // either will succeed. | |
530 ASSERT_EQ(1U, result.paths.size()); | |
531 EXPECT_EQ(OK, result.paths[0]->error); | |
532 ASSERT_EQ(3U, result.paths[0]->path.size()); | |
533 EXPECT_EQ(target_, result.paths[0]->path[0]); | |
534 if (result.paths[0]->path[1] != newintermediary_) { | |
535 DVLOG(1) << "USED OLD"; | |
536 EXPECT_EQ(oldintermediary_, result.paths[0]->path[1]); | |
537 EXPECT_EQ(oldroot_, result.paths[0]->path[2]); | |
538 } else { | |
539 DVLOG(1) << "USED NEW"; | |
540 EXPECT_EQ(newintermediary_, result.paths[0]->path[1]); | |
541 EXPECT_EQ(newroot_, result.paths[0]->path[2]); | |
542 } | |
543 } | |
544 | |
545 // Tests that multiple trust root matches on a single path will be considered. | |
546 // Both roots have the same subject but different keys. Only one of them will | |
547 // verify. | |
548 TEST_F(PathBuilderKeyRolloverTest, TestMultipleRootMatchesOnlyOneWorks) { | |
549 // Both newroot and oldroot are trusted. | |
550 TrustStore trust_store; | |
551 // Note: The test assumes newroot will be tried before oldroot. | |
552 // Currently this depends on the order the roots are added. | |
553 trust_store.AddTrustedCertificate(newroot_); | |
554 trust_store.AddTrustedCertificate(oldroot_); | |
555 | |
556 // Only oldintermediary is supplied, so the path with newroot should fail, | |
557 // oldroot should succeed. | |
558 CertIssuerSourceStatic sync_certs; | |
559 sync_certs.AddCert(oldintermediary_); | |
560 | |
561 CertPathBuilder::Result result; | |
562 CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, | |
563 &result); | |
564 path_builder.AddCertIssuerSource(&sync_certs); | |
565 | |
566 EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); | |
567 | |
568 EXPECT_EQ(OK, result.error()); | |
569 ASSERT_EQ(2U, result.paths.size()); | |
570 | |
571 // Path builder will first attempt: target <- oldintermediary <- newroot | |
572 // but it will fail since oldintermediary is signed by oldroot. | |
573 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error); | |
574 ASSERT_EQ(3U, result.paths[0]->path.size()); | |
575 EXPECT_EQ(target_, result.paths[0]->path[0]); | |
576 EXPECT_EQ(oldintermediary_, result.paths[0]->path[1]); | |
577 EXPECT_EQ(newroot_, result.paths[0]->path[2]); | |
578 | |
579 // Path builder will next attempt: | |
580 // target <- old intermediary <- oldroot | |
581 // which should succeed. | |
582 EXPECT_EQ(OK, result.paths[1]->error); | |
583 ASSERT_EQ(3U, result.paths[1]->path.size()); | |
584 EXPECT_EQ(target_, result.paths[1]->path[0]); | |
585 EXPECT_EQ(oldintermediary_, result.paths[1]->path[1]); | |
586 EXPECT_EQ(oldroot_, result.paths[1]->path[2]); | |
587 } | |
588 | |
589 // Tests that the path builder doesn't build longer than necessary paths. | |
590 TEST_F(PathBuilderKeyRolloverTest, TestRolloverLongChain) { | |
591 // Only oldroot is trusted. | |
592 TrustStore trust_store; | |
593 trust_store.AddTrustedCertificate(oldroot_); | |
594 | |
595 // New intermediate and new root are provided synchronously. | |
596 CertIssuerSourceStatic sync_certs; | |
597 sync_certs.AddCert(newintermediary_); | |
598 sync_certs.AddCert(newroot_); | |
599 | |
600 // Rollover cert is only provided asynchronously. This will force the | |
601 // pathbuilder to first try building a longer than necessary path. | |
602 AsyncCertIssuerSourceStatic async_certs; | |
603 async_certs.AddCert(newrootrollover_); | |
604 | |
605 CertPathBuilder::Result result; | |
606 CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, | |
607 &result); | |
608 path_builder.AddCertIssuerSource(&sync_certs); | |
609 path_builder.AddCertIssuerSource(&async_certs); | |
610 | |
611 EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); | |
612 | |
613 EXPECT_EQ(OK, result.error()); | |
614 ASSERT_EQ(3U, result.paths.size()); | |
615 | |
616 // Path builder will first attempt: target <- newintermediary <- oldroot | |
617 // but it will fail since newintermediary is signed by newroot. | |
618 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error); | |
619 ASSERT_EQ(3U, result.paths[0]->path.size()); | |
620 EXPECT_EQ(target_, result.paths[0]->path[0]); | |
621 EXPECT_EQ(newintermediary_, result.paths[0]->path[1]); | |
622 EXPECT_EQ(oldroot_, result.paths[0]->path[2]); | |
623 | |
624 // Path builder will next attempt: | |
625 // target <- newintermediary <- newroot <- oldroot | |
626 // but it will fail since newroot is self-signed. | |
627 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[1]->error); | |
628 ASSERT_EQ(4U, result.paths[1]->path.size()); | |
629 EXPECT_EQ(target_, result.paths[1]->path[0]); | |
630 EXPECT_EQ(newintermediary_, result.paths[1]->path[1]); | |
631 EXPECT_EQ(newroot_, result.paths[1]->path[2]); | |
632 EXPECT_EQ(oldroot_, result.paths[1]->path[3]); | |
633 | |
634 // Path builder will skip: | |
635 // target <- newintermediary <- newroot <- newrootrollover <- ... | |
636 // Since newroot and newrootrollover have the same Name+SAN+SPKI. | |
637 | |
638 // Finally path builder will use: | |
639 // target <- newintermediary <- newrootrollover <- oldroot | |
640 EXPECT_EQ(2U, result.best_result_index); | |
641 EXPECT_EQ(OK, result.paths[2]->error); | |
642 ASSERT_EQ(4U, result.paths[2]->path.size()); | |
643 EXPECT_EQ(target_, result.paths[2]->path[0]); | |
644 EXPECT_EQ(newintermediary_, result.paths[2]->path[1]); | |
645 EXPECT_EQ(newrootrollover_, result.paths[2]->path[2]); | |
646 EXPECT_EQ(oldroot_, result.paths[2]->path[3]); | |
647 } | |
648 | |
649 // If the target cert is a trust root, that alone is a valid path. | |
650 TEST_F(PathBuilderKeyRolloverTest, TestEndEntityIsTrustRoot) { | |
651 // Trust newintermediary. | |
652 TrustStore trust_store; | |
653 trust_store.AddTrustedCertificate(newintermediary_); | |
654 | |
655 CertPathBuilder::Result result; | |
656 // Newintermediary is also the target cert. | |
657 CertPathBuilder path_builder(newintermediary_, &trust_store, | |
658 &signature_policy_, time_, &result); | |
659 | |
660 EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); | |
661 | |
662 EXPECT_EQ(OK, result.error()); | |
663 | |
664 ASSERT_EQ(1U, result.paths.size()); | |
665 EXPECT_EQ(OK, result.paths[0]->error); | |
666 ASSERT_EQ(1U, result.paths[0]->path.size()); | |
667 EXPECT_EQ(newintermediary_, result.paths[0]->path[0]); | |
668 } | |
669 | |
670 // If target has same Name+SAN+SPKI as a necessary intermediate, test if a path | |
671 // can still be built. | |
672 // Since LoopChecker will prevent the intermediate from being included, this | |
673 // currently does NOT verify. This case shouldn't occur in the web PKI. | |
674 TEST_F(PathBuilderKeyRolloverTest, | |
675 TestEndEntityHasSameNameAndSpkiAsIntermediate) { | |
676 // Trust oldroot. | |
677 TrustStore trust_store; | |
678 trust_store.AddTrustedCertificate(oldroot_); | |
679 | |
680 // New root rollover is provided synchronously. | |
681 CertIssuerSourceStatic sync_certs; | |
682 sync_certs.AddCert(newrootrollover_); | |
683 | |
684 CertPathBuilder::Result result; | |
685 // Newroot is the target cert. | |
686 CertPathBuilder path_builder(newroot_, &trust_store, &signature_policy_, | |
687 time_, &result); | |
688 path_builder.AddCertIssuerSource(&sync_certs); | |
689 | |
690 EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); | |
691 | |
692 // This could actually be OK, but CertPathBuilder does not build the | |
693 // newroot <- newrootrollover <- oldroot path. | |
694 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.error()); | |
695 } | |
696 | |
697 // If target has same Name+SAN+SPKI as the trust root, test that a (trivial) | |
698 // path can still be built. | |
699 TEST_F(PathBuilderKeyRolloverTest, | |
700 TestEndEntityHasSameNameAndSpkiAsTrustAnchor) { | |
701 // Trust newrootrollover. | |
702 TrustStore trust_store; | |
703 trust_store.AddTrustedCertificate(newrootrollover_); | |
704 | |
705 CertPathBuilder::Result result; | |
706 // Newroot is the target cert. | |
707 CertPathBuilder path_builder(newroot_, &trust_store, &signature_policy_, | |
708 time_, &result); | |
709 | |
710 EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); | |
711 | |
712 EXPECT_EQ(OK, result.error()); | |
713 | |
714 ASSERT_FALSE(result.paths.empty()); | |
715 const CertPathBuilder::ResultPath* best_result = | |
716 result.paths[result.best_result_index].get(); | |
717 | |
718 // Newroot has same name+SPKI as newrootrollover, thus the path is valid and | |
719 // only contains newroot. | |
720 EXPECT_EQ(OK, best_result->error); | |
721 ASSERT_EQ(1U, best_result->path.size()); | |
722 EXPECT_EQ(newroot_, best_result->path[0]); | |
723 } | |
724 | |
725 // Test that PathBuilder will not try the same path twice if multiple | |
726 // CertIssuerSources provide the same certificate. | |
727 TEST_F(PathBuilderKeyRolloverTest, TestDuplicateIntermediates) { | |
728 // Create a separate copy of oldintermediary. | |
729 scoped_refptr<ParsedCertificate> oldintermediary_dupe( | |
730 ParsedCertificate::CreateFromCertificateCopy( | |
731 oldintermediary_->der_cert().AsStringPiece(), {})); | |
732 | |
733 // Only newroot is a trusted root. | |
734 TrustStore trust_store; | |
735 trust_store.AddTrustedCertificate(newroot_); | |
736 | |
737 // The oldintermediary is supplied synchronously by |sync_certs1| and | |
738 // another copy of oldintermediary is supplied synchronously by |sync_certs2|. | |
739 // The path target <- oldintermediary <- newroot should be built first, | |
740 // though it won't verify. It should not be attempted again even though | |
741 // oldintermediary was supplied twice. | |
742 CertIssuerSourceStatic sync_certs1; | |
743 sync_certs1.AddCert(oldintermediary_); | |
744 CertIssuerSourceStatic sync_certs2; | |
745 sync_certs2.AddCert(oldintermediary_dupe); | |
746 | |
747 // The newintermediary is supplied asynchronously, so the path | |
748 // target <- newintermediary <- newroot should be tried second. | |
749 AsyncCertIssuerSourceStatic async_certs; | |
750 async_certs.AddCert(newintermediary_); | |
751 | |
752 CertPathBuilder::Result result; | |
753 CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, | |
754 &result); | |
755 path_builder.AddCertIssuerSource(&sync_certs1); | |
756 path_builder.AddCertIssuerSource(&sync_certs2); | |
757 path_builder.AddCertIssuerSource(&async_certs); | |
758 | |
759 EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); | |
760 | |
761 EXPECT_EQ(OK, result.error()); | |
762 ASSERT_EQ(2U, result.paths.size()); | |
763 | |
764 // Path builder will first attempt: target <- oldintermediary <- newroot | |
765 // but it will fail since oldintermediary is signed by oldroot. | |
766 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error); | |
767 ASSERT_EQ(3U, result.paths[0]->path.size()); | |
768 EXPECT_EQ(target_, result.paths[0]->path[0]); | |
769 // Compare the DER instead of ParsedCertificate pointer, don't care which copy | |
770 // of oldintermediary was used in the path. | |
771 EXPECT_EQ(oldintermediary_->der_cert(), result.paths[0]->path[1]->der_cert()); | |
772 EXPECT_EQ(newroot_, result.paths[0]->path[2]); | |
773 | |
774 // Path builder will next attempt: target <- newintermediary <- newroot | |
775 // which will succeed. | |
776 EXPECT_EQ(1U, result.best_result_index); | |
777 EXPECT_EQ(OK, result.paths[1]->error); | |
778 ASSERT_EQ(3U, result.paths[1]->path.size()); | |
779 EXPECT_EQ(target_, result.paths[1]->path[0]); | |
780 EXPECT_EQ(newintermediary_, result.paths[1]->path[1]); | |
781 EXPECT_EQ(newroot_, result.paths[1]->path[2]); | |
782 } | |
783 | |
784 // Test that PathBuilder will not try the same path twice if the same cert is | |
785 // presented via a CertIssuerSources and a TrustAnchor. | |
786 TEST_F(PathBuilderKeyRolloverTest, TestDuplicateIntermediateAndRoot) { | |
787 // Create a separate copy of newroot. | |
788 scoped_refptr<ParsedCertificate> newroot_dupe( | |
789 ParsedCertificate::CreateFromCertificateCopy( | |
790 newroot_->der_cert().AsStringPiece(), {})); | |
791 | |
792 // Only newroot is a trusted root. | |
793 TrustStore trust_store; | |
794 trust_store.AddTrustedCertificate(newroot_); | |
795 | |
796 // The oldintermediary and newroot are supplied synchronously by |sync_certs|. | |
797 CertIssuerSourceStatic sync_certs; | |
798 sync_certs.AddCert(oldintermediary_); | |
799 sync_certs.AddCert(newroot_dupe); | |
800 | |
801 CertPathBuilder::Result result; | |
802 CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, | |
803 &result); | |
804 path_builder.AddCertIssuerSource(&sync_certs); | |
805 | |
806 EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); | |
807 | |
808 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.error()); | |
809 ASSERT_EQ(1U, result.paths.size()); | |
810 | |
811 // Path builder attempt: target <- oldintermediary <- newroot | |
812 // but it will fail since oldintermediary is signed by oldroot. | |
813 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error); | |
814 ASSERT_EQ(3U, result.paths[0]->path.size()); | |
815 EXPECT_EQ(target_, result.paths[0]->path[0]); | |
816 EXPECT_EQ(oldintermediary_, result.paths[0]->path[1]); | |
817 // Compare the DER instead of ParsedCertificate pointer, don't care which copy | |
818 // of newroot was used in the path. | |
819 EXPECT_EQ(newroot_->der_cert(), result.paths[0]->path[2]->der_cert()); | |
820 } | |
821 | |
822 class MockCertIssuerSourceRequest : public CertIssuerSource::Request { | |
823 public: | |
824 MOCK_METHOD1(GetNext, CompletionStatus(scoped_refptr<ParsedCertificate>*)); | |
825 }; | |
826 | |
827 class MockCertIssuerSource : public CertIssuerSource { | |
828 public: | |
829 MOCK_METHOD2(SyncGetIssuersOf, | |
830 void(const ParsedCertificate*, ParsedCertificateList*)); | |
831 MOCK_METHOD3(AsyncGetIssuersOf, | |
832 void(const ParsedCertificate*, | |
833 const IssuerCallback&, | |
834 std::unique_ptr<Request>*)); | |
835 }; | |
836 | |
837 // Helper class to pass the Request to the PathBuilder when it calls | |
838 // AsyncGetIssuersOf. (GoogleMock has a ByMove helper, but it apparently can | |
839 // only be used with Return, not SetArgPointee.) | |
840 class CertIssuerSourceRequestMover { | |
841 public: | |
842 CertIssuerSourceRequestMover(std::unique_ptr<CertIssuerSource::Request> req) | |
843 : request_(std::move(req)) {} | |
844 void MoveIt(const ParsedCertificate* cert, | |
845 const CertIssuerSource::IssuerCallback& issuers_callback, | |
846 std::unique_ptr<CertIssuerSource::Request>* out_req) { | |
847 *out_req = std::move(request_); | |
848 } | |
849 | |
850 private: | |
851 std::unique_ptr<CertIssuerSource::Request> request_; | |
852 }; | |
853 | |
854 // Test that a single CertIssuerSource returning multiple async batches of | |
855 // issuers is handled correctly. Due to the StrictMocks, it also tests that path | |
856 // builder does not request issuers of certs that it shouldn't. | |
857 TEST_F(PathBuilderKeyRolloverTest, TestMultipleAsyncCallbacksFromSingleSource) { | |
858 StrictMock<MockCertIssuerSource> cert_issuer_source; | |
859 | |
860 // Only newroot is a trusted root. | |
861 TrustStore trust_store; | |
862 trust_store.AddTrustedCertificate(newroot_); | |
863 | |
864 CertPathBuilder::Result result; | |
865 CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, | |
866 &result); | |
867 path_builder.AddCertIssuerSource(&cert_issuer_source); | |
868 | |
869 CertIssuerSource::IssuerCallback target_issuers_callback; | |
870 // Create the mock CertIssuerSource::Request... | |
871 std::unique_ptr<StrictMock<MockCertIssuerSourceRequest>> | |
872 target_issuers_req_owner(new StrictMock<MockCertIssuerSourceRequest>()); | |
873 // Keep a raw pointer to the Request... | |
874 StrictMock<MockCertIssuerSourceRequest>* target_issuers_req = | |
875 target_issuers_req_owner.get(); | |
876 // Setup helper class to pass ownership of the Request to the PathBuilder when | |
877 // it calls AsyncGetIssuersOf. | |
878 CertIssuerSourceRequestMover req_mover(std::move(target_issuers_req_owner)); | |
879 { | |
880 ::testing::InSequence s; | |
881 EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(target_.get(), _)); | |
882 EXPECT_CALL(cert_issuer_source, AsyncGetIssuersOf(target_.get(), _, _)) | |
883 .WillOnce( | |
884 DoAll(SaveArg<1>(&target_issuers_callback), | |
885 Invoke(&req_mover, &CertIssuerSourceRequestMover::MoveIt))); | |
886 } | |
887 | |
888 TestClosure callback; | |
889 CompletionStatus rv = path_builder.Run(callback.closure()); | |
890 ASSERT_EQ(CompletionStatus::ASYNC, rv); | |
891 | |
892 ASSERT_FALSE(target_issuers_callback.is_null()); | |
893 | |
894 ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); | |
895 | |
896 // First async batch: return oldintermediary_. | |
897 EXPECT_CALL(*target_issuers_req, GetNext(_)) | |
898 .WillOnce(DoAll(SetArgPointee<0>(oldintermediary_), | |
899 Return(CompletionStatus::SYNC))) | |
900 .WillOnce( | |
901 DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC))); | |
902 { | |
903 ::testing::InSequence s; | |
904 // oldintermediary_ does not create a valid path, so both sync and async | |
905 // lookups are expected. | |
906 EXPECT_CALL(cert_issuer_source, | |
907 SyncGetIssuersOf(oldintermediary_.get(), _)); | |
908 EXPECT_CALL(cert_issuer_source, | |
909 AsyncGetIssuersOf(oldintermediary_.get(), _, _)); | |
910 } | |
911 target_issuers_callback.Run(target_issuers_req); | |
912 ::testing::Mock::VerifyAndClearExpectations(target_issuers_req); | |
913 ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); | |
914 | |
915 // Second async batch: return newintermediary_. | |
916 EXPECT_CALL(*target_issuers_req, GetNext(_)) | |
917 .WillOnce(DoAll(SetArgPointee<0>(newintermediary_), | |
918 Return(CompletionStatus::SYNC))) | |
919 .WillOnce( | |
920 DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC))); | |
921 // newroot_ is in the trust store, so this path will be completed | |
922 // synchronously. AsyncGetIssuersOf will not be called on newintermediary_. | |
923 EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(newintermediary_.get(), _)); | |
924 target_issuers_callback.Run(target_issuers_req); | |
925 // Note that VerifyAndClearExpectations(target_issuers_req) is not called | |
926 // here. PathBuilder could have destroyed it already, so just let the | |
927 // expectations get checked by the destructor. | |
928 ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); | |
929 | |
930 // Ensure pathbuilder finished and filled result. | |
931 callback.WaitForResult(); | |
932 | |
933 EXPECT_EQ(OK, result.error()); | |
934 ASSERT_EQ(2U, result.paths.size()); | |
935 | |
936 // Path builder first attempts: target <- oldintermediary <- newroot | |
937 // but it will fail since oldintermediary is signed by oldroot. | |
938 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error); | |
939 ASSERT_EQ(3U, result.paths[0]->path.size()); | |
940 EXPECT_EQ(target_, result.paths[0]->path[0]); | |
941 EXPECT_EQ(oldintermediary_, result.paths[0]->path[1]); | |
942 EXPECT_EQ(newroot_, result.paths[0]->path[2]); | |
943 | |
944 // After the second batch of async results, path builder will attempt: | |
945 // target <- newintermediary <- newroot which will succeed. | |
946 EXPECT_EQ(OK, result.paths[1]->error); | |
947 ASSERT_EQ(3U, result.paths[1]->path.size()); | |
948 EXPECT_EQ(target_, result.paths[1]->path[0]); | |
949 EXPECT_EQ(newintermediary_, result.paths[1]->path[1]); | |
950 EXPECT_EQ(newroot_, result.paths[1]->path[2]); | |
951 } | |
952 | |
953 // Test that PathBuilder will not try the same path twice if CertIssuerSources | |
954 // asynchronously provide the same certificate multiple times. | |
955 TEST_F(PathBuilderKeyRolloverTest, TestDuplicateAsyncIntermediates) { | |
956 StrictMock<MockCertIssuerSource> cert_issuer_source; | |
957 | |
958 // Only newroot is a trusted root. | |
959 TrustStore trust_store; | |
960 trust_store.AddTrustedCertificate(newroot_); | |
961 | |
962 CertPathBuilder::Result result; | |
963 CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, | |
964 &result); | |
965 path_builder.AddCertIssuerSource(&cert_issuer_source); | |
966 | |
967 CertIssuerSource::IssuerCallback target_issuers_callback; | |
968 // Create the mock CertIssuerSource::Request... | |
969 std::unique_ptr<StrictMock<MockCertIssuerSourceRequest>> | |
970 target_issuers_req_owner(new StrictMock<MockCertIssuerSourceRequest>()); | |
971 // Keep a raw pointer to the Request... | |
972 StrictMock<MockCertIssuerSourceRequest>* target_issuers_req = | |
973 target_issuers_req_owner.get(); | |
974 // Setup helper class to pass ownership of the Request to the PathBuilder when | |
975 // it calls AsyncGetIssuersOf. | |
976 CertIssuerSourceRequestMover req_mover(std::move(target_issuers_req_owner)); | |
977 { | |
978 ::testing::InSequence s; | |
979 EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(target_.get(), _)); | |
980 EXPECT_CALL(cert_issuer_source, AsyncGetIssuersOf(target_.get(), _, _)) | |
981 .WillOnce( | |
982 DoAll(SaveArg<1>(&target_issuers_callback), | |
983 Invoke(&req_mover, &CertIssuerSourceRequestMover::MoveIt))); | |
984 } | |
985 | |
986 TestClosure callback; | |
987 CompletionStatus rv = path_builder.Run(callback.closure()); | |
988 ASSERT_EQ(CompletionStatus::ASYNC, rv); | |
989 | |
990 ASSERT_FALSE(target_issuers_callback.is_null()); | |
991 | |
992 ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); | |
993 | |
994 // First async batch: return oldintermediary_. | |
995 EXPECT_CALL(*target_issuers_req, GetNext(_)) | |
996 .WillOnce(DoAll(SetArgPointee<0>(oldintermediary_), | |
997 Return(CompletionStatus::SYNC))) | |
998 .WillOnce( | |
999 DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC))); | |
1000 { | |
1001 ::testing::InSequence s; | |
1002 // oldintermediary_ does not create a valid path, so both sync and async | |
1003 // lookups are expected. | |
1004 EXPECT_CALL(cert_issuer_source, | |
1005 SyncGetIssuersOf(oldintermediary_.get(), _)); | |
1006 EXPECT_CALL(cert_issuer_source, | |
1007 AsyncGetIssuersOf(oldintermediary_.get(), _, _)); | |
1008 } | |
1009 target_issuers_callback.Run(target_issuers_req); | |
1010 ::testing::Mock::VerifyAndClearExpectations(target_issuers_req); | |
1011 ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); | |
1012 | |
1013 // Second async batch: return a different copy of oldintermediary_ again. | |
1014 scoped_refptr<ParsedCertificate> oldintermediary_dupe( | |
1015 ParsedCertificate::CreateFromCertificateCopy( | |
1016 oldintermediary_->der_cert().AsStringPiece(), {})); | |
1017 EXPECT_CALL(*target_issuers_req, GetNext(_)) | |
1018 .WillOnce(DoAll(SetArgPointee<0>(oldintermediary_dupe), | |
1019 Return(CompletionStatus::SYNC))) | |
1020 .WillOnce( | |
1021 DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC))); | |
1022 target_issuers_callback.Run(target_issuers_req); | |
1023 // oldintermediary was already processed above, it should not generate any | |
1024 // more requests. | |
1025 ::testing::Mock::VerifyAndClearExpectations(target_issuers_req); | |
1026 ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); | |
1027 | |
1028 // Third async batch: return newintermediary_. | |
1029 EXPECT_CALL(*target_issuers_req, GetNext(_)) | |
1030 .WillOnce(DoAll(SetArgPointee<0>(newintermediary_), | |
1031 Return(CompletionStatus::SYNC))) | |
1032 .WillOnce( | |
1033 DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC))); | |
1034 // newroot_ is in the trust store, so this path will be completed | |
1035 // synchronously. AsyncGetIssuersOf will not be called on newintermediary_. | |
1036 EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(newintermediary_.get(), _)); | |
1037 target_issuers_callback.Run(target_issuers_req); | |
1038 // Note that VerifyAndClearExpectations(target_issuers_req) is not called | |
1039 // here. PathBuilder could have destroyed it already, so just let the | |
1040 // expectations get checked by the destructor. | |
1041 ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); | |
1042 | |
1043 // Ensure pathbuilder finished and filled result. | |
1044 callback.WaitForResult(); | |
1045 | |
1046 EXPECT_EQ(OK, result.error()); | |
1047 ASSERT_EQ(2U, result.paths.size()); | |
1048 | |
1049 // Path builder first attempts: target <- oldintermediary <- newroot | |
1050 // but it will fail since oldintermediary is signed by oldroot. | |
1051 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error); | |
1052 ASSERT_EQ(3U, result.paths[0]->path.size()); | |
1053 EXPECT_EQ(target_, result.paths[0]->path[0]); | |
1054 EXPECT_EQ(oldintermediary_, result.paths[0]->path[1]); | |
1055 EXPECT_EQ(newroot_, result.paths[0]->path[2]); | |
1056 | |
1057 // The second async result does not generate any path. | |
1058 | |
1059 // After the third batch of async results, path builder will attempt: | |
1060 // target <- newintermediary <- newroot which will succeed. | |
1061 EXPECT_EQ(OK, result.paths[1]->error); | |
1062 ASSERT_EQ(3U, result.paths[1]->path.size()); | |
1063 EXPECT_EQ(target_, result.paths[1]->path[0]); | |
1064 EXPECT_EQ(newintermediary_, result.paths[1]->path[1]); | |
1065 EXPECT_EQ(newroot_, result.paths[1]->path[2]); | |
1066 } | |
1067 | |
1068 } // namespace | |
1069 | |
1070 } // namespace net | |
OLD | NEW |