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