blob: 7da06fd788e2e28d0606760ae442f5a499e51dfe [file] [log] [blame]
// Copyright 2013 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Unit tests for Lockbox.
#include "cryptohome/lockbox.h"
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/notreached.h>
#include <brillo/secure_blob.h>
#include <gtest/gtest.h>
#include <libhwsec/frontend/cryptohome/mock_frontend.h>
#include <libhwsec-foundation/crypto/secure_blob_util.h>
#include <libhwsec-foundation/crypto/sha.h>
#include <libhwsec-foundation/error/testing_helper.h>
#include "cryptohome/mock_lockbox.h"
#include "cryptohome/mock_platform.h"
namespace cryptohome {
using ::brillo::SecureBlob;
using ::hwsec::TPMError;
using ::hwsec::TPMErrorBase;
using ::hwsec::TPMRetryAction;
using ::hwsec_foundation::SecureBlobToHex;
using ::hwsec_foundation::Sha256;
using ::hwsec_foundation::error::testing::ReturnError;
using ::hwsec_foundation::error::testing::ReturnOk;
using ::hwsec_foundation::error::testing::ReturnValue;
using ::testing::_;
using ::testing::DoAll;
using ::testing::Eq;
using ::testing::InSequence;
using ::testing::Mock;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
// Provides a test fixture for ensuring Lockbox-flows work as expected.
//
// Multiple helpers are included to ensure tests are starting from the same
// baseline for difference scenarios, such as first boot or all-other-normal
// boots.
class LockboxTest : public ::testing::Test {
public:
LockboxTest() : lockbox_(&hwsec_, hwsec::Space::kInstallAttributes) {}
LockboxTest(const LockboxTest&) = delete;
LockboxTest& operator=(const LockboxTest&) = delete;
~LockboxTest() override = default;
void SetUp() override {
// Create the OOBE data to reuse for post-boot tests.
// This generates the expected NVRAM value and serialized file data.
file_data_.assign(kFileData, kFileData + strlen(kFileData));
}
protected:
static inline constexpr char kFileData[] = "42";
Lockbox lockbox_;
NiceMock<hwsec::MockCryptohomeFrontend> hwsec_;
brillo::Blob file_data_;
};
TEST_F(LockboxTest, ResetOk) {
EXPECT_CALL(hwsec_, PrepareSpace(hwsec::Space::kInstallAttributes,
LockboxContents::kNvramSize))
.WillOnce(ReturnOk<TPMError>());
LockboxError error;
EXPECT_TRUE(lockbox_.Reset(&error));
}
TEST_F(LockboxTest, ResetFailed) {
EXPECT_CALL(hwsec_, PrepareSpace(hwsec::Space::kInstallAttributes,
LockboxContents::kNvramSize))
.WillOnce(ReturnError<TPMError>("fake", TPMRetryAction::kNoRetry));
LockboxError error;
EXPECT_FALSE(lockbox_.Reset(&error));
EXPECT_EQ(error, LockboxError::kTpmError);
}
TEST_F(LockboxTest, StoreOk) {
EXPECT_CALL(hwsec_, StoreSpace(hwsec::Space::kInstallAttributes, _))
.WillOnce(ReturnOk<TPMError>());
LockboxError error;
EXPECT_TRUE(lockbox_.Store(file_data_, &error));
}
TEST_F(LockboxTest, StoreFailed) {
EXPECT_CALL(hwsec_, StoreSpace(hwsec::Space::kInstallAttributes, _))
.WillOnce(ReturnError<TPMError>("fake", TPMRetryAction::kNoRetry));
LockboxError error;
EXPECT_FALSE(lockbox_.Store(file_data_, &error));
EXPECT_EQ(error, LockboxError::kTpmError);
}
class LockboxContentsTest : public testing::Test {
public:
LockboxContentsTest() = default;
void GenerateNvramData(brillo::SecureBlob* nvram_data) {
std::unique_ptr<LockboxContents> contents = LockboxContents::New();
ASSERT_TRUE(contents);
ASSERT_TRUE(contents->SetKeyMaterial(
brillo::SecureBlob(contents->key_material_size(), 'A')));
ASSERT_TRUE(contents->Protect({42}));
ASSERT_TRUE(contents->Encode(nvram_data));
}
void LoadAndVerify(const brillo::SecureBlob& nvram_data,
const brillo::Blob& data,
LockboxContents::VerificationResult expected_result) {
std::unique_ptr<LockboxContents> contents = LockboxContents::New();
ASSERT_TRUE(contents);
ASSERT_TRUE(contents->Decode(nvram_data));
EXPECT_EQ(expected_result, contents->Verify(data));
}
};
TEST_F(LockboxContentsTest, LoadAndVerifyOk) {
brillo::SecureBlob nvram_data;
ASSERT_NO_FATAL_FAILURE(GenerateNvramData(&nvram_data));
LoadAndVerify(nvram_data, {42}, LockboxContents::VerificationResult::kValid);
}
TEST_F(LockboxContentsTest, LoadAndVerifyBadSize) {
SecureBlob nvram_data;
ASSERT_NO_FATAL_FAILURE(GenerateNvramData(&nvram_data));
// Change the expected file size to 0.
nvram_data[0] = 0;
nvram_data[1] = 0;
nvram_data[2] = 0;
nvram_data[3] = 0;
LoadAndVerify(nvram_data, {42},
LockboxContents::VerificationResult::kSizeMismatch);
}
TEST_F(LockboxContentsTest, LoadAndVerifyBadHash) {
SecureBlob nvram_data;
ASSERT_NO_FATAL_FAILURE(GenerateNvramData(&nvram_data));
// Invalidate the hash.
nvram_data.back() ^= 0xff;
LoadAndVerify(nvram_data, {42},
LockboxContents::VerificationResult::kHashMismatch);
}
TEST_F(LockboxContentsTest, LoadAndVerifyBadData) {
SecureBlob nvram_data;
ASSERT_NO_FATAL_FAILURE(GenerateNvramData(&nvram_data));
LoadAndVerify(nvram_data, {17},
LockboxContents::VerificationResult::kHashMismatch);
}
} // namespace cryptohome