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 <stdio.h>
6 
7 #include "cast/common/certificate/cast_trust_store.h"
8 #include "cast/common/certificate/testing/test_helpers.h"
9 #include "cast/common/channel/proto/cast_channel.pb.h"
10 #include "cast/common/channel/testing/fake_cast_socket.h"
11 #include "cast/common/channel/testing/mock_socket_error_handler.h"
12 #include "cast/common/channel/virtual_connection_router.h"
13 #include "cast/common/public/cast_socket.h"
14 #include "cast/receiver/channel/device_auth_namespace_handler.h"
15 #include "cast/receiver/channel/static_credentials.h"
16 #include "cast/receiver/channel/testing/device_auth_test_helpers.h"
17 #include "cast/sender/channel/cast_auth_util.h"
18 #include "cast/sender/channel/message_util.h"
19 #include "gtest/gtest.h"
20 #include "platform/test/paths.h"
21 #include "testing/util/read_file.h"
22 
23 namespace openscreen {
24 namespace cast {
25 namespace {
26 
27 using ::cast::channel::CastMessage;
28 using ::cast::channel::DeviceAuthMessage;
29 
30 using ::testing::_;
31 using ::testing::Invoke;
32 
GetSpecificTestDataPath()33 const std::string& GetSpecificTestDataPath() {
34   static std::string data_path = GetTestDataPath() + "cast/receiver/channel/";
35   return data_path;
36 }
37 
38 class DeviceAuthTest : public ::testing::Test {
39  public:
SetUp()40   void SetUp() override {
41     socket_ = fake_cast_socket_pair_.socket.get();
42     router_.TakeSocket(&mock_error_handler_,
43                        std::move(fake_cast_socket_pair_.socket));
44     router_.AddHandlerForLocalId(kPlatformReceiverId, &auth_handler_);
45   }
46 
47  protected:
RunAuthTest(std::string serialized_crl,TrustStore * fake_crl_trust_store,bool should_succeed=true,bool record_this_test=false)48   void RunAuthTest(std::string serialized_crl,
49                    TrustStore* fake_crl_trust_store,
50                    bool should_succeed = true,
51                    bool record_this_test = false) {
52     bssl::UniquePtr<X509> parsed_cert;
53     TrustStore fake_trust_store;
54     InitStaticCredentialsFromFiles(
55         &creds_, &parsed_cert, &fake_trust_store, data_path_ + "device_key.pem",
56         data_path_ + "device_chain.pem", data_path_ + "device_tls.pem");
57     creds_.device_creds.serialized_crl = std::move(serialized_crl);
58 
59     // Send an auth challenge.  |auth_handler_| will automatically respond
60     // via |router_| and we will catch the result in |challenge_reply|.
61     AuthContext auth_context = AuthContext::Create();
62     CastMessage auth_challenge = CreateAuthChallengeMessage(auth_context);
63     if (record_this_test) {
64       std::string output;
65       DeviceAuthMessage auth_message;
66       ASSERT_EQ(auth_challenge.payload_type(),
67                 ::cast::channel::CastMessage_PayloadType_BINARY);
68       ASSERT_TRUE(
69           auth_message.ParseFromString(auth_challenge.payload_binary()));
70       ASSERT_TRUE(auth_message.has_challenge());
71       ASSERT_FALSE(auth_message.has_response());
72       ASSERT_FALSE(auth_message.has_error());
73       ASSERT_TRUE(auth_challenge.SerializeToString(&output));
74 
75       const std::string pb_path = data_path_ + "auth_challenge.pb";
76       FILE* fd = fopen(pb_path.c_str(), "wb");
77       ASSERT_TRUE(fd);
78       ASSERT_EQ(fwrite(output.data(), 1, output.size(), fd), output.size());
79       fclose(fd);
80     }
81     CastMessage challenge_reply;
82     EXPECT_CALL(fake_cast_socket_pair_.mock_peer_client, OnMessage(_, _))
83         .WillOnce(
84             Invoke([&challenge_reply](CastSocket* socket, CastMessage message) {
85               challenge_reply = std::move(message);
86             }));
87     ASSERT_TRUE(
88         fake_cast_socket_pair_.peer_socket->Send(std::move(auth_challenge))
89             .ok());
90 
91     if (record_this_test) {
92       std::string output;
93       DeviceAuthMessage auth_message;
94       ASSERT_EQ(challenge_reply.payload_type(),
95                 ::cast::channel::CastMessage_PayloadType_BINARY);
96       ASSERT_TRUE(
97           auth_message.ParseFromString(challenge_reply.payload_binary()));
98       ASSERT_TRUE(auth_message.has_response());
99       ASSERT_FALSE(auth_message.has_challenge());
100       ASSERT_FALSE(auth_message.has_error());
101       ASSERT_TRUE(auth_message.response().SerializeToString(&output));
102 
103       const std::string pb_path = data_path_ + "auth_response.pb";
104       FILE* fd = fopen(pb_path.c_str(), "wb");
105       ASSERT_TRUE(fd);
106       ASSERT_EQ(fwrite(output.data(), 1, output.size(), fd), output.size());
107       fclose(fd);
108     }
109 
110     DateTime December2019 = {};
111     December2019.year = 2019;
112     December2019.month = 12;
113     December2019.day = 17;
114     const ErrorOr<CastDeviceCertPolicy> error_or_policy =
115         AuthenticateChallengeReplyForTest(
116             challenge_reply, parsed_cert.get(), auth_context,
117             fake_crl_trust_store ? CRLPolicy::kCrlRequired
118                                  : CRLPolicy::kCrlOptional,
119             &fake_trust_store, fake_crl_trust_store, December2019);
120     EXPECT_EQ(error_or_policy.is_value(), should_succeed);
121   }
122 
123   const std::string& data_path_{GetSpecificTestDataPath()};
124   FakeCastSocketPair fake_cast_socket_pair_;
125   MockSocketErrorHandler mock_error_handler_;
126   CastSocket* socket_;
127 
128   StaticCredentialsProvider creds_;
129   VirtualConnectionRouter router_;
130   DeviceAuthNamespaceHandler auth_handler_{&creds_};
131 };
132 
TEST_F(DeviceAuthTest,MANUAL_SerializeTestData)133 TEST_F(DeviceAuthTest, MANUAL_SerializeTestData) {
134   if (::testing::GTEST_FLAG(filter) ==
135       "DeviceAuthTest.MANUAL_SerializeTestData") {
136     RunAuthTest(std::string(), nullptr, true, true);
137   }
138 }
139 
TEST_F(DeviceAuthTest,AuthIntegration)140 TEST_F(DeviceAuthTest, AuthIntegration) {
141   RunAuthTest(std::string(), nullptr);
142 }
143 
TEST_F(DeviceAuthTest,GoodCrl)144 TEST_F(DeviceAuthTest, GoodCrl) {
145   auto fake_crl_trust_store =
146       TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
147   RunAuthTest(ReadEntireFileToString(data_path_ + "good_crl.pb"),
148               &fake_crl_trust_store);
149 }
150 
TEST_F(DeviceAuthTest,InvalidCrlTime)151 TEST_F(DeviceAuthTest, InvalidCrlTime) {
152   auto fake_crl_trust_store =
153       TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
154   RunAuthTest(ReadEntireFileToString(data_path_ + "invalid_time_crl.pb"),
155               &fake_crl_trust_store, false);
156 }
157 
TEST_F(DeviceAuthTest,IssuerRevoked)158 TEST_F(DeviceAuthTest, IssuerRevoked) {
159   auto fake_crl_trust_store =
160       TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
161   RunAuthTest(ReadEntireFileToString(data_path_ + "issuer_revoked_crl.pb"),
162               &fake_crl_trust_store, false);
163 }
164 
TEST_F(DeviceAuthTest,DeviceRevoked)165 TEST_F(DeviceAuthTest, DeviceRevoked) {
166   auto fake_crl_trust_store =
167       TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
168   RunAuthTest(ReadEntireFileToString(data_path_ + "device_revoked_crl.pb"),
169               &fake_crl_trust_store, false);
170 }
171 
TEST_F(DeviceAuthTest,IssuerSerialRevoked)172 TEST_F(DeviceAuthTest, IssuerSerialRevoked) {
173   auto fake_crl_trust_store =
174       TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
175   RunAuthTest(
176       ReadEntireFileToString(data_path_ + "issuer_serial_revoked_crl.pb"),
177       &fake_crl_trust_store, false);
178 }
179 
TEST_F(DeviceAuthTest,DeviceSerialRevoked)180 TEST_F(DeviceAuthTest, DeviceSerialRevoked) {
181   auto fake_crl_trust_store =
182       TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
183   RunAuthTest(
184       ReadEntireFileToString(data_path_ + "device_serial_revoked_crl.pb"),
185       &fake_crl_trust_store, false);
186 }
187 
TEST_F(DeviceAuthTest,BadCrlSignerCert)188 TEST_F(DeviceAuthTest, BadCrlSignerCert) {
189   auto fake_crl_trust_store =
190       TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
191   RunAuthTest(ReadEntireFileToString(data_path_ + "bad_signer_cert_crl.pb"),
192               &fake_crl_trust_store, false);
193 }
194 
TEST_F(DeviceAuthTest,BadCrlSignature)195 TEST_F(DeviceAuthTest, BadCrlSignature) {
196   auto fake_crl_trust_store =
197       TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
198   RunAuthTest(ReadEntireFileToString(data_path_ + "bad_signature_crl.pb"),
199               &fake_crl_trust_store, false);
200 }
201 
202 }  // namespace
203 }  // namespace cast
204 }  // namespace openscreen
205