• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 "cast/common/certificate/cast_crl.h"
6 
7 #include "cast/common/certificate/cast_cert_validator.h"
8 #include "cast/common/certificate/cast_cert_validator_internal.h"
9 #include "cast/common/certificate/proto/test_suite.pb.h"
10 #include "cast/common/certificate/testing/test_helpers.h"
11 #include "gtest/gtest.h"
12 #include "platform/test/paths.h"
13 #include "testing/util/read_file.h"
14 #include "util/osp_logging.h"
15 
16 namespace openscreen {
17 namespace cast {
18 
19 // TODO(crbug.com/openscreen/90): Remove these after Chromium is migrated to
20 // openscreen::cast
21 using DeviceCertTestSuite = ::cast::certificate::DeviceCertTestSuite;
22 using VerificationResult = ::cast::certificate::VerificationResult;
23 using DeviceCertTest = ::cast::certificate::DeviceCertTest;
24 
25 namespace {
26 
27 // Indicates the expected result of test step's verification.
28 enum TestStepResult {
29   kResultSuccess,
30   kResultFail,
31 };
32 
33 // Verifies that the provided certificate chain is valid at the specified time
34 // and chains up to a trust anchor.
TestVerifyCertificate(TestStepResult expected_result,const std::vector<std::string> & der_certs,const DateTime & time,TrustStore * cast_trust_store)35 bool TestVerifyCertificate(TestStepResult expected_result,
36                            const std::vector<std::string>& der_certs,
37                            const DateTime& time,
38                            TrustStore* cast_trust_store) {
39   std::unique_ptr<CertVerificationContext> context;
40   CastDeviceCertPolicy policy;
41   Error result = VerifyDeviceCert(der_certs, time, &context, &policy, nullptr,
42                                   CRLPolicy::kCrlOptional, cast_trust_store);
43   bool success = (result.code() == Error::Code::kNone) ==
44                  (expected_result == kResultSuccess);
45   EXPECT_TRUE(success);
46   return success;
47 }
48 
49 // Verifies that the provided Cast CRL is signed by a trusted issuer
50 // and that the CRL can be parsed successfully.
51 // The validity of the CRL is also checked at the specified time.
TestVerifyCRL(TestStepResult expected_result,const std::string & crl_bundle,const DateTime & time,TrustStore * crl_trust_store)52 bool TestVerifyCRL(TestStepResult expected_result,
53                    const std::string& crl_bundle,
54                    const DateTime& time,
55                    TrustStore* crl_trust_store) {
56   std::unique_ptr<CastCRL> crl =
57       ParseAndVerifyCRL(crl_bundle, time, crl_trust_store);
58 
59   bool success = (crl != nullptr) == (expected_result == kResultSuccess);
60   EXPECT_TRUE(success);
61   return success;
62 }
63 
64 // Verifies that the certificate chain provided is not revoked according to
65 // the provided Cast CRL at |cert_time|.
66 // The provided CRL is verified at |crl_time|.
67 // If |crl_required| is set, then a valid Cast CRL must be provided.
68 // Otherwise, a missing CRL is be ignored.
TestVerifyRevocation(Error::Code expected_result,const std::vector<std::string> & der_certs,const std::string & crl_bundle,const DateTime & crl_time,const DateTime & cert_time,bool crl_required,TrustStore * cast_trust_store,TrustStore * crl_trust_store)69 bool TestVerifyRevocation(Error::Code expected_result,
70                           const std::vector<std::string>& der_certs,
71                           const std::string& crl_bundle,
72                           const DateTime& crl_time,
73                           const DateTime& cert_time,
74                           bool crl_required,
75                           TrustStore* cast_trust_store,
76                           TrustStore* crl_trust_store) {
77   std::unique_ptr<CastCRL> crl;
78   if (!crl_bundle.empty()) {
79     crl = ParseAndVerifyCRL(crl_bundle, crl_time, crl_trust_store);
80     EXPECT_NE(crl.get(), nullptr);
81   }
82 
83   std::unique_ptr<CertVerificationContext> context;
84   CastDeviceCertPolicy policy;
85   CRLPolicy crl_policy =
86       crl_required ? CRLPolicy::kCrlRequired : CRLPolicy::kCrlOptional;
87   Error result = VerifyDeviceCert(der_certs, cert_time, &context, &policy,
88                                   crl.get(), crl_policy, cast_trust_store);
89   EXPECT_EQ(expected_result, result.code());
90   return expected_result == result.code();
91 }
92 
GetSpecificTestDataPath()93 const std::string& GetSpecificTestDataPath() {
94   static std::string data_path = GetTestDataPath() + "cast/common/certificate/";
95   return data_path;
96 }
97 
RunTest(const DeviceCertTest & test_case)98 bool RunTest(const DeviceCertTest& test_case) {
99   std::unique_ptr<TrustStore> crl_trust_store;
100   std::unique_ptr<TrustStore> cast_trust_store;
101   if (test_case.use_test_trust_anchors()) {
102     crl_trust_store = std::make_unique<TrustStore>();
103     cast_trust_store = std::make_unique<TrustStore>();
104     *crl_trust_store = TrustStore::CreateInstanceFromPemFile(
105         GetSpecificTestDataPath() + "certificates/cast_crl_test_root_ca.pem");
106     *cast_trust_store = TrustStore::CreateInstanceFromPemFile(
107         GetSpecificTestDataPath() + "certificates/cast_test_root_ca.pem");
108 
109     EXPECT_FALSE(crl_trust_store->certs.empty());
110     EXPECT_FALSE(cast_trust_store->certs.empty());
111   }
112 
113   std::vector<std::string> der_cert_path;
114   for (const auto& cert : test_case.der_cert_path()) {
115     der_cert_path.push_back(cert);
116   }
117 
118   DateTime cert_verification_time;
119   EXPECT_TRUE(DateTimeFromSeconds(test_case.cert_verification_time_seconds(),
120                                   &cert_verification_time));
121 
122   uint64_t crl_verify_time = test_case.crl_verification_time_seconds();
123   DateTime crl_verification_time;
124   EXPECT_TRUE(DateTimeFromSeconds(crl_verify_time, &crl_verification_time));
125   if (crl_verify_time == 0) {
126     crl_verification_time = cert_verification_time;
127   }
128 
129   std::string crl_bundle = test_case.crl_bundle();
130   switch (test_case.expected_result()) {
131     case ::cast::certificate::PATH_VERIFICATION_FAILED:
132       return TestVerifyCertificate(kResultFail, der_cert_path,
133                                    cert_verification_time,
134                                    cast_trust_store.get());
135     case ::cast::certificate::CRL_VERIFICATION_FAILED:
136       return TestVerifyCRL(kResultFail, crl_bundle, crl_verification_time,
137                            crl_trust_store.get());
138     case ::cast::certificate::REVOCATION_CHECK_FAILED_WITHOUT_CRL:
139       return TestVerifyCertificate(kResultSuccess, der_cert_path,
140                                    cert_verification_time,
141                                    cast_trust_store.get()) &&
142              TestVerifyCRL(kResultFail, crl_bundle, crl_verification_time,
143                            crl_trust_store.get()) &&
144              TestVerifyRevocation(
145                  Error::Code::kErrCrlInvalid, der_cert_path, crl_bundle,
146                  crl_verification_time, cert_verification_time, true,
147                  cast_trust_store.get(), crl_trust_store.get());
148     case ::cast::certificate::
149         CRL_EXPIRED_AFTER_INITIAL_VERIFICATION:  // fallthrough
150     case ::cast::certificate::REVOCATION_CHECK_FAILED:
151       return TestVerifyCertificate(kResultSuccess, der_cert_path,
152                                    cert_verification_time,
153                                    cast_trust_store.get()) &&
154              TestVerifyCRL(kResultSuccess, crl_bundle, crl_verification_time,
155                            crl_trust_store.get()) &&
156              TestVerifyRevocation(
157                  Error::Code::kErrCertsRevoked, der_cert_path, crl_bundle,
158                  crl_verification_time, cert_verification_time, true,
159                  cast_trust_store.get(), crl_trust_store.get());
160     case ::cast::certificate::SUCCESS:
161       return (crl_bundle.empty() ||
162               TestVerifyCRL(kResultSuccess, crl_bundle, crl_verification_time,
163                             crl_trust_store.get())) &&
164              TestVerifyCertificate(kResultSuccess, der_cert_path,
165                                    cert_verification_time,
166                                    cast_trust_store.get()) &&
167              TestVerifyRevocation(Error::Code::kNone, der_cert_path, crl_bundle,
168                                   crl_verification_time, cert_verification_time,
169                                   !crl_bundle.empty(), cast_trust_store.get(),
170                                   crl_trust_store.get());
171     case ::cast::certificate::UNSPECIFIED:
172       return false;
173   }
174   return false;
175 }
176 
177 // Parses the provided test suite provided in wire-format proto.
178 // Each test contains the inputs and the expected output.
179 // To see the description of the test, execute the test.
180 // These tests are generated by a test generator in google3.
RunTestSuite(const std::string & test_suite_file_name)181 void RunTestSuite(const std::string& test_suite_file_name) {
182   std::string testsuite_raw = ReadEntireFileToString(test_suite_file_name);
183   ASSERT_FALSE(testsuite_raw.empty());
184   DeviceCertTestSuite test_suite;
185   ASSERT_TRUE(test_suite.ParseFromString(testsuite_raw));
186   int successes = 0;
187 
188   for (auto const& test_case : test_suite.tests()) {
189     bool result = RunTest(test_case);
190     successes += result;
191     EXPECT_TRUE(result) << test_case.description();
192   }
193   OSP_LOG_IF(ERROR, successes != test_suite.tests().size())
194       << "successes: " << successes
195       << ", failures: " << (test_suite.tests().size() - successes);
196 }
197 
TEST(CastCertificateTest,TestSuite1)198 TEST(CastCertificateTest, TestSuite1) {
199   RunTestSuite(GetSpecificTestDataPath() + "testsuite/testsuite1.pb");
200 }
201 
202 }  // namespace
203 }  // namespace cast
204 }  // namespace openscreen
205