205 lines
7.5 KiB
C++
205 lines
7.5 KiB
C++
// 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_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_;
|
|
VirtualConnectionRouter router_;
|
|
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
|