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/sender/channel/cast_auth_util.h"
6 
7 #include <string>
8 
9 #include "cast/common/certificate/cast_cert_validator.h"
10 #include "cast/common/certificate/cast_crl.h"
11 #include "cast/common/certificate/proto/test_suite.pb.h"
12 #include "cast/common/certificate/testing/test_helpers.h"
13 #include "cast/common/channel/proto/cast_channel.pb.h"
14 #include "gtest/gtest.h"
15 #include "platform/api/time.h"
16 #include "testing/util/read_file.h"
17 #include "util/logging.h"
18 
19 namespace openscreen {
20 namespace cast {
21 
22 // TODO(crbug.com/openscreen/90): Remove these after Chromium is migrated to
23 // openscreen::cast
24 using DeviceCertTestSuite = ::cast::certificate::DeviceCertTestSuite;
25 using VerificationResult = ::cast::certificate::VerificationResult;
26 using DeviceCertTest = ::cast::certificate::DeviceCertTest;
27 
28 namespace {
29 
30 using ::cast::channel::AuthResponse;
31 
ConvertTimeSeconds(const DateTime & time,uint64_t * seconds)32 bool ConvertTimeSeconds(const DateTime& time, uint64_t* seconds) {
33   static constexpr uint64_t kDaysPerYear = 365;
34   static constexpr uint64_t kHoursPerDay = 24;
35   static constexpr uint64_t kMinutesPerHour = 60;
36   static constexpr uint64_t kSecondsPerMinute = 60;
37 
38   static constexpr uint64_t kSecondsPerDay =
39       kSecondsPerMinute * kMinutesPerHour * kHoursPerDay;
40   static constexpr uint64_t kDaysPerQuadYear = 4 * kDaysPerYear + 1;
41   static constexpr uint64_t kDaysPerCentury =
42       kDaysPerQuadYear * 24 + kDaysPerYear * 4;
43   static constexpr uint64_t kDaysPerQuadCentury = 4 * kDaysPerCentury + 1;
44 
45   static constexpr uint64_t kDaysPerMonth[] = {
46       31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
47   };
48 
49   bool is_leap_year =
50       (time.year % 4 == 0 && (time.year % 100 != 0 || time.year % 400 == 0));
51   if (time.year < 1970 || time.month < 1 || time.day < 1 ||
52       time.day > (kDaysPerMonth[time.month - 1] + is_leap_year) ||
53       time.month > 12 || time.hour > 23 || time.minute > 59 ||
54       time.second > 60) {
55     return false;
56   }
57   uint64_t result = 0;
58   uint64_t year = time.year - 1970;
59   uint64_t first_two_years = year >= 2;
60   result += first_two_years * 2 * kDaysPerYear * kSecondsPerDay;
61   year -= first_two_years * 2;
62 
63   if (first_two_years) {
64     uint64_t twenty_eight_years = year >= 28;
65     result += twenty_eight_years * 7 * kDaysPerQuadYear * kSecondsPerDay;
66     year -= twenty_eight_years * 28;
67 
68     if (twenty_eight_years) {
69       uint64_t quad_centuries = year / 400;
70       result += quad_centuries * kDaysPerQuadCentury * kSecondsPerDay;
71       year -= quad_centuries * 400;
72 
73       uint64_t first_century = year >= 100;
74       result += first_century * (kDaysPerCentury + 1) * kSecondsPerDay;
75       year -= first_century * 100;
76 
77       uint64_t centuries = year / 100;
78       result += centuries * kDaysPerCentury * kSecondsPerDay;
79       year -= centuries * 100;
80     }
81 
82     uint64_t quad_years = year / 4;
83     result += quad_years * kDaysPerQuadYear * kSecondsPerDay;
84     year -= quad_years * 4;
85 
86     uint64_t first_year = year >= 1;
87     result += first_year * (kDaysPerYear + 1) * kSecondsPerDay;
88     year -= first_year;
89 
90     result += year * kDaysPerYear * kSecondsPerDay;
91     OSP_DCHECK_LE(year, 2);
92   }
93 
94   for (int i = 0; i < time.month - 1; ++i) {
95     uint64_t days = kDaysPerMonth[i];
96     result += days * kSecondsPerDay;
97   }
98   if (time.month >= 3 && is_leap_year) {
99     result += kSecondsPerDay;
100   }
101   result += (time.day - 1) * kSecondsPerDay;
102   result += time.hour * kMinutesPerHour * kSecondsPerMinute;
103   result += time.minute * kSecondsPerMinute;
104   result += time.second;
105 
106   *seconds = result;
107   return true;
108 }
109 
110 #define TEST_DATA_PREFIX OPENSCREEN_TEST_DATA_DIR "cast/common/certificate/"
111 
112 class CastAuthUtilTest : public ::testing::Test {
113  public:
CastAuthUtilTest()114   CastAuthUtilTest() {}
~CastAuthUtilTest()115   ~CastAuthUtilTest() override {}
116 
SetUp()117   void SetUp() override {}
118 
119  protected:
CreateAuthResponse(std::vector<uint8_t> * signed_data,::cast::channel::HashAlgorithm digest_algorithm)120   static AuthResponse CreateAuthResponse(
121       std::vector<uint8_t>* signed_data,
122       ::cast::channel::HashAlgorithm digest_algorithm) {
123     std::vector<std::string> chain = testing::ReadCertificatesFromPemFile(
124         TEST_DATA_PREFIX "certificates/chromecast_gen1.pem");
125     OSP_CHECK(!chain.empty());
126 
127     testing::SignatureTestData signatures = testing::ReadSignatureTestData(
128         TEST_DATA_PREFIX "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
129 
130     AuthResponse response;
131 
132     response.set_client_auth_certificate(chain[0]);
133     for (size_t i = 1; i < chain.size(); ++i) {
134       response.add_intermediate_certificate(chain[i]);
135     }
136 
137     response.set_hash_algorithm(digest_algorithm);
138     switch (digest_algorithm) {
139       case ::cast::channel::SHA1:
140         response.set_signature(
141             std::string(reinterpret_cast<const char*>(signatures.sha1.data),
142                         signatures.sha1.length));
143         break;
144       case ::cast::channel::SHA256:
145         response.set_signature(
146             std::string(reinterpret_cast<const char*>(signatures.sha256.data),
147                         signatures.sha256.length));
148         break;
149     }
150     *signed_data = std::vector<uint8_t>(
151         signatures.message.data,
152         signatures.message.data + signatures.message.length);
153 
154     return response;
155   }
156 
157   // Mangles a string by inverting the first byte.
MangleString(std::string * str)158   static void MangleString(std::string* str) { (*str)[0] = ~(*str)[0]; }
159 
160   // Mangles a vector by inverting the first byte.
MangleData(std::vector<uint8_t> * data)161   static void MangleData(std::vector<uint8_t>* data) {
162     (*data)[0] = ~(*data)[0];
163   }
164 };
165 
166 // Note on expiration: VerifyCredentials() depends on the system clock. In
167 // practice this shouldn't be a problem though since the certificate chain
168 // being verified doesn't expire until 2032.
TEST_F(CastAuthUtilTest,VerifySuccess)169 TEST_F(CastAuthUtilTest, VerifySuccess) {
170   std::vector<uint8_t> signed_data;
171   AuthResponse auth_response =
172       CreateAuthResponse(&signed_data, ::cast::channel::SHA256);
173   DateTime now = {};
174   ASSERT_TRUE(DateTimeFromSeconds(GetWallTimeSinceUnixEpoch().count(), &now));
175   ErrorOr<CastDeviceCertPolicy> result =
176       VerifyCredentialsForTest(auth_response, signed_data,
177                                CRLPolicy::kCrlOptional, nullptr, nullptr, now);
178   EXPECT_TRUE(result);
179   EXPECT_EQ(CastDeviceCertPolicy::kUnrestricted, result.value());
180 }
181 
TEST_F(CastAuthUtilTest,VerifyBadCA)182 TEST_F(CastAuthUtilTest, VerifyBadCA) {
183   std::vector<uint8_t> signed_data;
184   AuthResponse auth_response =
185       CreateAuthResponse(&signed_data, ::cast::channel::SHA256);
186   MangleString(auth_response.mutable_intermediate_certificate(0));
187   ErrorOr<CastDeviceCertPolicy> result =
188       VerifyCredentials(auth_response, signed_data);
189   EXPECT_FALSE(result);
190   EXPECT_EQ(Error::Code::kErrCertsParse, result.error().code());
191 }
192 
TEST_F(CastAuthUtilTest,VerifyBadClientAuthCert)193 TEST_F(CastAuthUtilTest, VerifyBadClientAuthCert) {
194   std::vector<uint8_t> signed_data;
195   AuthResponse auth_response =
196       CreateAuthResponse(&signed_data, ::cast::channel::SHA256);
197   MangleString(auth_response.mutable_client_auth_certificate());
198   ErrorOr<CastDeviceCertPolicy> result =
199       VerifyCredentials(auth_response, signed_data);
200   EXPECT_FALSE(result);
201   EXPECT_EQ(Error::Code::kErrCertsParse, result.error().code());
202 }
203 
TEST_F(CastAuthUtilTest,VerifyBadSignature)204 TEST_F(CastAuthUtilTest, VerifyBadSignature) {
205   std::vector<uint8_t> signed_data;
206   AuthResponse auth_response =
207       CreateAuthResponse(&signed_data, ::cast::channel::SHA256);
208   MangleString(auth_response.mutable_signature());
209   ErrorOr<CastDeviceCertPolicy> result =
210       VerifyCredentials(auth_response, signed_data);
211   EXPECT_FALSE(result);
212   EXPECT_EQ(Error::Code::kCastV2SignedBlobsMismatch, result.error().code());
213 }
214 
TEST_F(CastAuthUtilTest,VerifyEmptySignature)215 TEST_F(CastAuthUtilTest, VerifyEmptySignature) {
216   std::vector<uint8_t> signed_data;
217   AuthResponse auth_response =
218       CreateAuthResponse(&signed_data, ::cast::channel::SHA256);
219   auth_response.mutable_signature()->clear();
220   ErrorOr<CastDeviceCertPolicy> result =
221       VerifyCredentials(auth_response, signed_data);
222   EXPECT_FALSE(result);
223   EXPECT_EQ(Error::Code::kCastV2SignatureEmpty, result.error().code());
224 }
225 
TEST_F(CastAuthUtilTest,VerifyUnsupportedDigest)226 TEST_F(CastAuthUtilTest, VerifyUnsupportedDigest) {
227   std::vector<uint8_t> signed_data;
228   AuthResponse auth_response =
229       CreateAuthResponse(&signed_data, ::cast::channel::SHA1);
230   DateTime now = {};
231   ASSERT_TRUE(DateTimeFromSeconds(GetWallTimeSinceUnixEpoch().count(), &now));
232   ErrorOr<CastDeviceCertPolicy> result = VerifyCredentialsForTest(
233       auth_response, signed_data, CRLPolicy::kCrlOptional, nullptr, nullptr,
234       now, true);
235   EXPECT_FALSE(result);
236   EXPECT_EQ(Error::Code::kCastV2DigestUnsupported, result.error().code());
237 }
238 
TEST_F(CastAuthUtilTest,VerifyBackwardsCompatibleDigest)239 TEST_F(CastAuthUtilTest, VerifyBackwardsCompatibleDigest) {
240   std::vector<uint8_t> signed_data;
241   AuthResponse auth_response =
242       CreateAuthResponse(&signed_data, ::cast::channel::SHA1);
243   DateTime now = {};
244   ASSERT_TRUE(DateTimeFromSeconds(GetWallTimeSinceUnixEpoch().count(), &now));
245   ErrorOr<CastDeviceCertPolicy> result =
246       VerifyCredentialsForTest(auth_response, signed_data,
247                                CRLPolicy::kCrlOptional, nullptr, nullptr, now);
248   EXPECT_TRUE(result);
249 }
250 
TEST_F(CastAuthUtilTest,VerifyBadPeerCert)251 TEST_F(CastAuthUtilTest, VerifyBadPeerCert) {
252   std::vector<uint8_t> signed_data;
253   AuthResponse auth_response =
254       CreateAuthResponse(&signed_data, ::cast::channel::SHA256);
255   MangleData(&signed_data);
256   ErrorOr<CastDeviceCertPolicy> result =
257       VerifyCredentials(auth_response, signed_data);
258   EXPECT_FALSE(result);
259   EXPECT_EQ(Error::Code::kCastV2SignedBlobsMismatch, result.error().code());
260 }
261 
TEST_F(CastAuthUtilTest,VerifySenderNonceMatch)262 TEST_F(CastAuthUtilTest, VerifySenderNonceMatch) {
263   AuthContext context = AuthContext::Create();
264   const Error result = context.VerifySenderNonce(context.nonce(), true);
265   EXPECT_TRUE(result.ok());
266 }
267 
TEST_F(CastAuthUtilTest,VerifySenderNonceMismatch)268 TEST_F(CastAuthUtilTest, VerifySenderNonceMismatch) {
269   AuthContext context = AuthContext::Create();
270   std::string received_nonce = "test2";
271   EXPECT_NE(received_nonce, context.nonce());
272   ErrorOr<CastDeviceCertPolicy> result =
273       context.VerifySenderNonce(received_nonce, true);
274   EXPECT_FALSE(result);
275   EXPECT_EQ(Error::Code::kCastV2SenderNonceMismatch, result.error().code());
276 }
277 
TEST_F(CastAuthUtilTest,VerifySenderNonceMissing)278 TEST_F(CastAuthUtilTest, VerifySenderNonceMissing) {
279   AuthContext context = AuthContext::Create();
280   std::string received_nonce;
281   EXPECT_FALSE(context.nonce().empty());
282   ErrorOr<CastDeviceCertPolicy> result =
283       context.VerifySenderNonce(received_nonce, true);
284   EXPECT_FALSE(result);
285   EXPECT_EQ(Error::Code::kCastV2SenderNonceMismatch, result.error().code());
286 }
287 
TEST_F(CastAuthUtilTest,VerifyTLSCertificateSuccess)288 TEST_F(CastAuthUtilTest, VerifyTLSCertificateSuccess) {
289   std::vector<std::string> tls_cert_der = testing::ReadCertificatesFromPemFile(
290       TEST_DATA_PREFIX "certificates/test_tls_cert.pem");
291   std::string& der_cert = tls_cert_der[0];
292   const uint8_t* data = (const uint8_t*)der_cert.data();
293   X509* tls_cert = d2i_X509(nullptr, &data, der_cert.size());
294   DateTime not_before;
295   DateTime not_after;
296   ASSERT_TRUE(GetCertValidTimeRange(tls_cert, &not_before, &not_after));
297   uint64_t x;
298   ASSERT_TRUE(ConvertTimeSeconds(not_before, &x));
299   std::chrono::seconds s(x);
300 
301   const Error result = VerifyTLSCertificateValidity(tls_cert, s);
302   EXPECT_TRUE(result.ok());
303   X509_free(tls_cert);
304 }
305 
TEST_F(CastAuthUtilTest,VerifyTLSCertificateTooEarly)306 TEST_F(CastAuthUtilTest, VerifyTLSCertificateTooEarly) {
307   std::vector<std::string> tls_cert_der = testing::ReadCertificatesFromPemFile(
308       TEST_DATA_PREFIX "certificates/test_tls_cert.pem");
309   std::string& der_cert = tls_cert_der[0];
310   const uint8_t* data = (const uint8_t*)der_cert.data();
311   X509* tls_cert = d2i_X509(nullptr, &data, der_cert.size());
312   DateTime not_before;
313   DateTime not_after;
314   ASSERT_TRUE(GetCertValidTimeRange(tls_cert, &not_before, &not_after));
315   uint64_t x;
316   ASSERT_TRUE(ConvertTimeSeconds(not_before, &x));
317   std::chrono::seconds s(x - 1);
318 
319   ErrorOr<CastDeviceCertPolicy> result =
320       VerifyTLSCertificateValidity(tls_cert, s);
321   EXPECT_FALSE(result);
322   EXPECT_EQ(Error::Code::kCastV2TlsCertValidStartDateInFuture,
323             result.error().code());
324   X509_free(tls_cert);
325 }
326 
TEST_F(CastAuthUtilTest,VerifyTLSCertificateTooLate)327 TEST_F(CastAuthUtilTest, VerifyTLSCertificateTooLate) {
328   std::vector<std::string> tls_cert_der = testing::ReadCertificatesFromPemFile(
329       TEST_DATA_PREFIX "certificates/test_tls_cert.pem");
330   std::string& der_cert = tls_cert_der[0];
331   const uint8_t* data = (const uint8_t*)der_cert.data();
332   X509* tls_cert = d2i_X509(nullptr, &data, der_cert.size());
333   DateTime not_before;
334   DateTime not_after;
335   ASSERT_TRUE(GetCertValidTimeRange(tls_cert, &not_before, &not_after));
336   uint64_t x;
337   ASSERT_TRUE(ConvertTimeSeconds(not_after, &x));
338   std::chrono::seconds s(x + 2);
339 
340   ErrorOr<CastDeviceCertPolicy> result =
341       VerifyTLSCertificateValidity(tls_cert, s);
342   EXPECT_FALSE(result);
343   EXPECT_EQ(Error::Code::kCastV2TlsCertExpired, result.error().code());
344   X509_free(tls_cert);
345 }
346 
347 // Indicates the expected result of test step's verification.
348 enum TestStepResult {
349   RESULT_SUCCESS,
350   RESULT_FAIL,
351 };
352 
353 // Verifies that the certificate chain provided is not revoked according to
354 // the provided Cast CRL at |verification_time|.
355 // The provided CRL is verified at |verification_time|.
356 // If |crl_required| is set, then a valid Cast CRL must be provided.
357 // Otherwise, a missing CRL is be ignored.
TestVerifyRevocation(const std::vector<std::string> & certificate_chain,const std::string & crl_bundle,const DateTime & verification_time,bool crl_required,TrustStore * cast_trust_store,TrustStore * crl_trust_store)358 ErrorOr<CastDeviceCertPolicy> TestVerifyRevocation(
359     const std::vector<std::string>& certificate_chain,
360     const std::string& crl_bundle,
361     const DateTime& verification_time,
362     bool crl_required,
363     TrustStore* cast_trust_store,
364     TrustStore* crl_trust_store) {
365   AuthResponse response;
366 
367   if (certificate_chain.size() > 0) {
368     response.set_client_auth_certificate(certificate_chain[0]);
369     for (size_t i = 1; i < certificate_chain.size(); ++i) {
370       response.add_intermediate_certificate(certificate_chain[i]);
371     }
372   }
373 
374   response.set_crl(crl_bundle);
375 
376   CRLPolicy crl_policy = CRLPolicy::kCrlRequired;
377   if (!crl_required && crl_bundle.empty())
378     crl_policy = CRLPolicy::kCrlOptional;
379   ErrorOr<CastDeviceCertPolicy> result = VerifyCredentialsForTest(
380       response, std::vector<uint8_t>(), crl_policy, cast_trust_store,
381       crl_trust_store, verification_time);
382   // This test doesn't set the signature so it will just fail there.
383   EXPECT_FALSE(result);
384   return result;
385 }
386 
387 // Runs a single test case.
RunTest(const DeviceCertTest & test_case)388 bool RunTest(const DeviceCertTest& test_case) {
389   std::unique_ptr<TrustStore> crl_trust_store;
390   std::unique_ptr<TrustStore> cast_trust_store;
391   if (test_case.use_test_trust_anchors()) {
392     crl_trust_store = testing::CreateTrustStoreFromPemFile(
393         TEST_DATA_PREFIX "certificates/cast_crl_test_root_ca.pem");
394     cast_trust_store = testing::CreateTrustStoreFromPemFile(
395         TEST_DATA_PREFIX "certificates/cast_test_root_ca.pem");
396 
397     EXPECT_FALSE(crl_trust_store->certs.empty());
398     EXPECT_FALSE(cast_trust_store->certs.empty());
399   }
400 
401   std::vector<std::string> certificate_chain;
402   for (auto const& cert : test_case.der_cert_path()) {
403     certificate_chain.push_back(cert);
404   }
405 
406   // CastAuthUtil verifies the CRL at the same time as the certificate.
407   DateTime verification_time;
408   uint64_t cert_verify_time = test_case.cert_verification_time_seconds();
409   if (!cert_verify_time) {
410     cert_verify_time = test_case.crl_verification_time_seconds();
411   }
412   OSP_DCHECK(DateTimeFromSeconds(cert_verify_time, &verification_time));
413 
414   std::string crl_bundle = test_case.crl_bundle();
415   ErrorOr<CastDeviceCertPolicy> result(CastDeviceCertPolicy::kUnrestricted);
416   switch (test_case.expected_result()) {
417     case ::cast::certificate::PATH_VERIFICATION_FAILED:
418       result = TestVerifyRevocation(
419           certificate_chain, crl_bundle, verification_time, false,
420           cast_trust_store.get(), crl_trust_store.get());
421       EXPECT_EQ(result.error().code(),
422                 Error::Code::kCastV2CertNotSignedByTrustedCa);
423       return result.error().code() ==
424              Error::Code::kCastV2CertNotSignedByTrustedCa;
425     case ::cast::certificate::CRL_VERIFICATION_FAILED:
426     // Fall-through intended.
427     case ::cast::certificate::REVOCATION_CHECK_FAILED_WITHOUT_CRL:
428       result = TestVerifyRevocation(
429           certificate_chain, crl_bundle, verification_time, true,
430           cast_trust_store.get(), crl_trust_store.get());
431       EXPECT_EQ(result.error().code(), Error::Code::kErrCrlInvalid);
432       return result.error().code() == Error::Code::kErrCrlInvalid;
433     case ::cast::certificate::CRL_EXPIRED_AFTER_INITIAL_VERIFICATION:
434       // By-pass this test because CRL is always verified at the time the
435       // certificate is verified.
436       return true;
437     case ::cast::certificate::REVOCATION_CHECK_FAILED:
438       result = TestVerifyRevocation(
439           certificate_chain, crl_bundle, verification_time, true,
440           cast_trust_store.get(), crl_trust_store.get());
441       EXPECT_EQ(result.error().code(), Error::Code::kErrCertsRevoked);
442       return result.error().code() == Error::Code::kErrCertsRevoked;
443     case ::cast::certificate::SUCCESS:
444       result = TestVerifyRevocation(
445           certificate_chain, crl_bundle, verification_time, false,
446           cast_trust_store.get(), crl_trust_store.get());
447       EXPECT_EQ(result.error().code(), Error::Code::kCastV2SignedBlobsMismatch);
448       return result.error().code() == Error::Code::kCastV2SignedBlobsMismatch;
449     case ::cast::certificate::UNSPECIFIED:
450       return false;
451   }
452   return false;
453 }
454 
455 // Parses the provided test suite provided in wire-format proto.
456 // Each test contains the inputs and the expected output.
457 // To see the description of the test, execute the test.
458 // These tests are generated by a test generator in google3.
RunTestSuite(const std::string & test_suite_file_name)459 void RunTestSuite(const std::string& test_suite_file_name) {
460   std::string testsuite_raw = ReadEntireFileToString(test_suite_file_name);
461   DeviceCertTestSuite test_suite;
462   EXPECT_TRUE(test_suite.ParseFromString(testsuite_raw));
463   uint16_t successes = 0;
464 
465   for (auto const& test_case : test_suite.tests()) {
466     bool result = RunTest(test_case);
467     EXPECT_TRUE(result) << test_case.description();
468     successes += result;
469   }
470   OSP_LOG_IF(ERROR, successes != test_suite.tests().size())
471       << "successes: " << successes
472       << ", failures: " << (test_suite.tests().size() - successes);
473 }
474 
TEST_F(CastAuthUtilTest,CRLTestSuite)475 TEST_F(CastAuthUtilTest, CRLTestSuite) {
476   RunTestSuite("testsuite/testsuite1.pb");
477 }
478 
479 }  // namespace
480 }  // namespace cast
481 }  // namespace openscreen
482