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