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