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; |
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
|
+ 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 |