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