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

Unified Diff: components/cast_certificate/cast_cert_validator_unittest.cc

Issue 2255623003: Enable trust anchor constraints for the built-in Cast roots. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix some comments Created 4 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/cast_certificate/cast_cert_validator.cc ('k') | components/cast_certificate/cast_crl.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/cast_certificate/cast_cert_validator_unittest.cc
diff --git a/components/cast_certificate/cast_cert_validator_unittest.cc b/components/cast_certificate/cast_cert_validator_unittest.cc
index 30b5c38846d908125cc13ce58a4d67af1340d03d..ee6b47f0bea77598f3e672a146cef7464d9a61d8 100644
--- a/components/cast_certificate/cast_cert_validator_unittest.cc
+++ b/components/cast_certificate/cast_cert_validator_unittest.cc
@@ -5,6 +5,8 @@
#include "components/cast_certificate/cast_cert_validator.h"
#include "components/cast_certificate/cast_cert_validator_test_helpers.h"
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/trust_store.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cast_certificate {
@@ -23,6 +25,24 @@ enum TestResult {
RESULT_FAIL,
};
+enum TrustStoreDependency {
+ // Uses the built-in trust store for Cast. This is how certificates are
+ // verified in production.
+ TRUST_STORE_BUILTIN,
+
+ // Instead of using the built-in trust store, use root certificate in the
+ // provided test chain as the trust anchor.
+ //
+ // This trust anchor is initialized with anchor constraints, similar to how
+ // TrustAnchors in the built-in store are setup.
+ TRUST_STORE_FROM_TEST_FILE,
+
+ // This is the same as TRUST_STORE_FROM_TEST_FILE except the TrustAnchor is
+ // setup to NOT enforce anchor constraints. This mode is useful for
+ // verifying control groups. It is not how code works in production.
+ TRUST_STORE_FROM_TEST_FILE_UNCONSTRAINED,
+};
+
// Reads a test chain from |certs_file_name|, and asserts that verifying it as
// a Cast device certificate yields |expected_result|.
//
@@ -32,6 +52,8 @@ enum TestResult {
// * |expected_policy| - The policy that should have been identified for the
// device certificate.
// * |time| - The timestamp to use when verifying the certificate.
+// * |trust_store_dependency| - Which trust store to use when verifying (see
+// enum's definition).
// * |optional_signed_data_file_name| - optional path to a PEM file containing
// a valid signature generated by the device certificate.
//
@@ -40,14 +62,60 @@ void RunTest(TestResult expected_result,
CastDeviceCertPolicy expected_policy,
const std::string& certs_file_name,
const base::Time& time,
+ TrustStoreDependency trust_store_dependency,
const std::string& optional_signed_data_file_name) {
auto certs =
cast_certificate::testing::ReadCertificateChainFromFile(certs_file_name);
+ std::unique_ptr<net::TrustStore> trust_store;
+
+ switch (trust_store_dependency) {
+ case TRUST_STORE_BUILTIN:
+ // Leave trust_store as nullptr.
+ break;
+
+ case TRUST_STORE_FROM_TEST_FILE:
+ case TRUST_STORE_FROM_TEST_FILE_UNCONSTRAINED: {
+ ASSERT_FALSE(certs.empty());
+
+ // Parse the root certificate of the chain.
+ scoped_refptr<net::ParsedCertificate> root =
+ net::ParsedCertificate::CreateFromCertificateCopy(certs.back(), {});
+ ASSERT_TRUE(root);
+
+ // Remove it from the chain.
+ certs.pop_back();
+
+ // Add it to the trust store as a trust anchor
+ trust_store.reset(new net::TrustStore);
+
+ if (trust_store_dependency == TRUST_STORE_FROM_TEST_FILE_UNCONSTRAINED) {
+ // This is a test-only mode where anchor constraints are not enforced.
+ trust_store->AddTrustAnchor(
+ net::TrustAnchor::CreateFromCertificateNoConstraints(
+ std::move(root)));
+ } else {
+ // This is the regular mode used by the TrustAnchors for the built-in
+ // Cast store.
+ trust_store->AddTrustAnchor(
+ net::TrustAnchor::CreateFromCertificateWithConstraints(
+ std::move(root)));
+ }
+ }
+ }
+
std::unique_ptr<CertVerificationContext> context;
CastDeviceCertPolicy policy;
- bool result = VerifyDeviceCert(certs, time, &context, &policy, nullptr,
- CRLPolicy::CRL_OPTIONAL);
+
+ bool result;
+ if (trust_store.get()) {
+ result =
+ VerifyDeviceCertForTest(certs, time, &context, &policy, nullptr,
+ CRLPolicy::CRL_OPTIONAL, trust_store.get());
+ } else {
+ result = VerifyDeviceCert(certs, time, &context, &policy, nullptr,
+ CRLPolicy::CRL_OPTIONAL);
+ }
if (expected_result == RESULT_FAIL) {
ASSERT_FALSE(result);
@@ -131,11 +199,11 @@ base::Time MarchFirst2037() {
// 1: Eureka Gen1 ICA
//
// Chains to trust anchor:
-// Eureka Root CA (not included)
+// Eureka Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, ChromecastGen1) {
RunTest(RESULT_SUCCESS, "2ZZBG9 FA8FCA3EF91A", CastDeviceCertPolicy::NONE,
"certificates/chromecast_gen1.pem", AprilFirst2016(),
- "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
+ TRUST_STORE_BUILTIN, "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
}
// Tests verifying a valid certificate chain of length 2:
@@ -144,11 +212,11 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen1) {
// 1: Eureka Gen1 ICA
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, ChromecastGen1Reissue) {
RunTest(RESULT_SUCCESS, "2ZZBG9 FA8FCA3EF91A", CastDeviceCertPolicy::NONE,
"certificates/chromecast_gen1_reissue.pem", AprilFirst2016(),
- "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
+ TRUST_STORE_BUILTIN, "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
}
// Tests verifying a valid certificate chain of length 2:
@@ -157,10 +225,11 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen1Reissue) {
// 1: Chromecast ICA 3
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, ChromecastGen2) {
RunTest(RESULT_SUCCESS, "3ZZAK6 FA8FCA3F0D35", CastDeviceCertPolicy::NONE,
- "certificates/chromecast_gen2.pem", AprilFirst2016(), "");
+ "certificates/chromecast_gen2.pem", AprilFirst2016(),
+ TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 3:
@@ -170,10 +239,10 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen2) {
// 2: Widevine Cast Subroot
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, Fugu) {
RunTest(RESULT_SUCCESS, "-6394818897508095075", CastDeviceCertPolicy::NONE,
- "certificates/fugu.pem", AprilFirst2016(), "");
+ "certificates/fugu.pem", AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying an invalid certificate chain of length 1:
@@ -181,12 +250,13 @@ TEST(VerifyCastDeviceCertTest, Fugu) {
// 0: Cast Test Untrusted Device
//
// Chains to:
-// Cast Test Untrusted ICA (not included)
+// Cast Test Untrusted ICA (Not part of trust store)
//
// This is invalid because it does not chain to a trust anchor.
TEST(VerifyCastDeviceCertTest, Unchained) {
RunTest(RESULT_FAIL, "", CastDeviceCertPolicy::NONE,
- "certificates/unchained.pem", AprilFirst2016(), "");
+ "certificates/unchained.pem", AprilFirst2016(), TRUST_STORE_BUILTIN,
+ "");
}
// Tests verifying one of the self-signed trust anchors (chain of length 1):
@@ -194,14 +264,15 @@ TEST(VerifyCastDeviceCertTest, Unchained) {
// 0: Cast Root CA
//
// Chains to trust anchor:
-// Cast Root CA
+// Cast Root CA (built-in trust store)
//
// Although this is a valid and trusted certificate (it is one of the
// trust anchors after all) it fails the test as it is not a *device
// certificate*.
TEST(VerifyCastDeviceCertTest, CastRootCa) {
RunTest(RESULT_FAIL, "", CastDeviceCertPolicy::NONE,
- "certificates/cast_root_ca.pem", AprilFirst2016(), "");
+ "certificates/cast_root_ca.pem", AprilFirst2016(),
+ TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 2:
@@ -210,14 +281,14 @@ TEST(VerifyCastDeviceCertTest, CastRootCa) {
// 1: Chromecast ICA 4 (Audio)
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
//
// This device certificate has a policy that means it is valid only for audio
// devices.
TEST(VerifyCastDeviceCertTest, ChromecastAudio) {
RunTest(RESULT_SUCCESS, "4ZZDZJ FA8FCA7EFE3C",
CastDeviceCertPolicy::AUDIO_ONLY, "certificates/chromecast_audio.pem",
- AprilFirst2016(), "");
+ AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 3:
@@ -227,14 +298,14 @@ TEST(VerifyCastDeviceCertTest, ChromecastAudio) {
// 2: Cast Audio Dev Root CA
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
//
// This device certificate has a policy that means it is valid only for audio
// devices.
TEST(VerifyCastDeviceCertTest, MtkAudioDev) {
RunTest(RESULT_SUCCESS, "MediaTek Audio Dev Test",
CastDeviceCertPolicy::AUDIO_ONLY, "certificates/mtk_audio_dev.pem",
- JanuaryFirst2015(), "");
+ JanuaryFirst2015(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 2:
@@ -243,10 +314,10 @@ TEST(VerifyCastDeviceCertTest, MtkAudioDev) {
// 1: Cast TV ICA (Vizio)
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, Vizio) {
RunTest(RESULT_SUCCESS, "9V0000VB FA8FCA784D01", CastDeviceCertPolicy::NONE,
- "certificates/vizio.pem", AprilFirst2016(), "");
+ "certificates/vizio.pem", AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 2 using expired
@@ -257,15 +328,15 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen2InvalidTime) {
// Control test - certificate should be valid at some time otherwise
// this test is pointless.
RunTest(RESULT_SUCCESS, "3ZZAK6 FA8FCA3F0D35", CastDeviceCertPolicy::NONE,
- kCertsFile, AprilFirst2016(), "");
+ kCertsFile, AprilFirst2016(), TRUST_STORE_BUILTIN, "");
// Use a time before notBefore.
RunTest(RESULT_FAIL, "", CastDeviceCertPolicy::NONE, kCertsFile,
- JanuaryFirst2015(), "");
+ JanuaryFirst2015(), TRUST_STORE_BUILTIN, "");
// Use a time after notAfter.
RunTest(RESULT_FAIL, "", CastDeviceCertPolicy::NONE, kCertsFile,
- MarchFirst2037(), "");
+ MarchFirst2037(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 3:
@@ -275,7 +346,7 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen2InvalidTime) {
// 2: Cast Audio Dev Root CA
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
//
// This device certificate has a policy that means it is valid only for audio
// devices.
@@ -283,7 +354,7 @@ TEST(VerifyCastDeviceCertTest, AudioRefDevTestChain3) {
RunTest(RESULT_SUCCESS, "Audio Reference Dev Test",
CastDeviceCertPolicy::AUDIO_ONLY,
"certificates/audio_ref_dev_test_chain_3.pem", AprilFirst2016(),
- "signeddata/AudioReferenceDevTest.pem");
+ TRUST_STORE_BUILTIN, "signeddata/AudioReferenceDevTest.pem");
}
// Tests verifying a valid certificate chain of length 3. Note that the first
@@ -296,7 +367,7 @@ TEST(VerifyCastDeviceCertTest, AudioRefDevTestChain3) {
// 2: Cast Audio Sony CA
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
//
// This device certificate has a policy that means it is valid only for audio
// devices.
@@ -304,7 +375,51 @@ TEST(VerifyCastDeviceCertTest, IntermediateSerialNumberTooLong) {
RunTest(RESULT_SUCCESS, "8C579B806FFC8A9DFFFF F8:8F:CA:6B:E6:DA",
CastDeviceCertPolicy::AUDIO_ONLY,
"certificates/intermediate_serialnumber_toolong.pem",
- AprilFirst2016(), "");
+ AprilFirst2016(), TRUST_STORE_BUILTIN, "");
+}
+
+// Tests verifying a valid certificate chain of length 2 when the trust anchor
+// is "expired". This is expected to work since expiration is not an enforced
+// anchor constraint, even though it may appear in the root certificate.
+//
+// 0: CastDevice
+// 1: CastIntermediate
+//
+// Chains to trust anchor:
+// Expired CastRoot (provided by test data)
+TEST(VerifyCastDeviceCertTest, ExpiredTrustAnchor) {
+ // The root certificate is only valid in 2015, so validating with a time in
+ // 2016 means it is expired.
+ RunTest(RESULT_SUCCESS, "CastDevice", CastDeviceCertPolicy::NONE,
+ "certificates/expired_root.pem", AprilFirst2016(),
+ TRUST_STORE_FROM_TEST_FILE, "");
+}
+
+// Tests verifying a certificate chain where the root certificate has a pathlen
+// constraint which is violated by the chain. In this case Root has a pathlen=1
+// constraint, however neither intermediate is constrained.
+//
+// The expectation is for pathlen constraints on trust anchors to be enforced,
+// so this validation must fail.
+//
+// 0: Target
+// 1: Intermediate2
+// 2: Intermediate1
+//
+// Chains to trust anchor:
+// Root (provided by test data; has pathlen=1 constraint)
+TEST(VerifyCastDeviceCertTest, ViolatesPathlenTrustAnchorConstraint) {
+ // First do a control test -- when anchor constraints are NOT enforced this
+ // chain should validate just fine.
+ RunTest(RESULT_SUCCESS, "Target", CastDeviceCertPolicy::NONE,
+ "certificates/violates_root_pathlen_constraint.pem", AprilFirst2016(),
+ TRUST_STORE_FROM_TEST_FILE_UNCONSTRAINED, "");
+
+ // Now do the real test and verify validation fails when using a TrustAncho
+ // with pathlen constraint.
+ RunTest(RESULT_FAIL, "Target", CastDeviceCertPolicy::NONE,
+ "certificates/violates_root_pathlen_constraint.pem", AprilFirst2016(),
+ TRUST_STORE_FROM_TEST_FILE, "");
}
// ------------------------------------------------------
« no previous file with comments | « components/cast_certificate/cast_cert_validator.cc ('k') | components/cast_certificate/cast_crl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698