David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 1 | // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Xiaoyong Zhou | b6f2090 | 2018-01-17 17:54:48 -0800 | [diff] [blame] | 5 | #include "cryptohome/bootlockbox/boot_attributes.h" |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 6 | |
| 7 | #include <map> |
Gwendal Grignou | c7acaa9 | 2016-06-24 15:34:06 -0700 | [diff] [blame] | 8 | #include <memory> |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 9 | #include <string> |
| 10 | |
| 11 | #include <base/compiler_specific.h> |
Gwendal Grignou | dcdc1a4 | 2016-06-30 09:41:01 -0700 | [diff] [blame] | 12 | #include <base/files/file_path.h> |
Alex Vakulenko | e769653 | 2015-10-16 16:27:29 -0700 | [diff] [blame] | 13 | #include <brillo/secure_blob.h> |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 14 | #include <gmock/gmock.h> |
| 15 | #include <gtest/gtest.h> |
| 16 | |
Xiaoyong Zhou | b6f2090 | 2018-01-17 17:54:48 -0800 | [diff] [blame] | 17 | #include "cryptohome/bootlockbox/mock_boot_lockbox.h" |
Greg Kerr | f9b0fc1 | 2020-08-13 22:29:10 +0000 | [diff] [blame] | 18 | #include "cryptohome/install_attributes.pb.h" |
Alex Vakulenko | b4b694a | 2014-07-18 17:21:35 -0700 | [diff] [blame] | 19 | #include "cryptohome/mock_crypto.h" |
| 20 | #include "cryptohome/mock_platform.h" |
| 21 | #include "cryptohome/mock_tpm.h" |
| 22 | |
Gwendal Grignou | dcdc1a4 | 2016-06-30 09:41:01 -0700 | [diff] [blame] | 23 | using base::FilePath; |
Maksim Ivanov | cab8a0c | 2018-02-22 20:55:12 +0100 | [diff] [blame] | 24 | using ::testing::_; |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 25 | using ::testing::DoAll; |
| 26 | using ::testing::Invoke; |
Maksim Ivanov | cab8a0c | 2018-02-22 20:55:12 +0100 | [diff] [blame] | 27 | using ::testing::NiceMock; |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 28 | using ::testing::Return; |
| 29 | using ::testing::SetArgPointee; |
| 30 | |
| 31 | namespace cryptohome { |
| 32 | namespace { |
| 33 | |
| 34 | class BootAttributesTest : public testing::Test { |
| 35 | public: |
Tom Hughes | 6711cdc | 2020-09-14 08:34:01 -0700 | [diff] [blame] | 36 | BootAttributesTest() : fake_signature_("fake signature") {} |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 37 | |
Alex Vakulenko | 0945eaf | 2014-08-14 12:55:41 -0700 | [diff] [blame] | 38 | void SetUp() override { |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 39 | ON_CALL(mock_boot_lockbox_, Sign(_, _)) |
| 40 | .WillByDefault(DoAll(SetArgPointee<1>(fake_signature_), Return(true))); |
| 41 | |
Tom Hughes | 6711cdc | 2020-09-14 08:34:01 -0700 | [diff] [blame] | 42 | ON_CALL(mock_boot_lockbox_, Verify(_, _)).WillByDefault(Return(true)); |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 43 | |
| 44 | ON_CALL(mock_platform_, ReadFile(_, _)) |
| 45 | .WillByDefault(Invoke(this, &BootAttributesTest::FakeReadFile)); |
| 46 | |
Jorge Lucangeli Obes | ed0481c | 2018-05-01 09:46:22 -0400 | [diff] [blame] | 47 | ON_CALL(mock_platform_, ReadFileToSecureBlob(_, _)) |
| 48 | .WillByDefault( |
| 49 | Invoke(this, &BootAttributesTest::FakeReadFileToSecureBlob)); |
| 50 | |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 51 | ON_CALL(mock_platform_, WriteFile(_, _)) |
| 52 | .WillByDefault(Invoke(this, &BootAttributesTest::FakeWriteFile)); |
| 53 | |
| 54 | CreateFakeFiles(); |
| 55 | |
| 56 | boot_attributes_.reset( |
| 57 | new BootAttributes(&mock_boot_lockbox_, &mock_platform_)); |
| 58 | } |
| 59 | |
| 60 | void CreateFakeFiles() { |
| 61 | SerializedInstallAttributes message; |
| 62 | message.set_version(1); |
| 63 | SerializedInstallAttributes::Attribute* attr = message.add_attributes(); |
| 64 | attr->set_name("test1"); |
| 65 | attr->set_value("1234"); |
| 66 | |
Allen Webb | 9b4dc78 | 2020-05-15 13:09:44 -0700 | [diff] [blame] | 67 | brillo::Blob blob(message.ByteSizeLong()); |
Alex Vakulenko | 89f59bb | 2015-03-25 16:21:34 -0700 | [diff] [blame] | 68 | message.SerializeWithCachedSizesToArray(blob.data()); |
Gwendal Grignou | dcdc1a4 | 2016-06-30 09:41:01 -0700 | [diff] [blame] | 69 | files_[FilePath(BootAttributes::kAttributeFile)] = blob; |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 70 | |
| 71 | blob.clear(); |
Gwendal Grignou | dcdc1a4 | 2016-06-30 09:41:01 -0700 | [diff] [blame] | 72 | files_[FilePath(BootAttributes::kSignatureFile)] = blob; |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 73 | } |
| 74 | |
Gwendal Grignou | dcdc1a4 | 2016-06-30 09:41:01 -0700 | [diff] [blame] | 75 | bool FakeReadFile(const FilePath& filename, brillo::Blob* blob) { |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 76 | *blob = files_[filename]; |
| 77 | return true; |
| 78 | } |
| 79 | |
Jorge Lucangeli Obes | ed0481c | 2018-05-01 09:46:22 -0400 | [diff] [blame] | 80 | bool FakeReadFileToSecureBlob(const FilePath& filename, |
| 81 | brillo::SecureBlob* sblob) { |
| 82 | brillo::Blob temp = files_[filename]; |
| 83 | sblob->assign(temp.begin(), temp.end()); |
| 84 | return true; |
| 85 | } |
| 86 | |
Gwendal Grignou | dcdc1a4 | 2016-06-30 09:41:01 -0700 | [diff] [blame] | 87 | bool FakeWriteFile(const FilePath& filename, brillo::Blob blob) { |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 88 | files_[filename] = blob; |
| 89 | return true; |
| 90 | } |
| 91 | |
| 92 | protected: |
Alex Vakulenko | e769653 | 2015-10-16 16:27:29 -0700 | [diff] [blame] | 93 | const brillo::SecureBlob fake_signature_; |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 94 | |
Darren Krahn | 5c76c01 | 2014-09-22 15:14:52 -0700 | [diff] [blame] | 95 | NiceMock<MockBootLockbox> mock_boot_lockbox_; |
| 96 | NiceMock<MockPlatform> mock_platform_; |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 97 | |
Gwendal Grignou | c7acaa9 | 2016-06-24 15:34:06 -0700 | [diff] [blame] | 98 | std::unique_ptr<BootAttributes> boot_attributes_; |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 99 | |
Gwendal Grignou | dcdc1a4 | 2016-06-30 09:41:01 -0700 | [diff] [blame] | 100 | std::map<FilePath, brillo::Blob> files_; |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 101 | }; |
| 102 | |
| 103 | TEST_F(BootAttributesTest, BasicOperations) { |
| 104 | std::string value; |
| 105 | |
| 106 | // Empty initially. |
| 107 | EXPECT_FALSE(boot_attributes_->Get("test1", &value)); |
| 108 | |
| 109 | // Load values from the file. |
| 110 | EXPECT_TRUE(boot_attributes_->Load()); |
| 111 | EXPECT_TRUE(boot_attributes_->Get("test1", &value)); |
| 112 | EXPECT_EQ("1234", value); |
| 113 | |
| 114 | // The value should still be unavailable after Set(). |
| 115 | boot_attributes_->Set("test2", "5678"); |
| 116 | EXPECT_FALSE(boot_attributes_->Get("test2", &value)); |
| 117 | |
| 118 | // The value becomes available after FlushAndSign(). |
| 119 | EXPECT_TRUE(boot_attributes_->FlushAndSign()); |
| 120 | EXPECT_TRUE(boot_attributes_->Get("test2", &value)); |
| 121 | EXPECT_EQ("5678", value); |
| 122 | |
| 123 | // Overwrite a value |
| 124 | boot_attributes_->Set("test1", "abcd"); |
| 125 | EXPECT_TRUE(boot_attributes_->FlushAndSign()); |
| 126 | EXPECT_TRUE(boot_attributes_->Get("test1", &value)); |
| 127 | EXPECT_EQ("abcd", value); |
| 128 | |
| 129 | // Verify the attribute file content. |
Gwendal Grignou | dcdc1a4 | 2016-06-30 09:41:01 -0700 | [diff] [blame] | 130 | brillo::Blob blob = files_[FilePath(BootAttributes::kAttributeFile)]; |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 131 | SerializedInstallAttributes message; |
| 132 | message.ParseFromString( |
Alex Vakulenko | 89f59bb | 2015-03-25 16:21:34 -0700 | [diff] [blame] | 133 | std::string(reinterpret_cast<char*>(blob.data()), blob.size())); |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 134 | EXPECT_EQ(BootAttributes::kAttributeFileVersion, message.version()); |
| 135 | |
| 136 | EXPECT_EQ(2, message.attributes_size()); |
| 137 | bool has_test1 = false; |
| 138 | bool has_test2 = false; |
| 139 | for (int i = 0; i < message.attributes_size(); ++i) { |
| 140 | const SerializedInstallAttributes::Attribute& attr = message.attributes(i); |
| 141 | if (attr.name() == "test1") { |
| 142 | has_test1 = true; |
| 143 | EXPECT_EQ("abcd", attr.value()); |
| 144 | } else if (attr.name() == "test2") { |
| 145 | has_test2 = true; |
| 146 | EXPECT_EQ("5678", attr.value()); |
| 147 | } else { |
| 148 | FAIL(); |
| 149 | } |
| 150 | } |
| 151 | EXPECT_TRUE(has_test1); |
| 152 | EXPECT_TRUE(has_test2); |
| 153 | |
| 154 | // Verify the signature file content. |
Gwendal Grignou | dcdc1a4 | 2016-06-30 09:41:01 -0700 | [diff] [blame] | 155 | blob = files_[FilePath(BootAttributes::kSignatureFile)]; |
Tom Hughes | 6711cdc | 2020-09-14 08:34:01 -0700 | [diff] [blame] | 156 | EXPECT_EQ("fake signature", |
| 157 | std::string(reinterpret_cast<char*>(blob.data()), blob.size())); |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | TEST_F(BootAttributesTest, SignFailed) { |
Tom Hughes | 6711cdc | 2020-09-14 08:34:01 -0700 | [diff] [blame] | 161 | EXPECT_CALL(mock_boot_lockbox_, Sign(_, _)).WillRepeatedly(Return(false)); |
| 162 | EXPECT_CALL(mock_platform_, WriteFile(_, _)).Times(0); |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 163 | |
| 164 | boot_attributes_->Set("test", "1234"); |
| 165 | EXPECT_FALSE(boot_attributes_->FlushAndSign()); |
| 166 | } |
| 167 | |
| 168 | TEST_F(BootAttributesTest, WriteFileFailed) { |
Tom Hughes | 6711cdc | 2020-09-14 08:34:01 -0700 | [diff] [blame] | 169 | EXPECT_CALL(mock_platform_, WriteFile(_, _)).WillRepeatedly(Return(false)); |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 170 | |
| 171 | boot_attributes_->Set("test", "1234"); |
| 172 | EXPECT_FALSE(boot_attributes_->FlushAndSign()); |
| 173 | } |
| 174 | |
| 175 | TEST_F(BootAttributesTest, ReadFileFailed) { |
Jorge Lucangeli Obes | 36e3b77 | 2018-06-05 16:40:56 -0400 | [diff] [blame] | 176 | EXPECT_CALL(mock_platform_, ReadFile(_, _)).WillRepeatedly(Return(false)); |
Jorge Lucangeli Obes | ed0481c | 2018-05-01 09:46:22 -0400 | [diff] [blame] | 177 | EXPECT_CALL(mock_platform_, ReadFileToSecureBlob(_, _)) |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 178 | .WillRepeatedly(Return(false)); |
| 179 | |
| 180 | EXPECT_FALSE(boot_attributes_->Load()); |
| 181 | } |
| 182 | |
| 183 | TEST_F(BootAttributesTest, VerifyFailed) { |
Tom Hughes | 6711cdc | 2020-09-14 08:34:01 -0700 | [diff] [blame] | 184 | EXPECT_CALL(mock_boot_lockbox_, Verify(_, _)).WillRepeatedly(Return(false)); |
David Yu | 7acfc2e | 2014-06-28 08:32:50 +0800 | [diff] [blame] | 185 | |
| 186 | EXPECT_FALSE(boot_attributes_->Load()); |
| 187 | } |
| 188 | |
| 189 | } // namespace |
| 190 | } // namespace cryptohome |