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 |