Index: net/cert/internal/path_builder_unittest.cc |
diff --git a/net/cert/internal/path_builder_unittest.cc b/net/cert/internal/path_builder_unittest.cc |
index 432ea5274252a5fb661906c980985c580367c464..30c766bc07c75facbe93ec4e29473ae5319a6c33 100644 |
--- a/net/cert/internal/path_builder_unittest.cc |
+++ b/net/cert/internal/path_builder_unittest.cc |
@@ -17,6 +17,7 @@ |
#include "net/cert/internal/signature_policy.h" |
#include "net/cert/internal/test_helpers.h" |
#include "net/cert/internal/trust_store_in_memory.h" |
+#include "net/cert/internal/trust_store_test_helpers.h" |
#include "net/cert/internal/verify_certificate_chain.h" |
#include "net/cert/pem_tokenizer.h" |
#include "net/der/input.h" |
@@ -627,31 +628,141 @@ TEST_F(PathBuilderKeyRolloverTest, TestRolloverBothRootsTrusted) { |
} |
} |
-class MockTrustStore : public TrustStore { |
- public: |
- MOCK_CONST_METHOD2(FindTrustAnchorsByNormalizedName, |
- void(const der::Input& normalized_name, |
- TrustAnchors* matches)); |
-}; |
+// If trust anchors are provided both synchronously and asynchronously for the |
+// same cert, the synchronously provided ones should be tried first, and |
+// pathbuilder should finish synchronously. |
+TEST_F(PathBuilderKeyRolloverTest, TestSyncAnchorsPreferred) { |
+ TrustStoreInMemoryAsync trust_store; |
+ // Both oldintermediate and newintermediate are trusted, but oldintermediate |
+ // is returned synchronously and newintermediate asynchronously. |
+ trust_store.AddSyncTrustAnchor( |
+ TrustAnchor::CreateFromCertificateNoConstraints(oldintermediate_)); |
+ trust_store.AddAsyncTrustAnchor( |
+ TrustAnchor::CreateFromCertificateNoConstraints(newintermediate_)); |
+ |
+ CertPathBuilder::Result result; |
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, |
+ &result); |
+ |
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); |
+ |
+ EXPECT_EQ(OK, result.error()); |
+ |
+ ASSERT_EQ(1U, result.paths.size()); |
+ const auto& path = result.paths[0]->path; |
+ EXPECT_EQ(OK, result.paths[0]->error); |
+ ASSERT_EQ(1U, path.certs.size()); |
+ EXPECT_EQ(target_, path.certs[0]); |
+ EXPECT_EQ(oldintermediate_, path.trust_anchor->cert()); |
+} |
+ |
+// Async trust anchor checks should be done before synchronous issuer checks are |
+// considered. (Avoiding creating unnecessarily long paths.) |
+// |
+// Two valid paths could be built: |
+// newintermediate <- newrootrollover <- oldroot |
+// newintermediate <- newroot |
+// One invalid path could be built: |
+// newintermediate <- oldroot |
+// |
+// First: newintermediate <- oldroot will be tried, since oldroot is |
+// available synchronously, but this path will not verify. |
+// Second: newintermediate <- newroot should be built, even though |
+// newrootrollover issuer is available synchronously and newroot is async. This |
+// path should verify and pathbuilder will stop. |
+TEST_F(PathBuilderKeyRolloverTest, TestAsyncAnchorsBeforeSyncIssuers) { |
+ TrustStoreInMemoryAsync trust_store; |
+ trust_store.AddSyncTrustAnchor(oldroot_); |
+ trust_store.AddAsyncTrustAnchor( |
+ TrustAnchor::CreateFromCertificateNoConstraints(newroot_)); |
+ |
+ CertIssuerSourceStatic sync_certs; |
+ sync_certs.AddCert(newrootrollover_); |
+ |
+ CertPathBuilder::Result result; |
+ CertPathBuilder path_builder(newintermediate_, &trust_store, |
+ &signature_policy_, time_, &result); |
+ path_builder.AddCertIssuerSource(&sync_certs); |
+ |
+ EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); |
+ |
+ EXPECT_EQ(OK, result.error()); |
+ |
+ ASSERT_EQ(2U, result.paths.size()); |
+ { |
+ const auto& path = result.paths[0]->path; |
+ EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error); |
+ ASSERT_EQ(1U, path.certs.size()); |
+ EXPECT_EQ(newintermediate_, path.certs[0]); |
+ EXPECT_EQ(oldroot_, path.trust_anchor); |
+ } |
+ { |
+ const auto& path = result.paths[1]->path; |
+ EXPECT_EQ(OK, result.paths[1]->error); |
+ ASSERT_EQ(1U, path.certs.size()); |
+ EXPECT_EQ(newintermediate_, path.certs[0]); |
+ EXPECT_EQ(newroot_, path.trust_anchor->cert()); |
+ } |
+} |
+ |
+// If async trust anchor query returned no results, and there are no issuer |
+// sources, path building should fail at that point. |
+TEST_F(PathBuilderKeyRolloverTest, TestAsyncAnchorsNoMatchAndNoIssuerSources) { |
+ TrustStoreInMemoryAsync trust_store; |
+ trust_store.AddAsyncTrustAnchor( |
+ TrustAnchor::CreateFromCertificateNoConstraints(newroot_)); |
+ |
+ CertPathBuilder::Result result; |
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, |
+ &result); |
+ |
+ EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); |
+ |
+ EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.error()); |
+ |
+ ASSERT_EQ(0U, result.paths.size()); |
+} |
+ |
+// Both trust store and issuer source are async. Should successfully build a |
+// path. |
+TEST_F(PathBuilderKeyRolloverTest, TestAsyncAnchorsAndAsyncIssuers) { |
+ TrustStoreInMemoryAsync trust_store; |
+ trust_store.AddAsyncTrustAnchor( |
+ TrustAnchor::CreateFromCertificateNoConstraints(newroot_)); |
+ |
+ AsyncCertIssuerSourceStatic async_certs; |
+ async_certs.AddCert(newintermediate_); |
+ |
+ CertPathBuilder::Result result; |
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, |
+ &result); |
+ path_builder.AddCertIssuerSource(&async_certs); |
+ |
+ EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); |
+ |
+ EXPECT_EQ(OK, result.error()); |
+ |
+ ASSERT_EQ(1U, result.paths.size()); |
+ const auto& path = result.paths[0]->path; |
+ EXPECT_EQ(OK, result.paths[0]->error); |
+ ASSERT_EQ(2U, path.certs.size()); |
+ EXPECT_EQ(target_, path.certs[0]); |
+ EXPECT_EQ(newintermediate_, path.certs[1]); |
+ EXPECT_EQ(newroot_, path.trust_anchor->cert()); |
+} |
// Tests that multiple trust root matches on a single path will be considered. |
// Both roots have the same subject but different keys. Only one of them will |
// verify. |
TEST_F(PathBuilderKeyRolloverTest, TestMultipleRootMatchesOnlyOneWorks) { |
- NiceMock<MockTrustStore> trust_store; |
- // Default handler for any other TrustStore requests. |
- EXPECT_CALL(trust_store, FindTrustAnchorsByNormalizedName(_, _)) |
- .WillRepeatedly(Return()); |
- // Both newroot and oldroot are trusted, and newroot is returned first in the |
- // matches vector. |
- EXPECT_CALL(trust_store, FindTrustAnchorsByNormalizedName( |
- newroot_->normalized_subject(), _)) |
- .WillRepeatedly(Invoke( |
- [this](const der::Input& normalized_name, TrustAnchors* matches) { |
- matches->push_back( |
- TrustAnchor::CreateFromCertificateNoConstraints(newroot_)); |
- matches->push_back(oldroot_); |
- })); |
+ TrustStoreInMemoryAsync trust_store; |
+ // Since FindTrustAnchorsByNormalizedName returns newroot synchronously, it |
+ // should be tried first. |
+ trust_store.AddSyncTrustAnchor( |
+ TrustAnchor::CreateFromCertificateNoConstraints(newroot_)); |
+ // oldroot is returned asynchronously, so it should only be tried after the |
+ // path built with newroot fails. |
+ trust_store.AddAsyncTrustAnchor(oldroot_); |
// Only oldintermediate is supplied, so the path with newroot should fail, |
// oldroot should succeed. |
@@ -663,12 +774,9 @@ TEST_F(PathBuilderKeyRolloverTest, TestMultipleRootMatchesOnlyOneWorks) { |
&result); |
path_builder.AddCertIssuerSource(&sync_certs); |
- EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); |
+ EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); |
EXPECT_EQ(OK, result.error()); |
- // Since FindTrustAnchorsByNormalizedName returns newroot first, it should be |
- // tried first. (Note: this may change if PathBuilder starts prioritizing the |
- // path building order.) |
ASSERT_EQ(2U, result.paths.size()); |
{ |