/* * Copyright (C) 2020 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 #include #include #include #include #include #include #include "apex_file.h" #include "apexd_test_utils.h" #include "apexd_verity.h" namespace android { namespace apex { using namespace std::literals; using android::apex::testing::IsOk; using android::base::GetExecutableDirectory; using android::base::ReadFileToString; using android::base::StringPrintf; static std::string GetTestDataDir() { return GetExecutableDirectory(); } static std::string GetTestFile(const std::string& name) { return GetTestDataDir() + "/" + name; } TEST(ApexdVerityTest, ReusesHashtree) { TemporaryDir td; auto apex = ApexFile::Open(GetTestFile("apex.apexd_test_no_hashtree.apex")); ASSERT_TRUE(IsOk(apex)); auto verity_data = apex->VerifyApexVerity(apex->GetBundledPublicKey()); ASSERT_TRUE(IsOk(verity_data)); auto hashtree_file = StringPrintf("%s/hashtree", td.path); auto status = PrepareHashTree(*apex, *verity_data, hashtree_file); ASSERT_TRUE(IsOk(status)); ASSERT_EQ(KRegenerate, *status); std::string first_hashtree; ASSERT_TRUE(ReadFileToString(hashtree_file, &first_hashtree)) << "Failed to read " << hashtree_file; // Now call PrepareHashTree again. Since digest matches, hashtree should be // reused. status = PrepareHashTree(*apex, *verity_data, hashtree_file); ASSERT_TRUE(IsOk(status)); ASSERT_EQ(kReuse, *status); std::string second_hashtree; ASSERT_TRUE(ReadFileToString(hashtree_file, &second_hashtree)) << "Failed to read " << hashtree_file; // Hashtree file shouldn't be modified. ASSERT_EQ(first_hashtree, second_hashtree) << hashtree_file << " was regenerated"; } TEST(ApexdVerityTest, RegenerateHashree) { TemporaryDir td; auto apex = ApexFile::Open(GetTestFile("apex.apexd_test_no_hashtree.apex")); ASSERT_TRUE(IsOk(apex)); auto verity_data = apex->VerifyApexVerity(apex->GetBundledPublicKey()); ASSERT_TRUE(IsOk(verity_data)); auto hashtree_file = StringPrintf("%s/hashtree", td.path); auto status = PrepareHashTree(*apex, *verity_data, hashtree_file); ASSERT_TRUE(IsOk(status)); ASSERT_EQ(KRegenerate, *status); std::string first_hashtree; ASSERT_TRUE(ReadFileToString(hashtree_file, &first_hashtree)) << "Failed to read " << hashtree_file; auto apex2 = ApexFile::Open(GetTestFile("apex.apexd_test_no_hashtree_2.apex")); ASSERT_TRUE(IsOk(apex2)); auto verity_data2 = apex2->VerifyApexVerity(apex2->GetBundledPublicKey()); ASSERT_TRUE(IsOk(verity_data2)); // Now call PrepareHashTree again. Since digest doesn't match, hashtree // should be regenerated. status = PrepareHashTree(*apex2, *verity_data2, hashtree_file); ASSERT_TRUE(IsOk(status)); ASSERT_EQ(KRegenerate, *status); std::string second_hashtree; ASSERT_TRUE(ReadFileToString(hashtree_file, &second_hashtree)) << "Failed to read " << hashtree_file; // Hashtree file should be regenerated. ASSERT_NE(first_hashtree, second_hashtree) << hashtree_file << " was reused"; } TEST(ApexdVerityTest, CannotPrepareHashTreeForCompressedApex) { TemporaryDir td; auto apex = ApexFile::Open(GetTestFile("com.android.apex.compressed.v1.capex")); ASSERT_TRUE(IsOk(apex)); std::string hash_tree; ApexVerityData verity_data; auto result = PrepareHashTree(*apex, verity_data, hash_tree); ASSERT_FALSE(IsOk(result)); ASSERT_THAT( result.error().message(), ::testing::HasSubstr("Cannot prepare HashTree of compressed APEX")); } } // namespace apex } // namespace android