blob: 36a9fc8a449c28cf35d9b7e620c094b283c4da88 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdio.h>
#include "cast/common/certificate/cast_trust_store.h"
#include "cast/common/certificate/testing/test_helpers.h"
#include "cast/common/channel/proto/cast_channel.pb.h"
#include "cast/common/channel/testing/fake_cast_socket.h"
#include "cast/common/channel/testing/mock_socket_error_handler.h"
#include "cast/common/channel/virtual_connection_manager.h"
#include "cast/common/channel/virtual_connection_router.h"
#include "cast/common/public/cast_socket.h"
#include "cast/receiver/channel/device_auth_namespace_handler.h"
#include "cast/receiver/channel/static_credentials.h"
#include "cast/receiver/channel/testing/device_auth_test_helpers.h"
#include "cast/sender/channel/cast_auth_util.h"
#include "cast/sender/channel/message_util.h"
#include "gtest/gtest.h"
#include "platform/test/paths.h"
#include "testing/util/read_file.h"
namespace openscreen {
namespace cast {
namespace {
using ::cast::channel::CastMessage;
using ::cast::channel::DeviceAuthMessage;
using ::testing::_;
using ::testing::Invoke;
const std::string& GetSpecificTestDataPath() {
static std::string data_path = GetTestDataPath() + "cast/receiver/channel/";
return data_path;
}
class DeviceAuthTest : public ::testing::Test {
public:
void SetUp() override {
socket_ = fake_cast_socket_pair_.socket.get();
router_.TakeSocket(&mock_error_handler_,
std::move(fake_cast_socket_pair_.socket));
router_.AddHandlerForLocalId(kPlatformReceiverId, &auth_handler_);
}
protected:
void RunAuthTest(std::string serialized_crl,
TrustStore* fake_crl_trust_store,
bool should_succeed = true,
bool record_this_test = false) {
bssl::UniquePtr<X509> parsed_cert;
TrustStore fake_trust_store;
InitStaticCredentialsFromFiles(
&creds_, &parsed_cert, &fake_trust_store, data_path_ + "device_key.pem",
data_path_ + "device_chain.pem", data_path_ + "device_tls.pem");
creds_.device_creds.serialized_crl = std::move(serialized_crl);
// Send an auth challenge. |auth_handler_| will automatically respond
// via |router_| and we will catch the result in |challenge_reply|.
AuthContext auth_context = AuthContext::Create();
CastMessage auth_challenge = CreateAuthChallengeMessage(auth_context);
if (record_this_test) {
std::string output;
DeviceAuthMessage auth_message;
ASSERT_EQ(auth_challenge.payload_type(),
::cast::channel::CastMessage_PayloadType_BINARY);
ASSERT_TRUE(
auth_message.ParseFromString(auth_challenge.payload_binary()));
ASSERT_TRUE(auth_message.has_challenge());
ASSERT_FALSE(auth_message.has_response());
ASSERT_FALSE(auth_message.has_error());
ASSERT_TRUE(auth_challenge.SerializeToString(&output));
const std::string pb_path = data_path_ + "auth_challenge.pb";
FILE* fd = fopen(pb_path.c_str(), "wb");
ASSERT_TRUE(fd);
ASSERT_EQ(fwrite(output.data(), 1, output.size(), fd), output.size());
fclose(fd);
}
CastMessage challenge_reply;
EXPECT_CALL(fake_cast_socket_pair_.mock_peer_client, OnMessage(_, _))
.WillOnce(
Invoke([&challenge_reply](CastSocket* socket, CastMessage message) {
challenge_reply = std::move(message);
}));
ASSERT_TRUE(
fake_cast_socket_pair_.peer_socket->Send(std::move(auth_challenge))
.ok());
if (record_this_test) {
std::string output;
DeviceAuthMessage auth_message;
ASSERT_EQ(challenge_reply.payload_type(),
::cast::channel::CastMessage_PayloadType_BINARY);
ASSERT_TRUE(
auth_message.ParseFromString(challenge_reply.payload_binary()));
ASSERT_TRUE(auth_message.has_response());
ASSERT_FALSE(auth_message.has_challenge());
ASSERT_FALSE(auth_message.has_error());
ASSERT_TRUE(auth_message.response().SerializeToString(&output));
const std::string pb_path = data_path_ + "auth_response.pb";
FILE* fd = fopen(pb_path.c_str(), "wb");
ASSERT_TRUE(fd);
ASSERT_EQ(fwrite(output.data(), 1, output.size(), fd), output.size());
fclose(fd);
}
DateTime December2019 = {};
December2019.year = 2019;
December2019.month = 12;
December2019.day = 17;
const ErrorOr<CastDeviceCertPolicy> error_or_policy =
AuthenticateChallengeReplyForTest(
challenge_reply, parsed_cert.get(), auth_context,
fake_crl_trust_store ? CRLPolicy::kCrlRequired
: CRLPolicy::kCrlOptional,
&fake_trust_store, fake_crl_trust_store, December2019);
EXPECT_EQ(error_or_policy.is_value(), should_succeed);
}
const std::string& data_path_{GetSpecificTestDataPath()};
FakeCastSocketPair fake_cast_socket_pair_;
MockSocketErrorHandler mock_error_handler_;
CastSocket* socket_;
StaticCredentialsProvider creds_;
VirtualConnectionManager manager_;
VirtualConnectionRouter router_{&manager_};
DeviceAuthNamespaceHandler auth_handler_{&creds_};
};
TEST_F(DeviceAuthTest, MANUAL_SerializeTestData) {
if (::testing::GTEST_FLAG(filter) ==
"DeviceAuthTest.MANUAL_SerializeTestData") {
RunAuthTest(std::string(), nullptr, true, true);
}
}
TEST_F(DeviceAuthTest, AuthIntegration) {
RunAuthTest(std::string(), nullptr);
}
TEST_F(DeviceAuthTest, GoodCrl) {
auto fake_crl_trust_store =
TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
RunAuthTest(ReadEntireFileToString(data_path_ + "good_crl.pb"),
&fake_crl_trust_store);
}
TEST_F(DeviceAuthTest, InvalidCrlTime) {
auto fake_crl_trust_store =
TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
RunAuthTest(ReadEntireFileToString(data_path_ + "invalid_time_crl.pb"),
&fake_crl_trust_store, false);
}
TEST_F(DeviceAuthTest, IssuerRevoked) {
auto fake_crl_trust_store =
TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
RunAuthTest(ReadEntireFileToString(data_path_ + "issuer_revoked_crl.pb"),
&fake_crl_trust_store, false);
}
TEST_F(DeviceAuthTest, DeviceRevoked) {
auto fake_crl_trust_store =
TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
RunAuthTest(ReadEntireFileToString(data_path_ + "device_revoked_crl.pb"),
&fake_crl_trust_store, false);
}
TEST_F(DeviceAuthTest, IssuerSerialRevoked) {
auto fake_crl_trust_store =
TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
RunAuthTest(
ReadEntireFileToString(data_path_ + "issuer_serial_revoked_crl.pb"),
&fake_crl_trust_store, false);
}
TEST_F(DeviceAuthTest, DeviceSerialRevoked) {
auto fake_crl_trust_store =
TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
RunAuthTest(
ReadEntireFileToString(data_path_ + "device_serial_revoked_crl.pb"),
&fake_crl_trust_store, false);
}
TEST_F(DeviceAuthTest, BadCrlSignerCert) {
auto fake_crl_trust_store =
TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
RunAuthTest(ReadEntireFileToString(data_path_ + "bad_signer_cert_crl.pb"),
&fake_crl_trust_store, false);
}
TEST_F(DeviceAuthTest, BadCrlSignature) {
auto fake_crl_trust_store =
TrustStore::CreateInstanceFromPemFile(data_path_ + "crl_root.pem");
RunAuthTest(ReadEntireFileToString(data_path_ + "bad_signature_crl.pb"),
&fake_crl_trust_store, false);
}
} // namespace
} // namespace cast
} // namespace openscreen