1 /*
2  * Copyright (C) 2016 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 package android.appsecurity.cts;
18 
19 import static org.junit.Assert.fail;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertNull;
22 import static org.junit.Assume.assumeTrue;
23 
24 import android.platform.test.annotations.AsbSecurityTest;
25 import android.platform.test.annotations.Presubmit;
26 import android.platform.test.flag.junit.CheckFlagsRule;
27 import android.platform.test.flag.junit.host.HostFlagsValueProvider;
28 
29 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
30 import com.android.compatibility.common.util.CddTest;
31 import com.android.tradefed.device.DeviceNotAvailableException;
32 import com.android.tradefed.testtype.junit4.DeviceParameterizedRunner;
33 import com.android.tradefed.util.FileUtil;
34 
35 import org.junit.After;
36 import org.junit.Before;
37 import org.junit.Rule;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 
41 import java.io.BufferedOutputStream;
42 import java.io.File;
43 import java.io.FileOutputStream;
44 import java.io.IOException;
45 import java.io.InputStream;
46 import java.io.OutputStream;
47 import java.util.Locale;
48 import java.util.Objects;
49 import java.util.stream.Stream;
50 
51 import junitparams.Parameters;
52 
53 /**
54  * Tests for APK signature verification during installation.
55  */
56 @Presubmit
57 @RunWith(DeviceParameterizedRunner.class)
58 public class PkgInstallSignatureVerificationTest extends BaseAppSecurityTest {
59 
60     private static final String TEST_PKG = "android.appsecurity.cts.tinyapp";
61     private static final String TEST_PKG2 = "android.appsecurity.cts.tinyapp2";
62     private static final String COMPANION_TEST_PKG = "android.appsecurity.cts.tinyapp_companion";
63     private static final String COMPANION2_TEST_PKG = "android.appsecurity.cts.tinyapp_companion2";
64     private static final String COMPANION3_TEST_PKG = "android.appsecurity.cts.tinyapp_companion3";
65     private static final String DEVICE_TESTS_APK = "CtsV3SigningSchemeRotationTest.apk";
66     private static final String DEVICE_TESTS_PKG = "android.appsecurity.cts.v3rotationtests";
67     private static final String DEVICE_TESTS_CLASS = DEVICE_TESTS_PKG + ".V3RotationTest";
68     private static final String SERVICE_PKG = "android.appsecurity.cts.keyrotationtest";
69     private static final String SERVICE_TEST_PKG = "android.appsecurity.cts.keyrotationtest.test";
70     private static final String SERVICE_TEST_CLASS =
71             SERVICE_TEST_PKG + ".SignatureQueryServiceInstrumentationTest";
72     private static final String TEST_APK_RESOURCE_PREFIX = "/pkgsigverify/";
73     private static final String INSTALL_ARG_FORCE_QUERYABLE = "--force-queryable";
74     private static final String INSTALL_ARG_BYPASS_LOW_TARGET_SDK_BLOCK =
75             "--bypass-low-target-sdk-block";
76 
77     private static final String[] DSA_KEY_NAMES = {"1024", "2048", "3072"};
78     private static final String[] EC_KEY_NAMES = {"p256", "p384", "p521"};
79     private static final String[] RSA_KEY_NAMES = {"1024", "2048", "3072", "4096", "8192", "16384"};
80     private static final String[] RSA_KEY_NAMES_2048_AND_LARGER =
81             {"2048", "3072", "4096", "8192", "16384"};
82 
83     private static final boolean INCREMENTAL = true;
84     private static final boolean NON_INCREMENTAL = false;
85 
installOnIncremental()86     private static Object[] installOnIncremental() {
87         // Incremental and Non-Incremental.
88         return new Boolean[][]{{INCREMENTAL}, {NON_INCREMENTAL}};
89     }
90 
91     private boolean mUseIncrementalForInstallWithIdsig;
92 
93     @Rule
94     public final CheckFlagsRule mCheckFlagsRule =
95             HostFlagsValueProvider.createCheckFlagsRule(this::getDevice);
96 
97     @Before
setUp()98     public void setUp() throws Exception {
99         Utils.prepareSingleUser(getDevice());
100         uninstallPackage();
101         uninstallCompanionPackages();
102         installDeviceTestPkg();
103     }
104 
105     @After
tearDown()106     public void tearDown() throws Exception {
107         uninstallPackages();
108     }
109 
110     @Test
testInstallOriginalSucceeds()111     public void testInstallOriginalSucceeds() throws Exception {
112         // APK signed with v1 and v2 schemes. Obtained by building
113         // cts/hostsidetests/appsecurity/test-apps/tinyapp.
114         assertInstallSucceeds("original.apk");
115     }
116 
117     @Test
testInstallV1OneSignerMD5withRSA()118     public void testInstallV1OneSignerMD5withRSA() throws Exception {
119         // APK signed with v1 scheme only, one signer.
120         assertInstallSucceedsForEach(
121                 "v1-only-with-rsa-pkcs1-md5-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES);
122         assertInstallSucceedsForEach(
123                 "v1-only-with-rsa-pkcs1-md5-1.2.840.113549.1.1.4-%s.apk", RSA_KEY_NAMES);
124     }
125 
126     @Test
testInstallV1OneSignerSHA1withRSA()127     public void testInstallV1OneSignerSHA1withRSA() throws Exception {
128         // APK signed with v1 scheme only, one signer.
129         assertInstallSucceedsForEach(
130                 "v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES);
131         assertInstallSucceedsForEach(
132                 "v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.5-%s.apk", RSA_KEY_NAMES);
133     }
134 
135     @Test
testInstallV1OneSignerSHA224withRSA()136     public void testInstallV1OneSignerSHA224withRSA() throws Exception {
137         // APK signed with v1 scheme only, one signer.
138         assertInstallSucceedsForEach(
139                 "v1-only-with-rsa-pkcs1-sha224-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES);
140         assertInstallSucceedsForEach(
141                 "v1-only-with-rsa-pkcs1-sha224-1.2.840.113549.1.1.14-%s.apk", RSA_KEY_NAMES);
142     }
143 
144     @Test
testInstallV1OneSignerSHA256withRSA()145     public void testInstallV1OneSignerSHA256withRSA() throws Exception {
146         // APK signed with v1 scheme only, one signer.
147         assertInstallSucceedsForEach(
148                 "v1-only-with-rsa-pkcs1-sha256-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES);
149         assertInstallSucceedsForEach(
150                 "v1-only-with-rsa-pkcs1-sha256-1.2.840.113549.1.1.11-%s.apk", RSA_KEY_NAMES);
151     }
152 
153     @Test
testInstallV1OneSignerSHA384withRSA()154     public void testInstallV1OneSignerSHA384withRSA() throws Exception {
155         // APK signed with v1 scheme only, one signer.
156         assertInstallSucceedsForEach(
157                 "v1-only-with-rsa-pkcs1-sha384-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES);
158         assertInstallSucceedsForEach(
159                 "v1-only-with-rsa-pkcs1-sha384-1.2.840.113549.1.1.12-%s.apk", RSA_KEY_NAMES);
160     }
161 
162     @Test
testInstallV1OneSignerSHA512withRSA()163     public void testInstallV1OneSignerSHA512withRSA() throws Exception {
164         // APK signed with v1 scheme only, one signer.
165         assertInstallSucceedsForEach(
166                 "v1-only-with-rsa-pkcs1-sha512-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES);
167         assertInstallSucceedsForEach(
168                 "v1-only-with-rsa-pkcs1-sha512-1.2.840.113549.1.1.13-%s.apk", RSA_KEY_NAMES);
169     }
170 
171     @Test
testInstallV1OneSignerSHA1withECDSA()172     public void testInstallV1OneSignerSHA1withECDSA() throws Exception {
173         // APK signed with v1 scheme only, one signer.
174         assertInstallSucceedsForEach(
175                 "v1-only-with-ecdsa-sha1-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES);
176         assertInstallSucceedsForEach(
177                 "v1-only-with-ecdsa-sha1-1.2.840.10045.4.1-%s.apk", EC_KEY_NAMES);
178     }
179 
180     @Test
testInstallV1OneSignerSHA224withECDSA()181     public void testInstallV1OneSignerSHA224withECDSA() throws Exception {
182         // APK signed with v1 scheme only, one signer.
183         assertInstallSucceedsForEach(
184                 "v1-only-with-ecdsa-sha224-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES);
185         assertInstallSucceedsForEach(
186                 "v1-only-with-ecdsa-sha224-1.2.840.10045.4.3.1-%s.apk", EC_KEY_NAMES);
187     }
188 
189     @Test
testInstallV1OneSignerSHA256withECDSA()190     public void testInstallV1OneSignerSHA256withECDSA() throws Exception {
191         // APK signed with v1 scheme only, one signer.
192         assertInstallSucceedsForEach(
193                 "v1-only-with-ecdsa-sha256-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES);
194         assertInstallSucceedsForEach(
195                 "v1-only-with-ecdsa-sha256-1.2.840.10045.4.3.2-%s.apk", EC_KEY_NAMES);
196     }
197 
198     @Test
testInstallV1OneSignerSHA384withECDSA()199     public void testInstallV1OneSignerSHA384withECDSA() throws Exception {
200         // APK signed with v1 scheme only, one signer.
201         assertInstallSucceedsForEach(
202                 "v1-only-with-ecdsa-sha384-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES);
203         assertInstallSucceedsForEach(
204                 "v1-only-with-ecdsa-sha384-1.2.840.10045.4.3.3-%s.apk", EC_KEY_NAMES);
205     }
206 
207     @Test
testInstallV1OneSignerSHA512withECDSA()208     public void testInstallV1OneSignerSHA512withECDSA() throws Exception {
209         // APK signed with v1 scheme only, one signer.
210         assertInstallSucceedsForEach(
211                 "v1-only-with-ecdsa-sha512-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES);
212         assertInstallSucceedsForEach(
213                 "v1-only-with-ecdsa-sha512-1.2.840.10045.4.3.4-%s.apk", EC_KEY_NAMES);
214     }
215 
216     @Test
testInstallV1OneSignerSHA1withDSA()217     public void testInstallV1OneSignerSHA1withDSA() throws Exception {
218         // APK signed with v1 scheme only, one signer.
219         assertInstallSucceedsForEach(
220                 "v1-only-with-dsa-sha1-1.2.840.10040.4.1-%s.apk", DSA_KEY_NAMES);
221         assertInstallSucceedsForEach(
222                 "v1-only-with-dsa-sha1-1.2.840.10040.4.3-%s.apk", DSA_KEY_NAMES);
223     }
224 
225     @Test
testInstallV1OneSignerSHA224withDSA()226     public void testInstallV1OneSignerSHA224withDSA() throws Exception {
227         // APK signed with v1 scheme only, one signer.
228         assertInstallSucceedsForEach(
229                 "v1-only-with-dsa-sha224-1.2.840.10040.4.1-%s.apk", DSA_KEY_NAMES);
230         assertInstallSucceedsForEach(
231                 "v1-only-with-dsa-sha224-2.16.840.1.101.3.4.3.1-%s.apk", DSA_KEY_NAMES);
232     }
233 
234     @Test
testInstallV1OneSignerSHA256withDSA()235     public void testInstallV1OneSignerSHA256withDSA() throws Exception {
236         // APK signed with v1 scheme only, one signer.
237         assertInstallSucceedsForEach(
238                 "v1-only-with-dsa-sha256-1.2.840.10040.4.1-%s.apk", DSA_KEY_NAMES);
239         assertInstallSucceedsForEach(
240                 "v1-only-with-dsa-sha256-2.16.840.1.101.3.4.3.2-%s.apk", DSA_KEY_NAMES);
241     }
242 
243 //  Android platform doesn't support DSA with SHA-384 and SHA-512.
244 //    @Test
245 //    public void testInstallV1OneSignerSHA384withDSA() throws Exception {
246 //        // APK signed with v1 scheme only, one signer.
247 //        assertInstallSucceedsForEach(
248 //                "v1-only-with-dsa-sha384-2.16.840.1.101.3.4.3.3-%s.apk", DSA_KEY_NAMES);
249 //    }
250 //
251 //    @Test
252 //    public void testInstallV1OneSignerSHA512withDSA() throws Exception {
253 //        // APK signed with v1 scheme only, one signer.
254 //        assertInstallSucceedsForEach(
255 //                "v1-only-with-dsa-sha512-2.16.840.1.101.3.4.3.3-%s.apk", DSA_KEY_NAMES);
256 //    }
257 
258     @Test
testInstallV2StrippedFails()259     public void testInstallV2StrippedFails() throws Exception {
260         // APK signed with v1 and v2 schemes, but v2 signature was stripped from the file (by using
261         // zipalign).
262         // This should fail because the v1 signature indicates that the APK was supposed to be
263         // signed with v2 scheme as well, making the platform's anti-stripping protections reject
264         // the APK.
265         assertInstallFailsWithError("v2-stripped.apk", "Signature stripped");
266 
267         // Similar to above, but the X-Android-APK-Signed anti-stripping header in v1 signature
268         // lists unknown signature schemes in addition to APK Signature Scheme v2. Unknown schemes
269         // should be ignored.
270         assertInstallFailsWithError(
271                 "v2-stripped-with-ignorable-signing-schemes.apk", "Signature stripped");
272     }
273 
274     @Test
testInstallV2OneSignerOneSignature()275     public void testInstallV2OneSignerOneSignature() throws Exception {
276         // APK signed with v2 scheme only, one signer, one signature.
277         assertInstallSucceedsForEach("v2-only-with-dsa-sha256-%s.apk", DSA_KEY_NAMES);
278         assertInstallSucceedsForEach("v2-only-with-ecdsa-sha256-%s.apk", EC_KEY_NAMES);
279         assertInstallSucceedsForEach("v2-only-with-rsa-pkcs1-sha256-%s.apk", RSA_KEY_NAMES);
280         assertInstallSucceedsForEach("v2-only-with-rsa-pss-sha256-%s.apk", RSA_KEY_NAMES);
281 
282         // DSA with SHA-512 is not supported by Android platform and thus APK Signature Scheme v2
283         // does not support that either
284         // assertInstallSucceedsForEach("v2-only-with-dsa-sha512-%s.apk", DSA_KEY_NAMES);
285         assertInstallSucceedsForEach("v2-only-with-ecdsa-sha512-%s.apk", EC_KEY_NAMES);
286         assertInstallSucceedsForEach("v2-only-with-rsa-pkcs1-sha512-%s.apk", RSA_KEY_NAMES);
287         assertInstallSucceedsForEach(
288                 "v2-only-with-rsa-pss-sha512-%s.apk",
289                 RSA_KEY_NAMES_2048_AND_LARGER // 1024-bit key is too short for PSS with SHA-512
290         );
291     }
292 
293     @Test
testInstallV1SignatureOnlyDoesNotVerify()294     public void testInstallV1SignatureOnlyDoesNotVerify() throws Exception {
295         // APK signed with v1 scheme only, but not all digests match those recorded in
296         // META-INF/MANIFEST.MF.
297         String error = "META-INF/MANIFEST.MF has invalid digest";
298 
299         // Bitflip in classes.dex of otherwise good file.
300         assertInstallFailsWithError(
301                 "v1-only-with-tampered-classes-dex.apk", error);
302     }
303 
304     @Test
testInstallV2SignatureDoesNotVerify()305     public void testInstallV2SignatureDoesNotVerify() throws Exception {
306         // APK signed with v2 scheme only, but the signature over signed-data does not verify.
307         String error = "signature did not verify";
308 
309         // Bitflip in certificate field inside signed-data. Based on
310         // v2-only-with-dsa-sha256-1024.apk.
311         assertInstallFailsWithError("v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk", error);
312 
313         // Signature claims to be RSA PKCS#1 v1.5 with SHA-256, but is actually using SHA-512.
314         // Based on v2-only-with-rsa-pkcs1-sha256-2048.apk.
315         assertInstallFailsWithError(
316                 "v2-only-with-rsa-pkcs1-sha256-2048-sig-does-not-verify.apk", error);
317 
318         // Signature claims to be RSA PSS with SHA-256 and 32 bytes of salt, but is actually using 0
319         // bytes of salt. Based on v2-only-with-rsa-pkcs1-sha256-2048.apk. Obtained by modifying APK
320         // signer to use the wrong amount of salt.
321         assertInstallFailsWithError(
322                 "v2-only-with-rsa-pss-sha256-2048-sig-does-not-verify.apk", error);
323 
324         // Bitflip in the ECDSA signature. Based on v2-only-with-ecdsa-sha256-p256.apk.
325         assertInstallFailsWithError(
326                 "v2-only-with-ecdsa-sha256-p256-sig-does-not-verify.apk", error);
327     }
328 
329     @Test
testInstallV2ContentDigestMismatch()330     public void testInstallV2ContentDigestMismatch() throws Exception {
331         // APK signed with v2 scheme only, but the digest of contents does not match the digest
332         // stored in signed-data.
333         String error = "digest of contents did not verify";
334 
335         // Based on v2-only-with-rsa-pkcs1-sha512-4096.apk. Obtained by modifying APK signer to
336         // flip the leftmost bit in content digest before signing signed-data.
337         assertInstallFailsWithError(
338                 "v2-only-with-rsa-pkcs1-sha512-4096-digest-mismatch.apk", error);
339 
340         // Based on v2-only-with-ecdsa-sha256-p256.apk. Obtained by modifying APK signer to flip the
341         // leftmost bit in content digest before signing signed-data.
342         assertInstallFailsWithError(
343                 "v2-only-with-ecdsa-sha256-p256-digest-mismatch.apk", error);
344     }
345 
346     @Test
testInstallNoApkSignatureSchemeBlock()347     public void testInstallNoApkSignatureSchemeBlock() throws Exception {
348         // APK signed with v2 scheme only, but the rules for verifying APK Signature Scheme v2
349         // signatures say that this APK must not be verified using APK Signature Scheme v2.
350 
351         // Obtained from v2-only-with-rsa-pkcs1-sha512-4096.apk by flipping a bit in the magic
352         // field in the footer of APK Signing Block. This makes the APK Signing Block disappear.
353         assertInstallFails("v2-only-wrong-apk-sig-block-magic.apk");
354 
355         // Obtained by modifying APK signer to insert "GARBAGE" between ZIP Central Directory and
356         // End of Central Directory. The APK is otherwise fine and is signed with APK Signature
357         // Scheme v2. Based on v2-only-with-rsa-pkcs1-sha256.apk.
358         assertInstallFails("v2-only-garbage-between-cd-and-eocd.apk");
359 
360         // Obtained by modifying APK signer to truncate the ZIP Central Directory by one byte. The
361         // APK is otherwise fine and is signed with APK Signature Scheme v2. Based on
362         // v2-only-with-rsa-pkcs1-sha256.apk
363         assertInstallFails("v2-only-truncated-cd.apk");
364 
365         // Obtained by modifying the size in APK Signature Block header. Based on
366         // v2-only-with-ecdsa-sha512-p521.apk.
367         assertInstallFails("v2-only-apk-sig-block-size-mismatch.apk");
368 
369         // Obtained by modifying the ID under which APK Signature Scheme v2 Block is stored in
370         // APK Signing Block and by modifying the APK signer to not insert anti-stripping
371         // protections into JAR Signature. The APK should appear as having no APK Signature Scheme
372         // v2 Block and should thus successfully verify using JAR Signature Scheme.
373         assertInstallSucceeds("v1-with-apk-sig-block-but-without-apk-sig-scheme-v2-block.apk");
374     }
375 
376     @Test
testInstallV2UnknownPairIgnoredInApkSigningBlock()377     public void testInstallV2UnknownPairIgnoredInApkSigningBlock() throws Exception {
378         // Obtained by modifying APK signer to emit an unknown ID-value pair into APK Signing Block
379         // before the ID-value pair containing the APK Signature Scheme v2 Block. The unknown
380         // ID-value should be ignored.
381         assertInstallSucceeds("v2-only-unknown-pair-in-apk-sig-block.apk");
382     }
383 
384     @Test
testInstallV2IgnoresUnknownSignatureAlgorithms()385     public void testInstallV2IgnoresUnknownSignatureAlgorithms() throws Exception {
386         // APK is signed with a known signature algorithm and with a couple of unknown ones.
387         // Obtained by modifying APK signer to use "unknown" signature algorithms in addition to
388         // known ones.
389         assertInstallSucceeds("v2-only-with-ignorable-unsupported-sig-algs.apk");
390     }
391 
392     @Test
testInstallV2RejectsMismatchBetweenSignaturesAndDigestsBlocks()393     public void testInstallV2RejectsMismatchBetweenSignaturesAndDigestsBlocks() throws Exception {
394         // APK is signed with a single signature algorithm, but the digests block claims that it is
395         // signed with two different signature algorithms. Obtained by modifying APK Signer to
396         // emit an additional digest record with signature algorithm 0x12345678.
397         assertInstallFailsWithError(
398                 "v2-only-signatures-and-digests-block-mismatch.apk",
399                 "Signature algorithms don't match between digests and signatures records");
400     }
401 
402     @Test
testInstallV2RejectsMismatchBetweenPublicKeyAndCertificate()403     public void testInstallV2RejectsMismatchBetweenPublicKeyAndCertificate() throws Exception {
404         // APK is signed with v2 only. The public key field does not match the public key in the
405         // leaf certificate. Obtained by modifying APK signer to write out a modified leaf
406         // certificate where the RSA modulus has a bitflip.
407         assertInstallFailsWithError(
408                 "v2-only-cert-and-public-key-mismatch.apk",
409                 "Public key mismatch between certificate and signature record");
410     }
411 
412     @Test
testInstallV2RejectsSignerBlockWithNoCertificates()413     public void testInstallV2RejectsSignerBlockWithNoCertificates() throws Exception {
414         // APK is signed with v2 only. There are no certificates listed in the signer block.
415         // Obtained by modifying APK signer to output no certificates.
416         assertInstallFailsWithError("v2-only-no-certs-in-sig.apk", "No certificates listed");
417     }
418 
419     @Test
testInstallTwoSigners()420     public void testInstallTwoSigners() throws Exception {
421         // APK signed by two different signers.
422         assertInstallSucceeds("two-signers.apk");
423         // Because the install attempt below is an update, it also tests that the signing
424         // certificates exposed by v2 signatures above are the same as the one exposed by v1
425         // signatures in this APK.
426         assertInstallSucceeds("v1-only-two-signers.apk");
427         assertInstallSucceeds("v2-only-two-signers.apk");
428     }
429 
430     @Test
testInstallNegativeModulus()431     public void testInstallNegativeModulus() throws Exception {
432         // APK signed with a certificate that has a negative RSA modulus.
433         assertInstallSucceeds("v1-only-negative-modulus.apk");
434         assertInstallSucceeds("v2-only-negative-modulus.apk");
435         assertInstallSucceeds("v3-only-negative-modulus.apk");
436     }
437 
438     @Test
testInstallV2TwoSignersRejectsWhenOneBroken()439     public void testInstallV2TwoSignersRejectsWhenOneBroken() throws Exception {
440         // Bitflip in the ECDSA signature of second signer. Based on two-signers.apk.
441         // This asserts that breakage in any signer leads to rejection of the APK.
442         assertInstallFailsWithError(
443                 "two-signers-second-signer-v2-broken.apk", "signature did not verify");
444     }
445 
446     @Test
testInstallV2TwoSignersRejectsWhenOneWithoutSignatures()447     public void testInstallV2TwoSignersRejectsWhenOneWithoutSignatures() throws Exception {
448         // APK v2-signed by two different signers. However, there are no signatures for the second
449         // signer.
450         assertInstallFailsWithError(
451                 "v2-only-two-signers-second-signer-no-sig.apk", "No signatures");
452     }
453 
454     @Test
testInstallV2TwoSignersRejectsWhenOneWithoutSupportedSignatures()455     public void testInstallV2TwoSignersRejectsWhenOneWithoutSupportedSignatures() throws Exception {
456         // APK v2-signed by two different signers. However, there are no supported signatures for
457         // the second signer.
458         assertInstallFailsWithError(
459                 "v2-only-two-signers-second-signer-no-supported-sig.apk",
460                 "No supported signatures");
461     }
462 
463     @Test
testInstallV2RejectsWhenMissingCode()464     public void testInstallV2RejectsWhenMissingCode() throws Exception {
465         // Obtained by removing classes.dex from original.apk and then signing with v2 only.
466         // Although this has nothing to do with v2 signature verification, package manager wants
467         // signature verification / certificate collection to reject APKs with missing code
468         // (classes.dex) unless requested otherwise.
469         assertInstallFailsWithError("v2-only-missing-classes.dex.apk", "code is missing");
470     }
471 
472     @Test
testCorrectCertUsedFromPkcs7SignedDataCertsSet()473     public void testCorrectCertUsedFromPkcs7SignedDataCertsSet() throws Exception {
474         // Obtained by prepending the rsa-1024 certificate to the PKCS#7 SignedData certificates set
475         // of v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.1-2048.apk META-INF/CERT.RSA. The certs
476         // (in the order of appearance in the file) are thus: rsa-1024, rsa-2048. The package's
477         // signing cert is rsa-2048.
478         assertInstallSucceeds("v1-only-pkcs7-cert-bag-first-cert-not-used.apk");
479 
480         // Check that rsa-1024 was not used as the previously installed package's signing cert.
481         assertInstallFailsWithError(
482                 "v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.1-1024.apk",
483                 "signatures do not match");
484 
485         // Check that rsa-2048 was used as the previously installed package's signing cert.
486         assertInstallSucceeds("v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.1-2048.apk");
487     }
488 
489     @Test
testV1SchemeSignatureCertNotReencoded()490     public void testV1SchemeSignatureCertNotReencoded() throws Exception {
491         // Regression test for b/30148997 and b/18228011. When PackageManager does not preserve the
492         // original encoded form of signing certificates, bad things happen, such as rejection of
493         // completely valid updates to apps. The issue in b/30148997 and b/18228011 was that
494         // PackageManager started re-encoding signing certs into DER. This normally produces exactly
495         // the original form because X.509 certificates are supposed to be DER-encoded. However, a
496         // small fraction of Android apps uses X.509 certificates which are not DER-encoded. For
497         // such apps, re-encoding into DER changes the serialized form of the certificate, creating
498         // a mismatch with the serialized form stored in the PackageManager database, leading to the
499         // rejection of updates for the app.
500         //
501         // The signing certs of the two APKs differ only in how the cert's signature is encoded.
502         // From Android's perspective, these two APKs are signed by different entities and thus
503         // cannot be used to update one another. If signature verification code re-encodes certs
504         // into DER, both certs will be exactly the same and Android will accept these APKs as
505         // updates of each other. This test is thus asserting that the two APKs are not accepted as
506         // updates of each other.
507         //
508         // * v1-only-with-rsa-1024.apk cert's signature is DER-encoded
509         // * v1-only-with-rsa-1024-cert-not-der.apk cert's signature is not DER-encoded. It is
510         //   BER-encoded, with length encoded as two bytes instead of just one.
511         //   v1-only-with-rsa-1024-cert-not-der.apk META-INF/CERT.RSA was obtained from
512         //   v1-only-with-rsa-1024.apk META-INF/CERT.RSA by manually modifying the ASN.1 structure.
513         assertInstallSucceeds("v1-only-with-rsa-1024.apk");
514         assertInstallFailsWithError(
515                 "v1-only-with-rsa-1024-cert-not-der.apk", "signatures do not match");
516 
517         uninstallPackage();
518         assertInstallSucceeds("v1-only-with-rsa-1024-cert-not-der.apk");
519         assertInstallFailsWithError("v1-only-with-rsa-1024.apk", "signatures do not match");
520     }
521 
522     @Test
testV2SchemeSignatureCertNotReencoded()523     public void testV2SchemeSignatureCertNotReencoded() throws Exception {
524         // This test is here to catch something like b/30148997 and b/18228011 happening to the
525         // handling of APK Signature Scheme v2 signatures by PackageManager. When PackageManager
526         // does not preserve the original encoded form of signing certificates, bad things happen,
527         // such as rejection of completely valid updates to apps. The issue in b/30148997 and
528         // b/18228011 was that PackageManager started re-encoding signing certs into DER. This
529         // normally produces exactly the original form because X.509 certificates are supposed to be
530         // DER-encoded. However, a small fraction of Android apps uses X.509 certificates which are
531         // not DER-encoded. For such apps, re-encoding into DER changes the serialized form of the
532         // certificate, creating a mismatch with the serialized form stored in the PackageManager
533         // database, leading to the rejection of updates for the app.
534         //
535         // The signing certs of the two APKs differ only in how the cert's signature is encoded.
536         // From Android's perspective, these two APKs are signed by different entities and thus
537         // cannot be used to update one another. If signature verification code re-encodes certs
538         // into DER, both certs will be exactly the same and Android will accept these APKs as
539         // updates of each other. This test is thus asserting that the two APKs are not accepted as
540         // updates of each other.
541         //
542         // * v2-only-with-rsa-pkcs1-sha256-1024.apk cert's signature is DER-encoded
543         // * v2-only-with-rsa-pkcs1-sha256-1024-cert-not-der.apk cert's signature is not DER-encoded
544         //   It is BER-encoded, with length encoded as two bytes instead of just one.
545         assertInstallSucceeds("v2-only-with-rsa-pkcs1-sha256-1024.apk");
546         assertInstallFailsWithError(
547                 "v2-only-with-rsa-pkcs1-sha256-1024-cert-not-der.apk", "signatures do not match");
548 
549         uninstallPackage();
550         assertInstallSucceeds("v2-only-with-rsa-pkcs1-sha256-1024-cert-not-der.apk");
551         assertInstallFailsWithError(
552                 "v2-only-with-rsa-pkcs1-sha256-1024.apk", "signatures do not match");
553     }
554 
555     @Test
testInstallEphemeralRequiresV2Signature()556     public void testInstallEphemeralRequiresV2Signature() throws Exception {
557         assertInstallEphemeralFailsWithError("unsigned-ephemeral.apk",
558                 "Failed to collect certificates");
559         assertInstallEphemeralFailsWithError("v1-only-ephemeral.apk",
560                 "must be signed with APK Signature Scheme v2 or greater");
561         assertInstallEphemeralSucceeds("v2-only-ephemeral.apk");
562         assertInstallEphemeralSucceeds("v1-v2-ephemeral.apk"); // signed with both schemes
563     }
564 
565     @Test
testInstallEmpty()566     public void testInstallEmpty() throws Exception {
567         assertInstallFailsWithError("empty-unsigned.apk", "Unknown failure");
568         assertInstallFailsWithError("v1-only-empty.apk", "Unknown failure");
569         assertInstallFailsWithError("v2-only-empty.apk", "Unknown failure");
570     }
571 
572     @AsbSecurityTest(cveBugId = 64211847)
573     @Test
testInstallApkWhichDoesNotStartWithZipLocalFileHeaderMagic()574     public void testInstallApkWhichDoesNotStartWithZipLocalFileHeaderMagic() throws Exception {
575         // The APKs below are competely fine except they don't start with ZIP Local File Header
576         // magic. Thus, these APKs will install just fine unless Package Manager requires that APKs
577         // start with ZIP Local File Header magic.
578         String error = "Unknown failure";
579 
580         // Obtained by modifying apksigner to output four unused 0x00 bytes at the start of the APK
581         assertInstallFailsWithError("v1-only-starts-with-00000000-magic.apk", error);
582         assertInstallFailsWithError("v2-only-starts-with-00000000-magic.apk", error);
583 
584         // Obtained by modifying apksigner to output 8 unused bytes (DEX magic and version) at the
585         // start of the APK
586         assertInstallFailsWithError("v1-only-starts-with-dex-magic.apk", error);
587         assertInstallFailsWithError("v2-only-starts-with-dex-magic.apk", error);
588     }
589 
590     @Test
testInstallV3KeyRotation()591     public void testInstallV3KeyRotation() throws Exception {
592         // tests that a v3 signed APK with RSA key can rotate to a new key
593         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1.apk");
594         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
595     }
596 
597     @Test
testInstallV3KeyRotationToAncestor()598     public void testInstallV3KeyRotationToAncestor() throws Exception {
599         // tests that a v3 signed APK with RSA key cannot be upgraded by one of its past certs
600         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
601         assertInstallFails("v3-rsa-pkcs1-sha256-2048-1.apk");
602     }
603 
604     @Test
testInstallV3KeyRotationToAncestorWithRollback()605     public void testInstallV3KeyRotationToAncestorWithRollback() throws Exception {
606         // tests that a v3 signed APK with RSA key can be upgraded by one of its past certs if it
607         // has granted that cert the rollback capability
608         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-and-roll-caps.apk");
609         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1.apk");
610     }
611 
612     @Test
testInstallV3KeyRotationMultipleHops()613     public void testInstallV3KeyRotationMultipleHops() throws Exception {
614         // tests that a v3 signed APK with RSA key can rotate to a new key which is the result of
615         // multiple rotations from the original: APK signed with key 1 can be updated by key 3, when
616         // keys were: 1 -> 2 -> 3
617         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1.apk");
618         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-3-with-por_1_2_3-full-caps.apk");
619     }
620 
621     @Test
testInstallV3PorSignerMismatch()622     public void testInstallV3PorSignerMismatch() throws Exception {
623         // tests that an APK with a proof-of-rotation struct that doesn't include the current
624         // signing certificate fails to install
625         assertInstallFails("v3-rsa-pkcs1-sha256-2048-3-with-por_1_2-full-caps.apk");
626     }
627 
628     @Test
testInstallV3KeyRotationWrongPor()629     public void testInstallV3KeyRotationWrongPor() throws Exception {
630         // tests that a valid APK with a proof-of-rotation record can't upgrade an APK with a
631         // signing certificate that isn't in the proof-of-rotation record
632         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1.apk");
633         assertInstallFails("v3-rsa-pkcs1-sha256-2048-3-with-por_2_3-full-caps.apk");
634     }
635 
636     @Test
testInstallV3KeyRotationSharedUid()637     public void testInstallV3KeyRotationSharedUid() throws Exception {
638         // tests that a v3 signed sharedUid APK can still be sharedUid with apps with its older
639         // signing certificate, if it so desires
640         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-sharedUid.apk");
641         assertInstallSucceeds(
642                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-sharedUid-companion.apk");
643     }
644 
645     @Test
testInstallV3KeyRotationOlderSharedUid()646     public void testInstallV3KeyRotationOlderSharedUid() throws Exception {
647         // tests that a sharedUid APK can still install with another app that is signed by a newer
648         // signing certificate, but which allows sharedUid with the older one
649         assertInstallSucceeds(
650                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-sharedUid-companion.apk");
651         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-sharedUid.apk");
652     }
653 
654     @Test
testInstallV3KeyRotationSharedUidNoCap()655     public void testInstallV3KeyRotationSharedUidNoCap() throws Exception {
656         // tests that a v3 signed sharedUid APK cannot be sharedUid with apps with its older
657         // signing certificate, when it has not granted that certificate the sharedUid capability
658         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-sharedUid.apk");
659         assertInstallFails(
660                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-shUid-cap-sharedUid-companion.apk");
661     }
662 
663     @Test
testInstallV3KeyRotationOlderSharedUidNoCap()664     public void testInstallV3KeyRotationOlderSharedUidNoCap() throws Exception {
665         // tests that a sharedUid APK signed with an old certificate cannot install with
666         // an app having a proof-of-rotation structure that hasn't granted the older
667         // certificate the sharedUid capability
668         assertInstallSucceeds(
669                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-shUid-cap-sharedUid-companion.apk");
670         assertInstallFails("v3-rsa-pkcs1-sha256-2048-1-sharedUid.apk");
671     }
672 
673     @Test
testInstallV3NoRotationSharedUid()674     public void testInstallV3NoRotationSharedUid() throws Exception {
675         // tests that a sharedUid APK signed with a new certificate installs with
676         // an app having a proof-of-rotation structure that hasn't granted an older
677         // certificate the sharedUid capability
678         assertInstallSucceeds(
679                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-shUid-cap-sharedUid-companion.apk");
680         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-sharedUid.apk");
681     }
682 
683     @Test
testInstallV3MultipleAppsOneDeniesOldKeySharedUid()684     public void testInstallV3MultipleAppsOneDeniesOldKeySharedUid() throws Exception {
685         // If two apps are installed as part of a sharedUid, one granting access to the sharedUid
686         // to the previous key and the other revoking access to the sharedUid, then when an app
687         // signed with the old key attempts to join the sharedUid the installation should be blocked
688         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
689         assertInstallFromBuildSucceeds(
690                 "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
691         assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
692     }
693 
694     @Test
testInstallV3MultipleAppsOneUpdatedToDenyOldKeySharedUid()695     public void testInstallV3MultipleAppsOneUpdatedToDenyOldKeySharedUid() throws Exception {
696         // Similar to the test above if two apps are installed as part of a sharedUid with both
697         // granting access to the sharedUid to the previous key then an app signed with the previous
698         // key should be allowed to install and join the sharedUid. If one of the first two apps
699         // is then updated with a lineage that denies access to the sharedUid for the old key, all
700         // subsequent installs / updates with that old key should be blocked.
701         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps-sharedUid.apk");
702         assertInstallFromBuildSucceeds(
703                 "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
704         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid-companion2.apk");
705         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
706         assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
707     }
708 
709     @Test
testInstallV3SharedUidDeniedOnlyRotatedUpdateAllowed()710     public void testInstallV3SharedUidDeniedOnlyRotatedUpdateAllowed() throws Exception {
711         // To allow rotation after a signing key compromise, an APK that is already part of a
712         // shareddUserId can rotate to a new key with the old key being denied the SHARED_USER_ID
713         // capability and still be updated in the sharedUserId. Another app signed with this same
714         // lineage and capabilities that is not currently part of the sharedUserId will not be
715         // allowed to join as long as any apps signed with the untrusted key are still part of
716         // the sharedUserId.
717         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid.apk");
718         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid-companion2.apk");
719         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
720         // An app signed with the untrusted key is still part of the sharedUserId, so a new app
721         // that does not trust this key is not allowed to join the sharedUserId.
722         assertInstallFromBuildFails("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid-companion.apk");
723         assertInstallFromBuildSucceeds(
724                 "v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid-companion2.apk");
725         // Once all apps have rotated away from the untrusted key, a new app that also does not
726         // trust the previous key can now join the sharedUserId.
727         assertInstallFromBuildSucceeds(
728                 "v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid-companion.apk");
729     }
730 
731     @Test
testInstallV3FirstAppOnlySignedByNewKeyLastAppOldKey()732     public void testInstallV3FirstAppOnlySignedByNewKeyLastAppOldKey() throws Exception {
733         // This test verifies the following scenario:
734         // - First installed app in sharedUid only signed with new key without lineage.
735         // - Second installed app in sharedUid signed with new key and includes lineage granting
736         //   access to the old key to join the sharedUid.
737         // - Last installed app in sharedUid signed with old key.
738         // The lineage should be updated when the second app is installed to allow the installation
739         // of the app signed with the old key.
740         assertInstallFromBuildSucceeds("v3-ec-p256-2-sharedUid-companion.apk");
741         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps-sharedUid.apk");
742         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid-companion2.apk");
743     }
744 
745     @Test
testInstallV3AppSignedWithOldKeyUpdatedLineageDeniesShUidCap()746     public void testInstallV3AppSignedWithOldKeyUpdatedLineageDeniesShUidCap() throws Exception {
747         // If an app is installed as part of a sharedUid, and then that app is signed with a new key
748         // that rejects the previous key in the lineage the update should be allowed to proceed
749         // as the app is being updated to the newly rotated key.
750         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid.apk");
751         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
752     }
753 
754     @Test
testInstallV3TwoSharedUidAppsWithDivergedLineages()755     public void testInstallV3TwoSharedUidAppsWithDivergedLineages() throws Exception {
756         // Apps that are installed as part of the sharedUserId with a lineage must have common
757         // ancestors; the platform will allow the installation if the lineage of an app being
758         // installed as part of the sharedUserId is the same, a subset, or a superset of the
759         // existing lineage, but if the lineage diverges then the installation should be blocked.
760         assertInstallFromBuildSucceeds("v3-por_Y_1_2-default-caps-sharedUid.apk");
761         assertInstallFromBuildFails("v3-por_Z_1_2-default-caps-sharedUid-companion.apk");
762     }
763 
764     @Test
testInstallV3WithRestoredCapabilityInSharedUserId()765     public void testInstallV3WithRestoredCapabilityInSharedUserId() throws Exception {
766         // A sharedUserId contains the shared signing lineage for all packages in the UID; this
767         // shared lineage contain the full signing history for all packages along with the merged
768         // capabilities for each signer shared between the packages. This test verifies if one
769         // package revokes a capability from a previous signer, but subsequently restores that
770         // capability, then since all packages have granted the capability, it is restored to the
771         // previous signer in the shared lineage.
772 
773         // Install a package with the SHARED_USER_ID capability revoked for the original signer
774         // in the lineage; verify that a package signed with only the original signer cannot join
775         // the sharedUserId.
776         assertInstallFromBuildSucceeds(
777                 "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
778         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
779         assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
780 
781         // Update the package that revoked the SHARED_USER_ID with an updated lineage that restores
782         // this capability to the original signer; verify the package signed with the original
783         // signing key can now join the sharedUserId since all existing packages in the UID grant
784         // this capability to the original signer.
785         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps-sharedUid.apk");
786         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid-companion2.apk");
787     }
788 
789     @Test
testInstallV3WithRevokedCapabilityInSharedUserId()790     public void testInstallV3WithRevokedCapabilityInSharedUserId() throws Exception {
791         // While a capability can be restored to a common signer in the shared signing lineage, if
792         // one package has revoked a capability from a common signer and another package is
793         // installed / updated which restores the capability to that signer, the revocation of
794         // the capability by the existing package should take precedence. A capability can only
795         // be restored to a common signer if all packages in the sharedUserId have granted this
796         // capability to the signer.
797 
798         // Install a package with the SHARED_USER_ID capability revoked from the original signer,
799         // then install another package in the sharedUserId that grants this capability to the
800         // original signer. Since a package exists in the sharedUserId that has revoked this
801         // capability, another package signed with this capability shouldn't be able to join the
802         // sharedUserId.
803         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
804         assertInstallFromBuildSucceeds(
805                 "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
806         assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
807 
808         // Install the same package that grants the SHARED_USER_ID capability to the original
809         // signer; when iterating over the existing packages in the packages in the sharedUserId,
810         // the original version of this package should be skipped since the lineage from the
811         // updated package is used when merging with the shared lineage.
812         assertInstallFromBuildSucceeds(
813                 "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
814         assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
815 
816         // Install another package that has granted the SHARED_USER_ID to the original signer; this
817         // should trigger another merge with all packages in the sharedUserId. Since one still
818         // remains that revokes the capability, the capability should be revoked in the shared
819         // lineage.
820         assertInstallFromBuildSucceeds(
821                 "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion3.apk");
822         assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
823     }
824 
825     @Test
testInstallV3UpdateAfterRotation()826     public void testInstallV3UpdateAfterRotation() throws Exception {
827         // This test performs an end to end verification of the update of an app with a rotated
828         // key. The app under test exports a bound service that performs its own PackageManager key
829         // rotation API verification, and the instrumentation test binds to the service and invokes
830         // the verifySignatures method to verify that the key rotation APIs return the expected
831         // results. The instrumentation test app is signed with the same key and lineage as the
832         // app under test to also provide a second app that can be used for the checkSignatures
833         // verification.
834 
835         // Install the initial versions of the apps; the test method verifies the app under test is
836         // signed with the original signing key.
837         assertInstallFromBuildSucceeds("CtsSignatureQueryService.apk");
838         assertInstallFromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
839         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
840                 "verifySignatures_noRotation_succeeds");
841 
842         // Install the second version of the app signed with the rotated key. This test verifies the
843         // app still functions as expected after the update with the rotated key. The
844         // instrumentation test app is not updated here to allow verification of the pre-key
845         // rotation behavior for the checkSignatures APIs. These APIs should behave similar to the
846         // GET_SIGNATURES flag in that if one or both apps have a signing lineage if the oldest
847         // signers in the lineage match then the methods should return that the signatures match
848         // even if one is signed with a newer key in the lineage.
849         assertInstallFromBuildSucceeds("CtsSignatureQueryService_v2.apk");
850         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
851                 "verifySignatures_withRotation_succeeds");
852 
853         // Installs the third version of the app under test and the instrumentation test, both
854         // signed with the same rotated key and lineage. This test is intended to verify that the
855         // app can still be updated and function as expected after an update with a rotated key.
856         assertInstallFromBuildSucceeds("CtsSignatureQueryService_v3.apk");
857         assertInstallFromBuildSucceeds("CtsSignatureQueryServiceTest_v2.apk");
858         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
859                 "verifySignatures_withRotation_succeeds");
860     }
861 
862     @CddTest(requirement="4/C-0-2")
863     @Test
testInstallV31UpdateAfterRotation()864     public void testInstallV31UpdateAfterRotation() throws Exception {
865         // This test is the same as above, but using the v3.1 signature scheme for rotation.
866         assertInstallFromBuildSucceeds("CtsSignatureQueryService.apk");
867         assertInstallFromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
868         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
869                 "verifySignatures_noRotation_succeeds");
870 
871         assertInstallFromBuildSucceeds("CtsSignatureQueryService_v2-tgt-33.apk");
872         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
873                 "verifySignatures_withRotation_succeeds");
874 
875         assertInstallFromBuildSucceeds("CtsSignatureQueryService_v3-tgt-33.apk");
876         assertInstallFromBuildSucceeds("CtsSignatureQueryServiceTest_v2-tgt-33.apk");
877         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
878                 "verifySignatures_withRotation_succeeds");
879     }
880 
881     @CddTest(requirement="4/C-0-9")
882     @Test
883     @Parameters(method = "installOnIncremental")
testInstallV41UpdateAfterRotation(boolean onIncremental)884     public void testInstallV41UpdateAfterRotation(boolean onIncremental) throws Exception {
885         checkAssumptionAndSetIdsigInstallMode(onIncremental);
886 
887         // This test is the same as above, but using the v4.1 signature scheme for rotation.
888         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService.apk");
889         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
890         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
891                 "verifySignatures_noRotation_succeeds");
892 
893         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService_v2-tgt-33.apk");
894         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
895                 "verifySignatures_withRotation_succeeds");
896 
897         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService_v3-tgt-33.apk");
898         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest_v2-tgt-33.apk");
899         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
900                 "verifySignatures_withRotation_succeeds");
901     }
902 
903     @CddTest(requirement="4/C-0-9")
904     @Test
905     @Parameters(method = "installOnIncremental")
testInstallV41WrongBlockId(boolean onIncremental)906     public void testInstallV41WrongBlockId(boolean onIncremental) throws Exception {
907         checkAssumptionAndSetIdsigInstallMode(onIncremental);
908 
909         // This test is the same as above, but using the v4.1 signature scheme for rotation.
910         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService.apk");
911         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
912         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
913                 "verifySignatures_noRotation_succeeds");
914 
915         assertInstallV4FailsWithError("CtsSignatureQueryService_v2-tgt-33-wrongV41Block.apk",
916                 "Failed to find V4 signature block corresponding to V3 blockId: 462663009");
917     }
918 
919     @CddTest(requirement="4/C-0-9")
920     @Test
921     @Parameters(method = "installOnIncremental")
testInstallV41LegacyV4(boolean onIncremental)922     public void testInstallV41LegacyV4(boolean onIncremental) throws Exception {
923         checkAssumptionAndSetIdsigInstallMode(onIncremental);
924 
925         // This test is the same as above, but using the v4.1 signature scheme for rotation.
926         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService.apk");
927         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
928         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
929                 "verifySignatures_noRotation_succeeds");
930 
931         assertInstallV4FailsWithError("CtsSignatureQueryService_v2-tgt-33-legacyV4.apk",
932                 "Failed to find V4 signature block corresponding to V3 blockId: 462663009");
933     }
934 
935     @CddTest(requirement="4/C-0-9")
936     @Test
937     @Parameters(method = "installOnIncremental")
testInstallV41WrongDigest(boolean onIncremental)938     public void testInstallV41WrongDigest(boolean onIncremental) throws Exception {
939         checkAssumptionAndSetIdsigInstallMode(onIncremental);
940 
941         // This test is the same as above, but using the v4.1 signature scheme for rotation.
942         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService.apk");
943         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
944         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
945                 "verifySignatures_noRotation_succeeds");
946 
947         assertInstallV4FailsWithError("CtsSignatureQueryService_v2-tgt-33-wrongDigest.apk",
948                 "APK digest in V4 signature does not match V2/V3");
949     }
950 
951     @Test
testInstallV3KeyRotationSigPerm()952     public void testInstallV3KeyRotationSigPerm() throws Exception {
953         // tests that a v3 signed APK can still get a signature permission from an app with its
954         // older signing certificate.
955         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
956         assertInstallSucceeds(
957                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-permcli-companion.apk");
958         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
959     }
960 
961     @Test
testInstallV3KeyRotationOlderSigPerm()962     public void testInstallV3KeyRotationOlderSigPerm() throws Exception {
963         // tests that an apk with an older signing certificate than the one which defines a
964         // signature permission it wants gets the permission if the defining APK grants the
965         // capability
966         assertInstallSucceeds(
967                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-permdef.apk");
968         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permcli-companion.apk");
969         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
970     }
971 
972     @Test
testInstallV3KeyRotationSigPermNoCap()973     public void testInstallV3KeyRotationSigPermNoCap() throws Exception {
974         // tests that an APK signed by an older signing certificate is unable to get a requested
975         // signature permission when the defining APK has rotated to a newer signing certificiate
976         // and does not grant the permission capability to the older cert
977         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-perm-cap-permdef.apk");
978         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permcli-companion.apk");
979         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
980     }
981 
982     @Test
testInstallV3KeyRotationOlderSigPermNoCap()983     public void testInstallV3KeyRotationOlderSigPermNoCap() throws Exception {
984         // tests that an APK signed by a newer signing certificate than the APK which defines a
985         // signature permission is able to get that permission, even if the newer APK does not
986         // grant the permission capability to the older signing certificate.
987         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
988         assertInstallSucceeds(
989                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-perm-cap-permcli-companion.apk");
990         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
991     }
992 
993     @Test
testInstallV3NoRotationSigPerm()994     public void testInstallV3NoRotationSigPerm() throws Exception {
995         // make sure that an APK, which wants to use a signature permission defined by an APK, which
996         // has not granted that capability to older signing certificates, can still install
997         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-perm-cap-permdef.apk");
998         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-permcli-companion.apk");
999         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
1000     }
1001 
1002     @Test
testInstallV3CommonSignerInLineageWithPermCap()1003     public void testInstallV3CommonSignerInLineageWithPermCap() throws Exception {
1004         // If an APK requesting a signature permission has a common signer in the lineage with the
1005         // APK declaring the permission, and that signer is granted the permission capability in
1006         // the declaring APK, then the permission should be granted to the requesting app even
1007         // if their signers have diverged.
1008         assertInstallFromBuildSucceeds(
1009                 "v3-ec-p256-with-por_1_2_3-1-no-caps-2-default-declperm.apk");
1010         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2_4-companion-usesperm.apk");
1011         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
1012     }
1013 
1014     @Test
testInstallV3CommonSignerInLineageNoCaps()1015     public void testInstallV3CommonSignerInLineageNoCaps() throws Exception {
1016         // If an APK requesting a signature permission has a common signer in the lineage with the
1017         // APK declaring the permission, but the signer in the lineage has not been granted the
1018         // permission capability the permission should not be granted to the requesting app.
1019         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2_3-no-caps-declperm.apk");
1020         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2_4-companion-usesperm.apk");
1021         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
1022     }
1023 
1024     @Test
testKnownSignerPermGrantedWhenCurrentSignerInResource()1025     public void testKnownSignerPermGrantedWhenCurrentSignerInResource() throws Exception {
1026         // The knownSigner protection flag allows an app to declare other trusted signing
1027         // certificates in an array resource; if a requesting app's current signer is in this array
1028         // of trusted certificates then the permission should be granted.
1029         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-ec-p256-1-3.apk");
1030         assertInstallFromBuildSucceeds("v3-ec-p256_3-companion-uses-knownSigner.apk");
1031         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
1032 
1033         // If the declaring app changes the trusted certificates on an update any requesting app
1034         // that no longer meets the requirements based on its signing identity should have the
1035         // permission revoked. This app update only trusts ec-p256_1 but the app that was previously
1036         // granted the permission based on its signing identity is signed by ec-p256_3.
1037         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-str-res-ec-p256-1.apk");
1038         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
1039     }
1040 
1041     @Test
testKnownSignerPermCurrentSignerNotInResource()1042     public void testKnownSignerPermCurrentSignerNotInResource() throws Exception {
1043         // If an app requesting a knownSigner permission does not meet the requirements for a
1044         // signature permission and is not signed by any of the trusted certificates then the
1045         // permission should not be granted.
1046         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-ec-p256-1-3.apk");
1047         assertInstallFromBuildSucceeds("v3-ec-p256_2-companion-uses-knownSigner.apk");
1048         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
1049     }
1050 
1051     @Test
testKnownSignerPermGrantedWhenSignerInLineageInResource()1052     public void testKnownSignerPermGrantedWhenSignerInLineageInResource() throws Exception {
1053         // If an app requesting a knownSigner permission was previously signed by a certificate
1054         // that is trusted by the declaring app then the permission should be granted.
1055         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-ec-p256-1-3.apk");
1056         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-companion-uses-knownSigner.apk");
1057         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
1058 
1059         // If the declaring app changes the permission to no longer use the knownSigner flag then
1060         // any app granted the permission based on a signing identity from the set of trusted
1061         // certificates should have the permission revoked.
1062         assertInstallFromBuildSucceeds("v3-rsa-2048-declperm.apk");
1063         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
1064     }
1065 
1066     @Test
testKnownSignerPermSignerInLineageMatchesStringResource()1067     public void testKnownSignerPermSignerInLineageMatchesStringResource() throws Exception {
1068         // The knownSigner protection flag allows an app to declare a single known trusted
1069         // certificate digest using a string resource instead of a string-array resource. This test
1070         // verifies the knownSigner permission is granted to a requesting app if the single trusted
1071         // cert is in the requesting app's lineage.
1072         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-str-res-ec-p256-1.apk");
1073         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-companion-uses-knownSigner.apk");
1074         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
1075     }
1076 
1077     @Test
testKnownSignerPermSignerInLineageMatchesStringConst()1078     public void testKnownSignerPermSignerInLineageMatchesStringConst() throws Exception {
1079         // The knownSigner protection flag allows an app to declare a single known trusted
1080         // certificate digest using a string constant as the knownCerts attribute value instead of a
1081         // resource. This test verifies the knownSigner permission is granted to a requesting app if
1082         // the single trusted cert is in the requesting app's lineage.
1083         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-str-const-ec-p256-1.apk");
1084         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-companion-uses-knownSigner.apk");
1085         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
1086     }
1087 
1088     @Test
testInstallV3SigPermDoubleDefNewerSucceeds()1089     public void testInstallV3SigPermDoubleDefNewerSucceeds() throws Exception {
1090         // make sure that if an app defines a signature permission already defined by another app,
1091         // it successfully installs if the other app's signing cert is in its past signing certs and
1092         // the signature permission capability is granted
1093         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
1094         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-permdef-companion.apk");
1095     }
1096 
1097     @Test
testInstallV3SigPermDoubleDefOlderSucceeds()1098     public void testInstallV3SigPermDoubleDefOlderSucceeds() throws Exception {
1099         // make sure that if an app defines a signature permission already defined by another app,
1100         // it successfully installs if it is in the other app's past signing certs and the signature
1101         // permission capability is granted
1102         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-permdef-companion.apk");
1103         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
1104     }
1105 
1106     @Test
testInstallV3SigPermDoubleDefNewerNoCapFails()1107     public void testInstallV3SigPermDoubleDefNewerNoCapFails() throws Exception {
1108         // make sure that if an app defines a signature permission already defined by another app,
1109         // it fails to install if the other app's signing cert is in its past signing certs but the
1110         // signature permission capability is not granted
1111         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
1112         assertInstallFails(
1113                 "v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-no-perm-cap-permdef-companion.apk");
1114     }
1115 
1116     @Test
testInstallV3SigPermDoubleDefOlderNoCapFails()1117     public void testInstallV3SigPermDoubleDefOlderNoCapFails() throws Exception {
1118         // make sure that if an app defines a signature permission already defined by another app,
1119         // it fails to install if it is in the other app's past signing certs but the signature
1120         // permission capability is not granted
1121         assertInstallSucceeds(
1122                 "v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-no-perm-cap-permdef-companion.apk");
1123         assertInstallFails("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
1124     }
1125 
1126     @Test
testInstallV3SigPermDoubleDefSameNoCapSucceeds()1127     public void testInstallV3SigPermDoubleDefSameNoCapSucceeds() throws Exception {
1128         // make sure that if an app defines a signature permission already defined by another app,
1129         // it installs successfully when signed by the same certificate, even if the original app
1130         // does not grant signature capabilities to its past certs
1131         assertInstallSucceeds(
1132                 "v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-no-perm-cap-permdef-companion.apk");
1133         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-permdef.apk");
1134     }
1135 
1136     @Test
testInstallV3KeyRotationGetSignatures()1137     public void testInstallV3KeyRotationGetSignatures() throws Exception {
1138         // tests that a PackageInfo w/GET_SIGNATURES flag returns the older cert
1139         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
1140         Utils.runDeviceTests(
1141                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testGetSignaturesShowsOld");
1142     }
1143 
1144     @Test
testInstallV3KeyRotationGetSigningCertificates()1145     public void testInstallV3KeyRotationGetSigningCertificates() throws Exception {
1146         // tests that a PackageInfo w/GET_SIGNING_CERTIFICATES flag returns the old and new certs
1147         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
1148         Utils.runDeviceTests(
1149                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1150                 "testGetSigningCertificatesShowsAll");
1151     }
1152 
1153     @Test
testInstallV3KeyRotationGetApkContentsSigners()1154     public void testInstallV3KeyRotationGetApkContentsSigners() throws Exception {
1155         // The GET_SIGNING_CERTIFICATES flag results in a PackageInfo object returned with a
1156         // SigningInfo instance that can be used to query all certificates in the lineage or only
1157         // the current signer(s) via getApkContentsSigners. This test verifies when a V3 signed
1158         // package with a rotated key is queried getApkContentsSigners only returns the current
1159         // signer.
1160         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps.apk");
1161         Utils.runDeviceTests(
1162                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1163                 "testGetApkContentsSignersShowsCurrent");
1164     }
1165 
1166     @Test
testInstallV2MultipleSignersGetApkContentsSigners()1167     public void testInstallV2MultipleSignersGetApkContentsSigners() throws Exception {
1168         // Similar to the above test, but verifies when an APK is signed with two V2 signers
1169         // getApkContentsSigners returns both of the V2 signers.
1170         assertInstallFromBuildSucceeds("v1v2-ec-p256-two-signers-targetSdk-30.apk");
1171         Utils.runDeviceTests(
1172                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1173                 "testGetApkContentsSignersShowsMultipleSigners");
1174     }
1175 
1176     @Test
testInstallV3MultipleSignersInLineageGetSigningCertificateHistory()1177     public void testInstallV3MultipleSignersInLineageGetSigningCertificateHistory()
1178             throws Exception {
1179         // The APK used for this test is signed with a lineage containing 5 keys in the signing
1180         // history; this test verifies SigningInfo#getSigningCertificateHistory returns all of an
1181         // APKs signers in their order of rotation.
1182         assertInstallFromBuildSucceeds("v3-ec-p256-with-por-1_2_3_4_5-default-caps.apk");
1183         Utils.runDeviceTests(
1184                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1185                 "testGetSigningCertificateHistoryReturnsSignersInOrder");
1186     }
1187 
1188     @Test
testInstallV3KeyRotationHasSigningCertificate()1189     public void testInstallV3KeyRotationHasSigningCertificate() throws Exception {
1190         // tests that hasSigningCertificate() recognizes past and current signing certs
1191         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
1192         Utils.runDeviceTests(
1193                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1194                 "testHasSigningCertificate");
1195     }
1196 
1197     @Test
testInstallV3KeyRotationHasSigningCertificateSha256()1198     public void testInstallV3KeyRotationHasSigningCertificateSha256() throws Exception {
1199         // tests that hasSigningCertificate() recognizes past and current signing certs by sha256
1200         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
1201         Utils.runDeviceTests(
1202                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1203                 "testHasSigningCertificateSha256");
1204     }
1205 
1206     @Test
testInstallV3KeyRotationHasSigningCertificateByUid()1207     public void testInstallV3KeyRotationHasSigningCertificateByUid() throws Exception {
1208         // tests that hasSigningCertificate() recognizes past and current signing certs by uid
1209         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
1210         Utils.runDeviceTests(
1211                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1212                 "testHasSigningCertificateByUid");
1213     }
1214 
1215     @Test
testInstallV3KeyRotationHasSigningCertificateByUidSha256()1216     public void testInstallV3KeyRotationHasSigningCertificateByUidSha256() throws Exception {
1217         // tests that hasSigningCertificate() recognizes past and current signing certs by uid
1218         // and sha256
1219         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
1220         Utils.runDeviceTests(
1221                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1222                 "testHasSigningCertificateByUidSha256");
1223     }
1224 
1225     @Test
testInstallV3KeyRotationHasDuplicateSigningCertificateHistory()1226     public void testInstallV3KeyRotationHasDuplicateSigningCertificateHistory() throws Exception {
1227         // tests that an app's proof-of-rotation signing history cannot contain the same certificate
1228         // more than once.
1229         assertInstallFails("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2_2-full-caps.apk");
1230     }
1231 
1232     @Test
testInstallV3HasMultipleSigners()1233     public void testInstallV3HasMultipleSigners() throws Exception {
1234         // tests that an app can't be signed by multiple signers when using v3 signature scheme
1235         assertInstallFails("v3-rsa-pkcs1-sha256-2048-1_and_2.apk");
1236     }
1237 
1238     @Test
testInstallV3HasMultiplePlatformSigners()1239     public void testInstallV3HasMultiplePlatformSigners() throws Exception {
1240         // tests that an app can be signed by multiple v3 signers if they target different platform
1241         // versions
1242         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1_P_and_2_Qplus.apk");
1243     }
1244 
1245     @Test
testSharedKeyInSeparateLineageRetainsDeclaredCapabilities()1246     public void testSharedKeyInSeparateLineageRetainsDeclaredCapabilities() throws Exception {
1247         // This test verifies when a key is used in the signing lineage of multiple apps each
1248         // instance of the key retains its declared capabilities.
1249 
1250         // This app has granted the PERMISSION capability to the previous signer in the lineage
1251         // but has revoked the SHARED_USER_ID capability.
1252         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-declperm2.apk");
1253         // This app has granted the SHARED_USER_ID capability to the previous signer in the lineage
1254         // but has revoked the PERMISSION capability.
1255         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-perm-cap-sharedUid.apk");
1256 
1257         // Reboot the device to ensure that the capabilities written to packages.xml are properly
1258         // assigned to the packages installed above; it's possible immediately after a package
1259         // install the capabilities are as declared, but then during the reboot shared signing
1260         // keys also share the initial declared capabilities.
1261         getDevice().reboot();
1262 
1263         // This app is signed with the original shared signing key in the lineage and is part of the
1264         // sharedUserId; since the other app in this sharedUserId has granted the required
1265         // capability in the lineage the install should succeed.
1266         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid-companion2.apk");
1267         // This app is signed with the original shared signing key in the lineage and requests the
1268         // signature permission declared by the test app above. Since that app granted the
1269         // PERMISSION capability to the previous signer in the lineage this app should have the
1270         // permission granted.
1271         assertInstallFromBuildSucceeds("v3-ec-p256-1-companion-usesperm.apk");
1272         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
1273     }
1274 
1275     @CddTest(requirement="4/C-0-2")
1276     @Test
testV31TargetTPlatformUsesRotatedKey()1277     public void testV31TargetTPlatformUsesRotatedKey() throws Exception {
1278         // The v3.1 signature block is intended to allow applications to target T+ for APK signing
1279         // key rotation without needing multi-targeting APKs. This test verifies a standard APK
1280         // install with the rotated key in the v3.1 signing block targeting T is recognized by the
1281         // platform, and this rotated key is used as the signing identity.
1282         assertInstallSucceeds("v31-ec-p256_2-tgt-33.apk");
1283         Utils.runDeviceTests(
1284                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1285                 "testUsingRotatedSigner");
1286     }
1287 
1288     @CddTest(requirement="4/C-0-2")
1289     @Test
testV31TargetLaterThanDevicePlatformUsesOriginalKey()1290     public void testV31TargetLaterThanDevicePlatformUsesOriginalKey() throws Exception {
1291         // The v3.1 signature block allows targeting SDK versions later than T for rotation; for
1292         // this test a target of 100001 is used assuming it will be beyond the platform's version.
1293         // Since the target version for rotation is beyond the platform's version the original
1294         // signer from the v3.0 block should be used.
1295         assertInstallSucceeds("v31-ec-p256_2-tgt-100001.apk");
1296         Utils.runDeviceTests(
1297                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1298                 "testUsingOriginalSigner");
1299     }
1300 
1301     @CddTest(requirement="4/C-0-2")
1302     @Test
testV31SignersTargetPAnd100001PlatformUsesTargetPSigner()1303     public void testV31SignersTargetPAnd100001PlatformUsesTargetPSigner() throws Exception {
1304         // The v3.1 signature scheme allows signer configs to target SDK versions; if a rotated
1305         // signer config is targeting P, the v3.0 block will include a signature with that rotated
1306         // config. This test verifies when the v3.1 signer is targeting an SDK version beyond that
1307         // of the platform's, the rotated signing config from the v3.0 block is used by the
1308         // platform.
1309         assertInstallSucceeds("v31-ec-p256_2-tgt-28-ec-p256_3-tgt-100001.apk");
1310         Utils.runDeviceTests(
1311                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1312                 "testUsingRotatedSigner");
1313     }
1314 
1315     @CddTest(requirement="4/C-0-2")
1316     @Test
testV31BlockStrippedWithV3StrippingProtectionAttrSet()1317     public void testV31BlockStrippedWithV3StrippingProtectionAttrSet() throws Exception {
1318         // With the introduction of the v3.1 signature scheme, a new stripping protection attribute
1319         // has been added to the v3.0 signer to protect against stripping and modification of the
1320         // v3.1 signing block. This test verifies a stripped v3.1 block is detected when the v3.0
1321         // stripping protection attribute is set.
1322         assertInstallFails("v31-block-stripped-v3-attr-value-33.apk");
1323     }
1324 
1325     @CddTest(requirement="4/C-0-2")
1326     @Test
testV31BlockWithMultipleSignersUsesCorrectSigner()1327     public void testV31BlockWithMultipleSignersUsesCorrectSigner() throws Exception {
1328         // All of the APKs for this test use multiple v3.1 signers; those targeting SDK versions
1329         // expected to be outside the version of a device under test use the original signer, and
1330         // those targeting an expected range for a device use the rotated key. This test is
1331         // intended to ensure the signer with the min / max SDK version that matches the device
1332         // SDK version is used.
1333 
1334         // The APK used for this test contains two signers in the v3.1 signing block. The first
1335         // has a range from 100001 to Integer.MAX_VALUE and is using the original signing key;
1336         // the second targets 33 to 100000 using the rotated key.
1337         assertInstallSucceeds("v31-ec-p256_2-tgt-33-ec-p256-tgt-100001.apk");
1338         Utils.runDeviceTests(
1339                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1340                 "testUsingRotatedSigner");
1341         uninstallPackage();
1342 
1343         // The APK for this test contains two signers in the v3.1 block, one targeting SDK versions
1344         // 1 to 27 using the original signer, and the other targeting 33+ using the rotated signer.
1345         assertInstallSucceeds("v31-ec-p256_2-tgt-33-ec-p256-tgt-1-27.apk");
1346         Utils.runDeviceTests(
1347                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1348                 "testUsingRotatedSigner");
1349         uninstallPackage();
1350 
1351         // This APK combines the extra signers from the APKs above, one targeting 1 to 27 with the
1352         // original signing key, another targeting 100001+ with the original signing key, and the
1353         // last targeting 33 to 100000 with the rotated key.
1354         assertInstallSucceeds("v31-ec-p256_2-tgt-33-ec-p256-tgt-1-27-and-100001.apk");
1355         Utils.runDeviceTests(
1356                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1357                 "testUsingRotatedSigner");
1358     }
1359 
1360     @CddTest(requirement="4/C-0-2")
1361     @Test
testV31UpdateV3ToFromV31Succeeds()1362     public void testV31UpdateV3ToFromV31Succeeds() throws Exception {
1363         // Since the v3.1 block is just intended to allow targeting SDK versions T and later for
1364         // rotation, an APK signed with the rotated key in a v3.0 signing block should support
1365         // updates to an APK signed with the same signing key in a v3.1 signing block.
1366         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps.apk");
1367         assertInstallSucceeds("v31-ec-p256_2-tgt-33.apk");
1368         uninstallPackage();
1369 
1370         // Similarly an APK signed with the rotated key in a v3.1 signing block should support
1371         // updates to an APK signed with the same signing key in a v3.0 signing block.
1372         assertInstallSucceeds("v31-ec-p256_2-tgt-33.apk");
1373         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps.apk");
1374         uninstallPackage();
1375     }
1376 
1377     @CddTest(requirement="4/C-0-2")
1378     @Test
testV31RotationTargetModifiedReportedByV3()1379     public void testV31RotationTargetModifiedReportedByV3() throws Exception {
1380         // When determining if a signer in the v3.1 signing block should be applied, the min / max
1381         // SDK versions from the signer are compared against the device's SDK version; if the device
1382         // is not within the signer's range then the block is skipped, other v3.1 blocks are
1383         // checked, and finally the v3.0 block is used. The v3.0 signer block contains an additional
1384         // attribute with the rotation-min-sdk-version that was expected in the v3.1 signing
1385         // block; if this attribute's value does not match what was found in the v3.1 block the
1386         // APK should fail to install.
1387         assertInstallFails("v31-ec-p256_2-tgt-33-modified.apk");
1388     }
1389 
1390     @CddTest(requirement="4/C-0-2")
1391     @Test
testV31RotationTargetsDevRelease()1392     public void testV31RotationTargetsDevRelease() throws Exception {
1393         // The v3.1 signature scheme allows targeting a platform release under development through
1394         // the use of a rotation-targets-dev-release additional attribute. Since a platform under
1395         // development shares the same SDK version as the most recently released platform, the
1396         // attribute is used by the platform to determine if a signer block should be applied. If
1397         // the signer's minSdkVersion is the same as the device's SDK version and this attribute
1398         // is set, then the platform will check the value of ro.build.version.codename; a value of
1399         // "REL" indicates the platform is a release platform, so the current signer block will not
1400         // be used. During T's development, the SDK version is 31 and the codename is not "REL", so
1401         // this test APK will install on T during development as well as after its release since
1402         // the SDK version will be bumped at that point.
1403         assertInstallSucceeds("v31-ec-p256_2-tgt-31-dev-release.apk");
1404     }
1405 
1406     @Test
testInstallTargetSdk30WithV1Signers()1407     public void testInstallTargetSdk30WithV1Signers() throws Exception {
1408         // An app targeting SDK version >= 30 must have at least a V2 signature; this test verifies
1409         // an app targeting SDK version 30 with only a V1 signature fails to install.
1410         assertInstallFails("v1-ec-p256-two-signers-targetSdk-30.apk");
1411     }
1412 
1413     @Test
testInstallTargetSdk30WithV1V2Signers()1414     public void testInstallTargetSdk30WithV1V2Signers() throws Exception {
1415         // An app targeting SDK version >= 30 must have at least a V2 signature; this test verifies
1416         // that an app targeting SDK version 30 with both a V1 and V2 signature installs
1417         // successfully.
1418         installApkFromBuild("v1v2-ec-p256-two-signers-targetSdk-30.apk");
1419     }
1420 
1421     @Test
1422     @Parameters(method = "installOnIncremental")
testInstallV4WithV2Signer(boolean onIncremental)1423     public void testInstallV4WithV2Signer(boolean onIncremental) throws Exception {
1424         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1425 
1426         // APK generated with:
1427         // apksigner sign --v2-signing-enabled true --v3-signing-enabled false --v4-signing-enabled
1428         assertInstallV4Succeeds("v4-digest-v2.apk");
1429     }
1430 
1431     @Test
1432     @Parameters(method = "installOnIncremental")
testInstallV4WithV3Signer(boolean onIncremental)1433     public void testInstallV4WithV3Signer(boolean onIncremental) throws Exception {
1434         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1435 
1436         // APK generated with:
1437         // apksigner sign --v2-signing-enabled false --v3-signing-enabled true --v4-signing-enabled
1438         assertInstallV4Succeeds("v4-digest-v3.apk");
1439     }
1440 
1441     @Test
1442     @Parameters(method = "installOnIncremental")
testInstallV4WithV2V3Signer(boolean onIncremental)1443     public void testInstallV4WithV2V3Signer(boolean onIncremental) throws Exception {
1444         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1445 
1446         // APK generated with:
1447         // apksigner sign --v2-signing-enabled true --v3-signing-enabled true --v4-signing-enabled
1448         assertInstallV4Succeeds("v4-digest-v2v3.apk");
1449     }
1450 
1451     @Test
1452     @Parameters(method = "installOnIncremental")
testInstallV4WithV2NoVeritySigner(boolean onIncremental)1453     public void testInstallV4WithV2NoVeritySigner(boolean onIncremental) throws Exception {
1454         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1455 
1456         // APK generated with:
1457         // --v2-signing-enabled true --v3-signing-enabled false --v4-signing-enabled
1458         // Full commands in generate-apks.sh
1459         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withDSA.apk");
1460         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withEC.apk");
1461         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withRSA.apk");
1462         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha512withEC.apk");
1463         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha512withRSA.apk");
1464     }
1465 
1466     @Test
1467     @Parameters(method = "installOnIncremental")
testInstallV4WithV2VeritySigner(boolean onIncremental)1468     public void testInstallV4WithV2VeritySigner(boolean onIncremental) throws Exception {
1469         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1470 
1471         // APK generated with:
1472         // --v2-signing-enabled true --v3-signing-enabled false
1473         // --v4-signing-enabled --verity-enabled
1474         // Full commands in generate-apks.sh
1475         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withDSA-Verity.apk");
1476         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withEC-Verity.apk");
1477         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withRSA-Verity.apk");
1478     }
1479 
1480     @Test
1481     @Parameters(method = "installOnIncremental")
testInstallV4WithV3NoVeritySigner(boolean onIncremental)1482     public void testInstallV4WithV3NoVeritySigner(boolean onIncremental) throws Exception {
1483         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1484 
1485         // APK generated with:
1486         // --v2-signing-enabled false --v3-signing-enabled true --v4-signing-enabled
1487         // Full commands in generate-apks.sh
1488         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withDSA.apk");
1489         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withEC.apk");
1490         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withRSA.apk");
1491         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha512withEC.apk");
1492         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha512withRSA.apk");
1493     }
1494 
1495     @Test
1496     @Parameters(method = "installOnIncremental")
testInstallV4WithV3VeritySigner(boolean onIncremental)1497     public void testInstallV4WithV3VeritySigner(boolean onIncremental) throws Exception {
1498         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1499 
1500         // APK generated with:
1501         // --v2-signing-enabled false --v3-signing-enabled true
1502         // --v4-signing-enabled --verity-enabled
1503         // Full commands in generate-apks.sh
1504         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withDSA-Verity.apk");
1505         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withEC-Verity.apk");
1506         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withRSA-Verity.apk");
1507     }
1508 
1509     @Test
1510     @Parameters(method = "installOnIncremental")
testInstallV4WithV2SignerDoesNotVerify(boolean onIncremental)1511     public void testInstallV4WithV2SignerDoesNotVerify(boolean onIncremental) throws Exception {
1512         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1513 
1514         // APKs generated with:
1515         // apksigner sign -v2-signing-enabled true --v3-signing-enabled false --v4-signing-enabled
1516 
1517         // Malformed v4 signature - first byte of v4 signing_info.signature is flipped
1518         assertInstallV4FailsWithError("v4-digest-v2-badv4signature.apk", "did not verify");
1519         // Malformed digest - first byte of v4 signing_info.apk_digest is flipped
1520         assertInstallV4FailsWithError("v4-digest-v2-badv2digest.apk", "did not verify");
1521     }
1522 
1523     @Test
1524     @Parameters(method = "installOnIncremental")
testInstallV4WithV3SignerDoesNotVerify(boolean onIncremental)1525     public void testInstallV4WithV3SignerDoesNotVerify(boolean onIncremental) throws Exception {
1526         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1527 
1528         // APKs generated with:
1529         // apksigner sign -v2-signing-enabled false --v3-signing-enabled true --v4-signing-enabled
1530 
1531         // Malformed v4 signature - first byte of v4 signing_info.signature is flipped
1532         assertInstallV4FailsWithError("v4-digest-v3-badv4signature.apk", "did not verify");
1533 
1534         // Malformed digest - first byte of v4 signing_info.apk_digest is flipped
1535         assertInstallV4FailsWithError("v4-digest-v3-badv3digest.apk", "did not verify");
1536 
1537     }
1538 
1539     @Test
1540     @Parameters(method = "installOnIncremental")
testInstallV4WithV2V3SignerDoesNotVerify(boolean onIncremental)1541     public void testInstallV4WithV2V3SignerDoesNotVerify(boolean onIncremental) throws Exception {
1542         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1543 
1544         // APKs generated with:
1545         // apksigner sign -v2-signing-enabled true --v3-signing-enabled true --v4-signing-enabled
1546 
1547         // Malformed v4 signature - first byte of v4 signing_info.signature is flipped
1548         assertInstallV4FailsWithError("v4-digest-v2v3-badv4signature.apk", "did not verify");
1549 
1550         // Malformed digest - first byte of v4 signing_info.apk_digest is flipped
1551         assertInstallV4FailsWithError("v4-digest-v2v3-badv2v3digest.apk", "did not verify");
1552     }
1553 
1554     @Test
1555     @Parameters(method = "installOnIncremental")
testInstallV4With128BytesAdditionalDataSucceeds(boolean onIncremental)1556     public void testInstallV4With128BytesAdditionalDataSucceeds(boolean onIncremental)
1557             throws Exception {
1558         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1559 
1560         // Editing apksigner to fill additional data of size 128 bytes.
1561         assertInstallV4Succeeds("v4-digest-v3-128bytes-additional-data.apk");
1562     }
1563 
1564     @Test
1565     @Parameters(method = "installOnIncremental")
testInstallV4With256BytesAdditionalDataFails(boolean onIncremental)1566     public void testInstallV4With256BytesAdditionalDataFails(boolean onIncremental)
1567             throws Exception {
1568         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1569 
1570         // Editing apksigner to fill additional data of size 256 bytes.
1571         if (onIncremental) {
1572             // For incremental, a bad Merkle tree will fail.
1573             assertInstallV4FailsWithError("v4-digest-v3-256bytes-additional-data.apk",
1574                     "additionalData has to be at most 128 bytes");
1575         } else {
1576             // For non-incremental, Merkle tree in idsig is not used.
1577             assertInstallV4Succeeds("v4-digest-v3-256bytes-additional-data.apk");
1578         }
1579     }
1580 
1581     @Test
1582     @Parameters(method = "installOnIncremental")
testInstallV4With10MBytesAdditionalDataFails(boolean onIncremental)1583     public void testInstallV4With10MBytesAdditionalDataFails(boolean onIncremental)
1584             throws Exception {
1585         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1586 
1587         // Editing apksigner to fill additional data of size 10 * 1024 * 1024 bytes.
1588         if (onIncremental) {
1589             // For incremental, a bad Merkle tree will fail.
1590             assertInstallV4FailsWithError("v4-digest-v3-10mbytes-additional-data.apk",
1591                     "Failure");
1592         } else {
1593             // For non-incremental, Merkle tree in idsig is not used.
1594             assertInstallV4Succeeds("v4-digest-v3-10mbytes-additional-data.apk");
1595         }
1596     }
1597 
1598     @Test
1599     @Parameters(method = "installOnIncremental")
testInstallV4WithWrongBlockSize(boolean onIncremental)1600     public void testInstallV4WithWrongBlockSize(boolean onIncremental) throws Exception {
1601         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1602 
1603         // Editing apksigner with the wrong block size in the v4 signature.
1604         assertInstallV4FailsWithError("v4-digest-v3-wrong-block-size.apk",
1605                 "did not verify");
1606     }
1607 
1608     @Test
1609     @Parameters(method = "installOnIncremental")
testInstallV4WithDifferentBlockSize(boolean onIncremental)1610     public void testInstallV4WithDifferentBlockSize(boolean onIncremental) throws Exception {
1611         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1612 
1613         // Editing apksigner with the different block size (2048 instead of 4096).
1614         assertInstallV4FailsWithError("v4-digest-v3-merkle-tree-different-block-size.apk",
1615                 "Unsupported log2BlockSize: 11");
1616     }
1617 
1618     @Test
1619     @Parameters(method = "installOnIncremental")
testInstallV4WithWrongRawRootHash(boolean onIncremental)1620     public void testInstallV4WithWrongRawRootHash(boolean onIncremental) throws Exception {
1621         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1622 
1623         // Editing apksigner with the wrong raw root hash in the v4 signature.
1624         assertInstallV4FailsWithError("v4-digest-v3-wrong-raw-root-hash.apk", "Failure");
1625     }
1626 
1627     @Test
1628     @Parameters(method = "installOnIncremental")
testInstallV4WithWrongSignatureBytes(boolean onIncremental)1629     public void testInstallV4WithWrongSignatureBytes(boolean onIncremental) throws Exception {
1630         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1631 
1632         // Editing apksigner with the wrong signature bytes in the v4 signature.
1633         assertInstallV4FailsWithError("v4-digest-v3-wrong-sig-bytes.apk",
1634                 "did not verify");
1635     }
1636 
1637     @Test
1638     @Parameters(method = "installOnIncremental")
testInstallV4WithWrongSignatureBytesSize(boolean onIncremental)1639     public void testInstallV4WithWrongSignatureBytesSize(boolean onIncremental) throws Exception {
1640         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1641 
1642         // Editing apksigner with the wrong signature byte size in the v4 signature.
1643         assertInstallV4FailsWithError("v4-digest-v3-wrong-sig-bytes-size.apk",
1644                 "Failure");
1645     }
1646 
1647     @Test
1648     @Parameters(method = "installOnIncremental")
testInstallV4WithNoMerkleTree(boolean onIncremental)1649     public void testInstallV4WithNoMerkleTree(boolean onIncremental) throws Exception {
1650         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1651 
1652         if (onIncremental) {
1653             // Editing apksigner to not include the Merkle tree.
1654             assertInstallV4FailsWithError("v4-digest-v3-no-merkle-tree.apk",
1655                     "Failure");
1656         } else {
1657             assertInstallV4Succeeds("v4-digest-v3-no-merkle-tree.apk");
1658         }
1659     }
1660 
1661     @Test
1662     @Parameters(method = "installOnIncremental")
testInstallV4WithWithTrailingDataInMerkleTree(boolean onIncremental)1663     public void testInstallV4WithWithTrailingDataInMerkleTree(boolean onIncremental)
1664             throws Exception {
1665         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1666 
1667         // Editing apksigner to add trailing data after the Merkle tree.
1668         if (onIncremental) {
1669             // For incremental, a bad Merkle tree will fail.
1670             assertInstallV4FailsWithError("v4-digest-v3-merkle-tree-1mb-trailing-data.apk",
1671                     "Failure");
1672         } else {
1673             // For non-incremental, Merkle tree in idsig is not used.
1674             assertInstallV4Succeeds("v4-digest-v3-merkle-tree-1mb-trailing-data.apk");
1675         }
1676     }
1677 
1678     @Test
1679     @Parameters(method = "installOnIncremental")
testInstallV4WithMerkleTreeBitsFlipped(boolean onIncremental)1680     public void testInstallV4WithMerkleTreeBitsFlipped(boolean onIncremental) throws Exception {
1681         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1682 
1683         // Editing apksigner to flip few bits in the only node of the Merkle tree of a small app.
1684         if (onIncremental) {
1685             // For incremental, a bad Merkle tree will fail.
1686             assertInstallV4FailsWithError("v4-digest-v3-merkle-tree-bit-flipped.apk",
1687                     "Failed to parse");
1688         } else {
1689             // For non-incremental, Merkle tree in idsig is not used.
1690             assertInstallV4Succeeds("v4-digest-v3-merkle-tree-bit-flipped.apk");
1691         }
1692     }
1693 
1694     @Test
1695     @Parameters(method = "installOnIncremental")
testV4IncToV3NonIncSameKeyUpgradeSucceeds(boolean onIncremental)1696     public void testV4IncToV3NonIncSameKeyUpgradeSucceeds(boolean onIncremental) throws Exception {
1697         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1698 
1699         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1700         // to generate the apks
1701         assertInstallV4Succeeds("v4-inc-to-v3-noninc-ec-p256-appv1.apk");
1702 
1703         // non-incremental upgrade with the same key.
1704         assertInstallSucceeds("v4-inc-to-v3-noninc-ec-p256-appv2.apk");
1705     }
1706 
1707     @Test
1708     @Parameters(method = "installOnIncremental")
testV4IncToV3NonIncMismatchingKeyUpgradeFails(boolean onIncremental)1709     public void testV4IncToV3NonIncMismatchingKeyUpgradeFails(boolean onIncremental)
1710             throws Exception {
1711         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1712 
1713         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1714         // to generate the apks
1715         assertInstallV4Succeeds("v4-inc-to-v3-noninc-ec-p256-appv1.apk");
1716 
1717         // non-incremental upgrade with a mismatching key.
1718         assertInstallFailsWithError("v4-inc-to-v3-noninc-ec-p384-appv2.apk",
1719                 "signatures do not match newer version");
1720     }
1721 
1722     @Test
1723     @Parameters(method = "installOnIncremental")
testV4IncToV3NonIncRotatedKeyUpgradeSucceeds(boolean onIncremental)1724     public void testV4IncToV3NonIncRotatedKeyUpgradeSucceeds(boolean onIncremental)
1725             throws Exception {
1726         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1727 
1728         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1729         // to generate the apks
1730         assertInstallV4Succeeds("v4-inc-to-v3-noninc-ec-p256-appv1.apk");
1731 
1732         // non-incremental upgrade with key rotation.
1733         assertInstallSucceeds("v4-inc-to-v3-noninc-ec-p384-rotated-ec-p256-appv2.apk");
1734     }
1735 
1736     @Test
1737     @Parameters(method = "installOnIncremental")
testV4IncToV3NonIncMismatchedRotatedKeyUpgradeFails(boolean onIncremental)1738     public void testV4IncToV3NonIncMismatchedRotatedKeyUpgradeFails(boolean onIncremental)
1739             throws Exception {
1740         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1741 
1742         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1743         // to generate the apks
1744         assertInstallV4Succeeds("v4-inc-to-v3-noninc-dsa-3072-appv1.apk");
1745 
1746         // non-incremental upgrade with key rotation mismatch with key used in app v1.
1747         assertInstallFailsWithError("v4-inc-to-v3-noninc-ec-p384-rotated-ec-p256-appv2.apk",
1748                 "signatures do not match newer version");
1749     }
1750 
1751     @Test
1752     @Parameters(method = "installOnIncremental")
testV4IncToV2NonIncSameKeyUpgradeSucceeds(boolean onIncremental)1753     public void testV4IncToV2NonIncSameKeyUpgradeSucceeds(boolean onIncremental) throws Exception {
1754         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1755 
1756         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1757         // to generate the apks
1758         assertInstallV4Succeeds("v4-inc-to-v2-noninc-ec-p256-appv1.apk");
1759 
1760         // non-incremental upgrade with the same key.
1761         assertInstallSucceeds("v4-inc-to-v2-noninc-ec-p256-appv2.apk");
1762     }
1763 
1764     @Test
1765     @Parameters(method = "installOnIncremental")
testV4IncToV2NonIncMismatchingKeyUpgradeFails(boolean onIncremental)1766     public void testV4IncToV2NonIncMismatchingKeyUpgradeFails(boolean onIncremental)
1767             throws Exception {
1768         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1769 
1770         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1771         // to generate the apks
1772         assertInstallV4Succeeds("v4-inc-to-v2-noninc-ec-p256-appv1.apk");
1773 
1774         // non-incremental upgrade with a mismatching key.
1775         assertInstallFailsWithError("v4-inc-to-v2-noninc-ec-p384-appv2.apk",
1776                 "signatures do not match newer version");
1777     }
1778 
1779     @Test
1780     @Parameters(method = "installOnIncremental")
testInstallV4UpdateAfterRotation(boolean onIncremental)1781     public void testInstallV4UpdateAfterRotation(boolean onIncremental) throws Exception {
1782         checkAssumptionAndSetIdsigInstallMode(onIncremental);
1783 
1784         // This test performs an end to end verification of the update of an app with a rotated
1785         // key. The app under test exports a bound service that performs its own PackageManager key
1786         // rotation API verification, and the instrumentation test binds to the service and invokes
1787         // the verifySignatures method to verify that the key rotation APIs return the expected
1788         // results. The instrumentation test app is signed with the same key and lineage as the
1789         // app under test to also provide a second app that can be used for the checkSignatures
1790         // verification.
1791 
1792         // Install the initial versions of the apps; the test method verifies the app under test is
1793         // signed with the original signing key.
1794         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService.apk");
1795         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
1796         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
1797                 "verifySignatures_noRotation_succeeds");
1798 
1799         // Install the second version of the app signed with the rotated key. This test verifies the
1800         // app still functions as expected after the update with the rotated key. The
1801         // instrumentation test app is not updated here to allow verification of the pre-key
1802         // rotation behavior for the checkSignatures APIs. These APIs should behave similar to the
1803         // GET_SIGNATURES flag in that if one or both apps have a signing lineage if the oldest
1804         // signers in the lineage match then the methods should return that the signatures match
1805         // even if one is signed with a newer key in the lineage.
1806         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService_v2.apk");
1807         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
1808                 "verifySignatures_withRotation_succeeds");
1809 
1810         // Installs the third version of the app under test and the instrumentation test, both
1811         // signed with the same rotated key and lineage. This test is intended to verify that the
1812         // app can still be updated and function as expected after an update with a rotated key.
1813         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService_v3.apk");
1814         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest_v2.apk");
1815         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
1816                 "verifySignatures_withRotation_succeeds");
1817     }
1818 
hasIncrementalFeature()1819     private boolean hasIncrementalFeature() throws Exception {
1820         return "true\n".equals(getDevice().executeShellCommand(
1821                 "pm has-feature android.software.incremental_delivery"));
1822     }
1823 
checkAssumptionAndSetIdsigInstallMode(boolean onIncremental)1824     private void checkAssumptionAndSetIdsigInstallMode(boolean onIncremental) throws Exception {
1825         // Due to the limitation of existing test runners (i.e. DeviceParameterizedRunner and
1826         // DeviceJUnit4Parameterized), there's no easy way to parameterize only some of the test
1827         // methods while avoid recording the parameter manually.
1828         mUseIncrementalForInstallWithIdsig = onIncremental;
1829 
1830         if (onIncremental) {
1831             // V4 is only enabled on devices with Incremental feature
1832             assumeTrue(hasIncrementalFeature());
1833         } else {
1834             // Install V4 in classic install session
1835             assumeTrue(android.security.Flags.extendVbChainToUpdatedApk());
1836         }
1837     }
1838 
assertInstallSucceeds(String apkFilenameInResources)1839     private void assertInstallSucceeds(String apkFilenameInResources) throws Exception {
1840         String installResult = installPackageFromResource(apkFilenameInResources);
1841         if (installResult != null) {
1842             fail("Failed to install " + apkFilenameInResources + ": " + installResult);
1843         }
1844     }
1845 
assertInstallEphemeralSucceeds(String apkFilenameInResources)1846     private void assertInstallEphemeralSucceeds(String apkFilenameInResources) throws Exception {
1847         String installResult = installEphemeralPackageFromResource(apkFilenameInResources);
1848         if (installResult != null) {
1849             fail("Failed to install " + apkFilenameInResources + ": " + installResult);
1850         }
1851     }
1852 
assertInstallSucceedsForEach( String apkFilenamePatternInResources, String[] args)1853     private void assertInstallSucceedsForEach(
1854             String apkFilenamePatternInResources, String[] args) throws Exception {
1855         for (String arg : args) {
1856             String apkFilenameInResources =
1857                     String.format(Locale.US, apkFilenamePatternInResources, arg);
1858             String installResult = installPackageFromResource(apkFilenameInResources);
1859             if (installResult != null) {
1860                 fail("Failed to install " + apkFilenameInResources + ": " + installResult);
1861             }
1862             try {
1863                 uninstallPackage();
1864             } catch (Exception e) {
1865                 throw new RuntimeException(
1866                         "Failed to uninstall after installing " + apkFilenameInResources, e);
1867             }
1868         }
1869     }
1870 
assertInstallV4Succeeds(String apkFilenameInResources)1871     private void assertInstallV4Succeeds(String apkFilenameInResources) throws Exception {
1872         String installResult = installV4PackageFromResource(apkFilenameInResources);
1873         if (!installResult.equals("Success")) {
1874             fail("Failed to install " + apkFilenameInResources + ": " + installResult);
1875         }
1876     }
1877 
assertInstallV4FromBuildSucceeds(String apkName)1878     private void assertInstallV4FromBuildSucceeds(String apkName) throws Exception {
1879         String installResult = installV4PackageFromBuild(apkName);
1880         if (!installResult.equals("Success")) {
1881             fail("Failed to install " + apkName + ": " + installResult);
1882         }
1883     }
1884 
assertInstallV4SucceedsAndUninstall(String apkFilenameInResources)1885     private void assertInstallV4SucceedsAndUninstall(String apkFilenameInResources)
1886             throws Exception {
1887         assertInstallV4Succeeds(apkFilenameInResources);
1888         try {
1889             uninstallPackage();
1890         } catch (Exception e) {
1891             throw new RuntimeException(
1892                     "Failed to uninstall after installing " + apkFilenameInResources, e);
1893         }
1894     }
1895 
assertInstallV4FailsWithError(String apkFilenameInResources, String errorSubstring)1896     private void assertInstallV4FailsWithError(String apkFilenameInResources, String errorSubstring)
1897             throws Exception {
1898         String installResult = installV4PackageFromResource(apkFilenameInResources);
1899         if (installResult.equals("Success")) {
1900             fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail"
1901                     + " with \"" + errorSubstring + "\"");
1902         }
1903         assertContains(
1904                 "Install failure message of " + apkFilenameInResources,
1905                 errorSubstring,
1906                 installResult);
1907     }
1908 
assertInstallFailsWithError( String apkFilenameInResources, String errorSubstring)1909     private void assertInstallFailsWithError(
1910             String apkFilenameInResources, String errorSubstring) throws Exception {
1911         String installResult = installPackageFromResource(apkFilenameInResources);
1912         if (installResult == null) {
1913             fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail"
1914                     + " with \"" + errorSubstring + "\"");
1915         }
1916         assertContains(
1917                 "Install failure message of " + apkFilenameInResources,
1918                 errorSubstring,
1919                 installResult);
1920     }
1921 
assertInstallEphemeralFailsWithError( String apkFilenameInResources, String errorSubstring)1922     private void assertInstallEphemeralFailsWithError(
1923             String apkFilenameInResources, String errorSubstring) throws Exception {
1924         String installResult = installEphemeralPackageFromResource(apkFilenameInResources);
1925         if (installResult == null) {
1926             fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail"
1927                     + " with \"" + errorSubstring + "\"");
1928         }
1929         assertContains(
1930                 "Install failure message of " + apkFilenameInResources,
1931                 errorSubstring,
1932                 installResult);
1933     }
1934 
assertInstallFails(String apkFilenameInResources)1935     private void assertInstallFails(String apkFilenameInResources) throws Exception {
1936         String installResult = installPackageFromResource(apkFilenameInResources);
1937         if (installResult == null) {
1938             fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail");
1939         }
1940     }
1941 
assertContains(String message, String expectedSubstring, String actual)1942     private static void assertContains(String message, String expectedSubstring, String actual) {
1943         String errorPrefix = ((message != null) && (message.length() > 0)) ? (message + ": ") : "";
1944         if (actual == null) {
1945             fail(errorPrefix + "Expected to contain \"" + expectedSubstring + "\", but was null");
1946         }
1947         if (!actual.contains(expectedSubstring)) {
1948             fail(errorPrefix + "Expected to contain \"" + expectedSubstring + "\", but was \""
1949                     + actual + "\"");
1950         }
1951     }
1952 
installDeviceTestPkg()1953     private void installDeviceTestPkg() throws Exception {
1954         assertInstallFromBuildSucceeds(DEVICE_TESTS_APK);
1955     }
1956 
assertInstallFromBuildSucceeds(String apkName)1957     private void assertInstallFromBuildSucceeds(String apkName) throws Exception {
1958         String result = installApkFromBuild(apkName);
1959         assertNull("failed to install " + apkName + ", Reason: " + result, result);
1960     }
1961 
assertInstallFromBuildFails(String apkName)1962     private void assertInstallFromBuildFails(String apkName) throws Exception {
1963         String result = installApkFromBuild(apkName);
1964         assertNotNull("Successfully installed " + apkName + " when failure was expected", result);
1965     }
1966 
installApkFromBuild(String apkName)1967     private String installApkFromBuild(String apkName) throws Exception {
1968         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
1969         File apk = buildHelper.getTestFile(apkName);
1970         try {
1971             return getDevice().installPackage(apk, true, INSTALL_ARG_FORCE_QUERYABLE,
1972                     INSTALL_ARG_BYPASS_LOW_TARGET_SDK_BLOCK);
1973         } finally {
1974             getDevice().deleteFile("/data/local/tmp/" + apk.getName());
1975         }
1976     }
1977 
installPackageFromResource(String apkFilenameInResources, boolean ephemeral)1978     private String installPackageFromResource(String apkFilenameInResources, boolean ephemeral)
1979             throws IOException, DeviceNotAvailableException {
1980         // ITestDevice.installPackage API requires the APK to be install to be a File. We thus
1981         // copy the requested resource into a temporary file, attempt to install it, and delete the
1982         // file during cleanup.
1983         File apkFile = null;
1984         try {
1985             apkFile = getFileFromResource(apkFilenameInResources);
1986             if (ephemeral) {
1987                 return getDevice().installPackage(apkFile, true, "--ephemeral",
1988                         INSTALL_ARG_FORCE_QUERYABLE, INSTALL_ARG_BYPASS_LOW_TARGET_SDK_BLOCK);
1989             } else {
1990                 return getDevice().installPackage(apkFile, true, INSTALL_ARG_FORCE_QUERYABLE,
1991                         INSTALL_ARG_BYPASS_LOW_TARGET_SDK_BLOCK);
1992             }
1993         } finally {
1994             cleanUpFile(apkFile);
1995             getDevice().deleteFile("/data/local/tmp/" + apkFile.getName());
1996         }
1997     }
1998 
installV4PackageFromResource(String apkFilenameInResources)1999     private String installV4PackageFromResource(String apkFilenameInResources)
2000             throws IOException, DeviceNotAvailableException {
2001         File apkFile = null;
2002         File v4SignatureFile = null;
2003         String remoteApkFilePath = null, remoteV4SignaturePath = null;
2004         try {
2005             apkFile = getFileFromResource(apkFilenameInResources);
2006             v4SignatureFile = getFileFromResource(apkFilenameInResources + ".idsig");
2007             remoteApkFilePath = pushFileToRemote(apkFile);
2008             remoteV4SignaturePath = pushFileToRemote(v4SignatureFile);
2009             return installV4Package(remoteApkFilePath);
2010         } finally {
2011             cleanUpFile(apkFile);
2012             cleanUpFile(v4SignatureFile);
2013             getDevice().deleteFile(remoteApkFilePath);
2014             getDevice().deleteFile(remoteV4SignaturePath);
2015         }
2016     }
2017 
installV4PackageFromBuild(String apkName)2018     private String installV4PackageFromBuild(String apkName)
2019             throws IOException, DeviceNotAvailableException {
2020         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
2021         File apkFile = buildHelper.getTestFile(apkName);
2022         File v4SignatureFile = buildHelper.getTestFile(apkName + ".idsig");
2023         String remoteApkFilePath = pushFileToRemote(apkFile);
2024         String remoteV4SignaturePath = pushFileToRemote(v4SignatureFile);
2025         try {
2026             return installV4Package(remoteApkFilePath);
2027         } finally {
2028             getDevice().deleteFile(remoteApkFilePath);
2029             getDevice().deleteFile(remoteV4SignaturePath);
2030         }
2031     }
2032 
pushFileToRemote(File localFile)2033     private String pushFileToRemote(File localFile) throws DeviceNotAvailableException {
2034         String remotePath = "/data/local/tmp/pkginstalltest-" + localFile.getName();
2035         getDevice().pushFile(localFile, remotePath);
2036         return remotePath;
2037     }
2038 
installV4Package(String remoteApkPath)2039     private String installV4Package(String remoteApkPath)
2040             throws DeviceNotAvailableException {
2041         var installer = new InstallMultiple();
2042         if (mUseIncrementalForInstallWithIdsig) {
2043             installer.useIncremental();
2044         } else {
2045             // Add to the install session
2046             installer.addRemoteFile(remoteApkPath + ".idsig");
2047         }
2048         return installer
2049             .bypassLowTargetSdkBlock()
2050             .forceQueryable()
2051             .addRemoteFile(remoteApkPath)
2052             .runForResult();
2053     }
2054 
getFileFromResource(String filenameInResources)2055     private File getFileFromResource(String filenameInResources)
2056             throws IOException, IllegalArgumentException {
2057         String fullResourceName = TEST_APK_RESOURCE_PREFIX + filenameInResources;
2058         File tempDir = FileUtil.createTempDir("pkginstalltest");
2059         File file = new File(tempDir, filenameInResources);
2060         InputStream in = getClass().getResourceAsStream(fullResourceName);
2061         if (in == null) {
2062             throw new IllegalArgumentException("Resource not found: " + fullResourceName);
2063         }
2064         OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
2065         byte[] buf = new byte[65536];
2066         int chunkSize;
2067         while ((chunkSize = in.read(buf)) != -1) {
2068             out.write(buf, 0, chunkSize);
2069         }
2070         out.close();
2071         return file;
2072     }
2073 
cleanUpFile(File file)2074     private void cleanUpFile(File file) {
2075         if (file != null && file.exists()) {
2076             file.delete();
2077             // Delete the parent dir as well which is a temp dir
2078             File parent = file.getParentFile();
2079             if (parent.exists()) {
2080                 parent.delete();
2081             }
2082         }
2083     }
2084 
installPackageFromResource(String apkFilenameInResources)2085     private String installPackageFromResource(String apkFilenameInResources)
2086             throws IOException, DeviceNotAvailableException {
2087         return installPackageFromResource(apkFilenameInResources, false);
2088     }
2089 
installEphemeralPackageFromResource(String apkFilenameInResources)2090     private String installEphemeralPackageFromResource(String apkFilenameInResources)
2091             throws IOException, DeviceNotAvailableException {
2092         return installPackageFromResource(apkFilenameInResources, true);
2093     }
2094 
uninstallPackage()2095     private String uninstallPackage() throws DeviceNotAvailableException {
2096         String result1 = getDevice().uninstallPackage(TEST_PKG);
2097         String result2 = getDevice().uninstallPackage(TEST_PKG2);
2098         return result1 != null ? result1 : result2;
2099     }
2100 
uninstallCompanionPackages()2101     private String uninstallCompanionPackages() throws DeviceNotAvailableException {
2102         String result1 = getDevice().uninstallPackage(COMPANION_TEST_PKG);
2103         String result2 = getDevice().uninstallPackage(COMPANION2_TEST_PKG);
2104         String result3 = getDevice().uninstallPackage(COMPANION3_TEST_PKG);
2105         return Stream.of(result1, result2, result3)
2106                 .filter(Objects::nonNull)
2107                 .findFirst()
2108                 .orElse(null);
2109     }
2110 
uninstallDeviceTestPackage()2111     private String uninstallDeviceTestPackage() throws DeviceNotAvailableException {
2112         return getDevice().uninstallPackage(DEVICE_TESTS_PKG);
2113     }
2114 
uninstallServicePackages()2115     private void uninstallServicePackages() throws DeviceNotAvailableException {
2116         getDevice().uninstallPackage(SERVICE_PKG);
2117         getDevice().uninstallPackage(SERVICE_TEST_PKG);
2118     }
2119 
uninstallPackages()2120     private void uninstallPackages() throws DeviceNotAvailableException {
2121         uninstallPackage();
2122         uninstallCompanionPackages();
2123         uninstallDeviceTestPackage();
2124         uninstallServicePackages();
2125     }
2126 
2127     private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
InstallMultiple()2128         InstallMultiple() {
2129             super(getDevice(), getBuild(), getAbi(), /* grantPermissions */ true);
2130         }
2131 
2132         @Override
deriveRemoteName(String originalName, int index)2133         protected String deriveRemoteName(String originalName, int index) {
2134             return originalName;
2135         }
2136     }
2137 }
2138