OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/cert/cert_verify_proc.h" | 5 #include "net/cert/cert_verify_proc.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 bool SupportsDetectingKnownRoots() { | 100 bool SupportsDetectingKnownRoots() { |
101 #if defined(OS_ANDROID) | 101 #if defined(OS_ANDROID) |
102 // Before API level 17, Android does not expose the APIs necessary to get at | 102 // Before API level 17, Android does not expose the APIs necessary to get at |
103 // the verified certificate chain and detect known roots. | 103 // the verified certificate chain and detect known roots. |
104 if (base::android::BuildInfo::GetInstance()->sdk_int() < 17) | 104 if (base::android::BuildInfo::GetInstance()->sdk_int() < 17) |
105 return false; | 105 return false; |
106 #endif | 106 #endif |
107 return true; | 107 return true; |
108 } | 108 } |
109 | 109 |
| 110 // Template helper to load a series of certificate files into a CertificateList. |
| 111 // Like CertTestUtil's CreateCertificateListFromFile, except it can load a |
| 112 // series of individual certificates (to make the tests clearer). |
| 113 template <size_t N> |
| 114 void LoadCertificateFiles(const char* const (&cert_files)[N], |
| 115 CertificateList* certs) { |
| 116 certs->clear(); |
| 117 for (size_t i = 0; i < N; ++i) { |
| 118 SCOPED_TRACE(cert_files[i]); |
| 119 scoped_refptr<X509Certificate> cert = CreateCertificateChainFromFile( |
| 120 GetTestCertsDirectory(), cert_files[i], X509Certificate::FORMAT_AUTO); |
| 121 ASSERT_TRUE(cert); |
| 122 certs->push_back(cert); |
| 123 } |
| 124 } |
| 125 |
110 } // namespace | 126 } // namespace |
111 | 127 |
112 class CertVerifyProcTest : public testing::Test { | 128 class CertVerifyProcTest : public testing::Test { |
113 public: | 129 public: |
114 CertVerifyProcTest() | 130 CertVerifyProcTest() |
115 : verify_proc_(CertVerifyProc::CreateDefault()) { | 131 : verify_proc_(CertVerifyProc::CreateDefault()) { |
116 } | 132 } |
117 ~CertVerifyProcTest() override {} | 133 ~CertVerifyProcTest() override {} |
118 | 134 |
119 protected: | 135 protected: |
120 bool SupportsAdditionalTrustAnchors() { | 136 bool SupportsAdditionalTrustAnchors() { |
121 return verify_proc_->SupportsAdditionalTrustAnchors(); | 137 return verify_proc_->SupportsAdditionalTrustAnchors(); |
122 } | 138 } |
123 | 139 |
| 140 // Returns true if the underlying CertVerifyProc supports integrating CRLSets |
| 141 // into path building logic, such as allowing the selection of alternatively |
| 142 // valid paths when one or more are revoked. As the goal is to integrate this |
| 143 // into all platforms, this is a temporary, test-only flag to centralize the |
| 144 // conditionals in tests. |
| 145 bool SupportsCRLSetsInPathBuilding() { |
| 146 #if defined(OS_WIN) |
| 147 return true; |
| 148 #else |
| 149 return false; |
| 150 #endif |
| 151 } |
| 152 |
124 int Verify(X509Certificate* cert, | 153 int Verify(X509Certificate* cert, |
125 const std::string& hostname, | 154 const std::string& hostname, |
126 int flags, | 155 int flags, |
127 CRLSet* crl_set, | 156 CRLSet* crl_set, |
128 const CertificateList& additional_trust_anchors, | 157 const CertificateList& additional_trust_anchors, |
129 CertVerifyResult* verify_result) { | 158 CertVerifyResult* verify_result) { |
130 return verify_proc_->Verify(cert, hostname, std::string(), flags, crl_set, | 159 return verify_proc_->Verify(cert, hostname, std::string(), flags, crl_set, |
131 additional_trust_anchors, verify_result); | 160 additional_trust_anchors, verify_result); |
132 } | 161 } |
133 | 162 |
(...skipping 1231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1365 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); | 1394 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); |
1366 | 1395 |
1367 error = Verify(leaf.get(), | 1396 error = Verify(leaf.get(), |
1368 "test.example.com", | 1397 "test.example.com", |
1369 flags, | 1398 flags, |
1370 crl_set.get(), | 1399 crl_set.get(), |
1371 empty_cert_list_, | 1400 empty_cert_list_, |
1372 &verify_result); | 1401 &verify_result); |
1373 EXPECT_EQ(ERR_CERT_REVOKED, error); | 1402 EXPECT_EQ(ERR_CERT_REVOKED, error); |
1374 } | 1403 } |
| 1404 |
| 1405 // Tests that revocation by CRLSet functions properly with the certificate |
| 1406 // immediately before the trust anchor is revoked by that trust anchor, but |
| 1407 // another version to a different trust anchor exists. |
| 1408 // |
| 1409 // The two possible paths are: |
| 1410 // 1. A(B) -> B(C) -> C(D) -> D(D) |
| 1411 // 2. A(B) -> B(C) -> C(E) -> E(E) |
| 1412 // |
| 1413 // In this test, C(E) is revoked by CRLSet. It is configured to be the more |
| 1414 // preferable version compared to C(D), once revoked, it should be ignored. |
| 1415 TEST_F(CertVerifyProcTest, CRLSetRevokedIntermediateSameName) { |
| 1416 if (!SupportsCRLSetsInPathBuilding()) { |
| 1417 LOG(INFO) << "Skipping this test on this platform."; |
| 1418 return; |
| 1419 } |
| 1420 |
| 1421 const char* const kCertificatesToLoad[] = { |
| 1422 "multi-root-A-by-B.pem", "multi-root-B-by-C.pem", "multi-root-C-by-D.pem", |
| 1423 "multi-root-D-by-D.pem", "multi-root-C-by-E.pem", "multi-root-E-by-E.pem", |
| 1424 }; |
| 1425 CertificateList certs; |
| 1426 ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kCertificatesToLoad, &certs)); |
| 1427 |
| 1428 // Add D and E as trust anchors |
| 1429 ScopedTestRoot test_root_D(certs[3].get()); // D-by-D |
| 1430 ScopedTestRoot test_root_F(certs[5].get()); // E-by-E |
| 1431 |
| 1432 // Create a chain that sends A(B), B(C), C(E), C(D). The reason that |
| 1433 // both C(E) and C(D) are sent are to ensure both certificates are available |
| 1434 // for path building. The test |
| 1435 // CertVerifyProcTest.VerifyReturnChainFiltersUnrelatedCerts ensures this is |
| 1436 // safe to do. |
| 1437 X509Certificate::OSCertHandles intermediates; |
| 1438 intermediates.push_back(certs[1]->os_cert_handle()); // B-by-C |
| 1439 intermediates.push_back(certs[4]->os_cert_handle()); // C-by-E |
| 1440 intermediates.push_back(certs[2]->os_cert_handle()); // C-by-D |
| 1441 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( |
| 1442 certs[0]->os_cert_handle(), intermediates); |
| 1443 ASSERT_TRUE(cert); |
| 1444 |
| 1445 // Sanity check: Ensure that, without any revocation status, the to-be-revoked |
| 1446 // path is preferred. |
| 1447 int flags = 0; |
| 1448 CertVerifyResult verify_result; |
| 1449 int error = Verify(cert.get(), "127.0.0.1", flags, nullptr, empty_cert_list_, |
| 1450 &verify_result); |
| 1451 ASSERT_EQ(OK, error); |
| 1452 ASSERT_EQ(0U, verify_result.cert_status); |
| 1453 ASSERT_TRUE(verify_result.verified_cert.get()); |
| 1454 |
| 1455 // The expected path is A(B) -> B(C) -> C(E) -> E(E). |
| 1456 const X509Certificate::OSCertHandles& verified_intermediates = |
| 1457 verify_result.verified_cert->GetIntermediateCertificates(); |
| 1458 ASSERT_EQ(3U, verified_intermediates.size()); |
| 1459 scoped_refptr<X509Certificate> verified_root = |
| 1460 X509Certificate::CreateFromHandle(verified_intermediates[2], |
| 1461 X509Certificate::OSCertHandles()); |
| 1462 ASSERT_TRUE(verified_root.get()); |
| 1463 EXPECT_EQ("E Root CA", verified_root->subject().common_name); |
| 1464 |
| 1465 // Load a CRLSet that blocks C-by-E. |
| 1466 scoped_refptr<CRLSet> crl_set; |
| 1467 std::string crl_set_bytes; |
| 1468 EXPECT_TRUE(base::ReadFileToString( |
| 1469 GetTestCertsDirectory().AppendASCII("multi-root-crlset-C-by-E.raw"), |
| 1470 &crl_set_bytes)); |
| 1471 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); |
| 1472 |
| 1473 // Verify with the CRLSet. Because C-by-E is revoked, the expected path is |
| 1474 // A(B) -> B(C) -> C(D) -> D(D). |
| 1475 error = Verify(cert.get(), "127.0.0.1", flags, crl_set.get(), |
| 1476 empty_cert_list_, &verify_result); |
| 1477 ASSERT_EQ(OK, error); |
| 1478 ASSERT_EQ(0U, verify_result.cert_status); |
| 1479 ASSERT_TRUE(verify_result.verified_cert.get()); |
| 1480 |
| 1481 const X509Certificate::OSCertHandles& new_verified_intermediates = |
| 1482 verify_result.verified_cert->GetIntermediateCertificates(); |
| 1483 ASSERT_EQ(3U, new_verified_intermediates.size()); |
| 1484 verified_root = X509Certificate::CreateFromHandle( |
| 1485 new_verified_intermediates[2], X509Certificate::OSCertHandles()); |
| 1486 ASSERT_TRUE(verified_root.get()); |
| 1487 EXPECT_EQ("D Root CA", verified_root->subject().common_name); |
| 1488 |
| 1489 // Reverify without the CRLSet, to ensure that CRLSets do not persist between |
| 1490 // separate calls. As in the first verification, the expected path is |
| 1491 // A(B) -> B(C) -> C(E) -> E(E). |
| 1492 error = Verify(cert.get(), "127.0.0.1", flags, nullptr, empty_cert_list_, |
| 1493 &verify_result); |
| 1494 ASSERT_EQ(OK, error); |
| 1495 ASSERT_EQ(0U, verify_result.cert_status); |
| 1496 ASSERT_TRUE(verify_result.verified_cert.get()); |
| 1497 |
| 1498 const X509Certificate::OSCertHandles& final_verified_intermediates = |
| 1499 verify_result.verified_cert->GetIntermediateCertificates(); |
| 1500 ASSERT_EQ(3U, final_verified_intermediates.size()); |
| 1501 verified_root = X509Certificate::CreateFromHandle( |
| 1502 final_verified_intermediates[2], X509Certificate::OSCertHandles()); |
| 1503 ASSERT_TRUE(verified_root.get()); |
| 1504 EXPECT_EQ("E Root CA", verified_root->subject().common_name); |
| 1505 } |
| 1506 |
| 1507 // Tests that revocation by CRLSet functions properly when an intermediate is |
| 1508 // revoked by SPKI. In this case, path building should ignore all certificates |
| 1509 // with that SPKI, and search for alternatively keyed versions. |
| 1510 // |
| 1511 // The two possible paths are: |
| 1512 // 1. A(B) -> B(C) -> C(D) -> D(D) |
| 1513 // 2. A(B) -> B(F) -> F(E) -> E(E) |
| 1514 // |
| 1515 // The path building algorithm needs to explore B(C) once it discovers that |
| 1516 // F(E) is revoked, and that there are no valid paths with B(F). |
| 1517 TEST_F(CertVerifyProcTest, CRLSetRevokedIntermediateCrossIntermediates) { |
| 1518 if (!SupportsCRLSetsInPathBuilding()) { |
| 1519 LOG(INFO) << "Skipping this test on this platform."; |
| 1520 return; |
| 1521 } |
| 1522 |
| 1523 const char* const kCertificatesToLoad[] = { |
| 1524 "multi-root-A-by-B.pem", "multi-root-B-by-C.pem", "multi-root-C-by-D.pem", |
| 1525 "multi-root-D-by-D.pem", "multi-root-B-by-F.pem", "multi-root-F-by-E.pem", |
| 1526 "multi-root-E-by-E.pem", |
| 1527 }; |
| 1528 CertificateList certs; |
| 1529 ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kCertificatesToLoad, &certs)); |
| 1530 |
| 1531 // Add D and E as trust anchors |
| 1532 ScopedTestRoot test_root_D(certs[3].get()); // D-by-D |
| 1533 ScopedTestRoot test_root_F(certs[6].get()); // E-by-E |
| 1534 |
| 1535 // Create a chain that sends A(B), B(F), F(E), B(C), C(D). The reason that |
| 1536 // both B(C) and C(D) are sent are to ensure both certificates are available |
| 1537 // for path building. The test |
| 1538 // CertVerifyProcTest.VerifyReturnChainFiltersUnrelatedCerts ensures this is |
| 1539 // safe to do. |
| 1540 X509Certificate::OSCertHandles intermediates; |
| 1541 intermediates.push_back(certs[4]->os_cert_handle()); // B-by-F |
| 1542 intermediates.push_back(certs[5]->os_cert_handle()); // F-by-E |
| 1543 intermediates.push_back(certs[1]->os_cert_handle()); // B-by-C |
| 1544 intermediates.push_back(certs[2]->os_cert_handle()); // C-by-D |
| 1545 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( |
| 1546 certs[0]->os_cert_handle(), intermediates); |
| 1547 ASSERT_TRUE(cert); |
| 1548 |
| 1549 // Sanity check: Ensure that, without any revocation status, the to-be-revoked |
| 1550 // path is preferred. |
| 1551 int flags = 0; |
| 1552 CertVerifyResult verify_result; |
| 1553 int error = Verify(cert.get(), "127.0.0.1", flags, nullptr, empty_cert_list_, |
| 1554 &verify_result); |
| 1555 ASSERT_EQ(OK, error); |
| 1556 ASSERT_EQ(0U, verify_result.cert_status); |
| 1557 ASSERT_TRUE(verify_result.verified_cert.get()); |
| 1558 |
| 1559 // The expected path is A(B) -> B(F) -> F(E) -> E(E). |
| 1560 const X509Certificate::OSCertHandles& verified_intermediates = |
| 1561 verify_result.verified_cert->GetIntermediateCertificates(); |
| 1562 ASSERT_EQ(3U, verified_intermediates.size()); |
| 1563 scoped_refptr<X509Certificate> verified_root = |
| 1564 X509Certificate::CreateFromHandle(verified_intermediates[2], |
| 1565 X509Certificate::OSCertHandles()); |
| 1566 ASSERT_TRUE(verified_root.get()); |
| 1567 EXPECT_EQ("E Root CA", verified_root->subject().common_name); |
| 1568 |
| 1569 // Load a CRLSet that blocks F. |
| 1570 scoped_refptr<CRLSet> crl_set; |
| 1571 std::string crl_set_bytes; |
| 1572 EXPECT_TRUE(base::ReadFileToString( |
| 1573 GetTestCertsDirectory().AppendASCII("multi-root-crlset-F.raw"), |
| 1574 &crl_set_bytes)); |
| 1575 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); |
| 1576 |
| 1577 // Verify with the CRLSet. Because F is revoked, the expected path is |
| 1578 // A(B) -> B(C) -> C(D) -> D(D). |
| 1579 error = Verify(cert.get(), "127.0.0.1", flags, crl_set.get(), |
| 1580 empty_cert_list_, &verify_result); |
| 1581 ASSERT_EQ(OK, error); |
| 1582 ASSERT_EQ(0U, verify_result.cert_status); |
| 1583 ASSERT_TRUE(verify_result.verified_cert.get()); |
| 1584 |
| 1585 const X509Certificate::OSCertHandles& new_verified_intermediates = |
| 1586 verify_result.verified_cert->GetIntermediateCertificates(); |
| 1587 ASSERT_EQ(3U, new_verified_intermediates.size()); |
| 1588 verified_root = X509Certificate::CreateFromHandle( |
| 1589 new_verified_intermediates[2], X509Certificate::OSCertHandles()); |
| 1590 ASSERT_TRUE(verified_root.get()); |
| 1591 EXPECT_EQ("D Root CA", verified_root->subject().common_name); |
| 1592 |
| 1593 // Reverify without the CRLSet, to ensure that CRLSets do not persist between |
| 1594 // separate calls. As in the first verification, the expected path is |
| 1595 // A(B) -> B(F) -> F(E) -> E(E). |
| 1596 error = Verify(cert.get(), "127.0.0.1", flags, nullptr, empty_cert_list_, |
| 1597 &verify_result); |
| 1598 ASSERT_EQ(OK, error); |
| 1599 ASSERT_EQ(0U, verify_result.cert_status); |
| 1600 ASSERT_TRUE(verify_result.verified_cert.get()); |
| 1601 |
| 1602 const X509Certificate::OSCertHandles& final_verified_intermediates = |
| 1603 verify_result.verified_cert->GetIntermediateCertificates(); |
| 1604 ASSERT_EQ(3U, final_verified_intermediates.size()); |
| 1605 verified_root = X509Certificate::CreateFromHandle( |
| 1606 final_verified_intermediates[2], X509Certificate::OSCertHandles()); |
| 1607 ASSERT_TRUE(verified_root.get()); |
| 1608 EXPECT_EQ("E Root CA", verified_root->subject().common_name); |
| 1609 } |
| 1610 |
1375 #endif | 1611 #endif |
1376 | 1612 |
1377 enum ExpectedAlgorithms { | 1613 enum ExpectedAlgorithms { |
1378 EXPECT_MD2 = 1 << 0, | 1614 EXPECT_MD2 = 1 << 0, |
1379 EXPECT_MD4 = 1 << 1, | 1615 EXPECT_MD4 = 1 << 1, |
1380 EXPECT_MD5 = 1 << 2, | 1616 EXPECT_MD5 = 1 << 2, |
1381 EXPECT_SHA1 = 1 << 3, | 1617 EXPECT_SHA1 = 1 << 3, |
1382 EXPECT_SHA1_LEAF = 1 << 4, | 1618 EXPECT_SHA1_LEAF = 1 << 4, |
1383 }; | 1619 }; |
1384 | 1620 |
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1717 int flags = 0; | 1953 int flags = 0; |
1718 CertVerifyResult verify_result; | 1954 CertVerifyResult verify_result; |
1719 int error = Verify(cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, | 1955 int error = Verify(cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, |
1720 &verify_result); | 1956 &verify_result); |
1721 EXPECT_EQ(ERR_CERT_INVALID, error); | 1957 EXPECT_EQ(ERR_CERT_INVALID, error); |
1722 EXPECT_EQ(CERT_STATUS_INVALID, verify_result.cert_status); | 1958 EXPECT_EQ(CERT_STATUS_INVALID, verify_result.cert_status); |
1723 } | 1959 } |
1724 #endif // defined(OS_MACOSX) && !defined(OS_IOS) | 1960 #endif // defined(OS_MACOSX) && !defined(OS_IOS) |
1725 | 1961 |
1726 } // namespace net | 1962 } // namespace net |
OLD | NEW |