Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "base/time/time.h" | |
| 6 #include "components/cast_certificate/cast_cert_validator.h" | |
| 7 #include "components/cast_certificate/cast_cert_validator_test_helpers.h" | |
| 8 #include "components/cast_certificate/cast_crl.h" | |
| 9 #include "components/cast_certificate/proto/test_suite.pb.h" | |
| 10 #include "testing/gtest/include/gtest/gtest.h" | |
| 11 | |
| 12 namespace cast_certificate { | |
| 13 namespace { | |
| 14 | |
| 15 // Converts uint64_t unix timestamp to base::Time. | |
| 16 base::Time ConvertUnixTimestamp(uint64_t time) { | |
| 17 return base::Time::UnixEpoch() + base::TimeDelta::FromMilliseconds(time); | |
| 18 } | |
| 19 // Indicates the expected result of test step's verification. | |
| 20 enum TestStepResult { | |
| 21 RESULT_SUCCESS, | |
| 22 RESULT_FAIL, | |
| 23 }; | |
| 24 | |
| 25 // Verifies that the provided certificate chain is valid at the specified time | |
| 26 // and chains up to a trust anchor. | |
| 27 bool TestVerifyCertificate(TestStepResult expected_result, | |
| 28 const std::vector<std::string>& certificate_chain, | |
| 29 const base::Time& time) { | |
| 30 std::unique_ptr<CertVerificationContext> context; | |
| 31 CastDeviceCertPolicy policy; | |
| 32 bool result = VerifyDeviceCert(certificate_chain, time, &context, &policy, | |
| 33 nullptr, CRLPolicy::CRL_OPTIONAL); | |
| 34 if (expected_result != RESULT_SUCCESS) { | |
| 35 EXPECT_FALSE(result); | |
| 36 return !result; | |
| 37 } | |
| 38 EXPECT_TRUE(result); | |
| 39 return result; | |
| 40 } | |
| 41 | |
| 42 // Verifies that the provided Cast CRL is signed by a trusted issuer | |
| 43 // and that the CRL can be parsed successfully. | |
| 44 // The validity of the CRL is also checked at the specified time. | |
| 45 bool TestVerifyCRL(TestStepResult expected_result, | |
| 46 const std::string& crl_bundle, | |
| 47 const base::Time& time) { | |
| 48 std::unique_ptr<CastCRL> crl = ParseAndVerifyCRL(crl_bundle, time); | |
| 49 if (expected_result != RESULT_SUCCESS) { | |
| 50 EXPECT_EQ(crl, nullptr); | |
| 51 return crl == nullptr; | |
| 52 } | |
| 53 EXPECT_NE(crl, nullptr); | |
| 54 return crl != nullptr; | |
| 55 } | |
| 56 | |
| 57 // Verifies that the certificate chain provided is not revoked according to | |
| 58 // the provided Cast CRL at |cert_time|. | |
| 59 // The provided CRL is verified at |crl_time|. | |
| 60 // If |crl_required| is set, then a valid Cast CRL must be provided. | |
| 61 // Otherwise, a missing CRL is be ignored. | |
| 62 bool TestVerifyRevocation(TestStepResult expected_result, | |
| 63 const std::vector<std::string>& certificate_chain, | |
| 64 const std::string& crl_bundle, | |
| 65 const base::Time& crl_time, | |
| 66 const base::Time& cert_time, | |
| 67 bool crl_required) { | |
| 68 std::unique_ptr<CastCRL> crl; | |
| 69 if (!crl_bundle.empty()) { | |
| 70 crl = ParseAndVerifyCRL(crl_bundle, crl_time); | |
| 71 EXPECT_NE(crl.get(), nullptr); | |
| 72 } | |
| 73 | |
| 74 std::unique_ptr<CertVerificationContext> context; | |
| 75 CastDeviceCertPolicy policy; | |
| 76 CRLPolicy crl_policy = CRLPolicy::CRL_REQUIRED; | |
| 77 if (!crl_required) | |
| 78 crl_policy = CRLPolicy::CRL_OPTIONAL; | |
| 79 int result = VerifyDeviceCert(certificate_chain, cert_time, &context, &policy, | |
| 80 crl.get(), crl_policy); | |
| 81 if (expected_result != RESULT_SUCCESS) { | |
| 82 EXPECT_FALSE(result); | |
| 83 return !result; | |
| 84 } | |
| 85 EXPECT_TRUE(result); | |
| 86 return result; | |
| 87 } | |
| 88 | |
| 89 // Runs a single test case. | |
| 90 bool RunTest(const DeviceCertTest& test_case) { | |
| 91 bool use_test_trust_anchors = test_case.use_test_trust_anchors(); | |
| 92 if (use_test_trust_anchors) { | |
| 93 const auto crl_test_root = | |
| 94 cast_certificate::testing::ReadCertificateChainFromFile( | |
| 95 "certificates/cast_crl_test_root_ca.pem"); | |
| 96 EXPECT_EQ(crl_test_root.size(), 1u); | |
| 97 EXPECT_TRUE(SetCRLTrustAnchorForTest(crl_test_root[0])); | |
| 98 const auto cast_test_root = | |
| 99 cast_certificate::testing::ReadCertificateChainFromFile( | |
| 100 "certificates/cast_test_root_ca.pem"); | |
| 101 EXPECT_EQ(cast_test_root.size(), 1u); | |
| 102 EXPECT_TRUE(SetTrustAnchorForTest(cast_test_root[0])); | |
| 103 } | |
| 104 | |
| 105 VerificationResult expected_result = test_case.expected_result(); | |
| 106 | |
| 107 std::vector<std::string> certificate_chain; | |
| 108 for (auto const& cert : test_case.der_cert_path()) { | |
| 109 certificate_chain.push_back(cert); | |
| 110 } | |
| 111 | |
| 112 base::Time cert_verification_time = | |
| 113 ConvertUnixTimestamp(test_case.cert_verification_time_seconds() * 1000); | |
|
eroman
2016/07/19 01:54:59
I suggest changing ConvertUnixTimestamp to take se
ryanchung
2016/07/19 21:29:53
Done.
| |
| 114 | |
| 115 uint64_t crl_verify_time = test_case.crl_verification_time_seconds() * 1000; | |
|
eroman
2016/07/19 01:54:59
here for instance.
ryanchung
2016/07/19 21:29:54
Done.
| |
| 116 base::Time crl_verification_time = ConvertUnixTimestamp(crl_verify_time); | |
| 117 if (crl_verify_time == 0) | |
| 118 crl_verification_time = cert_verification_time; | |
| 119 | |
| 120 std::string crl_bundle = test_case.crl_bundle(); | |
| 121 switch (expected_result) { | |
| 122 case PATH_VERIFICATION_FAILED: | |
| 123 return TestVerifyCertificate(RESULT_FAIL, certificate_chain, | |
| 124 cert_verification_time); | |
| 125 break; | |
| 126 case CRL_VERIFICATION_FAILED: | |
| 127 return TestVerifyCRL(RESULT_FAIL, crl_bundle, crl_verification_time); | |
| 128 break; | |
| 129 case REVOCATION_CHECK_FAILED_WITHOUT_CRL: | |
| 130 return TestVerifyCertificate(RESULT_SUCCESS, certificate_chain, | |
| 131 cert_verification_time) && | |
| 132 TestVerifyCRL(RESULT_FAIL, crl_bundle, crl_verification_time) && | |
| 133 TestVerifyRevocation(RESULT_FAIL, certificate_chain, crl_bundle, | |
| 134 crl_verification_time, cert_verification_time, | |
| 135 true); | |
| 136 break; | |
| 137 case REVOCATION_CHECK_FAILED: | |
| 138 return TestVerifyCertificate(RESULT_SUCCESS, certificate_chain, | |
| 139 cert_verification_time) && | |
| 140 TestVerifyCRL(RESULT_SUCCESS, crl_bundle, crl_verification_time) && | |
| 141 TestVerifyRevocation(RESULT_FAIL, certificate_chain, crl_bundle, | |
| 142 crl_verification_time, cert_verification_time, | |
| 143 false); | |
| 144 break; | |
| 145 case SUCCESS: | |
| 146 return (crl_bundle.empty() || TestVerifyCRL(RESULT_SUCCESS, crl_bundle, | |
| 147 crl_verification_time)) && | |
| 148 TestVerifyCertificate(RESULT_SUCCESS, certificate_chain, | |
| 149 cert_verification_time) && | |
| 150 TestVerifyRevocation(RESULT_SUCCESS, certificate_chain, crl_bundle, | |
| 151 crl_verification_time, cert_verification_time, | |
| 152 !crl_bundle.empty()); | |
| 153 break; | |
| 154 case UNSPECIFIED: | |
| 155 return false; | |
| 156 break; | |
| 157 } | |
| 158 return false; | |
| 159 } | |
| 160 | |
| 161 // Parses the provided test suite provided in wire-format proto. | |
| 162 // Each test contains the inputs and the expected output. | |
| 163 // To see the description of the test, execute the test. | |
| 164 // These tests are generated by a test generator in google3. | |
| 165 void RunTestSuite(const std::string& test_suite_file_name) { | |
| 166 std::string testsuite_raw = | |
| 167 cast_certificate::testing::ReadTestFileToString(test_suite_file_name); | |
| 168 DeviceCertTestSuite test_suite; | |
| 169 EXPECT_TRUE(test_suite.ParseFromString(testsuite_raw)); | |
| 170 uint16_t success = 0; | |
| 171 uint16_t failed = 0; | |
| 172 std::vector<std::string> failed_tests; | |
| 173 | |
| 174 for (auto const& test_case : test_suite.tests()) { | |
| 175 LOG(INFO) << "[ RUN ] " << test_case.description(); | |
| 176 bool result = RunTest(test_case); | |
| 177 EXPECT_TRUE(result); | |
| 178 if (!result) { | |
| 179 LOG(INFO) << "[ FAILED ] " << test_case.description(); | |
| 180 ++failed; | |
| 181 failed_tests.push_back(test_case.description()); | |
| 182 } else { | |
| 183 LOG(INFO) << "[ PASSED ] " << test_case.description(); | |
| 184 ++success; | |
| 185 } | |
| 186 } | |
| 187 LOG(INFO) << "[ PASSED ] " << success << " test(s)."; | |
| 188 if (failed) { | |
| 189 LOG(INFO) << "[ FAILED ] " << failed << " test(s), listed below:"; | |
| 190 for (const auto& failed_test : failed_tests) { | |
| 191 LOG(INFO) << "[ FAILED ] " << failed_test; | |
| 192 } | |
| 193 } | |
| 194 } | |
| 195 | |
| 196 TEST(CastCertificateTest, TestSuite1) { | |
| 197 RunTestSuite("testsuite/testsuite1.pb"); | |
| 198 } | |
| 199 | |
| 200 } // namespace | |
| 201 | |
| 202 } // namespace cast_certificate | |
| OLD | NEW |