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