1 //
2 // Copyright (C) 2018 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "update_engine/payload_consumer/verity_writer_android.h"
18
19 #include <fcntl.h>
20
21 #include <brillo/secure_blob.h>
22 #include <gtest/gtest.h>
23
24 #include "update_engine/common/test_utils.h"
25 #include "update_engine/common/utils.h"
26 #include "update_engine/payload_consumer/file_descriptor.h"
27
28 namespace chromeos_update_engine {
29
30 class VerityWriterAndroidTest : public ::testing::Test {
31 protected:
SetUp()32 void SetUp() override {
33 partition_.target_path = temp_file_.path();
34 partition_.block_size = 4096;
35 partition_.hash_tree_data_offset = 0;
36 partition_.hash_tree_data_size = 4096;
37 partition_.hash_tree_offset = 4096;
38 partition_.hash_tree_size = 4096;
39 partition_.hash_tree_algorithm = "sha1";
40 partition_.fec_roots = 2;
41 partition_fd_ = std::make_shared<EintrSafeFileDescriptor>();
42 partition_fd_->Open(partition_.target_path.c_str(), O_RDWR);
43 }
44
45 VerityWriterAndroid verity_writer_;
46 InstallPlan::Partition partition_;
47 FileDescriptorPtr partition_fd_;
48 ScopedTempFile temp_file_;
49 };
50
TEST_F(VerityWriterAndroidTest,SimpleTest)51 TEST_F(VerityWriterAndroidTest, SimpleTest) {
52 brillo::Blob part_data(8192);
53 test_utils::WriteFileVector(partition_.target_path, part_data);
54 ASSERT_TRUE(verity_writer_.Init(partition_));
55 ASSERT_TRUE(verity_writer_.Update(0, part_data.data(), 4096));
56 ASSERT_TRUE(verity_writer_.Update(4096, part_data.data() + 4096, 4096));
57 ASSERT_TRUE(
58 verity_writer_.Finalize(partition_fd_.get(), partition_fd_.get()));
59 brillo::Blob actual_part;
60 utils::ReadFile(partition_.target_path, &actual_part);
61 // dd if=/dev/zero bs=4096 count=1 2>/dev/null | sha1sum | xxd -r -p |
62 // hexdump -v -e '/1 "0x%02x, "'
63 brillo::Blob hash = {0x1c, 0xea, 0xf7, 0x3d, 0xf4, 0x0e, 0x53,
64 0x1d, 0xf3, 0xbf, 0xb2, 0x6b, 0x4f, 0xb7,
65 0xcd, 0x95, 0xfb, 0x7b, 0xff, 0x1d};
66 memcpy(part_data.data() + 4096, hash.data(), hash.size());
67 ASSERT_EQ(part_data, actual_part);
68 }
69
TEST_F(VerityWriterAndroidTest,NoOpTest)70 TEST_F(VerityWriterAndroidTest, NoOpTest) {
71 partition_.hash_tree_data_size = 0;
72 partition_.hash_tree_size = 0;
73 brillo::Blob part_data(4096);
74 ASSERT_TRUE(verity_writer_.Init(partition_));
75 ASSERT_TRUE(verity_writer_.Update(0, part_data.data(), part_data.size()));
76 ASSERT_TRUE(verity_writer_.Update(4096, part_data.data(), part_data.size()));
77 ASSERT_TRUE(verity_writer_.Update(8192, part_data.data(), part_data.size()));
78 }
79
TEST_F(VerityWriterAndroidTest,DiscontinuedRead)80 TEST_F(VerityWriterAndroidTest, DiscontinuedRead) {
81 partition_.hash_tree_data_size = 8192;
82 partition_.hash_tree_size = 4096;
83 brillo::Blob part_data(4096);
84 ASSERT_TRUE(verity_writer_.Init(partition_));
85 ASSERT_TRUE(verity_writer_.Update(0, part_data.data(), part_data.size()));
86 ASSERT_FALSE(verity_writer_.Update(8192, part_data.data(), part_data.size()));
87 }
88
TEST_F(VerityWriterAndroidTest,InvalidHashAlgorithmTest)89 TEST_F(VerityWriterAndroidTest, InvalidHashAlgorithmTest) {
90 partition_.hash_tree_algorithm = "sha123";
91 ASSERT_FALSE(verity_writer_.Init(partition_));
92 }
93
TEST_F(VerityWriterAndroidTest,WrongHashTreeSizeTest)94 TEST_F(VerityWriterAndroidTest, WrongHashTreeSizeTest) {
95 partition_.hash_tree_size = 8192;
96 ASSERT_FALSE(verity_writer_.Init(partition_));
97 }
98
TEST_F(VerityWriterAndroidTest,SHA256Test)99 TEST_F(VerityWriterAndroidTest, SHA256Test) {
100 partition_.hash_tree_algorithm = "sha256";
101 brillo::Blob part_data(8192);
102 test_utils::WriteFileVector(partition_.target_path, part_data);
103 ASSERT_TRUE(verity_writer_.Init(partition_));
104 ASSERT_TRUE(verity_writer_.Update(0, part_data.data(), 4096));
105 ASSERT_TRUE(verity_writer_.Update(4096, part_data.data() + 4096, 4096));
106 ASSERT_TRUE(
107 verity_writer_.Finalize(partition_fd_.get(), partition_fd_.get()));
108 brillo::Blob actual_part;
109 utils::ReadFile(partition_.target_path, &actual_part);
110 // dd if=/dev/zero bs=4096 count=1 2>/dev/null | sha256sum | xxd -r -p |
111 // hexdump -v -e '/1 "0x%02x, "'
112 brillo::Blob hash = {0xad, 0x7f, 0xac, 0xb2, 0x58, 0x6f, 0xc6, 0xe9,
113 0x66, 0xc0, 0x04, 0xd7, 0xd1, 0xd1, 0x6b, 0x02,
114 0x4f, 0x58, 0x05, 0xff, 0x7c, 0xb4, 0x7c, 0x7a,
115 0x85, 0xda, 0xbd, 0x8b, 0x48, 0x89, 0x2c, 0xa7};
116 memcpy(part_data.data() + 4096, hash.data(), hash.size());
117 ASSERT_EQ(part_data, actual_part);
118 }
119
TEST_F(VerityWriterAndroidTest,NonZeroOffsetSHA256Test)120 TEST_F(VerityWriterAndroidTest, NonZeroOffsetSHA256Test) {
121 partition_.hash_tree_algorithm = "sha256";
122 partition_.hash_tree_data_offset = 100;
123 partition_.hash_tree_offset =
124 partition_.hash_tree_data_offset + partition_.hash_tree_data_size;
125 brillo::Blob part_data(8192 + partition_.hash_tree_data_offset);
126 test_utils::WriteFileVector(partition_.target_path, part_data);
127 ASSERT_TRUE(verity_writer_.Init(partition_));
128 ASSERT_TRUE(verity_writer_.Update(0, part_data.data(), 4096));
129 ASSERT_TRUE(verity_writer_.Update(4096, part_data.data() + 4096, 4096));
130 ASSERT_TRUE(verity_writer_.Update(
131 8192, part_data.data() + 8192, partition_.hash_tree_data_offset));
132 ASSERT_TRUE(
133 verity_writer_.Finalize(partition_fd_.get(), partition_fd_.get()));
134 brillo::Blob actual_part;
135 utils::ReadFile(partition_.target_path, &actual_part);
136 // dd if=/dev/zero bs=4096 count=1 2>/dev/null | sha256sum | xxd -r -p |
137 // hexdump -v -e '/1 "0x%02x, "'
138 brillo::Blob hash = {0xad, 0x7f, 0xac, 0xb2, 0x58, 0x6f, 0xc6, 0xe9,
139 0x66, 0xc0, 0x04, 0xd7, 0xd1, 0xd1, 0x6b, 0x02,
140 0x4f, 0x58, 0x05, 0xff, 0x7c, 0xb4, 0x7c, 0x7a,
141 0x85, 0xda, 0xbd, 0x8b, 0x48, 0x89, 0x2c, 0xa7};
142 memcpy(
143 part_data.data() + partition_.hash_tree_offset, hash.data(), hash.size());
144 ASSERT_EQ(part_data, actual_part);
145 }
146
TEST_F(VerityWriterAndroidTest,FECTest)147 TEST_F(VerityWriterAndroidTest, FECTest) {
148 partition_.fec_data_offset = 0;
149 partition_.fec_data_size = 4096;
150 partition_.fec_offset = 4096;
151 partition_.fec_size = 2 * 4096;
152 brillo::Blob part_data(3 * 4096, 0x1);
153 test_utils::WriteFileVector(partition_.target_path, part_data);
154 ASSERT_TRUE(verity_writer_.Init(partition_));
155 ASSERT_TRUE(verity_writer_.Update(0, part_data.data(), part_data.size()));
156 ASSERT_TRUE(
157 verity_writer_.Finalize(partition_fd_.get(), partition_fd_.get()));
158 brillo::Blob actual_part;
159 utils::ReadFile(partition_.target_path, &actual_part);
160 // Write FEC data.
161 for (size_t i = 4096; i < part_data.size(); i += 2) {
162 part_data[i] = 0x8e;
163 part_data[i + 1] = 0x8f;
164 }
165 ASSERT_EQ(part_data, actual_part);
166 }
167
TEST_F(VerityWriterAndroidTest,HashTreeDisabled)168 TEST_F(VerityWriterAndroidTest, HashTreeDisabled) {
169 partition_.hash_tree_size = 0;
170 partition_.hash_tree_data_size = 0;
171 partition_.hash_tree_offset = 0;
172 partition_.hash_tree_data_offset = 0;
173
174 partition_.fec_data_offset = 0;
175 partition_.fec_data_size = 4096;
176 partition_.fec_offset = 4096;
177 partition_.fec_size = 2 * 4096;
178 brillo::Blob part_data(3 * 4096, 0x1);
179 test_utils::WriteFileVector(partition_.target_path, part_data);
180 ASSERT_TRUE(verity_writer_.Init(partition_));
181 ASSERT_TRUE(verity_writer_.Update(0, part_data.data(), part_data.size()));
182 ASSERT_TRUE(
183 verity_writer_.Finalize(partition_fd_.get(), partition_fd_.get()));
184 }
185
186 } // namespace chromeos_update_engine
187