blob: d6fdbc90619b6b5555b826a19e0b57740f6497cf [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device_management/device_management_service.h"
#include <string>
#include <utility>
#include <vector>
#include <base/check.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <brillo/secure_blob.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <libhwsec/frontend/cryptohome/mock_frontend.h>
#include <libhwsec-foundation/error/testing_helper.h>
#include "device_management/fwmp/mock_firmware_management_parameters.h"
#include "device_management/install_attributes/mock_install_attributes.h"
#include "device_management/install_attributes/mock_platform.h"
#include "device_management/proto_bindings/device_management_interface.pb.h"
using ::hwsec::TPMError;
using ::hwsec_foundation::error::testing::IsOk;
using ::hwsec_foundation::error::testing::ReturnError;
using ::hwsec_foundation::error::testing::ReturnOk;
using ::hwsec_foundation::error::testing::ReturnValue;
using ::hwsec_foundation::status::MakeStatus;
using ::testing::_;
using ::testing::AtLeast;
using ::testing::DoAll;
using ::testing::ElementsAreArray;
using ::testing::Invoke;
using ::testing::Mock;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SaveArgPointee;
using ::testing::SetArgPointee;
using ::testing::StrictMock;
using TPMRetryAction = ::hwsec::TPMRetryAction;
namespace device_management {
// Make sure the Init of install attributes always be called at least once.
class DeviceManagementServiceEnsureInstallAttributeInitTest
: public ::testing::Test {
public:
void SetUp() override {
auto fwmp =
std::make_unique<StrictMock<MockFirmwareManagementParameters>>();
auto install_attrs = std::make_unique<StrictMock<MockInstallAttributes>>();
fwmp_ = fwmp.get();
install_attrs_ = install_attrs.get();
device_management_service_.SetParamsForTesting(std::move(fwmp),
std::move(install_attrs));
EXPECT_CALL(*install_attrs_, Init()).Times(AtLeast(1));
EXPECT_CALL(*install_attrs_, status())
.WillRepeatedly(Return(InstallAttributes::Status::kUnknown));
EXPECT_CALL(*install_attrs_, Get(_, _)).WillRepeatedly(Return(false));
// Called by Initialize().
EXPECT_CALL(hwsec_, RegisterOnReadyCallback)
.WillOnce([this](base::OnceCallback<void(hwsec::Status)> cb) {
hwsec_callback_ = std::move(cb);
});
}
protected:
StrictMock<hwsec::MockCryptohomeFrontend> hwsec_;
NiceMock<MockPlatform> platform_;
DeviceManagementService device_management_service_;
StrictMock<MockFirmwareManagementParameters>* fwmp_;
StrictMock<MockInstallAttributes>* install_attrs_;
base::OnceCallback<void(hwsec::Status)> hwsec_callback_;
};
TEST_F(DeviceManagementServiceEnsureInstallAttributeInitTest,
InitializeWithHwsecReady) {
device_management_service_.Initialize(hwsec_, platform_);
ASSERT_FALSE(hwsec_callback_.is_null());
// Test the cast that libhwsec is ready.
std::move(hwsec_callback_).Run(hwsec::OkStatus());
}
// These tests are only useful when the insecure fallback is on.
#if USE_TPM_INSECURE_FALLBACK
TEST_F(DeviceManagementServiceEnsureInstallAttributeInitTest,
InitializeWithHwsecNoBackend) {
device_management_service_.Initialize(hwsec_, platform_);
ASSERT_FALSE(hwsec_callback_.is_null());
// Test the case that there is no backend in libhwsec.
std::move(hwsec_callback_)
.Run(MakeStatus<TPMError>("No backend", TPMRetryAction::kNoRetry));
}
TEST_F(DeviceManagementServiceEnsureInstallAttributeInitTest,
InitializeWithHwsecNeverReady) {
device_management_service_.Initialize(hwsec_, platform_);
ASSERT_FALSE(hwsec_callback_.is_null());
// Test the cast that libhwsec never ready.
std::move(hwsec_callback_).Reset();
}
#endif // USE_TPM_INSECURE_FALLBACK
// Make sure the first install cases works correctly.
class DeviceManagementServiceInstallAttibuteFirstInstallTest
: public ::testing::Test {
public:
void SetUp() override {
auto fwmp =
std::make_unique<StrictMock<MockFirmwareManagementParameters>>();
auto install_attrs =
std::make_unique<InstallAttributes>(&platform_, &hwsec_);
fwmp_ = fwmp.get();
device_management_service_.SetParamsForTesting(std::move(fwmp),
std::move(install_attrs));
// Called by Initialize().
EXPECT_CALL(hwsec_, RegisterOnReadyCallback)
.WillOnce([this](base::OnceCallback<void(hwsec::Status)> cb) {
hwsec_callback_ = std::move(cb);
});
}
protected:
StrictMock<hwsec::MockCryptohomeFrontend> hwsec_;
NiceMock<MockPlatform> platform_;
DeviceManagementService device_management_service_;
StrictMock<MockFirmwareManagementParameters>* fwmp_;
base::OnceCallback<void(hwsec::Status)> hwsec_callback_;
};
TEST_F(DeviceManagementServiceInstallAttibuteFirstInstallTest,
InitializeWithHwsecReady) {
// Assume the libhwsec is ready.
EXPECT_CALL(hwsec_, IsEnabled()).WillRepeatedly(ReturnValue(true));
EXPECT_CALL(hwsec_, IsReady()).WillRepeatedly(ReturnValue(true));
EXPECT_CALL(hwsec_, PrepareSpace(_, _)).WillOnce(ReturnOk<TPMError>());
device_management_service_.Initialize(hwsec_, platform_);
// The install attributes may not be initialized yet here.
ASSERT_FALSE(hwsec_callback_.is_null());
std::move(hwsec_callback_).Run(hwsec::OkStatus());
EXPECT_EQ(InstallAttributes::Status::kFirstInstall,
device_management_service_.InstallAttributesGetStatus());
}
// These tests are only useful when the insecure fallback is on.
#if USE_TPM_INSECURE_FALLBACK
TEST_F(DeviceManagementServiceInstallAttibuteFirstInstallTest,
InitializeWithHwsecNoBackend) {
// Test the case that there is no backend in libhwsec.
EXPECT_CALL(hwsec_, IsEnabled())
.WillRepeatedly(
ReturnError<TPMError>("No backend", TPMRetryAction::kNoRetry));
EXPECT_CALL(hwsec_, IsReady())
.WillRepeatedly(
ReturnError<TPMError>("No backend", TPMRetryAction::kNoRetry));
device_management_service_.Initialize(hwsec_, platform_);
ASSERT_FALSE(hwsec_callback_.is_null());
std::move(hwsec_callback_)
.Run(MakeStatus<TPMError>("No backend", TPMRetryAction::kNoRetry));
EXPECT_EQ(InstallAttributes::Status::kFirstInstall,
device_management_service_.InstallAttributesGetStatus());
}
TEST_F(DeviceManagementServiceInstallAttibuteFirstInstallTest,
InitializeWithHwsecNeverReady) {
// Test the cast that libhwsec never ready.
EXPECT_CALL(hwsec_, IsEnabled()).WillRepeatedly(ReturnValue(false));
EXPECT_CALL(hwsec_, IsReady()).WillRepeatedly(ReturnValue(false));
device_management_service_.Initialize(hwsec_, platform_);
ASSERT_FALSE(hwsec_callback_.is_null());
std::move(hwsec_callback_).Reset();
EXPECT_EQ(InstallAttributes::Status::kFirstInstall,
device_management_service_.InstallAttributesGetStatus());
}
#endif // USE_TPM_INSECURE_FALLBACK
// Provides a test fixture to make sure operations related to FWMP,
// install_attributes etc. are working as expected.
class DeviceManagementServiceAPITest : public ::testing::Test {
public:
void SetUp() override {
auto fwmp =
std::make_unique<StrictMock<MockFirmwareManagementParameters>>();
auto install_attrs = std::make_unique<StrictMock<MockInstallAttributes>>();
fwmp_ = fwmp.get();
install_attrs_ = install_attrs.get();
device_management_service_.SetParamsForTesting(std::move(fwmp),
std::move(install_attrs));
}
protected:
constexpr static char kInstallAttributeName[] = "SomeRandomAttribute";
constexpr static uint8_t kInstallAttributeData[] = {0x01, 0x02, 0x00,
0x03, 0xFF, 0xAB};
DeviceManagementService device_management_service_;
StrictMock<MockFirmwareManagementParameters>* fwmp_;
StrictMock<MockInstallAttributes>* install_attrs_;
};
TEST_F(DeviceManagementServiceAPITest, GetFirmwareManagementParametersSuccess) {
const std::string kHash = "its_a_hash";
std::vector<uint8_t> hash(kHash.begin(), kHash.end());
constexpr uint32_t kFlag = 0x1234;
EXPECT_CALL(*fwmp_, Load()).WillOnce(Return(true));
EXPECT_CALL(*fwmp_, GetFlags(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(kFlag), Return(true)));
EXPECT_CALL(*fwmp_, GetDeveloperKeyHash(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(hash), Return(true)));
device_management::FirmwareManagementParameters fwmp;
EXPECT_EQ(device_management::DEVICE_MANAGEMENT_ERROR_NOT_SET,
device_management_service_.GetFirmwareManagementParameters(&fwmp));
EXPECT_EQ(kFlag, fwmp.flags());
EXPECT_EQ(kHash, fwmp.developer_key_hash());
}
TEST_F(DeviceManagementServiceAPITest, GetFirmwareManagementParametersFailure) {
constexpr uint32_t kFlag = 0x1234;
// Test Load() fail.
EXPECT_CALL(*fwmp_, Load()).WillRepeatedly(Return(false));
device_management::FirmwareManagementParameters fwmp;
EXPECT_EQ(device_management::
DEVICE_MANAGEMENT_ERROR_FIRMWARE_MANAGEMENT_PARAMETERS_INVALID,
device_management_service_.GetFirmwareManagementParameters(&fwmp));
// Test GetFlags() fail.
EXPECT_CALL(*fwmp_, Load()).WillRepeatedly(Return(true));
EXPECT_CALL(*fwmp_, GetFlags(_)).WillRepeatedly(Return(false));
EXPECT_EQ(device_management::
DEVICE_MANAGEMENT_ERROR_FIRMWARE_MANAGEMENT_PARAMETERS_INVALID,
device_management_service_.GetFirmwareManagementParameters(&fwmp));
// Test GetDeveloperKeyHash fail.
EXPECT_CALL(*fwmp_, Load()).WillRepeatedly(Return(true));
EXPECT_CALL(*fwmp_, GetFlags(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(kFlag), Return(true)));
EXPECT_CALL(*fwmp_, GetDeveloperKeyHash(_)).WillRepeatedly(Return(false));
EXPECT_EQ(device_management::
DEVICE_MANAGEMENT_ERROR_FIRMWARE_MANAGEMENT_PARAMETERS_INVALID,
device_management_service_.GetFirmwareManagementParameters(&fwmp));
}
TEST_F(DeviceManagementServiceAPITest, SetFirmwareManagementParametersSuccess) {
const std::string kHash = "its_a_hash";
std::vector<uint8_t> hash(kHash.begin(), kHash.end());
constexpr uint32_t kFlag = 0x1234;
std::vector<uint8_t> out_hash;
EXPECT_CALL(*fwmp_, Create()).WillOnce(Return(true));
EXPECT_CALL(*fwmp_, Store(kFlag, _))
.WillOnce(DoAll(SaveArgPointee<1>(&out_hash), Return(true)));
device_management::FirmwareManagementParameters fwmp;
fwmp.set_flags(kFlag);
fwmp.set_developer_key_hash(kHash);
EXPECT_EQ(device_management::DEVICE_MANAGEMENT_ERROR_NOT_SET,
device_management_service_.SetFirmwareManagementParameters(fwmp));
EXPECT_EQ(hash, out_hash);
}
TEST_F(DeviceManagementServiceAPITest, SetFirmwareManagementParametersNoHash) {
constexpr uint32_t kFlag = 0x1234;
EXPECT_CALL(*fwmp_, Create()).WillOnce(Return(true));
EXPECT_CALL(*fwmp_, Store(kFlag, nullptr)).WillOnce(Return(true));
device_management::FirmwareManagementParameters fwmp;
fwmp.set_flags(kFlag);
EXPECT_EQ(device_management::DEVICE_MANAGEMENT_ERROR_NOT_SET,
device_management_service_.SetFirmwareManagementParameters(fwmp));
}
TEST_F(DeviceManagementServiceAPITest,
SetFirmwareManagementParametersCreateError) {
const std::string kHash = "its_a_hash";
constexpr uint32_t kFlag = 0x1234;
EXPECT_CALL(*fwmp_, Create()).WillOnce(Return(false));
device_management::FirmwareManagementParameters fwmp;
fwmp.set_flags(kFlag);
fwmp.set_developer_key_hash(kHash);
EXPECT_EQ(
device_management::
DEVICE_MANAGEMENT_ERROR_FIRMWARE_MANAGEMENT_PARAMETERS_CANNOT_STORE,
device_management_service_.SetFirmwareManagementParameters(fwmp));
}
TEST_F(DeviceManagementServiceAPITest,
SetFirmwareManagementParametersStoreError) {
const std::string kHash = "its_a_hash";
constexpr uint32_t kFlag = 0x1234;
EXPECT_CALL(*fwmp_, Create()).WillOnce(Return(true));
EXPECT_CALL(*fwmp_, Store(_, _)).WillOnce(Return(false));
device_management::FirmwareManagementParameters fwmp;
fwmp.set_flags(kFlag);
fwmp.set_developer_key_hash(kHash);
EXPECT_EQ(
device_management::
DEVICE_MANAGEMENT_ERROR_FIRMWARE_MANAGEMENT_PARAMETERS_CANNOT_STORE,
device_management_service_.SetFirmwareManagementParameters(fwmp));
}
TEST_F(DeviceManagementServiceAPITest,
RemoveFirmwareManagementParametersSuccess) {
EXPECT_CALL(*fwmp_, Destroy()).WillOnce(Return(true));
EXPECT_TRUE(device_management_service_.RemoveFirmwareManagementParameters());
}
TEST_F(DeviceManagementServiceAPITest,
RemoveFirmwareManagementParametersFailure) {
EXPECT_CALL(*fwmp_, Destroy()).WillOnce(Return(false));
EXPECT_FALSE(device_management_service_.RemoveFirmwareManagementParameters());
}
TEST_F(DeviceManagementServiceAPITest, InstallAttributesEnterpriseOwned) {
brillo::Blob blob_true = brillo::BlobFromString("true");
blob_true.push_back(0);
EXPECT_CALL(*install_attrs_, Get("enterprise.owned", _))
.WillOnce(DoAll(SetArgPointee<1>(blob_true), Return(true)));
device_management_service_.DetectEnterpriseOwnership();
EXPECT_TRUE(device_management_service_.IsEnterpriseOwned());
}
TEST_F(DeviceManagementServiceAPITest, InstallAttributesNotEnterpriseOwned) {
brillo::Blob blob_false = brillo::BlobFromString("false");
blob_false.push_back(0);
EXPECT_CALL(*install_attrs_, Get("enterprise.owned", _))
.WillOnce(DoAll(SetArgPointee<1>(blob_false), Return(true)));
device_management_service_.DetectEnterpriseOwnership();
EXPECT_FALSE(device_management_service_.IsEnterpriseOwned());
}
TEST_F(DeviceManagementServiceAPITest, InstallAttributesGet) {
// Test for successful case.
EXPECT_CALL(*install_attrs_, Get(kInstallAttributeName, _))
.WillOnce(DoAll(SetArgPointee<1>(std::vector<uint8_t>(
std::begin(kInstallAttributeData),
std::end(kInstallAttributeData))),
Return(true)));
std::vector<uint8_t> data;
EXPECT_TRUE(device_management_service_.InstallAttributesGet(
kInstallAttributeName, &data));
EXPECT_THAT(data, ElementsAreArray(kInstallAttributeData));
// Test for unsuccessful case.
EXPECT_CALL(*install_attrs_, Get(kInstallAttributeName, _))
.WillOnce(Return(false));
EXPECT_FALSE(device_management_service_.InstallAttributesGet(
kInstallAttributeName, &data));
}
TEST_F(DeviceManagementServiceAPITest, InstallAttributesSet) {
// Test for successful case.
EXPECT_CALL(*install_attrs_, Set(kInstallAttributeName,
ElementsAreArray(kInstallAttributeData)))
.WillOnce(Return(true));
std::vector<uint8_t> data(std::begin(kInstallAttributeData),
std::end(kInstallAttributeData));
EXPECT_TRUE(device_management_service_.InstallAttributesSet(
kInstallAttributeName, data));
// Test for unsuccessful case.
EXPECT_CALL(*install_attrs_, Set(kInstallAttributeName,
ElementsAreArray(kInstallAttributeData)))
.WillOnce(Return(false));
EXPECT_FALSE(device_management_service_.InstallAttributesSet(
kInstallAttributeName, data));
}
TEST_F(DeviceManagementServiceAPITest, InstallAttributesFinalize) {
// Test for successful case.
EXPECT_CALL(*install_attrs_, Finalize()).WillOnce(Return(true));
EXPECT_CALL(*install_attrs_, Get(_, _)).WillOnce(Return(true));
EXPECT_TRUE(device_management_service_.InstallAttributesFinalize());
// Test for unsuccessful case.
EXPECT_CALL(*install_attrs_, Finalize()).WillOnce(Return(false));
EXPECT_CALL(*install_attrs_, Get(_, _)).WillOnce(Return(true));
EXPECT_FALSE(device_management_service_.InstallAttributesFinalize());
}
TEST_F(DeviceManagementServiceAPITest, InstallAttributesCount) {
constexpr int kCount = 42; // The Answer!!
EXPECT_CALL(*install_attrs_, Count()).WillOnce(Return(kCount));
EXPECT_EQ(kCount, device_management_service_.InstallAttributesCount());
}
TEST_F(DeviceManagementServiceAPITest, InstallAttributesIsSecure) {
// Test for successful case.
EXPECT_CALL(*install_attrs_, IsSecure()).WillOnce(Return(true));
EXPECT_TRUE(device_management_service_.InstallAttributesIsSecure());
// Test for unsuccessful case.
EXPECT_CALL(*install_attrs_, IsSecure()).WillOnce(Return(false));
EXPECT_FALSE(device_management_service_.InstallAttributesIsSecure());
}
TEST_F(DeviceManagementServiceAPITest, InstallAttributesGetStatus) {
constexpr InstallAttributes::Status status_list[] = {
InstallAttributes::Status::kUnknown,
InstallAttributes::Status::kTpmNotOwned,
InstallAttributes::Status::kFirstInstall,
InstallAttributes::Status::kValid,
InstallAttributes::Status::kInvalid,
};
for (auto s : status_list) {
EXPECT_CALL(*install_attrs_, status()).WillOnce(Return(s));
EXPECT_EQ(s, device_management_service_.InstallAttributesGetStatus());
}
}
TEST_F(DeviceManagementServiceAPITest, InstallAttributesStatusToProtoEnum) {
EXPECT_EQ(InstallAttributesState::UNKNOWN,
DeviceManagementService::InstallAttributesStatusToProtoEnum(
InstallAttributes::Status::kUnknown));
EXPECT_EQ(InstallAttributesState::TPM_NOT_OWNED,
DeviceManagementService::InstallAttributesStatusToProtoEnum(
InstallAttributes::Status::kTpmNotOwned));
EXPECT_EQ(InstallAttributesState::FIRST_INSTALL,
DeviceManagementService::InstallAttributesStatusToProtoEnum(
InstallAttributes::Status::kFirstInstall));
EXPECT_EQ(InstallAttributesState::VALID,
DeviceManagementService::InstallAttributesStatusToProtoEnum(
InstallAttributes::Status::kValid));
EXPECT_EQ(InstallAttributesState::INVALID,
DeviceManagementService::InstallAttributesStatusToProtoEnum(
InstallAttributes::Status::kInvalid));
static_assert(InstallAttributesState_MAX == 4,
"Incorrect element count in InstallAttributesState");
static_assert(static_cast<int>(InstallAttributes::Status::COUNT) == 5,
"Incorrect element count in InstallAttributes::Status");
}
} // namespace device_management