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 android.platform.test.annotations.AsbSecurityTest;
20 
21 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
22 import com.android.tradefed.build.IBuildInfo;
23 import com.android.tradefed.device.DeviceNotAvailableException;
24 import com.android.tradefed.testtype.DeviceTestCase;
25 import com.android.tradefed.testtype.IBuildReceiver;
26 import com.android.tradefed.util.FileUtil;
27 
28 import java.io.BufferedOutputStream;
29 import java.io.File;
30 import java.io.FileOutputStream;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.OutputStream;
34 import java.util.Locale;
35 
36 /**
37  * Tests for APK signature verification during installation.
38  */
39 public class PkgInstallSignatureVerificationTest extends DeviceTestCase implements IBuildReceiver {
40 
41     private static final String TEST_PKG = "android.appsecurity.cts.tinyapp";
42     private static final String COMPANION_TEST_PKG = "android.appsecurity.cts.tinyapp_companion";
43     private static final String COMPANION2_TEST_PKG = "android.appsecurity.cts.tinyapp_companion2";
44     private static final String DEVICE_TESTS_APK = "CtsV3SigningSchemeRotationTest.apk";
45     private static final String DEVICE_TESTS_PKG = "android.appsecurity.cts.v3rotationtests";
46     private static final String DEVICE_TESTS_CLASS = DEVICE_TESTS_PKG + ".V3RotationTest";
47     private static final String SERVICE_PKG = "android.appsecurity.cts.keyrotationtest";
48     private static final String SERVICE_TEST_PKG = "android.appsecurity.cts.keyrotationtest.test";
49     private static final String SERVICE_TEST_CLASS =
50             SERVICE_TEST_PKG + ".SignatureQueryServiceInstrumentationTest";
51     private static final String TEST_APK_RESOURCE_PREFIX = "/pkgsigverify/";
52     private static final String INSTALL_ARG_FORCE_QUERYABLE = "--force-queryable";
53 
54     private static final String[] DSA_KEY_NAMES = {"1024", "2048", "3072"};
55     private static final String[] EC_KEY_NAMES = {"p256", "p384", "p521"};
56     private static final String[] RSA_KEY_NAMES = {"1024", "2048", "3072", "4096", "8192", "16384"};
57     private static final String[] RSA_KEY_NAMES_2048_AND_LARGER =
58             {"2048", "3072", "4096", "8192", "16384"};
59 
60     private IBuildInfo mCtsBuild;
61 
62     @Override
setBuild(IBuildInfo buildInfo)63     public void setBuild(IBuildInfo buildInfo) {
64         mCtsBuild = buildInfo;
65     }
66 
67     @Override
setUp()68     protected void setUp() throws Exception {
69         super.setUp();
70 
71         Utils.prepareSingleUser(getDevice());
72         assertNotNull(mCtsBuild);
73         uninstallPackage();
74         uninstallCompanionPackages();
75         installDeviceTestPkg();
76     }
77 
78     @Override
tearDown()79     protected void tearDown() throws Exception {
80         try {
81             uninstallPackages();
82         } catch (DeviceNotAvailableException ignored) {
83         } finally {
84             super.tearDown();
85         }
86     }
87 
testInstallOriginalSucceeds()88     public void testInstallOriginalSucceeds() throws Exception {
89         // APK signed with v1 and v2 schemes. Obtained by building
90         // cts/hostsidetests/appsecurity/test-apps/tinyapp.
91         assertInstallSucceeds("original.apk");
92     }
93 
testInstallV1OneSignerMD5withRSA()94     public void testInstallV1OneSignerMD5withRSA() throws Exception {
95         // APK signed with v1 scheme only, one signer.
96         assertInstallSucceedsForEach(
97                 "v1-only-with-rsa-pkcs1-md5-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES);
98         assertInstallSucceedsForEach(
99                 "v1-only-with-rsa-pkcs1-md5-1.2.840.113549.1.1.4-%s.apk", RSA_KEY_NAMES);
100     }
101 
testInstallV1OneSignerSHA1withRSA()102     public void testInstallV1OneSignerSHA1withRSA() throws Exception {
103         // APK signed with v1 scheme only, one signer.
104         assertInstallSucceedsForEach(
105                 "v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES);
106         assertInstallSucceedsForEach(
107                 "v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.5-%s.apk", RSA_KEY_NAMES);
108     }
109 
testInstallV1OneSignerSHA224withRSA()110     public void testInstallV1OneSignerSHA224withRSA() throws Exception {
111         // APK signed with v1 scheme only, one signer.
112         assertInstallSucceedsForEach(
113                 "v1-only-with-rsa-pkcs1-sha224-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES);
114         assertInstallSucceedsForEach(
115                 "v1-only-with-rsa-pkcs1-sha224-1.2.840.113549.1.1.14-%s.apk", RSA_KEY_NAMES);
116     }
117 
testInstallV1OneSignerSHA256withRSA()118     public void testInstallV1OneSignerSHA256withRSA() throws Exception {
119         // APK signed with v1 scheme only, one signer.
120         assertInstallSucceedsForEach(
121                 "v1-only-with-rsa-pkcs1-sha256-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES);
122         assertInstallSucceedsForEach(
123                 "v1-only-with-rsa-pkcs1-sha256-1.2.840.113549.1.1.11-%s.apk", RSA_KEY_NAMES);
124     }
125 
testInstallV1OneSignerSHA384withRSA()126     public void testInstallV1OneSignerSHA384withRSA() throws Exception {
127         // APK signed with v1 scheme only, one signer.
128         assertInstallSucceedsForEach(
129                 "v1-only-with-rsa-pkcs1-sha384-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES);
130         assertInstallSucceedsForEach(
131                 "v1-only-with-rsa-pkcs1-sha384-1.2.840.113549.1.1.12-%s.apk", RSA_KEY_NAMES);
132     }
133 
testInstallV1OneSignerSHA512withRSA()134     public void testInstallV1OneSignerSHA512withRSA() throws Exception {
135         // APK signed with v1 scheme only, one signer.
136         assertInstallSucceedsForEach(
137                 "v1-only-with-rsa-pkcs1-sha512-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES);
138         assertInstallSucceedsForEach(
139                 "v1-only-with-rsa-pkcs1-sha512-1.2.840.113549.1.1.13-%s.apk", RSA_KEY_NAMES);
140     }
141 
testInstallV1OneSignerSHA1withECDSA()142     public void testInstallV1OneSignerSHA1withECDSA() throws Exception {
143         // APK signed with v1 scheme only, one signer.
144         assertInstallSucceedsForEach(
145                 "v1-only-with-ecdsa-sha1-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES);
146         assertInstallSucceedsForEach(
147                 "v1-only-with-ecdsa-sha1-1.2.840.10045.4.1-%s.apk", EC_KEY_NAMES);
148     }
149 
testInstallV1OneSignerSHA224withECDSA()150     public void testInstallV1OneSignerSHA224withECDSA() throws Exception {
151         // APK signed with v1 scheme only, one signer.
152         assertInstallSucceedsForEach(
153                 "v1-only-with-ecdsa-sha224-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES);
154         assertInstallSucceedsForEach(
155                 "v1-only-with-ecdsa-sha224-1.2.840.10045.4.3.1-%s.apk", EC_KEY_NAMES);
156     }
157 
testInstallV1OneSignerSHA256withECDSA()158     public void testInstallV1OneSignerSHA256withECDSA() throws Exception {
159         // APK signed with v1 scheme only, one signer.
160         assertInstallSucceedsForEach(
161                 "v1-only-with-ecdsa-sha256-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES);
162         assertInstallSucceedsForEach(
163                 "v1-only-with-ecdsa-sha256-1.2.840.10045.4.3.2-%s.apk", EC_KEY_NAMES);
164     }
165 
testInstallV1OneSignerSHA384withECDSA()166     public void testInstallV1OneSignerSHA384withECDSA() throws Exception {
167         // APK signed with v1 scheme only, one signer.
168         assertInstallSucceedsForEach(
169                 "v1-only-with-ecdsa-sha384-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES);
170         assertInstallSucceedsForEach(
171                 "v1-only-with-ecdsa-sha384-1.2.840.10045.4.3.3-%s.apk", EC_KEY_NAMES);
172     }
173 
testInstallV1OneSignerSHA512withECDSA()174     public void testInstallV1OneSignerSHA512withECDSA() throws Exception {
175         // APK signed with v1 scheme only, one signer.
176         assertInstallSucceedsForEach(
177                 "v1-only-with-ecdsa-sha512-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES);
178         assertInstallSucceedsForEach(
179                 "v1-only-with-ecdsa-sha512-1.2.840.10045.4.3.4-%s.apk", EC_KEY_NAMES);
180     }
181 
testInstallV1OneSignerSHA1withDSA()182     public void testInstallV1OneSignerSHA1withDSA() throws Exception {
183         // APK signed with v1 scheme only, one signer.
184         assertInstallSucceedsForEach(
185                 "v1-only-with-dsa-sha1-1.2.840.10040.4.1-%s.apk", DSA_KEY_NAMES);
186         assertInstallSucceedsForEach(
187                 "v1-only-with-dsa-sha1-1.2.840.10040.4.3-%s.apk", DSA_KEY_NAMES);
188     }
189 
testInstallV1OneSignerSHA224withDSA()190     public void testInstallV1OneSignerSHA224withDSA() throws Exception {
191         // APK signed with v1 scheme only, one signer.
192         assertInstallSucceedsForEach(
193                 "v1-only-with-dsa-sha224-1.2.840.10040.4.1-%s.apk", DSA_KEY_NAMES);
194         assertInstallSucceedsForEach(
195                 "v1-only-with-dsa-sha224-2.16.840.1.101.3.4.3.1-%s.apk", DSA_KEY_NAMES);
196     }
197 
testInstallV1OneSignerSHA256withDSA()198     public void testInstallV1OneSignerSHA256withDSA() throws Exception {
199         // APK signed with v1 scheme only, one signer.
200         assertInstallSucceedsForEach(
201                 "v1-only-with-dsa-sha256-1.2.840.10040.4.1-%s.apk", DSA_KEY_NAMES);
202         assertInstallSucceedsForEach(
203                 "v1-only-with-dsa-sha256-2.16.840.1.101.3.4.3.2-%s.apk", DSA_KEY_NAMES);
204     }
205 
206 //  Android platform doesn't support DSA with SHA-384 and SHA-512.
207 //    public void testInstallV1OneSignerSHA384withDSA() throws Exception {
208 //        // APK signed with v1 scheme only, one signer.
209 //        assertInstallSucceedsForEach(
210 //                "v1-only-with-dsa-sha384-2.16.840.1.101.3.4.3.3-%s.apk", DSA_KEY_NAMES);
211 //    }
212 //
213 //    public void testInstallV1OneSignerSHA512withDSA() throws Exception {
214 //        // APK signed with v1 scheme only, one signer.
215 //        assertInstallSucceedsForEach(
216 //                "v1-only-with-dsa-sha512-2.16.840.1.101.3.4.3.3-%s.apk", DSA_KEY_NAMES);
217 //    }
218 
testInstallV2StrippedFails()219     public void testInstallV2StrippedFails() throws Exception {
220         // APK signed with v1 and v2 schemes, but v2 signature was stripped from the file (by using
221         // zipalign).
222         // This should fail because the v1 signature indicates that the APK was supposed to be
223         // signed with v2 scheme as well, making the platform's anti-stripping protections reject
224         // the APK.
225         assertInstallFailsWithError("v2-stripped.apk", "Signature stripped");
226 
227         // Similar to above, but the X-Android-APK-Signed anti-stripping header in v1 signature
228         // lists unknown signature schemes in addition to APK Signature Scheme v2. Unknown schemes
229         // should be ignored.
230         assertInstallFailsWithError(
231                 "v2-stripped-with-ignorable-signing-schemes.apk", "Signature stripped");
232     }
233 
testInstallV2OneSignerOneSignature()234     public void testInstallV2OneSignerOneSignature() throws Exception {
235         // APK signed with v2 scheme only, one signer, one signature.
236         assertInstallSucceedsForEach("v2-only-with-dsa-sha256-%s.apk", DSA_KEY_NAMES);
237         assertInstallSucceedsForEach("v2-only-with-ecdsa-sha256-%s.apk", EC_KEY_NAMES);
238         assertInstallSucceedsForEach("v2-only-with-rsa-pkcs1-sha256-%s.apk", RSA_KEY_NAMES);
239         assertInstallSucceedsForEach("v2-only-with-rsa-pss-sha256-%s.apk", RSA_KEY_NAMES);
240 
241         // DSA with SHA-512 is not supported by Android platform and thus APK Signature Scheme v2
242         // does not support that either
243         // assertInstallSucceedsForEach("v2-only-with-dsa-sha512-%s.apk", DSA_KEY_NAMES);
244         assertInstallSucceedsForEach("v2-only-with-ecdsa-sha512-%s.apk", EC_KEY_NAMES);
245         assertInstallSucceedsForEach("v2-only-with-rsa-pkcs1-sha512-%s.apk", RSA_KEY_NAMES);
246         assertInstallSucceedsForEach(
247                 "v2-only-with-rsa-pss-sha512-%s.apk",
248                 RSA_KEY_NAMES_2048_AND_LARGER // 1024-bit key is too short for PSS with SHA-512
249         );
250     }
251 
testInstallV1SignatureOnlyDoesNotVerify()252     public void testInstallV1SignatureOnlyDoesNotVerify() throws Exception {
253         // APK signed with v1 scheme only, but not all digests match those recorded in
254         // META-INF/MANIFEST.MF.
255         String error = "META-INF/MANIFEST.MF has invalid digest";
256 
257         // Bitflip in classes.dex of otherwise good file.
258         assertInstallFailsWithError(
259                 "v1-only-with-tampered-classes-dex.apk", error);
260     }
261 
testInstallV2SignatureDoesNotVerify()262     public void testInstallV2SignatureDoesNotVerify() throws Exception {
263         // APK signed with v2 scheme only, but the signature over signed-data does not verify.
264         String error = "signature did not verify";
265 
266         // Bitflip in certificate field inside signed-data. Based on
267         // v2-only-with-dsa-sha256-1024.apk.
268         assertInstallFailsWithError("v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk", error);
269 
270         // Signature claims to be RSA PKCS#1 v1.5 with SHA-256, but is actually using SHA-512.
271         // Based on v2-only-with-rsa-pkcs1-sha256-2048.apk.
272         assertInstallFailsWithError(
273                 "v2-only-with-rsa-pkcs1-sha256-2048-sig-does-not-verify.apk", error);
274 
275         // Signature claims to be RSA PSS with SHA-256 and 32 bytes of salt, but is actually using 0
276         // bytes of salt. Based on v2-only-with-rsa-pkcs1-sha256-2048.apk. Obtained by modifying APK
277         // signer to use the wrong amount of salt.
278         assertInstallFailsWithError(
279                 "v2-only-with-rsa-pss-sha256-2048-sig-does-not-verify.apk", error);
280 
281         // Bitflip in the ECDSA signature. Based on v2-only-with-ecdsa-sha256-p256.apk.
282         assertInstallFailsWithError(
283                 "v2-only-with-ecdsa-sha256-p256-sig-does-not-verify.apk", error);
284     }
285 
testInstallV2ContentDigestMismatch()286     public void testInstallV2ContentDigestMismatch() throws Exception {
287         // APK signed with v2 scheme only, but the digest of contents does not match the digest
288         // stored in signed-data.
289         String error = "digest of contents did not verify";
290 
291         // Based on v2-only-with-rsa-pkcs1-sha512-4096.apk. Obtained by modifying APK signer to
292         // flip the leftmost bit in content digest before signing signed-data.
293         assertInstallFailsWithError(
294                 "v2-only-with-rsa-pkcs1-sha512-4096-digest-mismatch.apk", error);
295 
296         // Based on v2-only-with-ecdsa-sha256-p256.apk. Obtained by modifying APK signer to flip the
297         // leftmost bit in content digest before signing signed-data.
298         assertInstallFailsWithError(
299                 "v2-only-with-ecdsa-sha256-p256-digest-mismatch.apk", error);
300     }
301 
testInstallNoApkSignatureSchemeBlock()302     public void testInstallNoApkSignatureSchemeBlock() throws Exception {
303         // APK signed with v2 scheme only, but the rules for verifying APK Signature Scheme v2
304         // signatures say that this APK must not be verified using APK Signature Scheme v2.
305 
306         // Obtained from v2-only-with-rsa-pkcs1-sha512-4096.apk by flipping a bit in the magic
307         // field in the footer of APK Signing Block. This makes the APK Signing Block disappear.
308         assertInstallFails("v2-only-wrong-apk-sig-block-magic.apk");
309 
310         // Obtained by modifying APK signer to insert "GARBAGE" between ZIP Central Directory and
311         // End of Central Directory. The APK is otherwise fine and is signed with APK Signature
312         // Scheme v2. Based on v2-only-with-rsa-pkcs1-sha256.apk.
313         assertInstallFails("v2-only-garbage-between-cd-and-eocd.apk");
314 
315         // Obtained by modifying APK signer to truncate the ZIP Central Directory by one byte. The
316         // APK is otherwise fine and is signed with APK Signature Scheme v2. Based on
317         // v2-only-with-rsa-pkcs1-sha256.apk
318         assertInstallFails("v2-only-truncated-cd.apk");
319 
320         // Obtained by modifying the size in APK Signature Block header. Based on
321         // v2-only-with-ecdsa-sha512-p521.apk.
322         assertInstallFails("v2-only-apk-sig-block-size-mismatch.apk");
323 
324         // Obtained by modifying the ID under which APK Signature Scheme v2 Block is stored in
325         // APK Signing Block and by modifying the APK signer to not insert anti-stripping
326         // protections into JAR Signature. The APK should appear as having no APK Signature Scheme
327         // v2 Block and should thus successfully verify using JAR Signature Scheme.
328         assertInstallSucceeds("v1-with-apk-sig-block-but-without-apk-sig-scheme-v2-block.apk");
329     }
330 
testInstallV2UnknownPairIgnoredInApkSigningBlock()331     public void testInstallV2UnknownPairIgnoredInApkSigningBlock() throws Exception {
332         // Obtained by modifying APK signer to emit an unknown ID-value pair into APK Signing Block
333         // before the ID-value pair containing the APK Signature Scheme v2 Block. The unknown
334         // ID-value should be ignored.
335         assertInstallSucceeds("v2-only-unknown-pair-in-apk-sig-block.apk");
336     }
337 
testInstallV2IgnoresUnknownSignatureAlgorithms()338     public void testInstallV2IgnoresUnknownSignatureAlgorithms() throws Exception {
339         // APK is signed with a known signature algorithm and with a couple of unknown ones.
340         // Obtained by modifying APK signer to use "unknown" signature algorithms in addition to
341         // known ones.
342         assertInstallSucceeds("v2-only-with-ignorable-unsupported-sig-algs.apk");
343     }
344 
testInstallV2RejectsMismatchBetweenSignaturesAndDigestsBlocks()345     public void testInstallV2RejectsMismatchBetweenSignaturesAndDigestsBlocks() throws Exception {
346         // APK is signed with a single signature algorithm, but the digests block claims that it is
347         // signed with two different signature algorithms. Obtained by modifying APK Signer to
348         // emit an additional digest record with signature algorithm 0x12345678.
349         assertInstallFailsWithError(
350                 "v2-only-signatures-and-digests-block-mismatch.apk",
351                 "Signature algorithms don't match between digests and signatures records");
352     }
353 
testInstallV2RejectsMismatchBetweenPublicKeyAndCertificate()354     public void testInstallV2RejectsMismatchBetweenPublicKeyAndCertificate() throws Exception {
355         // APK is signed with v2 only. The public key field does not match the public key in the
356         // leaf certificate. Obtained by modifying APK signer to write out a modified leaf
357         // certificate where the RSA modulus has a bitflip.
358         assertInstallFailsWithError(
359                 "v2-only-cert-and-public-key-mismatch.apk",
360                 "Public key mismatch between certificate and signature record");
361     }
362 
testInstallV2RejectsSignerBlockWithNoCertificates()363     public void testInstallV2RejectsSignerBlockWithNoCertificates() throws Exception {
364         // APK is signed with v2 only. There are no certificates listed in the signer block.
365         // Obtained by modifying APK signer to output no certificates.
366         assertInstallFailsWithError("v2-only-no-certs-in-sig.apk", "No certificates listed");
367     }
368 
testInstallTwoSigners()369     public void testInstallTwoSigners() throws Exception {
370         // APK signed by two different signers.
371         assertInstallSucceeds("two-signers.apk");
372         // Because the install attempt below is an update, it also tests that the signing
373         // certificates exposed by v2 signatures above are the same as the one exposed by v1
374         // signatures in this APK.
375         assertInstallSucceeds("v1-only-two-signers.apk");
376         assertInstallSucceeds("v2-only-two-signers.apk");
377     }
378 
testInstallNegativeModulus()379     public void testInstallNegativeModulus() throws Exception {
380         // APK signed with a certificate that has a negative RSA modulus.
381         assertInstallSucceeds("v1-only-negative-modulus.apk");
382         assertInstallSucceeds("v2-only-negative-modulus.apk");
383         assertInstallSucceeds("v3-only-negative-modulus.apk");
384     }
385 
testInstallV2TwoSignersRejectsWhenOneBroken()386     public void testInstallV2TwoSignersRejectsWhenOneBroken() throws Exception {
387         // Bitflip in the ECDSA signature of second signer. Based on two-signers.apk.
388         // This asserts that breakage in any signer leads to rejection of the APK.
389         assertInstallFailsWithError(
390                 "two-signers-second-signer-v2-broken.apk", "signature did not verify");
391     }
392 
testInstallV2TwoSignersRejectsWhenOneWithoutSignatures()393     public void testInstallV2TwoSignersRejectsWhenOneWithoutSignatures() throws Exception {
394         // APK v2-signed by two different signers. However, there are no signatures for the second
395         // signer.
396         assertInstallFailsWithError(
397                 "v2-only-two-signers-second-signer-no-sig.apk", "No signatures");
398     }
399 
testInstallV2TwoSignersRejectsWhenOneWithoutSupportedSignatures()400     public void testInstallV2TwoSignersRejectsWhenOneWithoutSupportedSignatures() throws Exception {
401         // APK v2-signed by two different signers. However, there are no supported signatures for
402         // the second signer.
403         assertInstallFailsWithError(
404                 "v2-only-two-signers-second-signer-no-supported-sig.apk",
405                 "No supported signatures");
406     }
407 
testInstallV2RejectsWhenMissingCode()408     public void testInstallV2RejectsWhenMissingCode() throws Exception {
409         // Obtained by removing classes.dex from original.apk and then signing with v2 only.
410         // Although this has nothing to do with v2 signature verification, package manager wants
411         // signature verification / certificate collection to reject APKs with missing code
412         // (classes.dex) unless requested otherwise.
413         assertInstallFailsWithError("v2-only-missing-classes.dex.apk", "code is missing");
414     }
415 
testCorrectCertUsedFromPkcs7SignedDataCertsSet()416     public void testCorrectCertUsedFromPkcs7SignedDataCertsSet() throws Exception {
417         // Obtained by prepending the rsa-1024 certificate to the PKCS#7 SignedData certificates set
418         // of v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.1-2048.apk META-INF/CERT.RSA. The certs
419         // (in the order of appearance in the file) are thus: rsa-1024, rsa-2048. The package's
420         // signing cert is rsa-2048.
421         assertInstallSucceeds("v1-only-pkcs7-cert-bag-first-cert-not-used.apk");
422 
423         // Check that rsa-1024 was not used as the previously installed package's signing cert.
424         assertInstallFailsWithError(
425                 "v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.1-1024.apk",
426                 "signatures do not match");
427 
428         // Check that rsa-2048 was used as the previously installed package's signing cert.
429         assertInstallSucceeds("v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.1-2048.apk");
430     }
431 
testV1SchemeSignatureCertNotReencoded()432     public void testV1SchemeSignatureCertNotReencoded() throws Exception {
433         // Regression test for b/30148997 and b/18228011. When PackageManager does not preserve the
434         // original encoded form of signing certificates, bad things happen, such as rejection of
435         // completely valid updates to apps. The issue in b/30148997 and b/18228011 was that
436         // PackageManager started re-encoding signing certs into DER. This normally produces exactly
437         // the original form because X.509 certificates are supposed to be DER-encoded. However, a
438         // small fraction of Android apps uses X.509 certificates which are not DER-encoded. For
439         // such apps, re-encoding into DER changes the serialized form of the certificate, creating
440         // a mismatch with the serialized form stored in the PackageManager database, leading to the
441         // rejection of updates for the app.
442         //
443         // The signing certs of the two APKs differ only in how the cert's signature is encoded.
444         // From Android's perspective, these two APKs are signed by different entities and thus
445         // cannot be used to update one another. If signature verification code re-encodes certs
446         // into DER, both certs will be exactly the same and Android will accept these APKs as
447         // updates of each other. This test is thus asserting that the two APKs are not accepted as
448         // updates of each other.
449         //
450         // * v1-only-with-rsa-1024.apk cert's signature is DER-encoded
451         // * v1-only-with-rsa-1024-cert-not-der.apk cert's signature is not DER-encoded. It is
452         //   BER-encoded, with length encoded as two bytes instead of just one.
453         //   v1-only-with-rsa-1024-cert-not-der.apk META-INF/CERT.RSA was obtained from
454         //   v1-only-with-rsa-1024.apk META-INF/CERT.RSA by manually modifying the ASN.1 structure.
455         assertInstallSucceeds("v1-only-with-rsa-1024.apk");
456         assertInstallFailsWithError(
457                 "v1-only-with-rsa-1024-cert-not-der.apk", "signatures do not match");
458 
459         uninstallPackage();
460         assertInstallSucceeds("v1-only-with-rsa-1024-cert-not-der.apk");
461         assertInstallFailsWithError("v1-only-with-rsa-1024.apk", "signatures do not match");
462     }
463 
testV2SchemeSignatureCertNotReencoded()464     public void testV2SchemeSignatureCertNotReencoded() throws Exception {
465         // This test is here to catch something like b/30148997 and b/18228011 happening to the
466         // handling of APK Signature Scheme v2 signatures by PackageManager. When PackageManager
467         // does not preserve the original encoded form of signing certificates, bad things happen,
468         // such as rejection of completely valid updates to apps. The issue in b/30148997 and
469         // b/18228011 was that PackageManager started re-encoding signing certs into DER. This
470         // normally produces exactly the original form because X.509 certificates are supposed to be
471         // DER-encoded. However, a small fraction of Android apps uses X.509 certificates which are
472         // not DER-encoded. For such apps, re-encoding into DER changes the serialized form of the
473         // certificate, creating a mismatch with the serialized form stored in the PackageManager
474         // database, leading to the rejection of updates for the app.
475         //
476         // The signing certs of the two APKs differ only in how the cert's signature is encoded.
477         // From Android's perspective, these two APKs are signed by different entities and thus
478         // cannot be used to update one another. If signature verification code re-encodes certs
479         // into DER, both certs will be exactly the same and Android will accept these APKs as
480         // updates of each other. This test is thus asserting that the two APKs are not accepted as
481         // updates of each other.
482         //
483         // * v2-only-with-rsa-pkcs1-sha256-1024.apk cert's signature is DER-encoded
484         // * v2-only-with-rsa-pkcs1-sha256-1024-cert-not-der.apk cert's signature is not DER-encoded
485         //   It is BER-encoded, with length encoded as two bytes instead of just one.
486         assertInstallSucceeds("v2-only-with-rsa-pkcs1-sha256-1024.apk");
487         assertInstallFailsWithError(
488                 "v2-only-with-rsa-pkcs1-sha256-1024-cert-not-der.apk", "signatures do not match");
489 
490         uninstallPackage();
491         assertInstallSucceeds("v2-only-with-rsa-pkcs1-sha256-1024-cert-not-der.apk");
492         assertInstallFailsWithError(
493                 "v2-only-with-rsa-pkcs1-sha256-1024.apk", "signatures do not match");
494     }
495 
testInstallMaxSizedZipEocdComment()496     public void testInstallMaxSizedZipEocdComment() throws Exception {
497         // Obtained by modifying apksigner to produce a max-sized (0xffff bytes long) ZIP End of
498         // Central Directory comment, and signing the original.apk using the modified apksigner.
499         assertInstallSucceeds("v1-only-max-sized-eocd-comment.apk");
500         assertInstallSucceeds("v2-only-max-sized-eocd-comment.apk");
501     }
502 
testInstallEphemeralRequiresV2Signature()503     public void testInstallEphemeralRequiresV2Signature() throws Exception {
504         assertInstallEphemeralFailsWithError("unsigned-ephemeral.apk",
505                 "Failed to collect certificates");
506         assertInstallEphemeralFailsWithError("v1-only-ephemeral.apk",
507                 "must be signed with APK Signature Scheme v2 or greater");
508         assertInstallEphemeralSucceeds("v2-only-ephemeral.apk");
509         assertInstallEphemeralSucceeds("v1-v2-ephemeral.apk"); // signed with both schemes
510     }
511 
testInstallEmpty()512     public void testInstallEmpty() throws Exception {
513         assertInstallFailsWithError("empty-unsigned.apk", "Unknown failure");
514         assertInstallFailsWithError("v1-only-empty.apk", "Unknown failure");
515         assertInstallFailsWithError("v2-only-empty.apk", "Unknown failure");
516     }
517 
518     @AsbSecurityTest(cveBugId = 64211847)
testInstallApkWhichDoesNotStartWithZipLocalFileHeaderMagic()519     public void testInstallApkWhichDoesNotStartWithZipLocalFileHeaderMagic() throws Exception {
520         // The APKs below are competely fine except they don't start with ZIP Local File Header
521         // magic. Thus, these APKs will install just fine unless Package Manager requires that APKs
522         // start with ZIP Local File Header magic.
523         String error = "Unknown failure";
524 
525         // Obtained by modifying apksigner to output four unused 0x00 bytes at the start of the APK
526         assertInstallFailsWithError("v1-only-starts-with-00000000-magic.apk", error);
527         assertInstallFailsWithError("v2-only-starts-with-00000000-magic.apk", error);
528 
529         // Obtained by modifying apksigner to output 8 unused bytes (DEX magic and version) at the
530         // start of the APK
531         assertInstallFailsWithError("v1-only-starts-with-dex-magic.apk", error);
532         assertInstallFailsWithError("v2-only-starts-with-dex-magic.apk", error);
533     }
534 
testInstallV3KeyRotation()535     public void testInstallV3KeyRotation() throws Exception {
536         // tests that a v3 signed APK with RSA key can rotate to a new key
537         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1.apk");
538         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
539     }
540 
testInstallV3KeyRotationToAncestor()541     public void testInstallV3KeyRotationToAncestor() throws Exception {
542         // tests that a v3 signed APK with RSA key cannot be upgraded by one of its past certs
543         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
544         assertInstallFails("v3-rsa-pkcs1-sha256-2048-1.apk");
545     }
546 
testInstallV3KeyRotationToAncestorWithRollback()547     public void testInstallV3KeyRotationToAncestorWithRollback() throws Exception {
548         // tests that a v3 signed APK with RSA key can be upgraded by one of its past certs if it
549         // has granted that cert the rollback capability
550         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-and-roll-caps.apk");
551         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1.apk");
552     }
553 
testInstallV3KeyRotationMultipleHops()554     public void testInstallV3KeyRotationMultipleHops() throws Exception {
555         // tests that a v3 signed APK with RSA key can rotate to a new key which is the result of
556         // multiple rotations from the original: APK signed with key 1 can be updated by key 3, when
557         // keys were: 1 -> 2 -> 3
558         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1.apk");
559         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-3-with-por_1_2_3-full-caps.apk");
560     }
561 
testInstallV3PorSignerMismatch()562     public void testInstallV3PorSignerMismatch() throws Exception {
563         // tests that an APK with a proof-of-rotation struct that doesn't include the current
564         // signing certificate fails to install
565         assertInstallFails("v3-rsa-pkcs1-sha256-2048-3-with-por_1_2-full-caps.apk");
566     }
567 
testInstallV3KeyRotationWrongPor()568     public void testInstallV3KeyRotationWrongPor() throws Exception {
569         // tests that a valid APK with a proof-of-rotation record can't upgrade an APK with a
570         // signing certificate that isn't in the proof-of-rotation record
571         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1.apk");
572         assertInstallFails("v3-rsa-pkcs1-sha256-2048-3-with-por_2_3-full-caps.apk");
573     }
574 
testInstallV3KeyRotationSharedUid()575     public void testInstallV3KeyRotationSharedUid() throws Exception {
576         // tests that a v3 signed sharedUid APK can still be sharedUid with apps with its older
577         // signing certificate, if it so desires
578         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-sharedUid.apk");
579         assertInstallSucceeds(
580                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-sharedUid-companion.apk");
581     }
582 
testInstallV3KeyRotationOlderSharedUid()583     public void testInstallV3KeyRotationOlderSharedUid() throws Exception {
584 
585         // tests that a sharedUid APK can still install with another app that is signed by a newer
586         // signing certificate, but which allows sharedUid with the older one
587         assertInstallSucceeds(
588                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-sharedUid-companion.apk");
589         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-sharedUid.apk");
590     }
591 
testInstallV3KeyRotationSharedUidNoCap()592     public void testInstallV3KeyRotationSharedUidNoCap() throws Exception {
593         // tests that a v3 signed sharedUid APK cannot be sharedUid with apps with its older
594         // signing certificate, when it has not granted that certificate the sharedUid capability
595         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-sharedUid.apk");
596         assertInstallFails(
597                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-shUid-cap-sharedUid-companion.apk");
598     }
599 
testInstallV3KeyRotationOlderSharedUidNoCap()600     public void testInstallV3KeyRotationOlderSharedUidNoCap() throws Exception {
601         // tests that a sharedUid APK signed with an old certificate cannot install with
602         // an app having a proof-of-rotation structure that hasn't granted the older
603         // certificate the sharedUid capability
604         assertInstallSucceeds(
605                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-shUid-cap-sharedUid-companion.apk");
606         assertInstallFails("v3-rsa-pkcs1-sha256-2048-1-sharedUid.apk");
607     }
608 
testInstallV3NoRotationSharedUid()609     public void testInstallV3NoRotationSharedUid() throws Exception {
610         // tests that a sharedUid APK signed with a new certificate installs with
611         // an app having a proof-of-rotation structure that hasn't granted an older
612         // certificate the sharedUid capability
613         assertInstallSucceeds(
614                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-shUid-cap-sharedUid-companion.apk");
615         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-sharedUid.apk");
616     }
617 
testInstallV3MultipleAppsOneDeniesOldKeySharedUid()618     public void testInstallV3MultipleAppsOneDeniesOldKeySharedUid() throws Exception {
619         // If two apps are installed as part of a sharedUid, one granting access to the sharedUid
620         // to the previous key and the other revoking access to the sharedUid, then when an app
621         // signed with the old key attempts to join the sharedUid the installation should be blocked
622         assertInstallFromBuildSucceeds(
623                 "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
624         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
625         assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
626     }
627 
testInstallV3MultipleAppsOneUpdatedToDenyOldKeySharedUid()628     public void testInstallV3MultipleAppsOneUpdatedToDenyOldKeySharedUid() throws Exception {
629         // Similar to the test above if two apps are installed as part of a sharedUid with both
630         // granting access to the sharedUid to the previous key then an app signed with the previous
631         // key should be allowed to install and join the sharedUid. If one of the first two apps
632         // is then updated with a lineage that denies access to the sharedUid for the old key the
633         // installation of this updated app should be blocked.
634         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps-sharedUid.apk");
635         assertInstallFromBuildSucceeds(
636                 "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
637         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid-companion2.apk");
638         assertInstallFromBuildFails("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
639     }
640 
testInstallV3FirstAppOnlySignedByNewKeyLastAppOldKey()641     public void testInstallV3FirstAppOnlySignedByNewKeyLastAppOldKey() throws Exception {
642         // This test verifies the following scenario:
643         // - First installed app in sharedUid only signed with new key without lineage.
644         // - Second installed app in sharedUid signed with new key and includes lineage granting
645         //   access to the old key to join the sharedUid.
646         // - Last installed app in sharedUid signed with old key.
647         // The lineage should be updated when the second app is installed to allow the installation
648         // of the app signed with the old key.
649         assertInstallFromBuildSucceeds("v3-ec-p256-2-sharedUid-companion.apk");
650         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps-sharedUid.apk");
651         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid-companion2.apk");
652     }
653 
testInstallV3AppSignedWithOldKeyUpdatedLineageDeniesShUidCap()654     public void testInstallV3AppSignedWithOldKeyUpdatedLineageDeniesShUidCap() throws Exception {
655         // If an app is installed as part of a sharedUid, and then that app is signed with a new key
656         // that rejects the previous key in the lineage the update should be allowed to proceed
657         // as the app is being updated to the newly rotated key.
658         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid.apk");
659         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
660     }
661 
testInstallV3TwoSharedUidAppsWithDivergedLineages()662     public void testInstallV3TwoSharedUidAppsWithDivergedLineages() throws Exception {
663         // Apps that are installed as part of the sharedUserId with a lineage must have common
664         // ancestors; the platform will allow the installation if the lineage of an app being
665         // installed as part of the sharedUserId is the same, a subset, or a superset of the
666         // existing lineage, but if the lineage diverges then the installation should be blocked.
667         assertInstallFromBuildSucceeds("v3-por_Y_1_2-default-caps-sharedUid.apk");
668         assertInstallFromBuildFails("v3-por_Z_1_2-default-caps-sharedUid-companion.apk");
669     }
670 
testInstallV3UpdateAfterRotation()671     public void testInstallV3UpdateAfterRotation() throws Exception {
672         // This test performs an end to end verification of the update of an app with a rotated
673         // key. The app under test exports a bound service that performs its own PackageManager key
674         // rotation API verification, and the instrumentation test binds to the service and invokes
675         // the verifySignatures method to verify that the key rotation APIs return the expected
676         // results. The instrumentation test app is signed with the same key and lineage as the
677         // app under test to also provide a second app that can be used for the checkSignatures
678         // verification.
679 
680         // Install the initial versions of the apps; the test method verifies the app under test is
681         // signed with the original signing key.
682         assertInstallFromBuildSucceeds("CtsSignatureQueryService.apk");
683         assertInstallFromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
684         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
685                 "verifySignatures_noRotation_succeeds");
686 
687         // Install the second version of the app signed with the rotated key. This test verifies the
688         // app still functions as expected after the update with the rotated key. The
689         // instrumentation test app is not updated here to allow verification of the pre-key
690         // rotation behavior for the checkSignatures APIs. These APIs should behave similar to the
691         // GET_SIGNATURES flag in that if one or both apps have a signing lineage if the oldest
692         // signers in the lineage match then the methods should return that the signatures match
693         // even if one is signed with a newer key in the lineage.
694         assertInstallFromBuildSucceeds("CtsSignatureQueryService_v2.apk");
695         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
696                 "verifySignatures_withRotation_succeeds");
697 
698         // Installs the third version of the app under test and the instrumentation test, both
699         // signed with the same rotated key and lineage. This test is intended to verify that the
700         // app can still be updated and function as expected after an update with a rotated key.
701         assertInstallFromBuildSucceeds("CtsSignatureQueryService_v3.apk");
702         assertInstallFromBuildSucceeds("CtsSignatureQueryServiceTest_v2.apk");
703         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
704                 "verifySignatures_withRotation_succeeds");
705     }
706 
testInstallV3KeyRotationSigPerm()707     public void testInstallV3KeyRotationSigPerm() throws Exception {
708         // tests that a v3 signed APK can still get a signature permission from an app with its
709         // older signing certificate.
710         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
711         assertInstallSucceeds(
712                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-permcli-companion.apk");
713         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
714     }
715 
testInstallV3KeyRotationOlderSigPerm()716     public void testInstallV3KeyRotationOlderSigPerm() throws Exception {
717         // tests that an apk with an older signing certificate than the one which defines a
718         // signature permission it wants gets the permission if the defining APK grants the
719         // capability
720         assertInstallSucceeds(
721                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-permdef.apk");
722         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permcli-companion.apk");
723         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
724     }
725 
testInstallV3KeyRotationSigPermNoCap()726     public void testInstallV3KeyRotationSigPermNoCap() throws Exception {
727         // tests that an APK signed by an older signing certificate is unable to get a requested
728         // signature permission when the defining APK has rotated to a newer signing certificiate
729         // and does not grant the permission capability to the older cert
730         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-perm-cap-permdef.apk");
731         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permcli-companion.apk");
732         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
733     }
734 
testInstallV3KeyRotationOlderSigPermNoCap()735     public void testInstallV3KeyRotationOlderSigPermNoCap() throws Exception {
736         // tests that an APK signed by a newer signing certificate than the APK which defines a
737         // signature permission is able to get that permission, even if the newer APK does not
738         // grant the permission capability to the older signing certificate.
739         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
740         assertInstallSucceeds(
741                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-perm-cap-permcli-companion.apk");
742         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
743     }
744 
testInstallV3NoRotationSigPerm()745     public void testInstallV3NoRotationSigPerm() throws Exception {
746         // make sure that an APK, which wants to use a signature permission defined by an APK, which
747         // has not granted that capability to older signing certificates, can still install
748         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-perm-cap-permdef.apk");
749         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-permcli-companion.apk");
750         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
751     }
752 
testInstallV3CommonSignerInLineageWithPermCap()753     public void testInstallV3CommonSignerInLineageWithPermCap() throws Exception {
754         // If an APK requesting a signature permission has a common signer in the lineage with the
755         // APK declaring the permission, and that signer is granted the permission capability in
756         // the declaring APK, then the permission should be granted to the requesting app even
757         // if their signers have diverged.
758         assertInstallFromBuildSucceeds(
759                 "v3-ec-p256-with-por_1_2_3-1-no-caps-2-default-declperm.apk");
760         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2_4-companion-usesperm.apk");
761         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
762     }
763 
testInstallV3CommonSignerInLineageNoCaps()764     public void testInstallV3CommonSignerInLineageNoCaps() throws Exception {
765         // If an APK requesting a signature permission has a common signer in the lineage with the
766         // APK declaring the permission, but the signer in the lineage has not been granted the
767         // permission capability the permission should not be granted to the requesting app.
768         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2_3-no-caps-declperm.apk");
769         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2_4-companion-usesperm.apk");
770         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
771     }
772 
testKnownSignerPermGrantedWhenCurrentSignerInResource()773     public void testKnownSignerPermGrantedWhenCurrentSignerInResource() throws Exception {
774         // The knownSigner protection flag allows an app to declare other trusted signing
775         // certificates in an array resource; if a requesting app's current signer is in this array
776         // of trusted certificates then the permission should be granted.
777         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-ec-p256-1-3.apk");
778         assertInstallFromBuildSucceeds("v3-ec-p256_3-companion-uses-knownSigner.apk");
779         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
780 
781         // If the declaring app changes the trusted certificates on an update any requesting app
782         // that no longer meets the requirements based on its signing identity should have the
783         // permission revoked. This app update only trusts ec-p256_1 but the app that was previously
784         // granted the permission based on its signing identity is signed by ec-p256_3.
785         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-str-res-ec-p256-1.apk");
786         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
787     }
788 
testKnownSignerPermCurrentSignerNotInResource()789     public void testKnownSignerPermCurrentSignerNotInResource() throws Exception {
790         // If an app requesting a knownSigner permission does not meet the requirements for a
791         // signature permission and is not signed by any of the trusted certificates then the
792         // permission should not be granted.
793         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-ec-p256-1-3.apk");
794         assertInstallFromBuildSucceeds("v3-ec-p256_2-companion-uses-knownSigner.apk");
795         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
796     }
797 
testKnownSignerPermGrantedWhenSignerInLineageInResource()798     public void testKnownSignerPermGrantedWhenSignerInLineageInResource() throws Exception {
799         // If an app requesting a knownSigner permission was previously signed by a certificate
800         // that is trusted by the declaring app then the permission should be granted.
801         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-ec-p256-1-3.apk");
802         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-companion-uses-knownSigner.apk");
803         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
804 
805         // If the declaring app changes the permission to no longer use the knownSigner flag then
806         // any app granted the permission based on a signing identity from the set of trusted
807         // certificates should have the permission revoked.
808         assertInstallFromBuildSucceeds("v3-rsa-2048-declperm.apk");
809         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
810     }
811 
testKnownSignerPermSignerInLineageMatchesStringResource()812     public void testKnownSignerPermSignerInLineageMatchesStringResource() throws Exception {
813         // The knownSigner protection flag allows an app to declare a single known trusted
814         // certificate digest using a string resource instead of a string-array resource. This test
815         // verifies the knownSigner permission is granted to a requesting app if the single trusted
816         // cert is in the requesting app's lineage.
817         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-str-res-ec-p256-1.apk");
818         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-companion-uses-knownSigner.apk");
819         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
820     }
821 
testKnownSignerPermSignerInLineageMatchesStringConst()822     public void testKnownSignerPermSignerInLineageMatchesStringConst() throws Exception {
823         // The knownSigner protection flag allows an app to declare a single known trusted
824         // certificate digest using a string constant as the knownCerts attribute value instead of a
825         // resource. This test verifies the knownSigner permission is granted to a requesting app if
826         // the single trusted cert is in the requesting app's lineage.
827         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-str-const-ec-p256-1.apk");
828         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-companion-uses-knownSigner.apk");
829         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
830     }
831 
testInstallV3SigPermDoubleDefNewerSucceeds()832     public void testInstallV3SigPermDoubleDefNewerSucceeds() throws Exception {
833         // make sure that if an app defines a signature permission already defined by another app,
834         // it successfully installs if the other app's signing cert is in its past signing certs and
835         // the signature permission capability is granted
836         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
837         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-permdef-companion.apk");
838     }
839 
testInstallV3SigPermDoubleDefOlderSucceeds()840     public void testInstallV3SigPermDoubleDefOlderSucceeds() throws Exception {
841         // make sure that if an app defines a signature permission already defined by another app,
842         // it successfully installs if it is in the other app's past signing certs and the signature
843         // permission capability is granted
844         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-permdef-companion.apk");
845         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
846     }
847 
testInstallV3SigPermDoubleDefNewerNoCapFails()848     public void testInstallV3SigPermDoubleDefNewerNoCapFails() throws Exception {
849         // make sure that if an app defines a signature permission already defined by another app,
850         // it fails to install if the other app's signing cert is in its past signing certs but the
851         // signature permission capability is not granted
852         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
853         assertInstallFails(
854                 "v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-no-perm-cap-permdef-companion.apk");
855     }
856 
testInstallV3SigPermDoubleDefOlderNoCapFails()857     public void testInstallV3SigPermDoubleDefOlderNoCapFails() throws Exception {
858         // make sure that if an app defines a signature permission already defined by another app,
859         // it fails to install if it is in the other app's past signing certs but the signature
860         // permission capability is not granted
861         assertInstallSucceeds(
862                 "v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-no-perm-cap-permdef-companion.apk");
863         assertInstallFails("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
864     }
865 
testInstallV3SigPermDoubleDefSameNoCapSucceeds()866     public void testInstallV3SigPermDoubleDefSameNoCapSucceeds() throws Exception {
867         // make sure that if an app defines a signature permission already defined by another app,
868         // it installs successfully when signed by the same certificate, even if the original app
869         // does not grant signature capabilities to its past certs
870         assertInstallSucceeds(
871                 "v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-no-perm-cap-permdef-companion.apk");
872         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-permdef.apk");
873     }
874 
testInstallV3KeyRotationGetSignatures()875     public void testInstallV3KeyRotationGetSignatures() throws Exception {
876         // tests that a PackageInfo w/GET_SIGNATURES flag returns the older cert
877         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
878         Utils.runDeviceTests(
879                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testGetSignaturesShowsOld");
880     }
881 
testInstallV3KeyRotationGetSigningCertificates()882     public void testInstallV3KeyRotationGetSigningCertificates() throws Exception {
883         // tests that a PackageInfo w/GET_SIGNING_CERTIFICATES flag returns the old and new certs
884         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
885         Utils.runDeviceTests(
886                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
887                 "testGetSigningCertificatesShowsAll");
888     }
889 
testInstallV3KeyRotationGetApkContentsSigners()890     public void testInstallV3KeyRotationGetApkContentsSigners() throws Exception {
891         // The GET_SIGNING_CERTIFICATES flag results in a PackageInfo object returned with a
892         // SigningInfo instance that can be used to query all certificates in the lineage or only
893         // the current signer(s) via getApkContentsSigners. This test verifies when a V3 signed
894         // package with a rotated key is queried getApkContentsSigners only returns the current
895         // signer.
896         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps.apk");
897         Utils.runDeviceTests(
898                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
899                 "testGetApkContentsSignersShowsCurrent");
900     }
901 
testInstallV2MultipleSignersGetApkContentsSigners()902     public void testInstallV2MultipleSignersGetApkContentsSigners() throws Exception {
903         // Similar to the above test, but verifies when an APK is signed with two V2 signers
904         // getApkContentsSigners returns both of the V2 signers.
905         assertInstallFromBuildSucceeds("v1v2-ec-p256-two-signers-targetSdk-30.apk");
906         Utils.runDeviceTests(
907                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
908                 "testGetApkContentsSignersShowsMultipleSigners");
909     }
910 
testInstallV3KeyRotationHasSigningCertificate()911     public void testInstallV3KeyRotationHasSigningCertificate() throws Exception {
912         // tests that hasSigningCertificate() recognizes past and current signing certs
913         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
914         Utils.runDeviceTests(
915                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
916                 "testHasSigningCertificate");
917     }
918 
testInstallV3KeyRotationHasSigningCertificateSha256()919     public void testInstallV3KeyRotationHasSigningCertificateSha256() throws Exception {
920         // tests that hasSigningCertificate() recognizes past and current signing certs by sha256
921         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
922         Utils.runDeviceTests(
923                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
924                 "testHasSigningCertificateSha256");
925     }
926 
testInstallV3KeyRotationHasSigningCertificateByUid()927     public void testInstallV3KeyRotationHasSigningCertificateByUid() throws Exception {
928         // tests that hasSigningCertificate() recognizes past and current signing certs by uid
929         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
930         Utils.runDeviceTests(
931                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
932                 "testHasSigningCertificateByUid");
933     }
934 
testInstallV3KeyRotationHasSigningCertificateByUidSha256()935     public void testInstallV3KeyRotationHasSigningCertificateByUidSha256() throws Exception {
936         // tests that hasSigningCertificate() recognizes past and current signing certs by uid
937         // and sha256
938         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
939         Utils.runDeviceTests(
940                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
941                 "testHasSigningCertificateByUidSha256");
942     }
943 
testInstallV3KeyRotationHasDuplicateSigningCertificateHistory()944     public void testInstallV3KeyRotationHasDuplicateSigningCertificateHistory() throws Exception {
945         // tests that an app's proof-of-rotation signing history cannot contain the same certificate
946         // more than once.
947         assertInstallFails("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2_2-full-caps.apk");
948     }
949 
testInstallV3HasMultipleSigners()950     public void testInstallV3HasMultipleSigners() throws Exception {
951         // tests that an app can't be signed by multiple signers when using v3 signature scheme
952         assertInstallFails("v3-rsa-pkcs1-sha256-2048-1_and_2.apk");
953     }
954 
testInstallV3HasMultiplePlatformSigners()955     public void testInstallV3HasMultiplePlatformSigners() throws Exception {
956         // tests that an app can be signed by multiple v3 signers if they target different platform
957         // versions
958         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1_P_and_2_Qplus.apk");
959     }
960 
testInstallTargetSdk30WithV1Signers()961     public void testInstallTargetSdk30WithV1Signers() throws Exception {
962         // An app targeting SDK version >= 30 must have at least a V2 signature; this test verifies
963         // an app targeting SDK version 30 with only a V1 signature fails to install.
964         assertInstallFails("v1-ec-p256-two-signers-targetSdk-30.apk");
965     }
966 
testInstallTargetSdk30WithV1V2Signers()967     public void testInstallTargetSdk30WithV1V2Signers() throws Exception {
968         // An app targeting SDK version >= 30 must have at least a V2 signature; this test verifies
969         // that an app targeting SDK version 30 with both a V1 and V2 signature installs
970         // successfully.
971         installApkFromBuild("v1v2-ec-p256-two-signers-targetSdk-30.apk");
972     }
973 
testInstallV4WithV2Signer()974     public void testInstallV4WithV2Signer() throws Exception {
975         // V4 is only enabled on devices with Incremental feature
976         if (!hasIncrementalFeature()) {
977             return;
978         }
979 
980         // APK generated with:
981         // apksigner sign --v2-signing-enabled true --v3-signing-enabled false --v4-signing-enabled
982         assertInstallV4Succeeds("v4-digest-v2.apk");
983     }
984 
testInstallV4WithV3Signer()985     public void testInstallV4WithV3Signer() throws Exception {
986         // V4 is only enabled on devices with Incremental feature
987         if (!hasIncrementalFeature()) {
988             return;
989         }
990 
991         // APK generated with:
992         // apksigner sign --v2-signing-enabled false --v3-signing-enabled true --v4-signing-enabled
993         assertInstallV4Succeeds("v4-digest-v3.apk");
994     }
995 
testInstallV4WithV2V3Signer()996     public void testInstallV4WithV2V3Signer() throws Exception {
997         // V4 is only enabled on devices with Incremental feature
998         if (!hasIncrementalFeature()) {
999             return;
1000         }
1001 
1002         // APK generated with:
1003         // apksigner sign --v2-signing-enabled true --v3-signing-enabled true --v4-signing-enabled
1004         assertInstallV4Succeeds("v4-digest-v2v3.apk");
1005     }
1006 
testInstallV4WithV2NoVeritySigner()1007     public void testInstallV4WithV2NoVeritySigner() throws Exception {
1008         // V4 is only enabled on devices with Incremental feature
1009         if (!hasIncrementalFeature()) {
1010             return;
1011         }
1012 
1013         // APK generated with:
1014         // --v2-signing-enabled true --v3-signing-enabled false --v4-signing-enabled
1015         // Full commands in generate-apks.sh
1016         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withDSA.apk");
1017         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withEC.apk");
1018         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withRSA.apk");
1019         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha512withEC.apk");
1020         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha512withRSA.apk");
1021     }
1022 
testInstallV4WithV2VeritySigner()1023     public void testInstallV4WithV2VeritySigner() throws Exception {
1024         // V4 is only enabled on devices with Incremental feature
1025         if (!hasIncrementalFeature()) {
1026             return;
1027         }
1028 
1029         // APK generated with:
1030         // --v2-signing-enabled true --v3-signing-enabled false
1031         // --v4-signing-enabled --verity-enabled
1032         // Full commands in generate-apks.sh
1033         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withDSA-Verity.apk");
1034         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withEC-Verity.apk");
1035         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withRSA-Verity.apk");
1036     }
1037 
testInstallV4WithV3NoVeritySigner()1038     public void testInstallV4WithV3NoVeritySigner() throws Exception {
1039         // V4 is only enabled on devices with Incremental feature
1040         if (!hasIncrementalFeature()) {
1041             return;
1042         }
1043 
1044         // APK generated with:
1045         // --v2-signing-enabled false --v3-signing-enabled true --v4-signing-enabled
1046         // Full commands in generate-apks.sh
1047         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withDSA.apk");
1048         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withEC.apk");
1049         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withRSA.apk");
1050         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha512withEC.apk");
1051         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha512withRSA.apk");
1052     }
1053 
testInstallV4WithV3VeritySigner()1054     public void testInstallV4WithV3VeritySigner() throws Exception {
1055         // V4 is only enabled on devices with Incremental feature
1056         if (!hasIncrementalFeature()) {
1057             return;
1058         }
1059 
1060         // APK generated with:
1061         // --v2-signing-enabled false --v3-signing-enabled true
1062         // --v4-signing-enabled --verity-enabled
1063         // Full commands in generate-apks.sh
1064         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withDSA-Verity.apk");
1065         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withEC-Verity.apk");
1066         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withRSA-Verity.apk");
1067     }
1068 
testInstallV4WithV2SignerDoesNotVerify()1069     public void testInstallV4WithV2SignerDoesNotVerify() throws Exception {
1070         // V4 is only enabled on devices with Incremental feature
1071         if (!hasIncrementalFeature()) {
1072             return;
1073         }
1074 
1075         // APKs generated with:
1076         // apksigner sign -v2-signing-enabled true --v3-signing-enabled false --v4-signing-enabled
1077 
1078         // Malformed v4 signature - first byte of v4 signing_info.signature is flipped
1079         assertInstallV4FailsWithError("v4-digest-v2-badv4signature.apk", "did not verify");
1080         // Malformed digest - first byte of v4 signing_info.apk_digest is flipped
1081         assertInstallV4FailsWithError("v4-digest-v2-badv2digest.apk", "did not verify");
1082     }
1083 
testInstallV4WithV3SignerDoesNotVerify()1084     public void testInstallV4WithV3SignerDoesNotVerify() throws Exception {
1085         // V4 is only enabled on devices with Incremental feature
1086         if (!hasIncrementalFeature()) {
1087             return;
1088         }
1089 
1090         // APKs generated with:
1091         // apksigner sign -v2-signing-enabled false --v3-signing-enabled true --v4-signing-enabled
1092 
1093         // Malformed v4 signature - first byte of v4 signing_info.signature is flipped
1094         assertInstallV4FailsWithError("v4-digest-v3-badv4signature.apk", "did not verify");
1095 
1096         // Malformed digest - first byte of v4 signing_info.apk_digest is flipped
1097         assertInstallV4FailsWithError("v4-digest-v3-badv3digest.apk", "did not verify");
1098 
1099     }
1100 
testInstallV4WithV2V3SignerDoesNotVerify()1101     public void testInstallV4WithV2V3SignerDoesNotVerify() throws Exception {
1102         // V4 is only enabled on devices with Incremental feature
1103         if (!hasIncrementalFeature()) {
1104             return;
1105         }
1106 
1107         // APKs generated with:
1108         // apksigner sign -v2-signing-enabled true --v3-signing-enabled true --v4-signing-enabled
1109 
1110         // Malformed v4 signature - first byte of v4 signing_info.signature is flipped
1111         assertInstallV4FailsWithError("v4-digest-v2v3-badv4signature.apk", "did not verify");
1112 
1113         // Malformed digest - first byte of v4 signing_info.apk_digest is flipped
1114         assertInstallV4FailsWithError("v4-digest-v2v3-badv2v3digest.apk", "did not verify");
1115     }
1116 
testInstallV4With128BytesAdditionalDataSucceeds()1117     public void testInstallV4With128BytesAdditionalDataSucceeds() throws Exception {
1118         // V4 is only enabled on devices with Incremental feature
1119         if (!hasIncrementalFeature()) {
1120             return;
1121         }
1122 
1123         // Editing apksigner to fill additional data of size 128 bytes.
1124         assertInstallV4Succeeds("v4-digest-v3-128bytes-additional-data.apk");
1125     }
1126 
testInstallV4With256BytesAdditionalDataFails()1127     public void testInstallV4With256BytesAdditionalDataFails() throws Exception {
1128         // V4 is only enabled on devices with Incremental feature
1129         if (!hasIncrementalFeature()) {
1130             return;
1131         }
1132 
1133         // Editing apksigner to fill additional data of size 256 bytes.
1134         assertInstallV4FailsWithError("v4-digest-v3-256bytes-additional-data.apk",
1135                 "additionalData has to be at most 128 bytes");
1136     }
1137 
testInstallV4With10MBytesAdditionalDataFails()1138     public void testInstallV4With10MBytesAdditionalDataFails() throws Exception {
1139         // V4 is only enabled on devices with Incremental feature
1140         if (!hasIncrementalFeature()) {
1141             return;
1142         }
1143 
1144         // Editing apksigner to fill additional data of size 10 * 1024 * 1024 bytes.
1145         assertInstallV4FailsWithError("v4-digest-v3-10mbytes-additional-data.apk",
1146                 "Failure");
1147     }
1148 
testInstallV4WithWrongBlockSize()1149     public void testInstallV4WithWrongBlockSize() throws Exception {
1150         // V4 is only enabled on devices with Incremental feature
1151         if (!hasIncrementalFeature()) {
1152             return;
1153         }
1154 
1155         // Editing apksigner with the wrong block size in the v4 signature.
1156         assertInstallV4FailsWithError("v4-digest-v3-wrong-block-size.apk",
1157                 "did not verify");
1158     }
1159 
testInstallV4WithDifferentBlockSize()1160     public void testInstallV4WithDifferentBlockSize() throws Exception {
1161         // V4 is only enabled on devices with Incremental feature
1162         if (!hasIncrementalFeature()) {
1163             return;
1164         }
1165 
1166         // Editing apksigner with the different block size (2048 instead of 4096).
1167         assertInstallV4FailsWithError("v4-digest-v3-merkle-tree-different-block-size.apk",
1168                 "Unsupported log2BlockSize: 11");
1169     }
1170 
testInstallV4WithWrongRawRootHash()1171     public void testInstallV4WithWrongRawRootHash() throws Exception {
1172         // V4 is only enabled on devices with Incremental feature
1173         if (!hasIncrementalFeature()) {
1174             return;
1175         }
1176 
1177         // Editing apksigner with the wrong raw root hash in the v4 signature.
1178         assertInstallV4FailsWithError("v4-digest-v3-wrong-raw-root-hash.apk", "Failure");
1179     }
1180 
testInstallV4WithWrongSignatureBytes()1181     public void testInstallV4WithWrongSignatureBytes() throws Exception {
1182         // V4 is only enabled on devices with Incremental feature
1183         if (!hasIncrementalFeature()) {
1184             return;
1185         }
1186 
1187         // Editing apksigner with the wrong signature bytes in the v4 signature.
1188         assertInstallV4FailsWithError("v4-digest-v3-wrong-sig-bytes.apk",
1189                 "did not verify");
1190     }
1191 
testInstallV4WithWrongSignatureBytesSize()1192     public void testInstallV4WithWrongSignatureBytesSize() throws Exception {
1193         // V4 is only enabled on devices with Incremental feature
1194         if (!hasIncrementalFeature()) {
1195             return;
1196         }
1197 
1198         // Editing apksigner with the wrong signature byte size in the v4 signature.
1199         assertInstallV4FailsWithError("v4-digest-v3-wrong-sig-bytes-size.apk",
1200                 "Failure");
1201     }
1202 
testInstallV4WithNoMerkleTree()1203     public void testInstallV4WithNoMerkleTree() throws Exception {
1204         // V4 is only enabled on devices with Incremental feature
1205         if (!hasIncrementalFeature()) {
1206             return;
1207         }
1208 
1209         // Editing apksigner to not include the Merkle tree.
1210         assertInstallV4FailsWithError("v4-digest-v3-no-merkle-tree.apk",
1211                 "Failure");
1212     }
1213 
testInstallV4WithWithTrailingDataInMerkleTree()1214     public void testInstallV4WithWithTrailingDataInMerkleTree() throws Exception {
1215         // V4 is only enabled on devices with Incremental feature
1216         if (!hasIncrementalFeature()) {
1217             return;
1218         }
1219 
1220         // Editing apksigner to add trailing data after the Merkle tree
1221         assertInstallV4FailsWithError("v4-digest-v3-merkle-tree-1mb-trailing-data.apk",
1222                 "Failure");
1223     }
1224 
testInstallV4WithMerkleTreeBitsFlipped()1225     public void testInstallV4WithMerkleTreeBitsFlipped() throws Exception {
1226         // V4 is only enabled on devices with Incremental feature
1227         if (!hasIncrementalFeature()) {
1228             return;
1229         }
1230 
1231         // Editing apksigner to flip few bits in the only node of the Merkle tree of a small app.
1232         assertInstallV4FailsWithError("v4-digest-v3-merkle-tree-bit-flipped.apk",
1233                 "Failed to parse");
1234     }
1235 
testV4IncToV3NonIncSameKeyUpgradeSucceeds()1236     public void testV4IncToV3NonIncSameKeyUpgradeSucceeds() throws Exception {
1237         // V4 is only enabled on devices with Incremental feature
1238         if (!hasIncrementalFeature()) {
1239             return;
1240         }
1241 
1242         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1243         // to generate the apks
1244         assertInstallV4Succeeds("v4-inc-to-v3-noninc-ec-p256-appv1.apk");
1245 
1246         // non-incremental upgrade with the same key.
1247         assertInstallSucceeds("v4-inc-to-v3-noninc-ec-p256-appv2.apk");
1248     }
1249 
testV4IncToV3NonIncMismatchingKeyUpgradeFails()1250     public void testV4IncToV3NonIncMismatchingKeyUpgradeFails() throws Exception {
1251         // V4 is only enabled on devices with Incremental feature
1252         if (!hasIncrementalFeature()) {
1253             return;
1254         }
1255 
1256         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1257         // to generate the apks
1258         assertInstallV4Succeeds("v4-inc-to-v3-noninc-ec-p256-appv1.apk");
1259 
1260         // non-incremental upgrade with a mismatching key.
1261         assertInstallFailsWithError("v4-inc-to-v3-noninc-ec-p384-appv2.apk",
1262                 "signatures do not match previously installed version");
1263     }
1264 
testV4IncToV3NonIncRotatedKeyUpgradeSucceeds()1265     public void testV4IncToV3NonIncRotatedKeyUpgradeSucceeds() throws Exception {
1266         // V4 is only enabled on devices with Incremental feature
1267         if (!hasIncrementalFeature()) {
1268             return;
1269         }
1270 
1271         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1272         // to generate the apks
1273         assertInstallV4Succeeds("v4-inc-to-v3-noninc-ec-p256-appv1.apk");
1274 
1275         // non-incremental upgrade with key rotation.
1276         assertInstallSucceeds("v4-inc-to-v3-noninc-ec-p384-rotated-ec-p256-appv2.apk");
1277     }
1278 
testV4IncToV3NonIncMismatchedRotatedKeyUpgradeFails()1279     public void testV4IncToV3NonIncMismatchedRotatedKeyUpgradeFails() throws Exception {
1280         // V4 is only enabled on devices with Incremental feature
1281         if (!hasIncrementalFeature()) {
1282             return;
1283         }
1284 
1285         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1286         // to generate the apks
1287         assertInstallV4Succeeds("v4-inc-to-v3-noninc-dsa-3072-appv1.apk");
1288 
1289         // non-incremental upgrade with key rotation mismatch with key used in app v1.
1290         assertInstallFailsWithError("v4-inc-to-v3-noninc-ec-p384-rotated-ec-p256-appv2.apk",
1291                 "signatures do not match previously installed version");
1292     }
1293 
testV4IncToV2NonIncSameKeyUpgradeSucceeds()1294     public void testV4IncToV2NonIncSameKeyUpgradeSucceeds() throws Exception {
1295         // V4 is only enabled on devices with Incremental feature
1296         if (!hasIncrementalFeature()) {
1297             return;
1298         }
1299 
1300         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1301         // to generate the apks
1302         assertInstallV4Succeeds("v4-inc-to-v2-noninc-ec-p256-appv1.apk");
1303 
1304         // non-incremental upgrade with the same key.
1305         assertInstallSucceeds("v4-inc-to-v2-noninc-ec-p256-appv2.apk");
1306     }
1307 
testV4IncToV2NonIncMismatchingKeyUpgradeFails()1308     public void testV4IncToV2NonIncMismatchingKeyUpgradeFails() throws Exception {
1309         // V4 is only enabled on devices with Incremental feature
1310         if (!hasIncrementalFeature()) {
1311             return;
1312         }
1313 
1314         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1315         // to generate the apks
1316         assertInstallV4Succeeds("v4-inc-to-v2-noninc-ec-p256-appv1.apk");
1317 
1318         // non-incremental upgrade with a mismatching key.
1319         assertInstallFailsWithError("v4-inc-to-v2-noninc-ec-p384-appv2.apk",
1320                 "signatures do not match previously installed version");
1321     }
1322 
testInstallV4UpdateAfterRotation()1323     public void testInstallV4UpdateAfterRotation() throws Exception {
1324         // This test performs an end to end verification of the update of an app with a rotated
1325         // key. The app under test exports a bound service that performs its own PackageManager key
1326         // rotation API verification, and the instrumentation test binds to the service and invokes
1327         // the verifySignatures method to verify that the key rotation APIs return the expected
1328         // results. The instrumentation test app is signed with the same key and lineage as the
1329         // app under test to also provide a second app that can be used for the checkSignatures
1330         // verification.
1331 
1332         // Install the initial versions of the apps; the test method verifies the app under test is
1333         // signed with the original signing key.
1334         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService.apk");
1335         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
1336         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
1337                 "verifySignatures_noRotation_succeeds");
1338 
1339         // Install the second version of the app signed with the rotated key. This test verifies the
1340         // app still functions as expected after the update with the rotated key. The
1341         // instrumentation test app is not updated here to allow verification of the pre-key
1342         // rotation behavior for the checkSignatures APIs. These APIs should behave similar to the
1343         // GET_SIGNATURES flag in that if one or both apps have a signing lineage if the oldest
1344         // signers in the lineage match then the methods should return that the signatures match
1345         // even if one is signed with a newer key in the lineage.
1346         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService_v2.apk");
1347         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
1348                 "verifySignatures_withRotation_succeeds");
1349 
1350         // Installs the third version of the app under test and the instrumentation test, both
1351         // signed with the same rotated key and lineage. This test is intended to verify that the
1352         // app can still be updated and function as expected after an update with a rotated key.
1353         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService_v3.apk");
1354         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest_v2.apk");
1355         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
1356                 "verifySignatures_withRotation_succeeds");
1357     }
1358 
hasIncrementalFeature()1359     private boolean hasIncrementalFeature() throws Exception {
1360         return "true\n".equals(getDevice().executeShellCommand(
1361                 "pm has-feature android.software.incremental_delivery"));
1362     }
1363 
assertInstallSucceeds(String apkFilenameInResources)1364     private void assertInstallSucceeds(String apkFilenameInResources) throws Exception {
1365         String installResult = installPackageFromResource(apkFilenameInResources);
1366         if (installResult != null) {
1367             fail("Failed to install " + apkFilenameInResources + ": " + installResult);
1368         }
1369     }
1370 
assertInstallEphemeralSucceeds(String apkFilenameInResources)1371     private void assertInstallEphemeralSucceeds(String apkFilenameInResources) throws Exception {
1372         String installResult = installEphemeralPackageFromResource(apkFilenameInResources);
1373         if (installResult != null) {
1374             fail("Failed to install " + apkFilenameInResources + ": " + installResult);
1375         }
1376     }
1377 
assertInstallSucceedsForEach( String apkFilenamePatternInResources, String[] args)1378     private void assertInstallSucceedsForEach(
1379             String apkFilenamePatternInResources, String[] args) throws Exception {
1380         for (String arg : args) {
1381             String apkFilenameInResources =
1382                     String.format(Locale.US, apkFilenamePatternInResources, arg);
1383             String installResult = installPackageFromResource(apkFilenameInResources);
1384             if (installResult != null) {
1385                 fail("Failed to install " + apkFilenameInResources + ": " + installResult);
1386             }
1387             try {
1388                 uninstallPackage();
1389             } catch (Exception e) {
1390                 throw new RuntimeException(
1391                         "Failed to uninstall after installing " + apkFilenameInResources, e);
1392             }
1393         }
1394     }
1395 
assertInstallV4Succeeds(String apkFilenameInResources)1396     private void assertInstallV4Succeeds(String apkFilenameInResources) throws Exception {
1397         String installResult = installV4PackageFromResource(apkFilenameInResources);
1398         if (!installResult.equals("Success\n")) {
1399             fail("Failed to install " + apkFilenameInResources + ": " + installResult);
1400         }
1401     }
1402 
assertInstallV4FromBuildSucceeds(String apkName)1403     private void assertInstallV4FromBuildSucceeds(String apkName) throws Exception {
1404         String installResult = installV4PackageFromBuild(apkName);
1405         if (!installResult.equals("Success\n")) {
1406             fail("Failed to install " + apkName + ": " + installResult);
1407         }
1408     }
1409 
assertInstallV4SucceedsAndUninstall(String apkFilenameInResources)1410     private void assertInstallV4SucceedsAndUninstall(String apkFilenameInResources)
1411             throws Exception {
1412         assertInstallV4Succeeds(apkFilenameInResources);
1413         try {
1414             uninstallPackage();
1415         } catch (Exception e) {
1416             throw new RuntimeException(
1417                     "Failed to uninstall after installing " + apkFilenameInResources, e);
1418         }
1419     }
1420 
assertInstallV4FailsWithError(String apkFilenameInResources, String errorSubstring)1421     private void assertInstallV4FailsWithError(String apkFilenameInResources, String errorSubstring)
1422             throws Exception {
1423         String installResult = installV4PackageFromResource(apkFilenameInResources);
1424         if (installResult.equals("Success\n")) {
1425             fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail"
1426                     + " with \"" + errorSubstring + "\"");
1427         }
1428         assertContains(
1429                 "Install failure message of " + apkFilenameInResources,
1430                 errorSubstring,
1431                 installResult);
1432     }
1433 
assertInstallFailsWithError( String apkFilenameInResources, String errorSubstring)1434     private void assertInstallFailsWithError(
1435             String apkFilenameInResources, String errorSubstring) throws Exception {
1436         String installResult = installPackageFromResource(apkFilenameInResources);
1437         if (installResult == null) {
1438             fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail"
1439                     + " with \"" + errorSubstring + "\"");
1440         }
1441         assertContains(
1442                 "Install failure message of " + apkFilenameInResources,
1443                 errorSubstring,
1444                 installResult);
1445     }
1446 
assertInstallEphemeralFailsWithError( String apkFilenameInResources, String errorSubstring)1447     private void assertInstallEphemeralFailsWithError(
1448             String apkFilenameInResources, String errorSubstring) throws Exception {
1449         String installResult = installEphemeralPackageFromResource(apkFilenameInResources);
1450         if (installResult == null) {
1451             fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail"
1452                     + " with \"" + errorSubstring + "\"");
1453         }
1454         assertContains(
1455                 "Install failure message of " + apkFilenameInResources,
1456                 errorSubstring,
1457                 installResult);
1458     }
1459 
assertInstallFails(String apkFilenameInResources)1460     private void assertInstallFails(String apkFilenameInResources) throws Exception {
1461         String installResult = installPackageFromResource(apkFilenameInResources);
1462         if (installResult == null) {
1463             fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail");
1464         }
1465     }
1466 
assertContains(String message, String expectedSubstring, String actual)1467     private static void assertContains(String message, String expectedSubstring, String actual) {
1468         String errorPrefix = ((message != null) && (message.length() > 0)) ? (message + ": ") : "";
1469         if (actual == null) {
1470             fail(errorPrefix + "Expected to contain \"" + expectedSubstring + "\", but was null");
1471         }
1472         if (!actual.contains(expectedSubstring)) {
1473             fail(errorPrefix + "Expected to contain \"" + expectedSubstring + "\", but was \""
1474                     + actual + "\"");
1475         }
1476     }
1477 
installDeviceTestPkg()1478     private void installDeviceTestPkg() throws Exception {
1479         assertInstallFromBuildSucceeds(DEVICE_TESTS_APK);
1480     }
1481 
assertInstallFromBuildSucceeds(String apkName)1482     private void assertInstallFromBuildSucceeds(String apkName) throws Exception {
1483         String result = installApkFromBuild(apkName);
1484         assertNull("failed to install " + apkName + ", Reason: " + result, result);
1485     }
1486 
assertInstallFromBuildFails(String apkName)1487     private void assertInstallFromBuildFails(String apkName) throws Exception {
1488         String result = installApkFromBuild(apkName);
1489         assertNotNull("Successfully installed " + apkName + " when failure was expected", result);
1490     }
1491 
installApkFromBuild(String apkName)1492     private String installApkFromBuild(String apkName) throws Exception {
1493         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
1494         File apk = buildHelper.getTestFile(apkName);
1495         return getDevice().installPackage(apk, true, INSTALL_ARG_FORCE_QUERYABLE);
1496     }
1497 
installPackageFromResource(String apkFilenameInResources, boolean ephemeral)1498     private String installPackageFromResource(String apkFilenameInResources, boolean ephemeral)
1499             throws IOException, DeviceNotAvailableException {
1500         // ITestDevice.installPackage API requires the APK to be install to be a File. We thus
1501         // copy the requested resource into a temporary file, attempt to install it, and delete the
1502         // file during cleanup.
1503         File apkFile = null;
1504         try {
1505             apkFile = getFileFromResource(apkFilenameInResources);
1506             if (ephemeral) {
1507                 return getDevice().installPackage(apkFile, true, "--ephemeral",
1508                         INSTALL_ARG_FORCE_QUERYABLE);
1509             } else {
1510                 return getDevice().installPackage(apkFile, true, INSTALL_ARG_FORCE_QUERYABLE);
1511             }
1512         } finally {
1513             cleanUpFile(apkFile);
1514         }
1515     }
1516 
installV4PackageFromResource(String apkFilenameInResources)1517     private String installV4PackageFromResource(String apkFilenameInResources)
1518             throws IOException, DeviceNotAvailableException {
1519         File apkFile = null;
1520         File v4SignatureFile = null;
1521         try {
1522             apkFile = getFileFromResource(apkFilenameInResources);
1523             v4SignatureFile = getFileFromResource(apkFilenameInResources + ".idsig");
1524             String remoteApkFilePath = pushFileToRemote(apkFile);
1525             pushFileToRemote(v4SignatureFile);
1526             return installV4Package(remoteApkFilePath);
1527         } finally {
1528             cleanUpFile(apkFile);
1529             cleanUpFile(v4SignatureFile);
1530         }
1531     }
1532 
installV4PackageFromBuild(String apkName)1533     private String installV4PackageFromBuild(String apkName)
1534             throws IOException, DeviceNotAvailableException {
1535         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
1536         File apkFile = buildHelper.getTestFile(apkName);
1537         File v4SignatureFile = buildHelper.getTestFile(apkName + ".idsig");
1538         String remoteApkFilePath = pushFileToRemote(apkFile);
1539         pushFileToRemote(v4SignatureFile);
1540         return installV4Package(remoteApkFilePath);
1541     }
1542 
pushFileToRemote(File localFile)1543     private String pushFileToRemote(File localFile) throws DeviceNotAvailableException {
1544         String remotePath = "/data/local/tmp/pkginstalltest-" + localFile.getName();
1545         getDevice().pushFile(localFile, remotePath);
1546         return remotePath;
1547     }
1548 
installV4Package(String remoteApkPath)1549     private String installV4Package(String remoteApkPath)
1550             throws DeviceNotAvailableException {
1551         String command = "pm install-incremental --force-queryable -t -g " + remoteApkPath;
1552         return getDevice().executeShellCommand(command);
1553     }
1554 
getFileFromResource(String filenameInResources)1555     private File getFileFromResource(String filenameInResources)
1556             throws IOException, IllegalArgumentException {
1557         String fullResourceName = TEST_APK_RESOURCE_PREFIX + filenameInResources;
1558         File tempDir = FileUtil.createTempDir("pkginstalltest");
1559         File file = new File(tempDir, filenameInResources);
1560         InputStream in = getClass().getResourceAsStream(fullResourceName);
1561         if (in == null) {
1562             throw new IllegalArgumentException("Resource not found: " + fullResourceName);
1563         }
1564         OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
1565         byte[] buf = new byte[65536];
1566         int chunkSize;
1567         while ((chunkSize = in.read(buf)) != -1) {
1568             out.write(buf, 0, chunkSize);
1569         }
1570         out.close();
1571         return file;
1572     }
1573 
cleanUpFile(File file)1574     private void cleanUpFile(File file) {
1575         if (file != null && file.exists()) {
1576             file.delete();
1577         }
1578     }
1579 
installPackageFromResource(String apkFilenameInResources)1580     private String installPackageFromResource(String apkFilenameInResources)
1581             throws IOException, DeviceNotAvailableException {
1582         return installPackageFromResource(apkFilenameInResources, false);
1583     }
1584 
installEphemeralPackageFromResource(String apkFilenameInResources)1585     private String installEphemeralPackageFromResource(String apkFilenameInResources)
1586             throws IOException, DeviceNotAvailableException {
1587         return installPackageFromResource(apkFilenameInResources, true);
1588     }
1589 
uninstallPackage()1590     private String uninstallPackage() throws DeviceNotAvailableException {
1591         return getDevice().uninstallPackage(TEST_PKG);
1592     }
1593 
uninstallCompanionPackages()1594     private String uninstallCompanionPackages() throws DeviceNotAvailableException {
1595         String result1 = getDevice().uninstallPackage(COMPANION_TEST_PKG);
1596         String result2 = getDevice().uninstallPackage(COMPANION2_TEST_PKG);
1597         return result1 != null ? result1 : result2;
1598     }
1599 
uninstallDeviceTestPackage()1600     private String uninstallDeviceTestPackage() throws DeviceNotAvailableException {
1601         return getDevice().uninstallPackage(DEVICE_TESTS_PKG);
1602     }
1603 
uninstallServicePackages()1604     private void uninstallServicePackages() throws DeviceNotAvailableException {
1605         getDevice().uninstallPackage(SERVICE_PKG);
1606         getDevice().uninstallPackage(SERVICE_TEST_PKG);
1607     }
1608 
uninstallPackages()1609     private void uninstallPackages() throws DeviceNotAvailableException {
1610         uninstallPackage();
1611         uninstallCompanionPackages();
1612         uninstallDeviceTestPackage();
1613         uninstallServicePackages();
1614     }
1615 }
1616