1 /*
2 * Copyright (C) 2020 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 <string>
18
19 #include <errno.h>
20 #include <sys/stat.h>
21
22 #include <android-base/file.h>
23 #include <android-base/logging.h>
24 #include <android-base/stringprintf.h>
25 #include <gtest/gtest.h>
26
27 #include "apex_file.h"
28 #include "apexd_test_utils.h"
29 #include "apexd_verity.h"
30
31 namespace android {
32 namespace apex {
33
34 using namespace std::literals;
35
36 using android::apex::testing::IsOk;
37 using android::base::GetExecutableDirectory;
38 using android::base::ReadFileToString;
39 using android::base::StringPrintf;
40
GetTestDataDir()41 static std::string GetTestDataDir() { return GetExecutableDirectory(); }
GetTestFile(const std::string & name)42 static std::string GetTestFile(const std::string& name) {
43 return GetTestDataDir() + "/" + name;
44 }
45
TEST(ApexdVerityTest,ReusesHashtree)46 TEST(ApexdVerityTest, ReusesHashtree) {
47 TemporaryDir td;
48
49 auto apex = ApexFile::Open(GetTestFile("apex.apexd_test_no_hashtree.apex"));
50 ASSERT_TRUE(IsOk(apex));
51 auto verity_data = apex->VerifyApexVerity(apex->GetBundledPublicKey());
52 ASSERT_TRUE(IsOk(verity_data));
53
54 auto hashtree_file = StringPrintf("%s/hashtree", td.path);
55 auto status = PrepareHashTree(*apex, *verity_data, hashtree_file);
56 ASSERT_TRUE(IsOk(status));
57 ASSERT_EQ(KRegenerate, *status);
58
59 std::string first_hashtree;
60 ASSERT_TRUE(ReadFileToString(hashtree_file, &first_hashtree))
61 << "Failed to read " << hashtree_file;
62
63 // Now call PrepareHashTree again. Since digest matches, hashtree should be
64 // reused.
65 status = PrepareHashTree(*apex, *verity_data, hashtree_file);
66 ASSERT_TRUE(IsOk(status));
67 ASSERT_EQ(kReuse, *status);
68
69 std::string second_hashtree;
70 ASSERT_TRUE(ReadFileToString(hashtree_file, &second_hashtree))
71 << "Failed to read " << hashtree_file;
72
73 // Hashtree file shouldn't be modified.
74 ASSERT_EQ(first_hashtree, second_hashtree)
75 << hashtree_file << " was regenerated";
76 }
77
TEST(ApexdVerityTest,RegenerateHashree)78 TEST(ApexdVerityTest, RegenerateHashree) {
79 TemporaryDir td;
80
81 auto apex = ApexFile::Open(GetTestFile("apex.apexd_test_no_hashtree.apex"));
82 ASSERT_TRUE(IsOk(apex));
83 auto verity_data = apex->VerifyApexVerity(apex->GetBundledPublicKey());
84 ASSERT_TRUE(IsOk(verity_data));
85
86 auto hashtree_file = StringPrintf("%s/hashtree", td.path);
87 auto status = PrepareHashTree(*apex, *verity_data, hashtree_file);
88 ASSERT_TRUE(IsOk(status));
89 ASSERT_EQ(KRegenerate, *status);
90
91 std::string first_hashtree;
92 ASSERT_TRUE(ReadFileToString(hashtree_file, &first_hashtree))
93 << "Failed to read " << hashtree_file;
94
95 auto apex2 =
96 ApexFile::Open(GetTestFile("apex.apexd_test_no_hashtree_2.apex"));
97 ASSERT_TRUE(IsOk(apex2));
98 auto verity_data2 = apex2->VerifyApexVerity(apex2->GetBundledPublicKey());
99 ASSERT_TRUE(IsOk(verity_data2));
100
101 // Now call PrepareHashTree again. Since digest doesn't match, hashtree
102 // should be regenerated.
103 status = PrepareHashTree(*apex2, *verity_data2, hashtree_file);
104 ASSERT_TRUE(IsOk(status));
105 ASSERT_EQ(KRegenerate, *status);
106
107 std::string second_hashtree;
108 ASSERT_TRUE(ReadFileToString(hashtree_file, &second_hashtree))
109 << "Failed to read " << hashtree_file;
110
111 // Hashtree file should be regenerated.
112 ASSERT_NE(first_hashtree, second_hashtree) << hashtree_file << " was reused";
113 }
114
TEST(ApexdVerityTest,CannotPrepareHashTreeForCompressedApex)115 TEST(ApexdVerityTest, CannotPrepareHashTreeForCompressedApex) {
116 TemporaryDir td;
117
118 auto apex =
119 ApexFile::Open(GetTestFile("com.android.apex.compressed.v1.capex"));
120 ASSERT_TRUE(IsOk(apex));
121 std::string hash_tree;
122 ApexVerityData verity_data;
123 auto result = PrepareHashTree(*apex, verity_data, hash_tree);
124 ASSERT_FALSE(IsOk(result));
125 ASSERT_THAT(
126 result.error().message(),
127 ::testing::HasSubstr("Cannot prepare HashTree of compressed APEX"));
128 }
129
130 } // namespace apex
131 } // namespace android
132