summaryrefslogtreecommitdiff
path: root/libfec
diff options
context:
space:
mode:
authorTianjie Xu <xunchang@google.com>2019-11-21 10:25:17 -0800
committerTianjie Xu <xunchang@google.com>2019-12-18 11:34:57 -0800
commitfb4066a3900492e46a46b7d2ee09708e3168314f (patch)
tree4c87bb04b8f0caeb8be4d66e2973523dddcea04a /libfec
parentb577ab32de1cd9bdf672f49b036597b7c9fa3515 (diff)
downloadextras-fb4066a3900492e46a46b7d2ee09708e3168314f.tar.gz
Add test to parse verity data
Add a unittest to load and verify a VB1.0 image. Bug: 144388532 Test: unittest pass Change-Id: I1bfc93239a6696c58e9220864009759a2468e136
Diffstat (limited to 'libfec')
-rw-r--r--libfec/test/Android.bp27
-rw-r--r--libfec/test/fec_unittest.cpp169
2 files changed, 195 insertions, 1 deletions
diff --git a/libfec/test/Android.bp b/libfec/test/Android.bp
index 5cc6d86d..1bbad077 100644
--- a/libfec/test/Android.bp
+++ b/libfec/test/Android.bp
@@ -1,7 +1,6 @@
cc_defaults {
name: "fec_test_defaults",
- gtest: false,
sanitize: {
misc_undefined: ["integer"],
},
@@ -20,6 +19,7 @@ cc_defaults {
cc_test_host {
name: "fec_test_read",
defaults: ["fec_test_defaults"],
+ gtest: false,
srcs: ["test_read.cpp"],
static_libs: [
"libfec",
@@ -35,6 +35,31 @@ cc_test_host {
cc_test_host {
name: "fec_test_rs",
defaults: ["fec_test_defaults"],
+ gtest: false,
srcs: ["test_rs.c"],
static_libs: ["libfec_rs"],
}
+
+cc_test_host {
+ name: "fec_unittest",
+ defaults: ["fec_test_defaults"],
+ srcs: ["fec_unittest.cpp"],
+
+ gtest: true,
+ required: [
+ "fec",
+ ],
+ static_libs: [
+ "libverity_tree",
+ "libfec",
+ "libfec_rs",
+ "libcrypto_utils",
+ "libext4_utils",
+ "libsquashfs_utils",
+ "libgtest_prod",
+ "libcrypto",
+ "libcutils",
+ "liblog",
+ "libbase",
+ ],
+}
diff --git a/libfec/test/fec_unittest.cpp b/libfec/test/fec_unittest.cpp
new file mode 100644
index 00000000..f2c1e7dc
--- /dev/null
+++ b/libfec/test/fec_unittest.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <gtest/gtest.h>
+#include <verity/hash_tree_builder.h>
+
+#include "../fec_private.h"
+#include "fec/io.h"
+
+class FecUnitTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ // Construct a 1 MiB image as file system.
+ image_.reserve(1024 * 1024);
+ for (unsigned i = 0; i <= 255; i++) {
+ std::vector<uint8_t> tmp_vec(4096, i);
+ image_.insert(image_.end(), tmp_vec.begin(), tmp_vec.end());
+ }
+
+ // Build the hashtree.
+ HashTreeBuilder builder(4096, HashTreeBuilder::HashFunction("sha256"));
+ // Use a random salt.
+ salt_ = std::vector<uint8_t>(64, 10);
+ ASSERT_TRUE(builder.Initialize(image_.size(), salt_));
+ ASSERT_TRUE(builder.Update(image_.data(), image_.size()));
+ ASSERT_TRUE(builder.BuildHashTree());
+ root_hash_ = builder.root_hash();
+
+ // Append the hashtree to the end of image.
+ TemporaryFile temp_file;
+ ASSERT_TRUE(builder.WriteHashTreeToFd(temp_file.fd, 0));
+ android::base::ReadFileToString(temp_file.path, &hashtree_content_);
+ image_.insert(image_.end(), hashtree_content_.begin(),
+ hashtree_content_.end());
+ }
+
+ // Builds the verity metadata and appends the bytes to the image.
+ void BuildAndAppendsVerityMetadata() {
+ // The metadata table has the format: "1 block_device, block_device,
+ // BLOCK_SIZE, BLOCK_SIZE, data_blocks, data_blocks, 'sha256',
+ // root_hash, salt".
+ std::vector<std::string> table = {
+ "1",
+ "fake_block_device",
+ "fake_block_device",
+ "4096",
+ "4096",
+ "256",
+ "256",
+ "sha256",
+ HashTreeBuilder::BytesArrayToString(root_hash_),
+ HashTreeBuilder::BytesArrayToString(salt_),
+ };
+ verity_table_ = android::base::Join(table, ' ');
+
+ verity_header_ = {
+ 0xb001b001, 0, {}, static_cast<unsigned int>(verity_table_.size())
+ };
+
+ // Construct the verity metadata with header, table, and padding.
+ constexpr auto VERITY_META_SIZE = 8 * 4096;
+ image_.insert(image_.end(),
+ reinterpret_cast<uint8_t *>(&verity_header_),
+ reinterpret_cast<uint8_t *>(&verity_header_) +
+ sizeof(verity_header_));
+ image_.insert(image_.end(), verity_table_.data(),
+ verity_table_.data() + verity_table_.size());
+ std::vector<uint8_t> padding(
+ VERITY_META_SIZE - sizeof(verity_header_) - verity_table_.size(),
+ 0);
+ image_.insert(image_.end(), padding.begin(), padding.end());
+ }
+
+ static void BuildAndAppendsEccImage(const std::string &image_name,
+ const std::string &fec_name) {
+ std::vector<std::string> cmd = { "fec", "--encode", "--roots",
+ "2", image_name, fec_name };
+ ASSERT_EQ(0, std::system(android::base::Join(cmd, ' ').c_str()));
+ }
+
+ std::vector<uint8_t> image_;
+ std::vector<uint8_t> salt_;
+ std::vector<uint8_t> root_hash_;
+ std::string hashtree_content_;
+ verity_header verity_header_;
+ std::string verity_table_;
+};
+
+TEST_F(FecUnitTest, LoadVerityImage_ParseVerity) {
+ TemporaryFile verity_image;
+ BuildAndAppendsVerityMetadata();
+ ASSERT_TRUE(android::base::WriteFully(verity_image.fd, image_.data(),
+ image_.size()));
+
+ struct fec_handle *handle = nullptr;
+ ASSERT_EQ(0, fec_open(&handle, verity_image.path, O_RDONLY, FEC_FS_EXT4, 2));
+ std::unique_ptr<fec_handle> guard(handle);
+
+ ASSERT_EQ(image_.size(), handle->size);
+ ASSERT_EQ(1024 * 1024, handle->data_size); // filesystem size
+
+ ASSERT_EQ(1024 * 1024 + hashtree_content_.size(),
+ handle->verity.metadata_start);
+ ASSERT_EQ(verity_header_.length, handle->verity.header.length);
+ ASSERT_EQ(verity_table_, handle->verity.table);
+
+ // check the hashtree.
+ ASSERT_EQ(salt_, handle->hashtree().salt);
+ ASSERT_EQ(1024 * 1024, handle->hashtree().hash_start);
+ // the fec hashtree only stores the hash of the lowest level.
+ ASSERT_EQ(std::vector<uint8_t>(hashtree_content_.begin() + 4096,
+ hashtree_content_.end()),
+ handle->hashtree().hash);
+ ASSERT_EQ(hashtree_content_.size(), handle->hashtree().hash_size);
+}
+
+TEST_F(FecUnitTest, LoadVerityImage_ParseEcc) {
+ TemporaryFile verity_image;
+ BuildAndAppendsVerityMetadata();
+ ASSERT_TRUE(android::base::WriteFully(verity_image.fd, image_.data(),
+ image_.size()));
+ TemporaryFile ecc_image;
+ BuildAndAppendsEccImage(verity_image.path, ecc_image.path);
+ std::string ecc_content;
+ ASSERT_TRUE(android::base::ReadFileToString(ecc_image.path, &ecc_content));
+ ASSERT_TRUE(android::base::WriteStringToFd(ecc_content, verity_image.fd));
+ struct fec_handle *handle = nullptr;
+ ASSERT_EQ(0, fec_open(&handle, verity_image.path, O_RDONLY, FEC_FS_EXT4, 2));
+ std::unique_ptr<fec_handle> guard(handle);
+
+ ASSERT_EQ(1024 * 1024, handle->data_size); // filesystem size
+ ASSERT_EQ(1024 * 1024 + hashtree_content_.size(),
+ handle->verity.metadata_start);
+
+ fec_verity_metadata verity_metadata{};
+ ASSERT_EQ(0, fec_verity_get_metadata(handle, &verity_metadata));
+ ASSERT_FALSE(verity_metadata.disabled);
+ ASSERT_EQ(1024 * 1024, verity_metadata.data_size);
+ ASSERT_EQ(verity_table_, verity_metadata.table);
+
+ fec_ecc_metadata ecc_metadata{};
+ ASSERT_EQ(0, fec_ecc_get_metadata(handle, &ecc_metadata));
+ ASSERT_TRUE(ecc_metadata.valid);
+ ASSERT_EQ(handle->verity.metadata_start + 8 * 4096, ecc_metadata.start);
+ ASSERT_EQ(2, ecc_metadata.roots);
+ // 256 (data) + 3 (hashtree) + 8 (verity meta)
+ ASSERT_EQ(267, ecc_metadata.blocks);
+}