1 // Copyright 2014 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.
5 #include "components/cast_channel/cast_auth_util.h"
9 #include "base/logging.h"
10 #include "base/macros.h"
11 #include "base/test/scoped_feature_list.h"
12 #include "base/time/time.h"
13 #include "components/cast_certificate/cast_cert_validator.h"
14 #include "components/cast_certificate/cast_cert_validator_test_helpers.h"
15 #include "components/cast_certificate/cast_crl.h"
16 #include "components/cast_certificate/proto/test_suite.pb.h"
17 #include "components/cast_channel/proto/cast_channel.pb.h"
18 #include "net/cert/internal/trust_store_in_memory.h"
19 #include "net/cert/x509_certificate.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 namespace cast_channel {
25 class CastAuthUtilTest : public testing::Test {
28 ~CastAuthUtilTest() override {}
30 void SetUp() override {}
33 static AuthResponse CreateAuthResponse(std::string* signed_data,
34 HashAlgorithm digest_algorithm) {
35 auto chain = cast_certificate::testing::ReadCertificateChainFromFile(
36 "certificates/chromecast_gen1.pem");
37 CHECK(!chain.empty());
39 auto signature_data = cast_certificate::testing::ReadSignatureTestData(
40 "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
42 AuthResponse response;
44 response.set_client_auth_certificate(chain[0]);
45 for (size_t i = 1; i < chain.size(); ++i)
46 response.add_intermediate_certificate(chain[i]);
48 response.set_hash_algorithm(digest_algorithm);
49 switch (digest_algorithm) {
51 response.set_signature(signature_data.signature_sha1);
54 response.set_signature(signature_data.signature_sha256);
57 *signed_data = signature_data.message;
62 // Mangles a string by inverting the first byte.
63 static void MangleString(std::string* str) { (*str)[0] = ~(*str)[0]; }
66 // Note on expiration: VerifyCredentials() depends on the system clock. In
67 // practice this shouldn't be a problem though since the certificate chain
68 // being verified doesn't expire until 2032!
69 TEST_F(CastAuthUtilTest, VerifySuccess) {
70 std::string signed_data;
71 AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA256);
72 base::Time now = base::Time::Now();
73 AuthResult result = VerifyCredentialsForTest(
74 auth_response, signed_data, cast_certificate::CRLPolicy::CRL_OPTIONAL,
75 nullptr, nullptr, now);
76 EXPECT_TRUE(result.success());
77 EXPECT_EQ(static_cast<unsigned>(AuthResult::POLICY_NONE),
78 result.channel_policies);
81 TEST_F(CastAuthUtilTest, VerifyBadCA) {
82 std::string signed_data;
83 AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA256);
84 MangleString(auth_response.mutable_intermediate_certificate(0));
85 AuthResult result = VerifyCredentials(auth_response, signed_data);
86 EXPECT_FALSE(result.success());
87 EXPECT_EQ(AuthResult::ERROR_CERT_PARSING_FAILED, result.error_type);
90 TEST_F(CastAuthUtilTest, VerifyBadClientAuthCert) {
91 std::string signed_data;
92 AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA256);
93 MangleString(auth_response.mutable_client_auth_certificate());
94 AuthResult result = VerifyCredentials(auth_response, signed_data);
95 EXPECT_FALSE(result.success());
96 // TODO(eroman): Not quite right of an error.
97 EXPECT_EQ(AuthResult::ERROR_CERT_PARSING_FAILED, result.error_type);
100 TEST_F(CastAuthUtilTest, VerifyBadSignature) {
101 std::string signed_data;
102 AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA256);
103 MangleString(auth_response.mutable_signature());
104 AuthResult result = VerifyCredentials(auth_response, signed_data);
105 EXPECT_FALSE(result.success());
106 EXPECT_EQ(AuthResult::ERROR_SIGNED_BLOBS_MISMATCH, result.error_type);
109 TEST_F(CastAuthUtilTest, VerifyEmptySignature) {
110 std::string signed_data;
111 AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA256);
112 auth_response.mutable_signature()->clear();
113 AuthResult result = VerifyCredentials(auth_response, signed_data);
114 EXPECT_FALSE(result.success());
115 EXPECT_EQ(AuthResult::ERROR_SIGNATURE_EMPTY, result.error_type);
118 TEST_F(CastAuthUtilTest, VerifyUnsupportedDigest) {
119 base::test::ScopedFeatureList scoped_feature_list;
120 scoped_feature_list.InitAndEnableFeature(
121 base::Feature{"CastSHA256Enforced", base::FEATURE_DISABLED_BY_DEFAULT});
122 std::string signed_data;
123 AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA1);
124 base::Time now = base::Time::Now();
125 AuthResult result = VerifyCredentialsForTest(
126 auth_response, signed_data, cast_certificate::CRLPolicy::CRL_OPTIONAL,
127 nullptr, nullptr, now);
128 EXPECT_FALSE(result.success());
129 EXPECT_EQ(AuthResult::ERROR_DIGEST_UNSUPPORTED, result.error_type);
132 TEST_F(CastAuthUtilTest, VerifyBackwardsCompatibleDigest) {
133 std::string signed_data;
134 AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA1);
135 base::Time now = base::Time::Now();
136 AuthResult result = VerifyCredentialsForTest(
137 auth_response, signed_data, cast_certificate::CRLPolicy::CRL_OPTIONAL,
138 nullptr, nullptr, now);
139 EXPECT_TRUE(result.success());
142 TEST_F(CastAuthUtilTest, VerifyBadPeerCert) {
143 std::string signed_data;
144 AuthResponse auth_response = CreateAuthResponse(&signed_data, SHA256);
145 MangleString(&signed_data);
146 AuthResult result = VerifyCredentials(auth_response, signed_data);
147 EXPECT_FALSE(result.success());
148 EXPECT_EQ(AuthResult::ERROR_SIGNED_BLOBS_MISMATCH, result.error_type);
151 TEST_F(CastAuthUtilTest, VerifySenderNonceMatch) {
152 base::test::ScopedFeatureList scoped_feature_list;
153 scoped_feature_list.InitAndEnableFeature(
154 base::Feature{"CastNonceEnforced", base::FEATURE_DISABLED_BY_DEFAULT});
155 AuthContext context = AuthContext::Create();
156 AuthResult result = context.VerifySenderNonce(context.nonce());
157 EXPECT_TRUE(result.success());
160 TEST_F(CastAuthUtilTest, VerifySenderNonceMismatch) {
161 base::test::ScopedFeatureList scoped_feature_list;
162 scoped_feature_list.InitAndEnableFeature(
163 base::Feature{"CastNonceEnforced", base::FEATURE_DISABLED_BY_DEFAULT});
164 AuthContext context = AuthContext::Create();
165 std::string received_nonce = "test2";
166 EXPECT_NE(received_nonce, context.nonce());
167 AuthResult result = context.VerifySenderNonce(received_nonce);
168 EXPECT_FALSE(result.success());
169 EXPECT_EQ(AuthResult::ERROR_SENDER_NONCE_MISMATCH, result.error_type);
172 TEST_F(CastAuthUtilTest, VerifySenderNonceMissing) {
173 base::test::ScopedFeatureList scoped_feature_list;
174 scoped_feature_list.InitAndEnableFeature(
175 base::Feature{"CastNonceEnforced", base::FEATURE_DISABLED_BY_DEFAULT});
176 AuthContext context = AuthContext::Create();
177 std::string received_nonce;
178 EXPECT_FALSE(context.nonce().empty());
179 AuthResult result = context.VerifySenderNonce(received_nonce);
180 EXPECT_FALSE(result.success());
181 EXPECT_EQ(AuthResult::ERROR_SENDER_NONCE_MISMATCH, result.error_type);
184 TEST_F(CastAuthUtilTest, VerifyTLSCertificateSuccess) {
185 auto tls_cert_der = cast_certificate::testing::ReadCertificateChainFromFile(
186 "certificates/test_tls_cert.pem");
188 scoped_refptr<net::X509Certificate> tls_cert =
189 net::X509Certificate::CreateFromBytes(tls_cert_der[0].data(),
190 tls_cert_der[0].size());
191 std::string peer_cert_der;
193 VerifyTLSCertificate(*tls_cert, &peer_cert_der, tls_cert->valid_start());
194 EXPECT_TRUE(result.success());
197 TEST_F(CastAuthUtilTest, VerifyTLSCertificateTooEarly) {
198 auto tls_cert_der = cast_certificate::testing::ReadCertificateChainFromFile(
199 "certificates/test_tls_cert.pem");
201 scoped_refptr<net::X509Certificate> tls_cert =
202 net::X509Certificate::CreateFromBytes(tls_cert_der[0].data(),
203 tls_cert_der[0].size());
204 std::string peer_cert_der;
205 AuthResult result = VerifyTLSCertificate(
206 *tls_cert, &peer_cert_der,
207 tls_cert->valid_start() - base::TimeDelta::FromSeconds(1));
208 EXPECT_FALSE(result.success());
209 EXPECT_EQ(AuthResult::ERROR_TLS_CERT_VALID_START_DATE_IN_FUTURE,
213 TEST_F(CastAuthUtilTest, VerifyTLSCertificateTooLate) {
214 auto tls_cert_der = cast_certificate::testing::ReadCertificateChainFromFile(
215 "certificates/test_tls_cert.pem");
217 scoped_refptr<net::X509Certificate> tls_cert =
218 net::X509Certificate::CreateFromBytes(tls_cert_der[0].data(),
219 tls_cert_der[0].size());
220 std::string peer_cert_der;
221 AuthResult result = VerifyTLSCertificate(
222 *tls_cert, &peer_cert_der,
223 tls_cert->valid_expiry() + base::TimeDelta::FromSeconds(2));
224 EXPECT_FALSE(result.success());
225 EXPECT_EQ(AuthResult::ERROR_TLS_CERT_EXPIRED, result.error_type);
228 // Indicates the expected result of test step's verification.
229 enum TestStepResult {
234 // Verifies that the certificate chain provided is not revoked according to
235 // the provided Cast CRL at |verification_time|.
236 // The provided CRL is verified at |verification_time|.
237 // If |crl_required| is set, then a valid Cast CRL must be provided.
238 // Otherwise, a missing CRL is be ignored.
239 AuthResult TestVerifyRevocation(
240 const std::vector<std::string>& certificate_chain,
241 const std::string& crl_bundle,
242 const base::Time& verification_time,
244 net::TrustStore* cast_trust_store,
245 net::TrustStore* crl_trust_store) {
246 AuthResponse response;
248 if (certificate_chain.size() > 0) {
249 response.set_client_auth_certificate(certificate_chain[0]);
250 for (size_t i = 1; i < certificate_chain.size(); ++i)
251 response.add_intermediate_certificate(certificate_chain[i]);
254 response.set_crl(crl_bundle);
256 cast_certificate::CRLPolicy crl_policy =
257 cast_certificate::CRLPolicy::CRL_REQUIRED;
258 if (!crl_required && crl_bundle.empty())
259 crl_policy = cast_certificate::CRLPolicy::CRL_OPTIONAL;
261 VerifyCredentialsForTest(response, "", crl_policy, cast_trust_store,
262 crl_trust_store, verification_time);
263 // This test doesn't set the signature so it will just fail there.
264 EXPECT_FALSE(result.success());
268 // Runs a single test case.
269 bool RunTest(const cast_certificate::DeviceCertTest& test_case) {
270 std::unique_ptr<net::TrustStore> crl_trust_store;
271 std::unique_ptr<net::TrustStore> cast_trust_store;
272 if (test_case.use_test_trust_anchors()) {
273 crl_trust_store = cast_certificate::testing::CreateTrustStoreFromFile(
274 "certificates/cast_crl_test_root_ca.pem");
275 cast_trust_store = cast_certificate::testing::CreateTrustStoreFromFile(
276 "certificates/cast_test_root_ca.pem");
278 EXPECT_TRUE(crl_trust_store.get());
279 EXPECT_TRUE(cast_trust_store.get());
282 std::vector<std::string> certificate_chain;
283 for (auto const& cert : test_case.der_cert_path()) {
284 certificate_chain.push_back(cert);
287 // CastAuthUtil verifies the CRL at the same time as the certificate.
288 base::Time verification_time;
289 uint64_t cert_verify_time = test_case.cert_verification_time_seconds();
290 if (cert_verify_time) {
291 verification_time = cast_certificate::testing::ConvertUnixTimestampSeconds(
294 verification_time = cast_certificate::testing::ConvertUnixTimestampSeconds(
295 test_case.crl_verification_time_seconds());
298 std::string crl_bundle = test_case.crl_bundle();
300 switch (test_case.expected_result()) {
301 case cast_certificate::PATH_VERIFICATION_FAILED:
302 result = TestVerifyRevocation(
303 certificate_chain, crl_bundle, verification_time, false,
304 cast_trust_store.get(), crl_trust_store.get());
305 EXPECT_EQ(result.error_type,
306 AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA);
307 return result.error_type ==
308 AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA;
309 case cast_certificate::CRL_VERIFICATION_FAILED:
310 // Fall-through intended.
311 case cast_certificate::REVOCATION_CHECK_FAILED_WITHOUT_CRL:
312 result = TestVerifyRevocation(
313 certificate_chain, crl_bundle, verification_time, true,
314 cast_trust_store.get(), crl_trust_store.get());
315 EXPECT_EQ(result.error_type, AuthResult::ERROR_CRL_INVALID);
316 return result.error_type == AuthResult::ERROR_CRL_INVALID;
317 case cast_certificate::CRL_EXPIRED_AFTER_INITIAL_VERIFICATION:
318 // By-pass this test because CRL is always verified at the time the
319 // certificate is verified.
321 case cast_certificate::REVOCATION_CHECK_FAILED:
322 result = TestVerifyRevocation(
323 certificate_chain, crl_bundle, verification_time, true,
324 cast_trust_store.get(), crl_trust_store.get());
325 EXPECT_EQ(result.error_type, AuthResult::ERROR_CERT_REVOKED);
326 return result.error_type == AuthResult::ERROR_CERT_REVOKED;
327 case cast_certificate::SUCCESS:
328 result = TestVerifyRevocation(
329 certificate_chain, crl_bundle, verification_time, false,
330 cast_trust_store.get(), crl_trust_store.get());
331 EXPECT_EQ(result.error_type, AuthResult::ERROR_SIGNED_BLOBS_MISMATCH);
332 return result.error_type == AuthResult::ERROR_SIGNED_BLOBS_MISMATCH;
333 case cast_certificate::UNSPECIFIED:
339 // Parses the provided test suite provided in wire-format proto.
340 // Each test contains the inputs and the expected output.
341 // To see the description of the test, execute the test.
342 // These tests are generated by a test generator in google3.
343 void RunTestSuite(const std::string& test_suite_file_name) {
344 std::string testsuite_raw =
345 cast_certificate::testing::ReadTestFileToString(test_suite_file_name);
346 cast_certificate::DeviceCertTestSuite test_suite;
347 EXPECT_TRUE(test_suite.ParseFromString(testsuite_raw));
348 uint16_t success = 0;
350 std::vector<std::string> failed_tests;
352 for (auto const& test_case : test_suite.tests()) {
353 LOG(INFO) << "[ RUN ] " << test_case.description();
354 bool result = RunTest(test_case);
357 LOG(INFO) << "[ FAILED ] " << test_case.description();
359 failed_tests.push_back(test_case.description());
361 LOG(INFO) << "[ PASSED ] " << test_case.description();
365 LOG(INFO) << "[ PASSED ] " << success << " test(s).";
367 LOG(INFO) << "[ FAILED ] " << failed << " test(s), listed below:";
368 for (const auto& failed_test : failed_tests) {
369 LOG(INFO) << "[ FAILED ] " << failed_test;
374 TEST_F(CastAuthUtilTest, CRLTestSuite) {
375 RunTestSuite("testsuite/testsuite1.pb");
379 } // namespace cast_channel