Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: net/cert/cert_verify_proc_unittest.cc

Issue 1724413002: Perform CRLSet evaluation during Path Building on NSS (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix ChromeOS Test Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/cert/cert_verify_proc_nss.cc ('k') | net/data/ssl/certificates/multi-root-A-by-B.pem » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 bool SupportsAdditionalTrustAnchors() { 136 bool SupportsAdditionalTrustAnchors() {
137 return verify_proc_->SupportsAdditionalTrustAnchors(); 137 return verify_proc_->SupportsAdditionalTrustAnchors();
138 } 138 }
139 139
140 // Returns true if the underlying CertVerifyProc supports integrating CRLSets 140 // Returns true if the underlying CertVerifyProc supports integrating CRLSets
141 // into path building logic, such as allowing the selection of alternatively 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 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 143 // into all platforms, this is a temporary, test-only flag to centralize the
144 // conditionals in tests. 144 // conditionals in tests.
145 bool SupportsCRLSetsInPathBuilding() { 145 bool SupportsCRLSetsInPathBuilding() {
146 #if defined(OS_WIN) 146 #if defined(OS_WIN) || defined(USE_NSS_CERTS)
147 return true; 147 return true;
148 #else 148 #else
149 return false; 149 return false;
150 #endif 150 #endif
151 } 151 }
152 152
153 int Verify(X509Certificate* cert, 153 int Verify(X509Certificate* cert,
154 const std::string& hostname, 154 const std::string& hostname,
155 int flags, 155 int flags,
156 CRLSet* crl_set, 156 CRLSet* crl_set,
(...skipping 1115 matching lines...) Expand 10 before | Expand all | Expand 10 after
1272 1272
1273 error = Verify(leaf.get(), 1273 error = Verify(leaf.get(),
1274 "test.example.com", 1274 "test.example.com",
1275 flags, 1275 flags,
1276 crl_set.get(), 1276 crl_set.get(),
1277 empty_cert_list_, 1277 empty_cert_list_,
1278 &verify_result); 1278 &verify_result);
1279 EXPECT_EQ(ERR_CERT_REVOKED, error); 1279 EXPECT_EQ(ERR_CERT_REVOKED, error);
1280 } 1280 }
1281 1281
1282 // Tests that revocation by CRLSet functions properly with the certificate 1282 // Tests that CRLSets participate in path building functions, and that as
1283 // immediately before the trust anchor is revoked by that trust anchor, but 1283 // long as a valid path exists within the verification graph, verification
1284 // another version to a different trust anchor exists. 1284 // succeeds.
1285 // 1285 //
1286 // The two possible paths are: 1286 // In this test, there are two roots (D and E), and three possible paths
1287 // to validate a leaf (A):
1287 // 1. A(B) -> B(C) -> C(D) -> D(D) 1288 // 1. A(B) -> B(C) -> C(D) -> D(D)
1288 // 2. A(B) -> B(C) -> C(E) -> E(E) 1289 // 2. A(B) -> B(C) -> C(E) -> E(E)
1290 // 3. A(B) -> B(F) -> F(E) -> E(E)
1289 // 1291 //
1290 // In this test, C(E) is revoked by CRLSet. It is configured to be the more 1292 // Each permutation of revocation is tried:
1291 // preferable version compared to C(D), once revoked, it should be ignored. 1293 // 1. Revoking E by SPKI, so that only Path 1 is valid (as E is in Paths 2 & 3)
1292 TEST_F(CertVerifyProcTest, CRLSetRevokedIntermediateSameName) { 1294 // 2. Revoking C(D) and F(E) by serial, so that only Path 2 is valid.
1295 // 3. Revoking C by SPKI, so that only Path 3 is valid (as C is in Paths 1 & 2)
1296 TEST_F(CertVerifyProcTest, CRLSetDuringPathBuilding) {
1293 if (!SupportsCRLSetsInPathBuilding()) { 1297 if (!SupportsCRLSetsInPathBuilding()) {
1294 LOG(INFO) << "Skipping this test on this platform."; 1298 LOG(INFO) << "Skipping this test on this platform.";
1295 return; 1299 return;
1296 } 1300 }
1297 1301
1298 const char* const kCertificatesToLoad[] = { 1302 const char* const kPath1Files[] = {
1299 "multi-root-A-by-B.pem", "multi-root-B-by-C.pem", "multi-root-C-by-D.pem", 1303 "multi-root-A-by-B.pem", "multi-root-B-by-C.pem", "multi-root-C-by-D.pem",
1300 "multi-root-D-by-D.pem", "multi-root-C-by-E.pem", "multi-root-E-by-E.pem", 1304 "multi-root-D-by-D.pem"};
1301 }; 1305 const char* const kPath2Files[] = {
1302 CertificateList certs; 1306 "multi-root-A-by-B.pem", "multi-root-B-by-C.pem", "multi-root-C-by-E.pem",
1303 ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kCertificatesToLoad, &certs)); 1307 "multi-root-E-by-E.pem"};
1308 const char* const kPath3Files[] = {
1309 "multi-root-A-by-B.pem", "multi-root-B-by-F.pem", "multi-root-F-by-E.pem",
1310 "multi-root-E-by-E.pem"};
1304 1311
1305 // Add D and E as trust anchors 1312 CertificateList path_1_certs;
1306 ScopedTestRoot test_root_D(certs[3].get()); // D-by-D 1313 ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kPath1Files, &path_1_certs));
1307 ScopedTestRoot test_root_F(certs[5].get()); // E-by-E
1308 1314
1309 // Create a chain that sends A(B), B(C), C(E), C(D). The reason that 1315 CertificateList path_2_certs;
1310 // both C(E) and C(D) are sent are to ensure both certificates are available 1316 ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kPath2Files, &path_2_certs));
1311 // for path building. The test 1317
1312 // CertVerifyProcTest.VerifyReturnChainFiltersUnrelatedCerts ensures this is 1318 CertificateList path_3_certs;
1313 // safe to do. 1319 ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kPath3Files, &path_3_certs));
1320
1321 // Add D and E as trust anchors.
1322 ScopedTestRoot test_root_D(path_1_certs[3].get()); // D-by-D
1323 ScopedTestRoot test_root_E(path_2_certs[3].get()); // E-by-E
1324
1325 // Create a chain that contains all the certificate paths possible.
1326 // CertVerifyProcTest.VerifyReturnChainFiltersUnrelatedCerts already
1327 // ensures that it's safe to send additional certificates as inputs, and
1328 // that they're ignored if not necessary.
1329 // This is to avoid relying on AIA or internal object caches when
1330 // interacting with the underlying library.
1314 X509Certificate::OSCertHandles intermediates; 1331 X509Certificate::OSCertHandles intermediates;
1315 intermediates.push_back(certs[1]->os_cert_handle()); // B-by-C 1332 intermediates.push_back(path_1_certs[1]->os_cert_handle()); // B-by-C
1316 intermediates.push_back(certs[4]->os_cert_handle()); // C-by-E 1333 intermediates.push_back(path_1_certs[2]->os_cert_handle()); // C-by-D
1317 intermediates.push_back(certs[2]->os_cert_handle()); // C-by-D 1334 intermediates.push_back(path_2_certs[2]->os_cert_handle()); // C-by-E
1335 intermediates.push_back(path_3_certs[1]->os_cert_handle()); // B-by-F
1336 intermediates.push_back(path_3_certs[2]->os_cert_handle()); // F-by-E
1318 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( 1337 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
1319 certs[0]->os_cert_handle(), intermediates); 1338 path_1_certs[0]->os_cert_handle(), intermediates);
1320 ASSERT_TRUE(cert); 1339 ASSERT_TRUE(cert);
1321 1340
1322 // Sanity check: Ensure that, without any revocation status, the to-be-revoked 1341 struct TestPermutations {
1323 // path is preferred. 1342 const char* crlset;
1324 int flags = 0; 1343 bool expect_valid;
1325 CertVerifyResult verify_result; 1344 scoped_refptr<X509Certificate> expected_intermediate;
1326 int error = Verify(cert.get(), "127.0.0.1", flags, nullptr, empty_cert_list_, 1345 } kTests[] = {
1327 &verify_result); 1346 {"multi-root-crlset-D-and-E.raw", false, nullptr},
1328 ASSERT_EQ(OK, error); 1347 {"multi-root-crlset-E.raw", true, path_1_certs[2].get()},
1329 ASSERT_EQ(0U, verify_result.cert_status); 1348 {"multi-root-crlset-CD-and-FE.raw", true, path_2_certs[2].get()},
1330 ASSERT_TRUE(verify_result.verified_cert.get()); 1349 {"multi-root-crlset-C.raw", true, path_3_certs[2].get()},
1350 {"multi-root-crlset-unrelated.raw", true, nullptr}};
1331 1351
1332 // The expected path is A(B) -> B(C) -> C(E) -> E(E). 1352 for (const auto& testcase : kTests) {
1333 const X509Certificate::OSCertHandles& verified_intermediates = 1353 SCOPED_TRACE(testcase.crlset);
1334 verify_result.verified_cert->GetIntermediateCertificates(); 1354 scoped_refptr<CRLSet> crl_set;
1335 ASSERT_EQ(3U, verified_intermediates.size()); 1355 std::string crl_set_bytes;
1336 scoped_refptr<X509Certificate> verified_root = 1356 EXPECT_TRUE(base::ReadFileToString(
1337 X509Certificate::CreateFromHandle(verified_intermediates[2], 1357 GetTestCertsDirectory().AppendASCII(testcase.crlset), &crl_set_bytes));
1338 X509Certificate::OSCertHandles()); 1358 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
1339 ASSERT_TRUE(verified_root.get());
1340 EXPECT_EQ("E Root CA", verified_root->subject().common_name);
1341 1359
1342 // Load a CRLSet that blocks C-by-E. 1360 int flags = 0;
1343 scoped_refptr<CRLSet> crl_set; 1361 CertVerifyResult verify_result;
1344 std::string crl_set_bytes; 1362 int error = Verify(cert.get(), "127.0.0.1", flags, crl_set.get(),
1345 EXPECT_TRUE(base::ReadFileToString( 1363 empty_cert_list_, &verify_result);
1346 GetTestCertsDirectory().AppendASCII("multi-root-crlset-C-by-E.raw"),
1347 &crl_set_bytes));
1348 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
1349 1364
1350 // Verify with the CRLSet. Because C-by-E is revoked, the expected path is 1365 if (!testcase.expect_valid) {
1351 // A(B) -> B(C) -> C(D) -> D(D). 1366 EXPECT_NE(OK, error);
1352 error = Verify(cert.get(), "127.0.0.1", flags, crl_set.get(), 1367 EXPECT_NE(0U, verify_result.cert_status);
1353 empty_cert_list_, &verify_result); 1368 continue;
1354 ASSERT_EQ(OK, error); 1369 }
1355 ASSERT_EQ(0U, verify_result.cert_status);
1356 ASSERT_TRUE(verify_result.verified_cert.get());
1357 1370
1358 const X509Certificate::OSCertHandles& new_verified_intermediates = 1371 ASSERT_EQ(OK, error);
1359 verify_result.verified_cert->GetIntermediateCertificates(); 1372 ASSERT_EQ(0U, verify_result.cert_status);
1360 ASSERT_EQ(3U, new_verified_intermediates.size()); 1373 ASSERT_TRUE(verify_result.verified_cert.get());
1361 verified_root = X509Certificate::CreateFromHandle(
1362 new_verified_intermediates[2], X509Certificate::OSCertHandles());
1363 ASSERT_TRUE(verified_root.get());
1364 EXPECT_EQ("D Root CA", verified_root->subject().common_name);
1365 1374
1366 // Reverify without the CRLSet, to ensure that CRLSets do not persist between 1375 if (!testcase.expected_intermediate)
1367 // separate calls. As in the first verification, the expected path is 1376 continue;
1368 // A(B) -> B(C) -> C(E) -> E(E).
1369 error = Verify(cert.get(), "127.0.0.1", flags, nullptr, empty_cert_list_,
1370 &verify_result);
1371 ASSERT_EQ(OK, error);
1372 ASSERT_EQ(0U, verify_result.cert_status);
1373 ASSERT_TRUE(verify_result.verified_cert.get());
1374 1377
1375 const X509Certificate::OSCertHandles& final_verified_intermediates = 1378 const X509Certificate::OSCertHandles& verified_intermediates =
1376 verify_result.verified_cert->GetIntermediateCertificates(); 1379 verify_result.verified_cert->GetIntermediateCertificates();
1377 ASSERT_EQ(3U, final_verified_intermediates.size()); 1380 ASSERT_EQ(3U, verified_intermediates.size());
1378 verified_root = X509Certificate::CreateFromHandle(
1379 final_verified_intermediates[2], X509Certificate::OSCertHandles());
1380 ASSERT_TRUE(verified_root.get());
1381 EXPECT_EQ("E Root CA", verified_root->subject().common_name);
1382 }
1383 1381
1384 // Tests that revocation by CRLSet functions properly when an intermediate is 1382 scoped_refptr<X509Certificate> intermediate =
1385 // revoked by SPKI. In this case, path building should ignore all certificates 1383 X509Certificate::CreateFromHandle(verified_intermediates[1],
1386 // with that SPKI, and search for alternatively keyed versions. 1384 X509Certificate::OSCertHandles());
1387 // 1385 ASSERT_TRUE(intermediate);
1388 // The two possible paths are: 1386
1389 // 1. A(B) -> B(C) -> C(D) -> D(D) 1387 EXPECT_TRUE(testcase.expected_intermediate->Equals(intermediate.get()))
1390 // 2. A(B) -> B(F) -> F(E) -> E(E) 1388 << "Expected: " << testcase.expected_intermediate->subject().common_name
1391 // 1389 << " issued by " << testcase.expected_intermediate->issuer().common_name
1392 // The path building algorithm needs to explore B(C) once it discovers that 1390 << "; Got: " << intermediate->subject().common_name << " issued by "
1393 // F(E) is revoked, and that there are no valid paths with B(F). 1391 << intermediate->issuer().common_name;
1394 TEST_F(CertVerifyProcTest, CRLSetRevokedIntermediateCrossIntermediates) {
1395 if (!SupportsCRLSetsInPathBuilding()) {
1396 LOG(INFO) << "Skipping this test on this platform.";
1397 return;
1398 } 1392 }
1399
1400 const char* const kCertificatesToLoad[] = {
1401 "multi-root-A-by-B.pem", "multi-root-B-by-C.pem", "multi-root-C-by-D.pem",
1402 "multi-root-D-by-D.pem", "multi-root-B-by-F.pem", "multi-root-F-by-E.pem",
1403 "multi-root-E-by-E.pem",
1404 };
1405 CertificateList certs;
1406 ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kCertificatesToLoad, &certs));
1407
1408 // Add D and E as trust anchors
1409 ScopedTestRoot test_root_D(certs[3].get()); // D-by-D
1410 ScopedTestRoot test_root_F(certs[6].get()); // E-by-E
1411
1412 // Create a chain that sends A(B), B(F), F(E), B(C), C(D). The reason that
1413 // both B(C) and C(D) are sent are to ensure both certificates are available
1414 // for path building. The test
1415 // CertVerifyProcTest.VerifyReturnChainFiltersUnrelatedCerts ensures this is
1416 // safe to do.
1417 X509Certificate::OSCertHandles intermediates;
1418 intermediates.push_back(certs[4]->os_cert_handle()); // B-by-F
1419 intermediates.push_back(certs[5]->os_cert_handle()); // F-by-E
1420 intermediates.push_back(certs[1]->os_cert_handle()); // B-by-C
1421 intermediates.push_back(certs[2]->os_cert_handle()); // C-by-D
1422 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
1423 certs[0]->os_cert_handle(), intermediates);
1424 ASSERT_TRUE(cert);
1425
1426 // Sanity check: Ensure that, without any revocation status, the to-be-revoked
1427 // path is preferred.
1428 int flags = 0;
1429 CertVerifyResult verify_result;
1430 int error = Verify(cert.get(), "127.0.0.1", flags, nullptr, empty_cert_list_,
1431 &verify_result);
1432 ASSERT_EQ(OK, error);
1433 ASSERT_EQ(0U, verify_result.cert_status);
1434 ASSERT_TRUE(verify_result.verified_cert.get());
1435
1436 // The expected path is A(B) -> B(F) -> F(E) -> E(E).
1437 const X509Certificate::OSCertHandles& verified_intermediates =
1438 verify_result.verified_cert->GetIntermediateCertificates();
1439 ASSERT_EQ(3U, verified_intermediates.size());
1440 scoped_refptr<X509Certificate> verified_root =
1441 X509Certificate::CreateFromHandle(verified_intermediates[2],
1442 X509Certificate::OSCertHandles());
1443 ASSERT_TRUE(verified_root.get());
1444 EXPECT_EQ("E Root CA", verified_root->subject().common_name);
1445
1446 // Load a CRLSet that blocks F.
1447 scoped_refptr<CRLSet> crl_set;
1448 std::string crl_set_bytes;
1449 EXPECT_TRUE(base::ReadFileToString(
1450 GetTestCertsDirectory().AppendASCII("multi-root-crlset-F.raw"),
1451 &crl_set_bytes));
1452 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
1453
1454 // Verify with the CRLSet. Because F is revoked, the expected path is
1455 // A(B) -> B(C) -> C(D) -> D(D).
1456 error = Verify(cert.get(), "127.0.0.1", flags, crl_set.get(),
1457 empty_cert_list_, &verify_result);
1458 ASSERT_EQ(OK, error);
1459 ASSERT_EQ(0U, verify_result.cert_status);
1460 ASSERT_TRUE(verify_result.verified_cert.get());
1461
1462 const X509Certificate::OSCertHandles& new_verified_intermediates =
1463 verify_result.verified_cert->GetIntermediateCertificates();
1464 ASSERT_EQ(3U, new_verified_intermediates.size());
1465 verified_root = X509Certificate::CreateFromHandle(
1466 new_verified_intermediates[2], X509Certificate::OSCertHandles());
1467 ASSERT_TRUE(verified_root.get());
1468 EXPECT_EQ("D Root CA", verified_root->subject().common_name);
1469
1470 // Reverify without the CRLSet, to ensure that CRLSets do not persist between
1471 // separate calls. As in the first verification, the expected path is
1472 // A(B) -> B(F) -> F(E) -> E(E).
1473 error = Verify(cert.get(), "127.0.0.1", flags, nullptr, empty_cert_list_,
1474 &verify_result);
1475 ASSERT_EQ(OK, error);
1476 ASSERT_EQ(0U, verify_result.cert_status);
1477 ASSERT_TRUE(verify_result.verified_cert.get());
1478
1479 const X509Certificate::OSCertHandles& final_verified_intermediates =
1480 verify_result.verified_cert->GetIntermediateCertificates();
1481 ASSERT_EQ(3U, final_verified_intermediates.size());
1482 verified_root = X509Certificate::CreateFromHandle(
1483 final_verified_intermediates[2], X509Certificate::OSCertHandles());
1484 ASSERT_TRUE(verified_root.get());
1485 EXPECT_EQ("E Root CA", verified_root->subject().common_name);
1486 } 1393 }
1487 1394
1488 #endif 1395 #endif
1489 1396
1490 enum ExpectedAlgorithms { 1397 enum ExpectedAlgorithms {
1491 EXPECT_MD2 = 1 << 0, 1398 EXPECT_MD2 = 1 << 0,
1492 EXPECT_MD4 = 1 << 1, 1399 EXPECT_MD4 = 1 << 1,
1493 EXPECT_MD5 = 1 << 2, 1400 EXPECT_MD5 = 1 << 2,
1494 EXPECT_SHA1 = 1 << 3, 1401 EXPECT_SHA1 = 1 << 3,
1495 EXPECT_SHA1_LEAF = 1 << 4, 1402 EXPECT_SHA1_LEAF = 1 << 4,
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
1830 int flags = 0; 1737 int flags = 0;
1831 CertVerifyResult verify_result; 1738 CertVerifyResult verify_result;
1832 int error = Verify(cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, 1739 int error = Verify(cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_,
1833 &verify_result); 1740 &verify_result);
1834 EXPECT_EQ(ERR_CERT_INVALID, error); 1741 EXPECT_EQ(ERR_CERT_INVALID, error);
1835 EXPECT_EQ(CERT_STATUS_INVALID, verify_result.cert_status); 1742 EXPECT_EQ(CERT_STATUS_INVALID, verify_result.cert_status);
1836 } 1743 }
1837 #endif // defined(OS_MACOSX) && !defined(OS_IOS) 1744 #endif // defined(OS_MACOSX) && !defined(OS_IOS)
1838 1745
1839 } // namespace net 1746 } // namespace net
OLDNEW
« no previous file with comments | « net/cert/cert_verify_proc_nss.cc ('k') | net/data/ssl/certificates/multi-root-A-by-B.pem » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698