Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 "extensions/browser/api/cast_channel/cast_auth_util.h" | 5 #include "extensions/browser/api/cast_channel/cast_auth_util.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/macros.h" | 9 #include "base/macros.h" |
| 10 #include "base/time/time.h" | |
| 11 #include "components/cast_certificate/cast_cert_validator.h" | |
| 10 #include "components/cast_certificate/cast_cert_validator_test_helpers.h" | 12 #include "components/cast_certificate/cast_cert_validator_test_helpers.h" |
| 13 #include "components/cast_certificate/cast_crl.h" | |
| 14 #include "components/cast_certificate/proto/test_suite.pb.h" | |
| 11 #include "extensions/common/api/cast_channel/cast_channel.pb.h" | 15 #include "extensions/common/api/cast_channel/cast_channel.pb.h" |
| 16 #include "net/cert/internal/trust_store_in_memory.h" | |
| 12 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
| 13 | 18 |
| 14 namespace extensions { | 19 namespace extensions { |
| 15 namespace api { | 20 namespace api { |
| 16 namespace cast_channel { | 21 namespace cast_channel { |
| 17 namespace { | 22 namespace { |
| 18 | 23 |
| 19 class CastAuthUtilTest : public testing::Test { | 24 class CastAuthUtilTest : public testing::Test { |
| 20 public: | 25 public: |
| 21 CastAuthUtilTest() {} | 26 CastAuthUtilTest() {} |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 47 // Mangles a string by inverting the first byte. | 52 // Mangles a string by inverting the first byte. |
| 48 static void MangleString(std::string* str) { (*str)[0] = ~(*str)[0]; } | 53 static void MangleString(std::string* str) { (*str)[0] = ~(*str)[0]; } |
| 49 }; | 54 }; |
| 50 | 55 |
| 51 // Note on expiration: VerifyCredentials() depends on the system clock. In | 56 // Note on expiration: VerifyCredentials() depends on the system clock. In |
| 52 // practice this shouldn't be a problem though since the certificate chain | 57 // practice this shouldn't be a problem though since the certificate chain |
| 53 // being verified doesn't expire until 2032! | 58 // being verified doesn't expire until 2032! |
| 54 TEST_F(CastAuthUtilTest, VerifySuccess) { | 59 TEST_F(CastAuthUtilTest, VerifySuccess) { |
| 55 std::string signed_data; | 60 std::string signed_data; |
| 56 AuthResponse auth_response = CreateAuthResponse(&signed_data); | 61 AuthResponse auth_response = CreateAuthResponse(&signed_data); |
| 57 AuthResult result = VerifyCredentials(auth_response, signed_data); | 62 base::Time now = base::Time::Now(); |
| 63 AuthResult result = VerifyCredentialsForTest( | |
| 64 auth_response, signed_data, cast_certificate::CRLPolicy::CRL_OPTIONAL, | |
| 65 nullptr, nullptr, now, now); | |
| 58 EXPECT_TRUE(result.success()); | 66 EXPECT_TRUE(result.success()); |
| 59 EXPECT_EQ(AuthResult::POLICY_NONE, result.channel_policies); | 67 EXPECT_EQ(AuthResult::POLICY_NONE, result.channel_policies); |
| 60 } | 68 } |
| 61 | 69 |
| 62 TEST_F(CastAuthUtilTest, VerifyBadCA) { | 70 TEST_F(CastAuthUtilTest, VerifyBadCA) { |
| 63 std::string signed_data; | 71 std::string signed_data; |
| 64 AuthResponse auth_response = CreateAuthResponse(&signed_data); | 72 AuthResponse auth_response = CreateAuthResponse(&signed_data); |
| 65 MangleString(auth_response.mutable_intermediate_certificate(0)); | 73 MangleString(auth_response.mutable_intermediate_certificate(0)); |
| 66 AuthResult result = VerifyCredentials(auth_response, signed_data); | 74 AuthResult result = VerifyCredentials(auth_response, signed_data); |
| 67 EXPECT_FALSE(result.success()); | 75 EXPECT_FALSE(result.success()); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 89 | 97 |
| 90 TEST_F(CastAuthUtilTest, VerifyBadPeerCert) { | 98 TEST_F(CastAuthUtilTest, VerifyBadPeerCert) { |
| 91 std::string signed_data; | 99 std::string signed_data; |
| 92 AuthResponse auth_response = CreateAuthResponse(&signed_data); | 100 AuthResponse auth_response = CreateAuthResponse(&signed_data); |
| 93 MangleString(&signed_data); | 101 MangleString(&signed_data); |
| 94 AuthResult result = VerifyCredentials(auth_response, signed_data); | 102 AuthResult result = VerifyCredentials(auth_response, signed_data); |
| 95 EXPECT_FALSE(result.success()); | 103 EXPECT_FALSE(result.success()); |
| 96 EXPECT_EQ(AuthResult::ERROR_SIGNED_BLOBS_MISMATCH, result.error_type); | 104 EXPECT_EQ(AuthResult::ERROR_SIGNED_BLOBS_MISMATCH, result.error_type); |
| 97 } | 105 } |
| 98 | 106 |
| 107 // Indicates the expected result of test step's verification. | |
| 108 enum TestStepResult { | |
| 109 RESULT_SUCCESS, | |
| 110 RESULT_FAIL, | |
| 111 }; | |
| 112 | |
| 113 // Verifies that the certificate chain provided is not revoked according to | |
| 114 // the provided Cast CRL at |cert_time|. | |
| 115 // The provided CRL is verified at |crl_time|. | |
| 116 // If |crl_required| is set, then a valid Cast CRL must be provided. | |
| 117 // Otherwise, a missing CRL is be ignored. | |
| 118 AuthResult TestVerifyRevocation( | |
| 119 const std::vector<std::string>& certificate_chain, | |
| 120 const std::string& crl_bundle, | |
| 121 const base::Time& crl_time, | |
| 122 const base::Time& cert_time, | |
| 123 bool crl_required, | |
| 124 net::TrustStore* cast_trust_store, | |
| 125 net::TrustStore* crl_trust_store) { | |
| 126 AuthResponse response; | |
| 127 | |
| 128 if (certificate_chain.size() > 0) { | |
| 129 response.set_client_auth_certificate(certificate_chain[0]); | |
| 130 for (size_t i = 1; i < certificate_chain.size(); ++i) | |
| 131 response.add_intermediate_certificate(certificate_chain[i]); | |
| 132 } | |
| 133 | |
| 134 response.set_crl(crl_bundle); | |
| 135 | |
| 136 cast_certificate::CRLPolicy crl_policy = | |
| 137 cast_certificate::CRLPolicy::CRL_REQUIRED; | |
| 138 if (!crl_required && crl_bundle.empty()) | |
| 139 crl_policy = cast_certificate::CRLPolicy::CRL_OPTIONAL; | |
| 140 AuthResult result = | |
| 141 VerifyCredentialsForTest(response, "", crl_policy, cast_trust_store, | |
| 142 crl_trust_store, cert_time, crl_time); | |
| 143 // This test doesn't set the signature so it will just fail there. | |
| 144 EXPECT_FALSE(result.success()); | |
| 145 return result; | |
| 146 } | |
| 147 | |
| 148 // Runs a single test case. | |
| 149 bool RunTest(const cast_certificate::DeviceCertTest& test_case) { | |
| 150 std::unique_ptr<net::TrustStore> crl_trust_store; | |
| 151 std::unique_ptr<net::TrustStore> cast_trust_store; | |
| 152 if (test_case.use_test_trust_anchors()) { | |
| 153 crl_trust_store = cast_certificate::testing::CreateTrustStoreFromFile( | |
| 154 "certificates/cast_crl_test_root_ca.pem"); | |
| 155 cast_trust_store = cast_certificate::testing::CreateTrustStoreFromFile( | |
| 156 "certificates/cast_test_root_ca.pem"); | |
| 157 | |
| 158 EXPECT_TRUE(crl_trust_store.get()); | |
| 159 EXPECT_TRUE(cast_trust_store.get()); | |
| 160 } | |
| 161 | |
| 162 std::vector<std::string> certificate_chain; | |
| 163 for (auto const& cert : test_case.der_cert_path()) { | |
| 164 certificate_chain.push_back(cert); | |
| 165 } | |
| 166 | |
| 167 base::Time cert_verification_time = | |
| 168 cast_certificate::testing::ConvertUnixTimestampSeconds( | |
| 169 test_case.cert_verification_time_seconds()); | |
| 170 | |
| 171 uint64_t crl_verify_time = test_case.crl_verification_time_seconds(); | |
| 172 base::Time crl_verification_time = | |
| 173 cast_certificate::testing::ConvertUnixTimestampSeconds(crl_verify_time); | |
| 174 if (crl_verify_time == 0) | |
| 175 crl_verification_time = cert_verification_time; | |
| 176 | |
| 177 std::string crl_bundle = test_case.crl_bundle(); | |
| 178 AuthResult result; | |
| 179 switch (test_case.expected_result()) { | |
| 180 case cast_certificate::PATH_VERIFICATION_FAILED: | |
| 181 result = TestVerifyRevocation( | |
| 182 certificate_chain, crl_bundle, crl_verification_time, | |
| 183 cert_verification_time, false, cast_trust_store.get(), | |
| 184 crl_trust_store.get()); | |
| 185 EXPECT_EQ(result.error_type, | |
| 186 AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA); | |
| 187 return result.error_type == | |
| 188 AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA; | |
| 189 break; | |
|
eroman
2016/09/22 22:02:51
nit: I suggest omitting the break when there is al
ryanchung
2016/09/22 22:43:35
Done. Removed breaks here and in cast_crl_unittest
| |
| 190 case cast_certificate::CRL_VERIFICATION_FAILED: | |
| 191 // Fall-through intended. | |
| 192 case cast_certificate::REVOCATION_CHECK_FAILED_WITHOUT_CRL: | |
| 193 result = TestVerifyRevocation( | |
| 194 certificate_chain, crl_bundle, crl_verification_time, | |
| 195 cert_verification_time, true, cast_trust_store.get(), | |
| 196 crl_trust_store.get()); | |
| 197 EXPECT_EQ(result.error_type, AuthResult::ERROR_CRL_INVALID); | |
| 198 return result.error_type == AuthResult::ERROR_CRL_INVALID; | |
| 199 break; | |
| 200 case cast_certificate::REVOCATION_CHECK_FAILED: | |
| 201 result = TestVerifyRevocation( | |
| 202 certificate_chain, crl_bundle, crl_verification_time, | |
| 203 cert_verification_time, true, cast_trust_store.get(), | |
| 204 crl_trust_store.get()); | |
| 205 EXPECT_EQ(result.error_type, AuthResult::ERROR_CERT_REVOKED); | |
| 206 return result.error_type == AuthResult::ERROR_CERT_REVOKED; | |
| 207 break; | |
| 208 case cast_certificate::SUCCESS: | |
| 209 result = TestVerifyRevocation( | |
| 210 certificate_chain, crl_bundle, crl_verification_time, | |
| 211 cert_verification_time, false, cast_trust_store.get(), | |
| 212 crl_trust_store.get()); | |
| 213 EXPECT_EQ(result.error_type, AuthResult::ERROR_SIGNED_BLOBS_MISMATCH); | |
| 214 return result.error_type == AuthResult::ERROR_SIGNED_BLOBS_MISMATCH; | |
| 215 break; | |
| 216 case UNSPECIFIED: | |
| 217 return false; | |
| 218 break; | |
| 219 } | |
| 220 return false; | |
| 221 } | |
| 222 | |
| 223 // Parses the provided test suite provided in wire-format proto. | |
| 224 // Each test contains the inputs and the expected output. | |
| 225 // To see the description of the test, execute the test. | |
| 226 // These tests are generated by a test generator in google3. | |
| 227 void RunTestSuite(const std::string& test_suite_file_name) { | |
| 228 std::string testsuite_raw = | |
| 229 cast_certificate::testing::ReadTestFileToString(test_suite_file_name); | |
| 230 cast_certificate::DeviceCertTestSuite test_suite; | |
| 231 EXPECT_TRUE(test_suite.ParseFromString(testsuite_raw)); | |
| 232 uint16_t success = 0; | |
| 233 uint16_t failed = 0; | |
| 234 std::vector<std::string> failed_tests; | |
| 235 | |
| 236 for (auto const& test_case : test_suite.tests()) { | |
| 237 LOG(INFO) << "[ RUN ] " << test_case.description(); | |
| 238 bool result = RunTest(test_case); | |
| 239 EXPECT_TRUE(result); | |
| 240 if (!result) { | |
| 241 LOG(INFO) << "[ FAILED ] " << test_case.description(); | |
| 242 ++failed; | |
| 243 failed_tests.push_back(test_case.description()); | |
| 244 } else { | |
| 245 LOG(INFO) << "[ PASSED ] " << test_case.description(); | |
| 246 ++success; | |
| 247 } | |
| 248 } | |
| 249 LOG(INFO) << "[ PASSED ] " << success << " test(s)."; | |
| 250 if (failed) { | |
| 251 LOG(INFO) << "[ FAILED ] " << failed << " test(s), listed below:"; | |
| 252 for (const auto& failed_test : failed_tests) { | |
| 253 LOG(INFO) << "[ FAILED ] " << failed_test; | |
| 254 } | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 TEST_F(CastAuthUtilTest, CRLTestSuite) { | |
| 259 RunTestSuite("testsuite/testsuite1.pb"); | |
| 260 } | |
| 261 | |
| 99 } // namespace | 262 } // namespace |
| 100 } // namespace cast_channel | 263 } // namespace cast_channel |
| 101 } // namespace api | 264 } // namespace api |
| 102 } // namespace extensions | 265 } // namespace extensions |
| OLD | NEW |