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