1 /*
2 * Copyright (C) 2024 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 "apexd_brand_new_verifier.h"
18
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <android-base/properties.h>
22 #include <android-base/result-gmock.h>
23 #include <android-base/stringprintf.h>
24 #include <gtest/gtest.h>
25 #include <sys/stat.h>
26
27 #include <filesystem>
28 #include <string>
29
30 #include "apex_constants.h"
31 #include "apex_file_repository.h"
32 #include "apexd_test_utils.h"
33
34 namespace android::apex {
35
36 namespace fs = std::filesystem;
37
38 using android::base::GetExecutableDirectory;
39 using android::base::testing::Ok;
40 using android::base::testing::WithMessage;
41 using ::testing::Not;
42
GetTestDataDir()43 static std::string GetTestDataDir() { return GetExecutableDirectory(); }
GetTestFile(const std::string & name)44 static std::string GetTestFile(const std::string& name) {
45 return GetTestDataDir() + "/" + name;
46 }
47
TEST(BrandNewApexVerifierTest,SucceedPublicKeyMatch)48 TEST(BrandNewApexVerifierTest, SucceedPublicKeyMatch) {
49 ApexFileRepository::EnableBrandNewApex();
50 auto& file_repository = ApexFileRepository::GetInstance();
51 const auto partition = ApexPartition::System;
52 TemporaryDir trusted_key_dir;
53 fs::copy(GetTestFile("apexd_testdata/com.android.apex.brand.new.avbpubkey"),
54 trusted_key_dir.path);
55 file_repository.AddBrandNewApexCredentialAndBlocklist(
56 {{partition, trusted_key_dir.path}});
57
58 auto apex = ApexFile::Open(GetTestFile("com.android.apex.brand.new.apex"));
59 ASSERT_RESULT_OK(apex);
60
61 auto ret = VerifyBrandNewPackageAgainstPreinstalled(*apex);
62 ASSERT_RESULT_OK(ret);
63 ASSERT_EQ(*ret, partition);
64
65 file_repository.Reset();
66 }
67
TEST(BrandNewApexVerifierTest,SucceedVersionBiggerThanBlocked)68 TEST(BrandNewApexVerifierTest, SucceedVersionBiggerThanBlocked) {
69 ApexFileRepository::EnableBrandNewApex();
70 auto& file_repository = ApexFileRepository::GetInstance();
71 const auto partition = ApexPartition::System;
72 TemporaryDir config_dir;
73 fs::copy(GetTestFile("apexd_testdata/com.android.apex.brand.new.avbpubkey"),
74 config_dir.path);
75 fs::copy(GetTestFile("apexd_testdata/blocklist.json"), config_dir.path);
76 file_repository.AddBrandNewApexCredentialAndBlocklist(
77 {{partition, config_dir.path}});
78
79 auto apex = ApexFile::Open(GetTestFile("com.android.apex.brand.new.v2.apex"));
80 ASSERT_RESULT_OK(apex);
81
82 auto ret = VerifyBrandNewPackageAgainstPreinstalled(*apex);
83 ASSERT_RESULT_OK(ret);
84 ASSERT_EQ(*ret, partition);
85
86 file_repository.Reset();
87 }
88
TEST(BrandNewApexVerifierTest,SucceedMatchActive)89 TEST(BrandNewApexVerifierTest, SucceedMatchActive) {
90 ApexFileRepository::EnableBrandNewApex();
91 auto& file_repository = ApexFileRepository::GetInstance();
92 TemporaryDir trusted_key_dir, data_dir;
93 fs::copy(GetTestFile("apexd_testdata/com.android.apex.brand.new.avbpubkey"),
94 trusted_key_dir.path);
95 fs::copy(GetTestFile("com.android.apex.brand.new.apex"), data_dir.path);
96 file_repository.AddBrandNewApexCredentialAndBlocklist(
97 {{ApexPartition::System, trusted_key_dir.path}});
98 file_repository.AddDataApex(data_dir.path);
99
100 auto apex = ApexFile::Open(GetTestFile("com.android.apex.brand.new.v2.apex"));
101 ASSERT_RESULT_OK(apex);
102
103 auto ret = VerifyBrandNewPackageAgainstActive(*apex);
104 ASSERT_RESULT_OK(ret);
105
106 file_repository.Reset();
107 }
108
TEST(BrandNewApexVerifierTest,SucceedSkipPreinstalled)109 TEST(BrandNewApexVerifierTest, SucceedSkipPreinstalled) {
110 ApexFileRepository::EnableBrandNewApex();
111 auto& file_repository = ApexFileRepository::GetInstance();
112 TemporaryDir built_in_dir;
113 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
114 file_repository.AddPreInstalledApex(
115 {{ApexPartition::System, built_in_dir.path}});
116
117 auto apex = ApexFile::Open(GetTestFile("apex.apexd_test.apex"));
118 ASSERT_RESULT_OK(apex);
119
120 auto ret = VerifyBrandNewPackageAgainstActive(*apex);
121 ASSERT_RESULT_OK(ret);
122
123 file_repository.Reset();
124 }
125
TEST(BrandNewApexVerifierTest,SucceedSkipWithoutDataVersion)126 TEST(BrandNewApexVerifierTest, SucceedSkipWithoutDataVersion) {
127 ApexFileRepository::EnableBrandNewApex();
128 auto& file_repository = ApexFileRepository::GetInstance();
129
130 auto apex = ApexFile::Open(GetTestFile("com.android.apex.brand.new.apex"));
131 ASSERT_RESULT_OK(apex);
132
133 auto ret = VerifyBrandNewPackageAgainstActive(*apex);
134 ASSERT_RESULT_OK(ret);
135
136 file_repository.Reset();
137 }
138
TEST(BrandNewApexVerifierTest,FailBrandNewApexDisabled)139 TEST(BrandNewApexVerifierTest, FailBrandNewApexDisabled) {
140 auto& file_repository = ApexFileRepository::GetInstance();
141 const auto partition = ApexPartition::System;
142 TemporaryDir trusted_key_dir;
143 fs::copy(GetTestFile("apexd_testdata/com.android.apex.brand.new.avbpubkey"),
144 trusted_key_dir.path);
145 file_repository.AddBrandNewApexCredentialAndBlocklist(
146 {{partition, trusted_key_dir.path}});
147
148 auto apex = ApexFile::Open(GetTestFile("com.android.apex.brand.new.apex"));
149 ASSERT_RESULT_OK(apex);
150
151 ASSERT_DEATH(
152 { VerifyBrandNewPackageAgainstPreinstalled(*apex); },
153 "Brand-new APEX must be enabled in order to do verification.");
154 ASSERT_DEATH(
155 { VerifyBrandNewPackageAgainstActive(*apex); },
156 "Brand-new APEX must be enabled in order to do verification.");
157
158 file_repository.Reset();
159 }
160
TEST(BrandNewApexVerifierTest,FailNoMatchingPublicKey)161 TEST(BrandNewApexVerifierTest, FailNoMatchingPublicKey) {
162 ApexFileRepository::EnableBrandNewApex();
163
164 auto apex = ApexFile::Open(GetTestFile("com.android.apex.brand.new.apex"));
165 ASSERT_RESULT_OK(apex);
166
167 auto ret = VerifyBrandNewPackageAgainstPreinstalled(*apex);
168 ASSERT_THAT(
169 ret,
170 HasError(WithMessage(("No pre-installed public key found for the "
171 "brand-new APEX: com.android.apex.brand.new"))));
172 }
173
TEST(BrandNewApexVerifierTest,FailBlockedByVersion)174 TEST(BrandNewApexVerifierTest, FailBlockedByVersion) {
175 ApexFileRepository::EnableBrandNewApex();
176 auto& file_repository = ApexFileRepository::GetInstance();
177 const auto partition = ApexPartition::System;
178 TemporaryDir config_dir;
179 fs::copy(GetTestFile("apexd_testdata/com.android.apex.brand.new.avbpubkey"),
180 config_dir.path);
181 fs::copy(GetTestFile("apexd_testdata/blocklist.json"), config_dir.path);
182 file_repository.AddBrandNewApexCredentialAndBlocklist(
183 {{partition, config_dir.path}});
184
185 auto apex = ApexFile::Open(GetTestFile("com.android.apex.brand.new.apex"));
186 ASSERT_RESULT_OK(apex);
187
188 auto ret = VerifyBrandNewPackageAgainstPreinstalled(*apex);
189 ASSERT_THAT(ret,
190 HasError(WithMessage(
191 ("Brand-new APEX is blocked: com.android.apex.brand.new"))));
192
193 file_repository.Reset();
194 }
195
TEST(BrandNewApexVerifierTest,FailPublicKeyNotMatchActive)196 TEST(BrandNewApexVerifierTest, FailPublicKeyNotMatchActive) {
197 ApexFileRepository::EnableBrandNewApex();
198 auto& file_repository = ApexFileRepository::GetInstance();
199 TemporaryDir trusted_key_dir, data_dir;
200 fs::copy(GetTestFile("apexd_testdata/com.android.apex.brand.new.avbpubkey"),
201 trusted_key_dir.path);
202 fs::copy(GetTestFile(
203 "apexd_testdata/com.android.apex.brand.new.another.avbpubkey"),
204 trusted_key_dir.path);
205 fs::copy(GetTestFile("com.android.apex.brand.new.apex"), data_dir.path);
206 file_repository.AddBrandNewApexCredentialAndBlocklist(
207 {{ApexPartition::System, trusted_key_dir.path}});
208 file_repository.AddDataApex(data_dir.path);
209
210 auto apex =
211 ApexFile::Open(GetTestFile("com.android.apex.brand.new.v2.diffkey.apex"));
212 ASSERT_RESULT_OK(apex);
213
214 auto ret = VerifyBrandNewPackageAgainstActive(*apex);
215 ASSERT_THAT(
216 ret,
217 HasError(WithMessage(("Brand-new APEX public key doesn't match existing "
218 "active APEX: com.android.apex.brand.new"))));
219
220 file_repository.Reset();
221 }
222
223 } // namespace android::apex
224