| Index: extensions/browser/api/cast_channel/cast_auth_util_unittest.cc
|
| diff --git a/extensions/browser/api/cast_channel/cast_auth_util_unittest.cc b/extensions/browser/api/cast_channel/cast_auth_util_unittest.cc
|
| index 9393eac753237a0c236972e16a92d80bce9bf8c5..3ff13ef730a35d4a79724874b499b45a6b30b749 100644
|
| --- a/extensions/browser/api/cast_channel/cast_auth_util_unittest.cc
|
| +++ b/extensions/browser/api/cast_channel/cast_auth_util_unittest.cc
|
| @@ -7,8 +7,13 @@
|
| #include <string>
|
|
|
| #include "base/macros.h"
|
| +#include "base/time/time.h"
|
| +#include "components/cast_certificate/cast_cert_validator.h"
|
| #include "components/cast_certificate/cast_cert_validator_test_helpers.h"
|
| +#include "components/cast_certificate/cast_crl.h"
|
| +#include "components/cast_certificate/proto/test_suite.pb.h"
|
| #include "extensions/common/api/cast_channel/cast_channel.pb.h"
|
| +#include "net/cert/internal/trust_store_in_memory.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| namespace extensions {
|
| @@ -54,7 +59,10 @@ class CastAuthUtilTest : public testing::Test {
|
| TEST_F(CastAuthUtilTest, VerifySuccess) {
|
| std::string signed_data;
|
| AuthResponse auth_response = CreateAuthResponse(&signed_data);
|
| - AuthResult result = VerifyCredentials(auth_response, signed_data);
|
| + base::Time now = base::Time::Now();
|
| + AuthResult result = VerifyCredentialsForTest(
|
| + auth_response, signed_data, cast_certificate::CRLPolicy::CRL_OPTIONAL,
|
| + nullptr, nullptr, now, now);
|
| EXPECT_TRUE(result.success());
|
| EXPECT_EQ(AuthResult::POLICY_NONE, result.channel_policies);
|
| }
|
| @@ -96,6 +104,161 @@ TEST_F(CastAuthUtilTest, VerifyBadPeerCert) {
|
| EXPECT_EQ(AuthResult::ERROR_SIGNED_BLOBS_MISMATCH, result.error_type);
|
| }
|
|
|
| +// Indicates the expected result of test step's verification.
|
| +enum TestStepResult {
|
| + RESULT_SUCCESS,
|
| + RESULT_FAIL,
|
| +};
|
| +
|
| +// Verifies that the certificate chain provided is not revoked according to
|
| +// the provided Cast CRL at |cert_time|.
|
| +// The provided CRL is verified at |crl_time|.
|
| +// If |crl_required| is set, then a valid Cast CRL must be provided.
|
| +// Otherwise, a missing CRL is be ignored.
|
| +AuthResult TestVerifyRevocation(
|
| + const std::vector<std::string>& certificate_chain,
|
| + const std::string& crl_bundle,
|
| + const base::Time& crl_time,
|
| + const base::Time& cert_time,
|
| + bool crl_required,
|
| + net::TrustStore* cast_trust_store,
|
| + net::TrustStore* crl_trust_store) {
|
| + AuthResponse response;
|
| +
|
| + if (certificate_chain.size() > 0) {
|
| + response.set_client_auth_certificate(certificate_chain[0]);
|
| + for (size_t i = 1; i < certificate_chain.size(); ++i)
|
| + response.add_intermediate_certificate(certificate_chain[i]);
|
| + }
|
| +
|
| + response.set_crl(crl_bundle);
|
| +
|
| + cast_certificate::CRLPolicy crl_policy =
|
| + cast_certificate::CRLPolicy::CRL_REQUIRED;
|
| + if (!crl_required && crl_bundle.empty())
|
| + crl_policy = cast_certificate::CRLPolicy::CRL_OPTIONAL;
|
| + AuthResult result =
|
| + VerifyCredentialsForTest(response, "", crl_policy, cast_trust_store,
|
| + crl_trust_store, cert_time, crl_time);
|
| + // This test doesn't set the signature so it will just fail there.
|
| + EXPECT_FALSE(result.success());
|
| + return result;
|
| +}
|
| +
|
| +// Runs a single test case.
|
| +bool RunTest(const cast_certificate::DeviceCertTest& test_case) {
|
| + std::unique_ptr<net::TrustStore> crl_trust_store;
|
| + std::unique_ptr<net::TrustStore> cast_trust_store;
|
| + if (test_case.use_test_trust_anchors()) {
|
| + crl_trust_store = cast_certificate::testing::CreateTrustStoreFromFile(
|
| + "certificates/cast_crl_test_root_ca.pem");
|
| + cast_trust_store = cast_certificate::testing::CreateTrustStoreFromFile(
|
| + "certificates/cast_test_root_ca.pem");
|
| +
|
| + EXPECT_TRUE(crl_trust_store.get());
|
| + EXPECT_TRUE(cast_trust_store.get());
|
| + }
|
| +
|
| + std::vector<std::string> certificate_chain;
|
| + for (auto const& cert : test_case.der_cert_path()) {
|
| + certificate_chain.push_back(cert);
|
| + }
|
| +
|
| + base::Time cert_verification_time =
|
| + cast_certificate::testing::ConvertUnixTimestampSeconds(
|
| + test_case.cert_verification_time_seconds());
|
| +
|
| + uint64_t crl_verify_time = test_case.crl_verification_time_seconds();
|
| + base::Time crl_verification_time =
|
| + cast_certificate::testing::ConvertUnixTimestampSeconds(crl_verify_time);
|
| + if (crl_verify_time == 0)
|
| + crl_verification_time = cert_verification_time;
|
| +
|
| + std::string crl_bundle = test_case.crl_bundle();
|
| + AuthResult result;
|
| + switch (test_case.expected_result()) {
|
| + case cast_certificate::PATH_VERIFICATION_FAILED:
|
| + result = TestVerifyRevocation(
|
| + certificate_chain, crl_bundle, crl_verification_time,
|
| + cert_verification_time, false, cast_trust_store.get(),
|
| + crl_trust_store.get());
|
| + EXPECT_EQ(result.error_type,
|
| + AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA);
|
| + return result.error_type ==
|
| + AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA;
|
| + break;
|
| + case cast_certificate::CRL_VERIFICATION_FAILED:
|
| + // Fall-through intended.
|
| + case cast_certificate::REVOCATION_CHECK_FAILED_WITHOUT_CRL:
|
| + result = TestVerifyRevocation(
|
| + certificate_chain, crl_bundle, crl_verification_time,
|
| + cert_verification_time, true, cast_trust_store.get(),
|
| + crl_trust_store.get());
|
| + EXPECT_EQ(result.error_type, AuthResult::ERROR_CRL_INVALID);
|
| + return result.error_type == AuthResult::ERROR_CRL_INVALID;
|
| + break;
|
| + case cast_certificate::REVOCATION_CHECK_FAILED:
|
| + result = TestVerifyRevocation(
|
| + certificate_chain, crl_bundle, crl_verification_time,
|
| + cert_verification_time, true, cast_trust_store.get(),
|
| + crl_trust_store.get());
|
| + EXPECT_EQ(result.error_type, AuthResult::ERROR_CERT_REVOKED);
|
| + return result.error_type == AuthResult::ERROR_CERT_REVOKED;
|
| + break;
|
| + case cast_certificate::SUCCESS:
|
| + result = TestVerifyRevocation(
|
| + certificate_chain, crl_bundle, crl_verification_time,
|
| + cert_verification_time, false, cast_trust_store.get(),
|
| + crl_trust_store.get());
|
| + EXPECT_EQ(result.error_type, AuthResult::ERROR_SIGNED_BLOBS_MISMATCH);
|
| + return result.error_type == AuthResult::ERROR_SIGNED_BLOBS_MISMATCH;
|
| + break;
|
| + case UNSPECIFIED:
|
| + return false;
|
| + break;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +// Parses the provided test suite provided in wire-format proto.
|
| +// Each test contains the inputs and the expected output.
|
| +// To see the description of the test, execute the test.
|
| +// These tests are generated by a test generator in google3.
|
| +void RunTestSuite(const std::string& test_suite_file_name) {
|
| + std::string testsuite_raw =
|
| + cast_certificate::testing::ReadTestFileToString(test_suite_file_name);
|
| + cast_certificate::DeviceCertTestSuite test_suite;
|
| + EXPECT_TRUE(test_suite.ParseFromString(testsuite_raw));
|
| + uint16_t success = 0;
|
| + uint16_t failed = 0;
|
| + std::vector<std::string> failed_tests;
|
| +
|
| + for (auto const& test_case : test_suite.tests()) {
|
| + LOG(INFO) << "[ RUN ] " << test_case.description();
|
| + bool result = RunTest(test_case);
|
| + EXPECT_TRUE(result);
|
| + if (!result) {
|
| + LOG(INFO) << "[ FAILED ] " << test_case.description();
|
| + ++failed;
|
| + failed_tests.push_back(test_case.description());
|
| + } else {
|
| + LOG(INFO) << "[ PASSED ] " << test_case.description();
|
| + ++success;
|
| + }
|
| + }
|
| + LOG(INFO) << "[ PASSED ] " << success << " test(s).";
|
| + if (failed) {
|
| + LOG(INFO) << "[ FAILED ] " << failed << " test(s), listed below:";
|
| + for (const auto& failed_test : failed_tests) {
|
| + LOG(INFO) << "[ FAILED ] " << failed_test;
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST_F(CastAuthUtilTest, CRLTestSuite) {
|
| + RunTestSuite("testsuite/testsuite1.pb");
|
| +}
|
| +
|
| } // namespace
|
| } // namespace cast_channel
|
| } // namespace api
|
|
|