summaryrefslogtreecommitdiffstats
path: root/net/cert
diff options
context:
space:
mode:
authorrsleevi <rsleevi@chromium.org>2016-03-03 14:24:59 -0800
committerCommit bot <commit-bot@chromium.org>2016-03-03 22:26:00 +0000
commitc45d7cce9017369c36ecbe3ed2d4567eea786f24 (patch)
treef956c9db5066ffc4df967e23de0e3cc20b21c580 /net/cert
parent078436bd5a6b1b3ac15a56660d9e1442b462733d (diff)
downloadchromium_src-c45d7cce9017369c36ecbe3ed2d4567eea786f24.zip
chromium_src-c45d7cce9017369c36ecbe3ed2d4567eea786f24.tar.gz
chromium_src-c45d7cce9017369c36ecbe3ed2d4567eea786f24.tar.bz2
Perform CRLSet evaluation during Path Building on NSS
When using NSS for certificate verification, add CRLSet checking by injecting a revocation callback function which will examine the CRLSet and reject the certificate. If the CRLSet does not affirmatively reject it, continue invoking the originally supplied application callback (such as the ChromeOS callback) and allow it an opportunity to reject. Because of how NSS caches virtually everything, horribly so, this restructures the unittests to no longer depend on how the underlying library will select the path (since with NSS, it's fundamentally non-determistic), and instead tests that as long as a singular certificate path is still valid and un-revoked, it can be discovered. BUG=589336 TEST=CertVerifyProcTest.CRLSet* Review URL: https://codereview.chromium.org/1724413002 Cr-Commit-Position: refs/heads/master@{#379113}
Diffstat (limited to 'net/cert')
-rw-r--r--net/cert/cert_verify_proc_nss.cc119
-rw-r--r--net/cert/cert_verify_proc_unittest.cc277
2 files changed, 178 insertions, 218 deletions
diff --git a/net/cert/cert_verify_proc_nss.cc b/net/cert/cert_verify_proc_nss.cc
index ca8e811..cad20b9 100644
--- a/net/cert/cert_verify_proc_nss.cc
+++ b/net/cert/cert_verify_proc_nss.cc
@@ -279,7 +279,7 @@ enum CRLSetResult {
// that some EV sites would otherwise take the hit of an OCSP lookup for
// no reason.
// kCRLSetOk: otherwise.
-CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list,
+CRLSetResult CheckRevocationWithCRLSet(const CERTCertList* cert_list,
CERTCertificate* root,
CRLSet* crl_set) {
std::vector<CERTCertificate*> certs;
@@ -352,6 +352,50 @@ CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list,
return kCRLSetOk;
}
+// Arguments for CheckChainRevocationWithCRLSet that are curried within the
+// CERTChainVerifyCallback's isChainValidArg.
+struct CheckChainRevocationArgs {
+ // The CRLSet to evaluate against.
+ CRLSet* crl_set = nullptr;
+
+ // The next callback to invoke, if the CRLSet does not report any errors.
+ CERTChainVerifyCallback* next_callback = nullptr;
+
+ // Indicates that the application callback failure was due to a CRLSet
+ // revocation, rather than due to |next_callback| rejecting it. This is
+ // used to map the error back to the proper caller-visible error code.
+ bool was_revoked = false;
+};
+
+SECStatus CheckChainRevocationWithCRLSet(void* is_chain_valid_arg,
+ const CERTCertList* current_chain,
+ PRBool* chain_ok) {
+ CHECK(is_chain_valid_arg);
+
+ CheckChainRevocationArgs* args =
+ static_cast<CheckChainRevocationArgs*>(is_chain_valid_arg);
+
+ CRLSetResult crlset_result = kCRLSetUnknown;
+ if (args->crl_set) {
+ crlset_result =
+ CheckRevocationWithCRLSet(current_chain, nullptr, args->crl_set);
+ }
+
+ if (crlset_result == kCRLSetRevoked) {
+ args->was_revoked = true;
+ *chain_ok = PR_FALSE;
+ return SECSuccess;
+ }
+ args->was_revoked = false;
+
+ *chain_ok = PR_TRUE;
+ if (!args->next_callback || !args->next_callback->isChainValid)
+ return SECSuccess;
+
+ return (*args->next_callback->isChainValid)(
+ args->next_callback->isChainValidArg, current_chain, chain_ok);
+}
+
// Forward declarations.
SECStatus RetryPKIXVerifyCertWithWorkarounds(
CERTCertificate* cert_handle, int num_policy_oids,
@@ -825,6 +869,22 @@ int CertVerifyProcNSS::VerifyInternalImpl(
verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
}
+ // Setup a callback to call into CheckChainRevocationWithCRLSet with the
+ // current CRLSet. If the CRLSet revokes a given chain, |was_revoked|
+ // will be set to true.
+ // The same callback and args are used for every invocation of
+ // PKIXVerifyCert, as CheckChainRevocationWithCRLSet handles resetting
+ // |was_revoked| as necessary.
+ CheckChainRevocationArgs check_chain_revocation_args;
+ check_chain_revocation_args.crl_set = crl_set;
+ check_chain_revocation_args.next_callback = chain_verify_callback;
+
+ CERTChainVerifyCallback crlset_callback;
+ memset(&crlset_callback, 0, sizeof(crlset_callback));
+ crlset_callback.isChainValid = &CheckChainRevocationWithCRLSet;
+ crlset_callback.isChainValidArg =
+ static_cast<void*>(&check_chain_revocation_args);
+
// Make sure that the cert is valid now.
SECCertTimeValidity validity = CERT_CheckCertValidTimes(
cert_handle, PR_Now(), PR_TRUE);
@@ -862,15 +922,9 @@ int CertVerifyProcNSS::VerifyInternalImpl(
CertificateListToCERTCertList(additional_trust_anchors));
}
- SECStatus status = PKIXVerifyCert(cert_handle,
- check_revocation,
- false,
- cert_io_enabled,
- NULL,
- 0,
- trust_anchors.get(),
- chain_verify_callback,
- cvout);
+ SECStatus status =
+ PKIXVerifyCert(cert_handle, check_revocation, false, cert_io_enabled,
+ NULL, 0, trust_anchors.get(), &crlset_callback, cvout);
if (status == SECSuccess &&
(flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) &&
@@ -880,15 +934,8 @@ int CertVerifyProcNSS::VerifyInternalImpl(
// NSS tests for that feature.
scoped_cvout.Clear();
verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
- status = PKIXVerifyCert(cert_handle,
- true,
- true,
- cert_io_enabled,
- NULL,
- 0,
- trust_anchors.get(),
- chain_verify_callback,
- cvout);
+ status = PKIXVerifyCert(cert_handle, true, true, cert_io_enabled, NULL, 0,
+ trust_anchors.get(), &crlset_callback, cvout);
}
if (status == SECSuccess) {
@@ -910,13 +957,25 @@ int CertVerifyProcNSS::VerifyInternalImpl(
CRLSetResult crl_set_result = kCRLSetUnknown;
if (crl_set) {
- crl_set_result = CheckRevocationWithCRLSet(
- cvout[cvout_cert_list_index].value.pointer.chain,
- cvout[cvout_trust_anchor_index].value.pointer.cert,
- crl_set);
- if (crl_set_result == kCRLSetRevoked) {
+ if (status == SECSuccess) {
+ // Reverify the returned chain; NSS should have already called
+ // CheckChainRevocationWithCRLSet prior to returning, but given the
+ // edge cases (self-signed certs that are trusted; cached chains;
+ // unreadable code), this is more about defense in depth than
+ // functional necessity.
+ crl_set_result = CheckRevocationWithCRLSet(
+ cvout[cvout_cert_list_index].value.pointer.chain,
+ cvout[cvout_trust_anchor_index].value.pointer.cert, crl_set);
+ if (crl_set_result == kCRLSetRevoked) {
+ PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
+ status = SECFailure;
+ }
+ } else if (PORT_GetError() == SEC_ERROR_APPLICATION_CALLBACK_ERROR &&
+ check_chain_revocation_args.was_revoked) {
+ // If a CRLSet was supplied, and the error was an application callback
+ // error, then it was directed through the CRLSet code and that
+ // particular chain was revoked.
PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
- status = SECFailure;
}
}
@@ -949,14 +1008,8 @@ int CertVerifyProcNSS::VerifyInternalImpl(
if (check_revocation)
verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
- if (VerifyEV(cert_handle,
- flags,
- crl_set,
- check_revocation,
- metadata,
- ev_policy_oid,
- trust_anchors.get(),
- chain_verify_callback)) {
+ if (VerifyEV(cert_handle, flags, crl_set, check_revocation, metadata,
+ ev_policy_oid, trust_anchors.get(), &crlset_callback)) {
verify_result->cert_status |= CERT_STATUS_IS_EV;
}
}
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc
index be9868d..be7f4d1 100644
--- a/net/cert/cert_verify_proc_unittest.cc
+++ b/net/cert/cert_verify_proc_unittest.cc
@@ -143,7 +143,7 @@ class CertVerifyProcTest : public testing::Test {
// into all platforms, this is a temporary, test-only flag to centralize the
// conditionals in tests.
bool SupportsCRLSetsInPathBuilding() {
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(USE_NSS_CERTS)
return true;
#else
return false;
@@ -1279,210 +1279,117 @@ TEST_F(CertVerifyProcTest, CRLSetLeafSerial) {
EXPECT_EQ(ERR_CERT_REVOKED, error);
}
-// Tests that revocation by CRLSet functions properly with the certificate
-// immediately before the trust anchor is revoked by that trust anchor, but
-// another version to a different trust anchor exists.
+// Tests that CRLSets participate in path building functions, and that as
+// long as a valid path exists within the verification graph, verification
+// succeeds.
//
-// The two possible paths are:
+// In this test, there are two roots (D and E), and three possible paths
+// to validate a leaf (A):
// 1. A(B) -> B(C) -> C(D) -> D(D)
// 2. A(B) -> B(C) -> C(E) -> E(E)
+// 3. A(B) -> B(F) -> F(E) -> E(E)
//
-// In this test, C(E) is revoked by CRLSet. It is configured to be the more
-// preferable version compared to C(D), once revoked, it should be ignored.
-TEST_F(CertVerifyProcTest, CRLSetRevokedIntermediateSameName) {
+// Each permutation of revocation is tried:
+// 1. Revoking E by SPKI, so that only Path 1 is valid (as E is in Paths 2 & 3)
+// 2. Revoking C(D) and F(E) by serial, so that only Path 2 is valid.
+// 3. Revoking C by SPKI, so that only Path 3 is valid (as C is in Paths 1 & 2)
+TEST_F(CertVerifyProcTest, CRLSetDuringPathBuilding) {
if (!SupportsCRLSetsInPathBuilding()) {
LOG(INFO) << "Skipping this test on this platform.";
return;
}
- const char* const kCertificatesToLoad[] = {
+ const char* const kPath1Files[] = {
"multi-root-A-by-B.pem", "multi-root-B-by-C.pem", "multi-root-C-by-D.pem",
- "multi-root-D-by-D.pem", "multi-root-C-by-E.pem", "multi-root-E-by-E.pem",
- };
- CertificateList certs;
- ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kCertificatesToLoad, &certs));
-
- // Add D and E as trust anchors
- ScopedTestRoot test_root_D(certs[3].get()); // D-by-D
- ScopedTestRoot test_root_F(certs[5].get()); // E-by-E
-
- // Create a chain that sends A(B), B(C), C(E), C(D). The reason that
- // both C(E) and C(D) are sent are to ensure both certificates are available
- // for path building. The test
- // CertVerifyProcTest.VerifyReturnChainFiltersUnrelatedCerts ensures this is
- // safe to do.
+ "multi-root-D-by-D.pem"};
+ const char* const kPath2Files[] = {
+ "multi-root-A-by-B.pem", "multi-root-B-by-C.pem", "multi-root-C-by-E.pem",
+ "multi-root-E-by-E.pem"};
+ const char* const kPath3Files[] = {
+ "multi-root-A-by-B.pem", "multi-root-B-by-F.pem", "multi-root-F-by-E.pem",
+ "multi-root-E-by-E.pem"};
+
+ CertificateList path_1_certs;
+ ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kPath1Files, &path_1_certs));
+
+ CertificateList path_2_certs;
+ ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kPath2Files, &path_2_certs));
+
+ CertificateList path_3_certs;
+ ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kPath3Files, &path_3_certs));
+
+ // Add D and E as trust anchors.
+ ScopedTestRoot test_root_D(path_1_certs[3].get()); // D-by-D
+ ScopedTestRoot test_root_E(path_2_certs[3].get()); // E-by-E
+
+ // Create a chain that contains all the certificate paths possible.
+ // CertVerifyProcTest.VerifyReturnChainFiltersUnrelatedCerts already
+ // ensures that it's safe to send additional certificates as inputs, and
+ // that they're ignored if not necessary.
+ // This is to avoid relying on AIA or internal object caches when
+ // interacting with the underlying library.
X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(certs[1]->os_cert_handle()); // B-by-C
- intermediates.push_back(certs[4]->os_cert_handle()); // C-by-E
- intermediates.push_back(certs[2]->os_cert_handle()); // C-by-D
+ intermediates.push_back(path_1_certs[1]->os_cert_handle()); // B-by-C
+ intermediates.push_back(path_1_certs[2]->os_cert_handle()); // C-by-D
+ intermediates.push_back(path_2_certs[2]->os_cert_handle()); // C-by-E
+ intermediates.push_back(path_3_certs[1]->os_cert_handle()); // B-by-F
+ intermediates.push_back(path_3_certs[2]->os_cert_handle()); // F-by-E
scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
- certs[0]->os_cert_handle(), intermediates);
+ path_1_certs[0]->os_cert_handle(), intermediates);
ASSERT_TRUE(cert);
- // Sanity check: Ensure that, without any revocation status, the to-be-revoked
- // path is preferred.
- int flags = 0;
- CertVerifyResult verify_result;
- int error = Verify(cert.get(), "127.0.0.1", flags, nullptr, empty_cert_list_,
- &verify_result);
- ASSERT_EQ(OK, error);
- ASSERT_EQ(0U, verify_result.cert_status);
- ASSERT_TRUE(verify_result.verified_cert.get());
+ struct TestPermutations {
+ const char* crlset;
+ bool expect_valid;
+ scoped_refptr<X509Certificate> expected_intermediate;
+ } kTests[] = {
+ {"multi-root-crlset-D-and-E.raw", false, nullptr},
+ {"multi-root-crlset-E.raw", true, path_1_certs[2].get()},
+ {"multi-root-crlset-CD-and-FE.raw", true, path_2_certs[2].get()},
+ {"multi-root-crlset-C.raw", true, path_3_certs[2].get()},
+ {"multi-root-crlset-unrelated.raw", true, nullptr}};
+
+ for (const auto& testcase : kTests) {
+ SCOPED_TRACE(testcase.crlset);
+ scoped_refptr<CRLSet> crl_set;
+ std::string crl_set_bytes;
+ EXPECT_TRUE(base::ReadFileToString(
+ GetTestCertsDirectory().AppendASCII(testcase.crlset), &crl_set_bytes));
+ ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
+
+ int flags = 0;
+ CertVerifyResult verify_result;
+ int error = Verify(cert.get(), "127.0.0.1", flags, crl_set.get(),
+ empty_cert_list_, &verify_result);
+
+ if (!testcase.expect_valid) {
+ EXPECT_NE(OK, error);
+ EXPECT_NE(0U, verify_result.cert_status);
+ continue;
+ }
- // The expected path is A(B) -> B(C) -> C(E) -> E(E).
- const X509Certificate::OSCertHandles& verified_intermediates =
- verify_result.verified_cert->GetIntermediateCertificates();
- ASSERT_EQ(3U, verified_intermediates.size());
- scoped_refptr<X509Certificate> verified_root =
- X509Certificate::CreateFromHandle(verified_intermediates[2],
- X509Certificate::OSCertHandles());
- ASSERT_TRUE(verified_root.get());
- EXPECT_EQ("E Root CA", verified_root->subject().common_name);
-
- // Load a CRLSet that blocks C-by-E.
- scoped_refptr<CRLSet> crl_set;
- std::string crl_set_bytes;
- EXPECT_TRUE(base::ReadFileToString(
- GetTestCertsDirectory().AppendASCII("multi-root-crlset-C-by-E.raw"),
- &crl_set_bytes));
- ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
+ ASSERT_EQ(OK, error);
+ ASSERT_EQ(0U, verify_result.cert_status);
+ ASSERT_TRUE(verify_result.verified_cert.get());
- // Verify with the CRLSet. Because C-by-E is revoked, the expected path is
- // A(B) -> B(C) -> C(D) -> D(D).
- error = Verify(cert.get(), "127.0.0.1", flags, crl_set.get(),
- empty_cert_list_, &verify_result);
- ASSERT_EQ(OK, error);
- ASSERT_EQ(0U, verify_result.cert_status);
- ASSERT_TRUE(verify_result.verified_cert.get());
+ if (!testcase.expected_intermediate)
+ continue;
- const X509Certificate::OSCertHandles& new_verified_intermediates =
- verify_result.verified_cert->GetIntermediateCertificates();
- ASSERT_EQ(3U, new_verified_intermediates.size());
- verified_root = X509Certificate::CreateFromHandle(
- new_verified_intermediates[2], X509Certificate::OSCertHandles());
- ASSERT_TRUE(verified_root.get());
- EXPECT_EQ("D Root CA", verified_root->subject().common_name);
-
- // Reverify without the CRLSet, to ensure that CRLSets do not persist between
- // separate calls. As in the first verification, the expected path is
- // A(B) -> B(C) -> C(E) -> E(E).
- error = Verify(cert.get(), "127.0.0.1", flags, nullptr, empty_cert_list_,
- &verify_result);
- ASSERT_EQ(OK, error);
- ASSERT_EQ(0U, verify_result.cert_status);
- ASSERT_TRUE(verify_result.verified_cert.get());
+ const X509Certificate::OSCertHandles& verified_intermediates =
+ verify_result.verified_cert->GetIntermediateCertificates();
+ ASSERT_EQ(3U, verified_intermediates.size());
- const X509Certificate::OSCertHandles& final_verified_intermediates =
- verify_result.verified_cert->GetIntermediateCertificates();
- ASSERT_EQ(3U, final_verified_intermediates.size());
- verified_root = X509Certificate::CreateFromHandle(
- final_verified_intermediates[2], X509Certificate::OSCertHandles());
- ASSERT_TRUE(verified_root.get());
- EXPECT_EQ("E Root CA", verified_root->subject().common_name);
-}
+ scoped_refptr<X509Certificate> intermediate =
+ X509Certificate::CreateFromHandle(verified_intermediates[1],
+ X509Certificate::OSCertHandles());
+ ASSERT_TRUE(intermediate);
-// Tests that revocation by CRLSet functions properly when an intermediate is
-// revoked by SPKI. In this case, path building should ignore all certificates
-// with that SPKI, and search for alternatively keyed versions.
-//
-// The two possible paths are:
-// 1. A(B) -> B(C) -> C(D) -> D(D)
-// 2. A(B) -> B(F) -> F(E) -> E(E)
-//
-// The path building algorithm needs to explore B(C) once it discovers that
-// F(E) is revoked, and that there are no valid paths with B(F).
-TEST_F(CertVerifyProcTest, CRLSetRevokedIntermediateCrossIntermediates) {
- if (!SupportsCRLSetsInPathBuilding()) {
- LOG(INFO) << "Skipping this test on this platform.";
- return;
+ EXPECT_TRUE(testcase.expected_intermediate->Equals(intermediate.get()))
+ << "Expected: " << testcase.expected_intermediate->subject().common_name
+ << " issued by " << testcase.expected_intermediate->issuer().common_name
+ << "; Got: " << intermediate->subject().common_name << " issued by "
+ << intermediate->issuer().common_name;
}
-
- const char* const kCertificatesToLoad[] = {
- "multi-root-A-by-B.pem", "multi-root-B-by-C.pem", "multi-root-C-by-D.pem",
- "multi-root-D-by-D.pem", "multi-root-B-by-F.pem", "multi-root-F-by-E.pem",
- "multi-root-E-by-E.pem",
- };
- CertificateList certs;
- ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kCertificatesToLoad, &certs));
-
- // Add D and E as trust anchors
- ScopedTestRoot test_root_D(certs[3].get()); // D-by-D
- ScopedTestRoot test_root_F(certs[6].get()); // E-by-E
-
- // Create a chain that sends A(B), B(F), F(E), B(C), C(D). The reason that
- // both B(C) and C(D) are sent are to ensure both certificates are available
- // for path building. The test
- // CertVerifyProcTest.VerifyReturnChainFiltersUnrelatedCerts ensures this is
- // safe to do.
- X509Certificate::OSCertHandles intermediates;
- intermediates.push_back(certs[4]->os_cert_handle()); // B-by-F
- intermediates.push_back(certs[5]->os_cert_handle()); // F-by-E
- intermediates.push_back(certs[1]->os_cert_handle()); // B-by-C
- intermediates.push_back(certs[2]->os_cert_handle()); // C-by-D
- scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
- certs[0]->os_cert_handle(), intermediates);
- ASSERT_TRUE(cert);
-
- // Sanity check: Ensure that, without any revocation status, the to-be-revoked
- // path is preferred.
- int flags = 0;
- CertVerifyResult verify_result;
- int error = Verify(cert.get(), "127.0.0.1", flags, nullptr, empty_cert_list_,
- &verify_result);
- ASSERT_EQ(OK, error);
- ASSERT_EQ(0U, verify_result.cert_status);
- ASSERT_TRUE(verify_result.verified_cert.get());
-
- // The expected path is A(B) -> B(F) -> F(E) -> E(E).
- const X509Certificate::OSCertHandles& verified_intermediates =
- verify_result.verified_cert->GetIntermediateCertificates();
- ASSERT_EQ(3U, verified_intermediates.size());
- scoped_refptr<X509Certificate> verified_root =
- X509Certificate::CreateFromHandle(verified_intermediates[2],
- X509Certificate::OSCertHandles());
- ASSERT_TRUE(verified_root.get());
- EXPECT_EQ("E Root CA", verified_root->subject().common_name);
-
- // Load a CRLSet that blocks F.
- scoped_refptr<CRLSet> crl_set;
- std::string crl_set_bytes;
- EXPECT_TRUE(base::ReadFileToString(
- GetTestCertsDirectory().AppendASCII("multi-root-crlset-F.raw"),
- &crl_set_bytes));
- ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
-
- // Verify with the CRLSet. Because F is revoked, the expected path is
- // A(B) -> B(C) -> C(D) -> D(D).
- error = Verify(cert.get(), "127.0.0.1", flags, crl_set.get(),
- empty_cert_list_, &verify_result);
- ASSERT_EQ(OK, error);
- ASSERT_EQ(0U, verify_result.cert_status);
- ASSERT_TRUE(verify_result.verified_cert.get());
-
- const X509Certificate::OSCertHandles& new_verified_intermediates =
- verify_result.verified_cert->GetIntermediateCertificates();
- ASSERT_EQ(3U, new_verified_intermediates.size());
- verified_root = X509Certificate::CreateFromHandle(
- new_verified_intermediates[2], X509Certificate::OSCertHandles());
- ASSERT_TRUE(verified_root.get());
- EXPECT_EQ("D Root CA", verified_root->subject().common_name);
-
- // Reverify without the CRLSet, to ensure that CRLSets do not persist between
- // separate calls. As in the first verification, the expected path is
- // A(B) -> B(F) -> F(E) -> E(E).
- error = Verify(cert.get(), "127.0.0.1", flags, nullptr, empty_cert_list_,
- &verify_result);
- ASSERT_EQ(OK, error);
- ASSERT_EQ(0U, verify_result.cert_status);
- ASSERT_TRUE(verify_result.verified_cert.get());
-
- const X509Certificate::OSCertHandles& final_verified_intermediates =
- verify_result.verified_cert->GetIntermediateCertificates();
- ASSERT_EQ(3U, final_verified_intermediates.size());
- verified_root = X509Certificate::CreateFromHandle(
- final_verified_intermediates[2], X509Certificate::OSCertHandles());
- ASSERT_TRUE(verified_root.get());
- EXPECT_EQ("E Root CA", verified_root->subject().common_name);
}
#endif