blob: 42efdf8e8856b6b66eafeaf5b6e83be08932d9a8 [file] [log] [blame]
// Copyright 2018 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "bootlockbox/hwsec_space_impl.h"
#include <memory>
#include <utility>
#include <brillo/secure_blob.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <libhwsec/error/tpm_error.h>
#include <libhwsec/error/tpm_retry_action.h>
#include <libhwsec/frontend/bootlockbox/mock_frontend.h>
#include <libhwsec-foundation/error/testing_helper.h>
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 testing::_;
using testing::Invoke;
using testing::NiceMock;
using testing::Return;
namespace {
// A helper function to serialize a uint16_t.
std::string uint16_to_string(uint16_t value) {
const char* bytes = reinterpret_cast<const char*>(&value);
return std::string(bytes, sizeof(uint16_t));
}
} // namespace
namespace bootlockbox {
class HwsecSpaceImplTest : public testing::Test {
public:
void SetUp() override {
auto hwsec = std::make_unique<hwsec::MockBootLockboxFrontend>();
hwsec_ptr_ = hwsec.get();
space_utility_ = std::make_unique<HwsecSpaceImpl>(std::move(hwsec));
}
protected:
hwsec::MockBootLockboxFrontend* hwsec_ptr_;
std::unique_ptr<HwsecSpaceImpl> space_utility_;
};
TEST_F(HwsecSpaceImplTest, DefineSpaceSuccess) {
EXPECT_CALL(*hwsec_ptr_, GetSpaceState())
.WillOnce(ReturnValue(hwsec::BootLockboxFrontend::StorageState{
.preparable = true,
.readable = false,
.writable = false,
.destroyable = true,
}));
EXPECT_CALL(*hwsec_ptr_, PrepareSpace(kSpaceSize))
.WillOnce(ReturnOk<hwsec::TPMError>());
EXPECT_EQ(space_utility_->DefineSpace(), SpaceState::kSpaceUninitialized);
}
TEST_F(HwsecSpaceImplTest, DefineSpaceAlreadyDefined) {
EXPECT_CALL(*hwsec_ptr_, GetSpaceState())
.WillOnce(ReturnValue(hwsec::BootLockboxFrontend::StorageState{
.preparable = false,
.readable = true,
.writable = true,
.destroyable = false,
}));
EXPECT_EQ(space_utility_->DefineSpace(), SpaceState::kSpaceUninitialized);
}
TEST_F(HwsecSpaceImplTest, DefineSpaceCannotPrepare) {
EXPECT_CALL(*hwsec_ptr_, GetSpaceState())
.WillOnce(ReturnValue(hwsec::BootLockboxFrontend::StorageState{
.preparable = false,
.readable = true,
.writable = false,
.destroyable = false,
}));
EXPECT_EQ(space_utility_->DefineSpace(), SpaceState::kSpaceError);
}
TEST_F(HwsecSpaceImplTest, DefineSpacePrepareFail) {
EXPECT_CALL(*hwsec_ptr_, GetSpaceState())
.WillOnce(ReturnValue(hwsec::BootLockboxFrontend::StorageState{
.preparable = true,
.readable = false,
.writable = false,
.destroyable = true,
}));
EXPECT_CALL(*hwsec_ptr_, PrepareSpace(kSpaceSize))
.WillOnce(ReturnError<hwsec::TPMError>("Fake error",
hwsec::TPMRetryAction::kNoRetry));
EXPECT_EQ(space_utility_->DefineSpace(), SpaceState::kSpaceUndefined);
}
TEST_F(HwsecSpaceImplTest, DefineSpacePowerWash) {
EXPECT_CALL(*hwsec_ptr_, GetSpaceState())
.WillOnce(ReturnError<hwsec::TPMError>("Fake error",
hwsec::TPMRetryAction::kNoRetry));
EXPECT_EQ(space_utility_->DefineSpace(), SpaceState::kSpaceNeedPowerwash);
}
TEST_F(HwsecSpaceImplTest, ReadSpaceReboot) {
EXPECT_CALL(*hwsec_ptr_, GetSpaceState())
.WillOnce(ReturnError<hwsec::TPMError>("Fake error",
hwsec::TPMRetryAction::kNoRetry));
std::string data;
EXPECT_EQ(space_utility_->ReadSpace(&data), SpaceState::kSpaceNeedPowerwash);
}
TEST_F(HwsecSpaceImplTest, ReadSpaceLengthFail) {
std::string nvram_data = uint16_to_string(1) /* version */ +
uint16_to_string(0) /* flags */ +
std::string(3, '\x3');
EXPECT_CALL(*hwsec_ptr_, GetSpaceState())
.WillOnce(ReturnValue(hwsec::BootLockboxFrontend::StorageState{
.preparable = false,
.readable = true,
.writable = true,
.destroyable = false,
}));
EXPECT_CALL(*hwsec_ptr_, LoadSpace())
.WillOnce(ReturnValue(brillo::BlobFromString(nvram_data)));
std::string data;
EXPECT_EQ(space_utility_->ReadSpace(&data), SpaceState::kSpaceError);
}
TEST_F(HwsecSpaceImplTest, ReadSpaceUninitializedFail) {
std::string nvram_data = std::string(kSpaceSize, '\0');
EXPECT_CALL(*hwsec_ptr_, GetSpaceState())
.WillOnce(ReturnValue(hwsec::BootLockboxFrontend::StorageState{
.preparable = false,
.readable = true,
.writable = true,
.destroyable = false,
}));
EXPECT_CALL(*hwsec_ptr_, LoadSpace())
.WillOnce(ReturnValue(brillo::BlobFromString(nvram_data)));
std::string data;
EXPECT_EQ(space_utility_->ReadSpace(&data), SpaceState::kSpaceUninitialized);
}
TEST_F(HwsecSpaceImplTest, ReadSpaceVersionFail) {
BootLockboxSpace space{.version = 2};
std::string nvram_data =
std::string(reinterpret_cast<char*>(&space), kSpaceSize);
EXPECT_CALL(*hwsec_ptr_, GetSpaceState())
.WillOnce(ReturnValue(hwsec::BootLockboxFrontend::StorageState{
.preparable = false,
.readable = true,
.writable = true,
.destroyable = false,
}));
EXPECT_CALL(*hwsec_ptr_, LoadSpace())
.WillOnce(ReturnValue(brillo::BlobFromString(nvram_data)));
std::string data;
EXPECT_EQ(space_utility_->ReadSpace(&data), SpaceState::kSpaceError);
}
TEST_F(HwsecSpaceImplTest, ReadSpaceSuccess) {
std::string test_digest(SHA256_DIGEST_LENGTH, 'a');
BootLockboxSpace space{
.version = 1,
.flags = 0,
};
memcpy(space.digest, test_digest.c_str(), SHA256_DIGEST_LENGTH);
std::string nvram_data =
std::string(reinterpret_cast<char*>(&space), kSpaceSize);
EXPECT_CALL(*hwsec_ptr_, GetSpaceState())
.WillOnce(ReturnValue(hwsec::BootLockboxFrontend::StorageState{
.preparable = false,
.readable = true,
.writable = true,
.destroyable = false,
}));
EXPECT_CALL(*hwsec_ptr_, LoadSpace())
.WillOnce(ReturnValue(brillo::BlobFromString(nvram_data)));
std::string data;
EXPECT_EQ(space_utility_->ReadSpace(&data), SpaceState::kSpaceNormal);
EXPECT_EQ(data, test_digest);
}
TEST_F(HwsecSpaceImplTest, WriteSpaceSuccess) {
std::string nvram_data(SHA256_DIGEST_LENGTH, 'a');
std::string data = uint16_to_string(1) /* version */ +
uint16_to_string(0) /* flags */ + nvram_data;
EXPECT_CALL(*hwsec_ptr_, StoreSpace(brillo::BlobFromString(data)))
.WillOnce(ReturnOk<hwsec::TPMError>());
EXPECT_TRUE(space_utility_->WriteSpace(nvram_data));
}
TEST_F(HwsecSpaceImplTest, WriteSpaceInvalidLength) {
std::string nvram_data = "data of invalid length";
EXPECT_CALL(*hwsec_ptr_, StoreSpace(_)).Times(0);
EXPECT_FALSE(space_utility_->WriteSpace(nvram_data));
}
TEST_F(HwsecSpaceImplTest, LockSpace) {
EXPECT_CALL(*hwsec_ptr_, LockSpace()).WillOnce(ReturnOk<hwsec::TPMError>());
EXPECT_TRUE(space_utility_->LockSpace());
}
TEST_F(HwsecSpaceImplTest, LockSpaceFail) {
EXPECT_CALL(*hwsec_ptr_, LockSpace())
.WillOnce(ReturnError<hwsec::TPMError>("Fake error",
hwsec::TPMRetryAction::kNoRetry));
EXPECT_FALSE(space_utility_->LockSpace());
}
} // namespace bootlockbox