1 /*
2  * Copyright (C) 2019 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 "fs_avb_test_util.h"
18 
19 #include <stdlib.h>
20 
21 #include <android-base/file.h>
22 #include <base/files/file_util.h>
23 #include <base/strings/string_util.h>
24 
25 namespace fs_avb_host_test {
26 
27 // Need to match the data setting in Android.bp:
28 //     data: ["tests/data/*"]
29 base::FilePath BaseFsAvbTest::data_dir_ = base::FilePath("tests/data");
30 
SetUp()31 void BaseFsAvbTest::SetUp() {
32     // Changes current directory to test executable directory so that relative path
33     // references to test dependencies don't rely on being manually run from
34     // the executable directory. With this, we can just open "./tests/data/testkey_rsa2048.pem"
35     // from the source.
36     base::SetCurrentDirectory(base::FilePath(android::base::GetExecutableDirectory()));
37 
38     // Creates a temporary directory, e.g., /tmp/libfs_avb-tests.XXXXXX to stash images in.
39     base::FilePath tmp_dir;
40     ASSERT_TRUE(GetTempDir(&tmp_dir));
41     base::CreateTemporaryDirInDir(tmp_dir, "libfs_avb-tests.", &test_dir_);
42 }
43 
TearDown()44 void BaseFsAvbTest::TearDown() {
45     // Nukes temporary directory.
46     ASSERT_NE(std::string::npos, test_dir_.value().find("libfs_avb-tests"));
47     ASSERT_TRUE(base::DeleteFile(test_dir_, true /* recursive */));
48 }
49 
CalcVBMetaDigest(const std::string & file_name,const std::string & hash_algorithm)50 std::string BaseFsAvbTest::CalcVBMetaDigest(const std::string& file_name,
51                                             const std::string& hash_algorithm) {
52     auto iter = vbmeta_images_.find(file_name);
53     EXPECT_NE(iter, vbmeta_images_.end());  // ensures file_name is generated before.
54 
55     // Gets the image path from iterator->second.path: VBMetaImage.path.
56     base::FilePath image_path = iter->second.path;
57     base::FilePath vbmeta_digest_path = test_dir_.Append("vbmeta_digest");
58     EXPECT_COMMAND(0,
59                    "avbtool calculate_vbmeta_digest --image %s --hash_algorithm %s"
60                    " --output %s",
61                    image_path.value().c_str(), hash_algorithm.c_str(),
62                    vbmeta_digest_path.value().c_str());
63     // Reads the content of the output digest file.
64     std::string vbmeta_digest_data;
65     EXPECT_TRUE(base::ReadFileToString(vbmeta_digest_path, &vbmeta_digest_data));
66     // Returns the trimmed digest.
67     std::string trimmed_digest_data;
68     base::TrimString(vbmeta_digest_data, " \t\n", &trimmed_digest_data);
69     return trimmed_digest_data;
70 }
71 
GenerateVBMetaImage(const std::string & file_name,const std::string & avb_algorithm,uint64_t rollback_index,const base::FilePath & key_path,const std::vector<base::FilePath> & include_descriptor_image_paths,const std::vector<ChainPartitionConfig> & chain_partitions,const std::string & additional_options)72 base::FilePath BaseFsAvbTest::GenerateVBMetaImage(
73         const std::string& file_name, const std::string& avb_algorithm, uint64_t rollback_index,
74         const base::FilePath& key_path,
75         const std::vector<base::FilePath>& include_descriptor_image_paths,
76         const std::vector<ChainPartitionConfig>& chain_partitions,
77         const std::string& additional_options) {
78     // --algorithm and --key
79     std::string signing_options;
80     if (avb_algorithm == "") {
81         signing_options = " --algorithm NONE ";
82     } else {
83         signing_options =
84                 std::string(" --algorithm ") + avb_algorithm + " --key " + key_path.value() + " ";
85     }
86     // --include_descriptors_from_image
87     std::string include_descriptor_options;
88     for (const auto& path : include_descriptor_image_paths) {
89         include_descriptor_options += " --include_descriptors_from_image " + path.value();
90     }
91     // --chain_partitions
92     std::string chain_partition_options;
93     for (const auto& partition : chain_partitions) {
94         chain_partition_options += base::StringPrintf(
95                 " --chain_partition %s:%u:%s", partition.partition_name.c_str(),
96                 partition.rollback_index_location, partition.key_blob_path.value().c_str());
97     }
98     // Starts to 'make_vbmeta_image'.
99     VBMetaImage vbmeta_image;
100     vbmeta_image.path = test_dir_.Append(file_name);
101     EXPECT_COMMAND(0,
102                    "avbtool make_vbmeta_image"
103                    " --rollback_index %" PRIu64
104                    " %s %s %s %s"
105                    " --output %s",
106                    rollback_index, signing_options.c_str(), include_descriptor_options.c_str(),
107                    chain_partition_options.c_str(), additional_options.c_str(),
108                    vbmeta_image.path.value().c_str());
109     int64_t file_size;
110     EXPECT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size));
111     vbmeta_image.content.resize(file_size);
112     EXPECT_TRUE(base::ReadFile(vbmeta_image.path,
113                                reinterpret_cast<char*>(vbmeta_image.content.data()), file_size));
114     // Stores the generated vbmeta image into vbmeta_images_ member object.
115     vbmeta_images_.emplace(file_name, std::move(vbmeta_image));
116 
117     return vbmeta_images_[file_name].path;  // returns the path.
118 }
119 
ExtractVBMetaImage(const base::FilePath & image_path,const std::string & output_file_name,const size_t padding_size)120 base::FilePath BaseFsAvbTest::ExtractVBMetaImage(const base::FilePath& image_path,
121                                                  const std::string& output_file_name,
122                                                  const size_t padding_size) {
123     VBMetaImage vbmeta_image;
124     vbmeta_image.path = test_dir_.Append(output_file_name);
125     GTEST_LOG_(INFO) << "ExtractVBMetaImage: " << image_path << " to " << output_file_name;
126     EXPECT_COMMAND(0,
127                    "avbtool extract_vbmeta_image"
128                    " --image %s"
129                    " --output %s"
130                    " --padding_size %zu",
131                    image_path.value().c_str(), vbmeta_image.path.value().c_str(), padding_size);
132     int64_t file_size;
133     EXPECT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size));
134     vbmeta_image.content.resize(file_size);
135     EXPECT_TRUE(base::ReadFile(vbmeta_image.path,
136                                reinterpret_cast<char*>(vbmeta_image.content.data()), file_size));
137     // Stores the extracted vbmeta image into vbmeta_images_ member object.
138     vbmeta_images_.emplace(output_file_name, std::move(vbmeta_image));
139 
140     // Returns the output file path.
141     return vbmeta_images_[output_file_name].path;
142 }
143 
144 // Generates a file with name |file_name| of size |image_size| with
145 // known content (0x00 0x01 0x02 .. 0xff 0x00 0x01 ..).
GenerateImage(const std::string & file_name,size_t image_size,uint8_t start_byte)146 base::FilePath BaseFsAvbTest::GenerateImage(const std::string& file_name, size_t image_size,
147                                             uint8_t start_byte) {
148     std::vector<uint8_t> image;
149     image.resize(image_size);
150     for (size_t n = 0; n < image_size; n++) {
151         image[n] = uint8_t(n + start_byte);
152     }
153     base::FilePath image_path = test_dir_.Append(file_name);
154     EXPECT_EQ(image_size,
155               static_cast<const size_t>(base::WriteFile(
156                       image_path, reinterpret_cast<const char*>(image.data()), image.size())));
157     return image_path;
158 }
159 
AddAvbFooter(const base::FilePath & image_path,const std::string & footer_type,const std::string & partition_name,const uint64_t partition_size,const std::string & avb_algorithm,uint64_t rollback_index,const base::FilePath & key_path,const std::string & salt,const std::string & additional_options)160 void BaseFsAvbTest::AddAvbFooter(const base::FilePath& image_path, const std::string& footer_type,
161                                  const std::string& partition_name, const uint64_t partition_size,
162                                  const std::string& avb_algorithm, uint64_t rollback_index,
163                                  const base::FilePath& key_path, const std::string& salt,
164                                  const std::string& additional_options) {
165     // 'add_hash_footer' or 'add_hashtree_footer'.
166     EXPECT_TRUE(footer_type == "hash" or footer_type == "hashtree");
167     std::string add_footer_option = "add_" + footer_type + "_footer";
168 
169     std::string signing_options;
170     if (avb_algorithm == "") {
171         signing_options = " --algorithm NONE ";
172     } else {
173         signing_options =
174                 std::string(" --algorithm ") + avb_algorithm + " --key " + key_path.value() + " ";
175     }
176     EXPECT_COMMAND(0,
177                    "avbtool %s"
178                    " --image %s"
179                    " --partition_name %s "
180                    " --partition_size %" PRIu64 " --rollback_index %" PRIu64
181                    " --salt %s"
182                    " %s %s",
183                    add_footer_option.c_str(), image_path.value().c_str(), partition_name.c_str(),
184                    partition_size, rollback_index, salt.c_str(), signing_options.c_str(),
185                    additional_options.c_str());
186 }
187 
GenerateImageAndExtractVBMetaData(const std::string & partition_name,const size_t image_size,const size_t partition_size,const std::string & footer_type,const base::FilePath & avb_signing_key,const std::string & avb_algorithm,const uint64_t rollback_index)188 VBMetaData BaseFsAvbTest::GenerateImageAndExtractVBMetaData(
189         const std::string& partition_name, const size_t image_size, const size_t partition_size,
190         const std::string& footer_type, const base::FilePath& avb_signing_key,
191         const std::string& avb_algorithm, const uint64_t rollback_index) {
192     // Generates a raw image first
193     base::FilePath image_path = GenerateImage(partition_name + ".img", image_size);
194 
195     // Appends AVB Hashtree Footer.
196     AddAvbFooter(image_path, footer_type, partition_name, partition_size, avb_algorithm,
197                  rollback_index, avb_signing_key, "d00df00d",
198                  "--internal_release_string \"unit test\"");
199 
200     // Extracts vbmeta from the ram image into another *-vbmeta.img.
201     auto vbmeta_image = ExtractVBMetaImage(image_path, partition_name + "-vbmeta.img");
202 
203     // Loads *-vbmeta.img into a VBMetaData.
204     std::string vbmeta_buffer;
205     EXPECT_TRUE(base::ReadFileToString(vbmeta_image, &vbmeta_buffer));
206 
207     return {(const uint8_t*)vbmeta_buffer.data(), vbmeta_buffer.size(), partition_name};
208 }
209 
LoadVBMetaData(const std::string & file_name)210 VBMetaData BaseFsAvbTest::LoadVBMetaData(const std::string& file_name) {
211     auto iter = vbmeta_images_.find(file_name);
212     EXPECT_NE(iter, vbmeta_images_.end());  // ensures file_name is generated before.
213 
214     // Gets the image path from iterator->second.path: VBMetaImage.path.
215     base::FilePath image_path = iter->second.path;
216 
217     // Loads the vbmeta_image into a VBMetaData.
218     std::string vbmeta_buffer;
219     EXPECT_TRUE(base::ReadFileToString(image_path, &vbmeta_buffer));
220 
221     std::string partition_name = image_path.RemoveExtension().BaseName().value();
222     return {(const uint8_t*)vbmeta_buffer.data(), vbmeta_buffer.size(), partition_name};
223 }
224 
ExtractAndLoadVBMetaData(const base::FilePath & image_path,const std::string & output_file_name)225 VBMetaData BaseFsAvbTest::ExtractAndLoadVBMetaData(const base::FilePath& image_path,
226                                                    const std::string& output_file_name) {
227     ExtractVBMetaImage(image_path, output_file_name);
228     return LoadVBMetaData(output_file_name);
229 }
230 
InfoImage(const base::FilePath & image_path)231 std::string BaseFsAvbTest::InfoImage(const base::FilePath& image_path) {
232     base::FilePath tmp_path = test_dir_.Append("info_output.txt");
233     EXPECT_COMMAND(0, "avbtool info_image --image %s --output %s", image_path.value().c_str(),
234                    tmp_path.value().c_str());
235     std::string info_data;
236     EXPECT_TRUE(base::ReadFileToString(tmp_path, &info_data));
237     return info_data;
238 }
239 
InfoImage(const std::string & file_name)240 std::string BaseFsAvbTest::InfoImage(const std::string& file_name) {
241     auto iter = vbmeta_images_.find(file_name);
242     EXPECT_NE(iter, vbmeta_images_.end());  // ensures file_name is generated before.
243     // Gets the image path from iterator->second.path: VBMetaImage.path.
244     base::FilePath image_path = iter->second.path;
245     return InfoImage(image_path);
246 }
247 
ExtractPublicKeyAvb(const base::FilePath & key_path)248 base::FilePath BaseFsAvbTest::ExtractPublicKeyAvb(const base::FilePath& key_path) {
249     std::string file_name = key_path.RemoveExtension().BaseName().value();
250     base::FilePath tmp_path = test_dir_.Append(file_name + "public_key.bin");
251     EXPECT_COMMAND(0,
252                    "avbtool extract_public_key --key %s"
253                    " --output %s",
254                    key_path.value().c_str(), tmp_path.value().c_str());
255     return tmp_path;
256 }
257 
ExtractPublicKeyAvbBlob(const base::FilePath & key_path)258 std::string BaseFsAvbTest::ExtractPublicKeyAvbBlob(const base::FilePath& key_path) {
259     base::FilePath tmp_path = test_dir_.Append("public_key.bin");
260     EXPECT_COMMAND(0,
261                    "avbtool extract_public_key --key %s"
262                    " --output %s",
263                    key_path.value().c_str(), tmp_path.value().c_str());
264     std::string key_data;
265     EXPECT_TRUE(base::ReadFileToString(tmp_path, &key_data));
266     return key_data;
267 }
268 
269 }  // namespace fs_avb_host_test
270