Chromium Code Reviews| 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) { | |
|
davidben
2016/01/28 20:52:32
Optional: This could also be a for each loop if yo
Ryan Sleevi
2016/02/05 21:26:03
? Were you thinking Go?
std::for_each is awful
I
davidben
2016/02/05 21:32:45
for each loops are hardly a Go innovation...
| |
| 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: |
| (...skipping 1233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1353 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); | 1369 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); |
| 1354 | 1370 |
| 1355 error = Verify(leaf.get(), | 1371 error = Verify(leaf.get(), |
| 1356 "test.example.com", | 1372 "test.example.com", |
| 1357 flags, | 1373 flags, |
| 1358 crl_set.get(), | 1374 crl_set.get(), |
| 1359 empty_cert_list_, | 1375 empty_cert_list_, |
| 1360 &verify_result); | 1376 &verify_result); |
| 1361 EXPECT_EQ(ERR_CERT_REVOKED, error); | 1377 EXPECT_EQ(ERR_CERT_REVOKED, error); |
| 1362 } | 1378 } |
| 1379 | |
| 1380 // Tests that revocation by CRLSet functions properly with the certificate | |
| 1381 // immediately before the trust anchor is revoked by that trust anchor, but | |
| 1382 // another version to a different trust anchor exists. | |
| 1383 // | |
| 1384 // The two possible paths are: | |
| 1385 // 1. A(B) -> B(C) -> C(D) -> D(D) | |
| 1386 // 2. A(B) -> B(C) -> C(E) -> E(E) | |
| 1387 // | |
| 1388 // In this test, C(E) is revoked by CRLSet. It is configured to be the more | |
| 1389 // preferable version compared to C(D), once revoked, it should be ignored. | |
| 1390 TEST_F(CertVerifyProcTest, CRLSetRevokedIntermediateSameName) { | |
| 1391 const char* const kCertificatesToLoad[] = { | |
| 1392 "multi-root-A-by-B.pem", "multi-root-B-by-C.pem", "multi-root-C-by-D.pem", | |
| 1393 "multi-root-D-by-D.pem", "multi-root-C-by-E.pem", "multi-root-E-by-E.pem", | |
| 1394 }; | |
| 1395 CertificateList certs; | |
| 1396 ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kCertificatesToLoad, &certs)); | |
| 1397 | |
| 1398 // Add D and E as trust anchors | |
| 1399 ScopedTestRoot test_root_D(certs[3].get()); // D-by-D | |
| 1400 ScopedTestRoot test_root_F(certs[5].get()); // E-by-E | |
| 1401 | |
| 1402 // Create a chain that sends A(B), B(C), C(E), C(D). The reason that | |
| 1403 // both C(E) and C(D) are sent are to ensure both certificates are available | |
| 1404 // for path building. The test | |
| 1405 // CertVerifyProcTest.VerifyReturnChainFiltersUnrelatedCerts ensures this is | |
| 1406 // safe to do. | |
| 1407 X509Certificate::OSCertHandles intermediates; | |
| 1408 intermediates.push_back(certs[1]->os_cert_handle()); // B-by-C | |
| 1409 intermediates.push_back(certs[4]->os_cert_handle()); // C-by-E | |
| 1410 intermediates.push_back(certs[2]->os_cert_handle()); // C-by-D | |
| 1411 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( | |
| 1412 certs[0]->os_cert_handle(), intermediates); | |
| 1413 ASSERT_TRUE(cert); | |
| 1414 | |
| 1415 // Sanity check: Ensure that, without any revocation status, the to-be-revoked | |
| 1416 // path is preferred. | |
| 1417 int flags = 0; | |
| 1418 CertVerifyResult verify_result; | |
| 1419 int error = Verify(cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, | |
|
davidben
2016/01/28 20:52:32
Nit: nullptr
| |
| 1420 &verify_result); | |
| 1421 ASSERT_EQ(OK, error); | |
| 1422 ASSERT_EQ(0U, verify_result.cert_status); | |
| 1423 ASSERT_TRUE(verify_result.verified_cert.get()); | |
| 1424 | |
| 1425 // The expected path is A(B) -> B(C) -> C(E) -> E(E). | |
| 1426 const X509Certificate::OSCertHandles& verified_intermediates = | |
| 1427 verify_result.verified_cert->GetIntermediateCertificates(); | |
| 1428 ASSERT_EQ(3U, verified_intermediates.size()); | |
| 1429 scoped_refptr<X509Certificate> verified_root = | |
| 1430 X509Certificate::CreateFromHandle(verified_intermediates[2], | |
| 1431 X509Certificate::OSCertHandles()); | |
| 1432 ASSERT_TRUE(verified_root.get()); | |
| 1433 EXPECT_EQ("E Root CA", verified_root->subject().common_name); | |
| 1434 | |
| 1435 // Load a CRLSet that blocks C-by-E. | |
| 1436 scoped_refptr<CRLSet> crl_set; | |
| 1437 std::string crl_set_bytes; | |
| 1438 EXPECT_TRUE(base::ReadFileToString( | |
| 1439 GetTestCertsDirectory().AppendASCII("multi-root-crlset-C-by-E.raw"), | |
| 1440 &crl_set_bytes)); | |
| 1441 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); | |
| 1442 | |
| 1443 // Verify with the CRLSet. Because C-by-E is revoked, the expected path is | |
| 1444 // A(B) -> B(C) -> C(D) -> D(D). | |
| 1445 error = Verify(cert.get(), "127.0.0.1", flags, crl_set.get(), | |
| 1446 empty_cert_list_, &verify_result); | |
| 1447 ASSERT_EQ(OK, error); | |
| 1448 ASSERT_EQ(0U, verify_result.cert_status); | |
| 1449 ASSERT_TRUE(verify_result.verified_cert.get()); | |
| 1450 | |
| 1451 const X509Certificate::OSCertHandles& new_verified_intermediates = | |
| 1452 verify_result.verified_cert->GetIntermediateCertificates(); | |
| 1453 ASSERT_EQ(3U, new_verified_intermediates.size()); | |
| 1454 verified_root = X509Certificate::CreateFromHandle( | |
| 1455 new_verified_intermediates[2], X509Certificate::OSCertHandles()); | |
| 1456 ASSERT_TRUE(verified_root.get()); | |
| 1457 EXPECT_EQ("D Root CA", verified_root->subject().common_name); | |
| 1458 | |
| 1459 // Reverify without the CRLSet, to ensure that CRLSets do not persist between | |
| 1460 // separate calls. As in the first verification, the expected path is | |
| 1461 // A(B) -> B(C) -> C(E) -> E(E). | |
| 1462 error = Verify(cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, | |
| 1463 &verify_result); | |
| 1464 ASSERT_EQ(OK, error); | |
| 1465 ASSERT_EQ(0U, verify_result.cert_status); | |
| 1466 ASSERT_TRUE(verify_result.verified_cert.get()); | |
| 1467 | |
| 1468 const X509Certificate::OSCertHandles& final_verified_intermediates = | |
| 1469 verify_result.verified_cert->GetIntermediateCertificates(); | |
| 1470 ASSERT_EQ(3U, final_verified_intermediates.size()); | |
| 1471 verified_root = X509Certificate::CreateFromHandle( | |
| 1472 final_verified_intermediates[2], X509Certificate::OSCertHandles()); | |
| 1473 ASSERT_TRUE(verified_root.get()); | |
| 1474 EXPECT_EQ("E Root CA", verified_root->subject().common_name); | |
| 1475 } | |
| 1476 | |
| 1477 // Tests that revocation by CRLSet functions properly when an intermediate is | |
| 1478 // revoked by SPKI. In this case, path building should ignore all certificates | |
| 1479 // with that SPKI, and search for alternatively keyed versions. | |
| 1480 // | |
| 1481 // The two possible paths are: | |
| 1482 // 1. A(B) -> B(C) -> C(D) -> D(D) | |
| 1483 // 2. A(B) -> B(F) -> F(E) -> E(E) | |
| 1484 // | |
| 1485 // The path building algorithm needs to explore B(C) once it discovers that | |
| 1486 // F(E) is revoked, and that there are no valid paths with B(F). | |
| 1487 TEST_F(CertVerifyProcTest, CRLSetRevokedIntermediateCrossIntermediates) { | |
| 1488 const char* const kCertificatesToLoad[] = { | |
| 1489 "multi-root-A-by-B.pem", "multi-root-B-by-C.pem", "multi-root-C-by-D.pem", | |
| 1490 "multi-root-D-by-D.pem", "multi-root-B-by-F.pem", "multi-root-F-by-E.pem", | |
| 1491 "multi-root-E-by-E.pem", | |
| 1492 }; | |
| 1493 CertificateList certs; | |
| 1494 ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kCertificatesToLoad, &certs)); | |
| 1495 | |
| 1496 // Add D and E as trust anchors | |
| 1497 ScopedTestRoot test_root_D(certs[3].get()); // D-by-D | |
| 1498 ScopedTestRoot test_root_F(certs[6].get()); // E-by-E | |
| 1499 | |
| 1500 // Create a chain that sends A(B), B(F), F(E), B(C), C(D). The reason that | |
| 1501 // both B(C) and C(D) are sent are to ensure both certificates are available | |
| 1502 // for path building. The test | |
| 1503 // CertVerifyProcTest.VerifyReturnChainFiltersUnrelatedCerts ensures this is | |
| 1504 // safe to do. | |
| 1505 X509Certificate::OSCertHandles intermediates; | |
| 1506 intermediates.push_back(certs[4]->os_cert_handle()); // B-by-F | |
| 1507 intermediates.push_back(certs[5]->os_cert_handle()); // F-by-E | |
| 1508 intermediates.push_back(certs[1]->os_cert_handle()); // B-by-C | |
| 1509 intermediates.push_back(certs[2]->os_cert_handle()); // C-by-D | |
| 1510 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( | |
| 1511 certs[0]->os_cert_handle(), intermediates); | |
| 1512 ASSERT_TRUE(cert); | |
| 1513 | |
| 1514 // Sanity check: Ensure that, without any revocation status, the to-be-revoked | |
| 1515 // path is preferred. | |
| 1516 int flags = 0; | |
| 1517 CertVerifyResult verify_result; | |
| 1518 int error = Verify(cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, | |
| 1519 &verify_result); | |
| 1520 ASSERT_EQ(OK, error); | |
| 1521 ASSERT_EQ(0U, verify_result.cert_status); | |
| 1522 ASSERT_TRUE(verify_result.verified_cert.get()); | |
| 1523 | |
| 1524 // The expected path is A(B) -> B(F) -> F(E) -> E(E). | |
| 1525 const X509Certificate::OSCertHandles& verified_intermediates = | |
| 1526 verify_result.verified_cert->GetIntermediateCertificates(); | |
| 1527 ASSERT_EQ(3U, verified_intermediates.size()); | |
| 1528 scoped_refptr<X509Certificate> verified_root = | |
| 1529 X509Certificate::CreateFromHandle(verified_intermediates[2], | |
| 1530 X509Certificate::OSCertHandles()); | |
| 1531 ASSERT_TRUE(verified_root.get()); | |
| 1532 EXPECT_EQ("E Root CA", verified_root->subject().common_name); | |
| 1533 | |
| 1534 // Load a CRLSet that blocks F. | |
| 1535 scoped_refptr<CRLSet> crl_set; | |
| 1536 std::string crl_set_bytes; | |
| 1537 EXPECT_TRUE(base::ReadFileToString( | |
| 1538 GetTestCertsDirectory().AppendASCII("multi-root-crlset-F.raw"), | |
| 1539 &crl_set_bytes)); | |
| 1540 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); | |
| 1541 | |
| 1542 // Verify with the CRLSet. Because F is revoked, the expected path is | |
| 1543 // A(B) -> B(C) -> C(D) -> D(D). | |
| 1544 error = Verify(cert.get(), "127.0.0.1", flags, crl_set.get(), | |
| 1545 empty_cert_list_, &verify_result); | |
| 1546 ASSERT_EQ(OK, error); | |
| 1547 ASSERT_EQ(0U, verify_result.cert_status); | |
| 1548 ASSERT_TRUE(verify_result.verified_cert.get()); | |
| 1549 | |
| 1550 const X509Certificate::OSCertHandles& new_verified_intermediates = | |
| 1551 verify_result.verified_cert->GetIntermediateCertificates(); | |
| 1552 ASSERT_EQ(3U, new_verified_intermediates.size()); | |
| 1553 verified_root = X509Certificate::CreateFromHandle( | |
| 1554 new_verified_intermediates[2], X509Certificate::OSCertHandles()); | |
| 1555 ASSERT_TRUE(verified_root.get()); | |
| 1556 EXPECT_EQ("D Root CA", verified_root->subject().common_name); | |
|
davidben
2016/01/28 20:52:32
Could the existence of C(E) being used in a previo
Ryan Sleevi
2016/02/05 21:26:03
I'm not sure I understand your question. Line 1532
davidben
2016/02/05 21:32:45
*C*(E), not F(E). This tests revokes F(E) and does
Ryan Sleevi
2016/02/05 21:39:26
That's hard to answer, I think, in that you're ask
davidben
2016/02/05 21:46:48
I'm just asking if they do that right now. I agree
Ryan Sleevi
2016/02/05 21:52:11
Right, but I'm not sure that ambiguity is a proble
| |
| 1557 | |
| 1558 // Reverify without the CRLSet, to ensure that CRLSets do not persist between | |
| 1559 // separate calls. As in the first verification, the expected path is | |
| 1560 // A(B) -> B(F) -> F(E) -> E(E). | |
| 1561 error = Verify(cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, | |
| 1562 &verify_result); | |
| 1563 ASSERT_EQ(OK, error); | |
| 1564 ASSERT_EQ(0U, verify_result.cert_status); | |
| 1565 ASSERT_TRUE(verify_result.verified_cert.get()); | |
| 1566 | |
| 1567 const X509Certificate::OSCertHandles& final_verified_intermediates = | |
| 1568 verify_result.verified_cert->GetIntermediateCertificates(); | |
| 1569 ASSERT_EQ(3U, final_verified_intermediates.size()); | |
| 1570 verified_root = X509Certificate::CreateFromHandle( | |
| 1571 final_verified_intermediates[2], X509Certificate::OSCertHandles()); | |
| 1572 ASSERT_TRUE(verified_root.get()); | |
| 1573 EXPECT_EQ("E Root CA", verified_root->subject().common_name); | |
| 1574 } | |
| 1575 | |
| 1363 #endif | 1576 #endif |
| 1364 | 1577 |
| 1365 enum ExpectedAlgorithms { | 1578 enum ExpectedAlgorithms { |
| 1366 EXPECT_MD2 = 1 << 0, | 1579 EXPECT_MD2 = 1 << 0, |
| 1367 EXPECT_MD4 = 1 << 1, | 1580 EXPECT_MD4 = 1 << 1, |
| 1368 EXPECT_MD5 = 1 << 2, | 1581 EXPECT_MD5 = 1 << 2, |
| 1369 EXPECT_SHA1 = 1 << 3, | 1582 EXPECT_SHA1 = 1 << 3, |
| 1370 EXPECT_SHA1_LEAF = 1 << 4, | 1583 EXPECT_SHA1_LEAF = 1 << 4, |
| 1371 }; | 1584 }; |
| 1372 | 1585 |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1705 int flags = 0; | 1918 int flags = 0; |
| 1706 CertVerifyResult verify_result; | 1919 CertVerifyResult verify_result; |
| 1707 int error = Verify(cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, | 1920 int error = Verify(cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, |
| 1708 &verify_result); | 1921 &verify_result); |
| 1709 EXPECT_EQ(ERR_CERT_INVALID, error); | 1922 EXPECT_EQ(ERR_CERT_INVALID, error); |
| 1710 EXPECT_EQ(CERT_STATUS_INVALID, verify_result.cert_status); | 1923 EXPECT_EQ(CERT_STATUS_INVALID, verify_result.cert_status); |
| 1711 } | 1924 } |
| 1712 #endif // defined(OS_MACOSX) && !defined(OS_IOS) | 1925 #endif // defined(OS_MACOSX) && !defined(OS_IOS) |
| 1713 | 1926 |
| 1714 } // namespace net | 1927 } // namespace net |
| OLD | NEW |