• 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(
629                 "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
630         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.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 the
639         // installation of this updated app 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         assertInstallFromBuildFails("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
645     }
646 
testInstallV3FirstAppOnlySignedByNewKeyLastAppOldKey()647     public void testInstallV3FirstAppOnlySignedByNewKeyLastAppOldKey() throws Exception {
648         // This test verifies the following scenario:
649         // - First installed app in sharedUid only signed with new key without lineage.
650         // - Second installed app in sharedUid signed with new key and includes lineage granting
651         //   access to the old key to join the sharedUid.
652         // - Last installed app in sharedUid signed with old key.
653         // The lineage should be updated when the second app is installed to allow the installation
654         // of the app signed with the old key.
655         assertInstallFromBuildSucceeds("v3-ec-p256-2-sharedUid-companion.apk");
656         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps-sharedUid.apk");
657         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid-companion2.apk");
658     }
659 
testInstallV3AppSignedWithOldKeyUpdatedLineageDeniesShUidCap()660     public void testInstallV3AppSignedWithOldKeyUpdatedLineageDeniesShUidCap() throws Exception {
661         // If an app is installed as part of a sharedUid, and then that app is signed with a new key
662         // that rejects the previous key in the lineage the update should be allowed to proceed
663         // as the app is being updated to the newly rotated key.
664         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid.apk");
665         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
666     }
667 
testInstallV3TwoSharedUidAppsWithDivergedLineages()668     public void testInstallV3TwoSharedUidAppsWithDivergedLineages() throws Exception {
669         // Apps that are installed as part of the sharedUserId with a lineage must have common
670         // ancestors; the platform will allow the installation if the lineage of an app being
671         // installed as part of the sharedUserId is the same, a subset, or a superset of the
672         // existing lineage, but if the lineage diverges then the installation should be blocked.
673         assertInstallFromBuildSucceeds("v3-por_Y_1_2-default-caps-sharedUid.apk");
674         assertInstallFromBuildFails("v3-por_Z_1_2-default-caps-sharedUid-companion.apk");
675     }
676 
testInstallV3WithRestoredCapabilityInSharedUserId()677     public void testInstallV3WithRestoredCapabilityInSharedUserId() throws Exception {
678         // A sharedUserId contains the shared signing lineage for all packages in the UID; this
679         // shared lineage contain the full signing history for all packages along with the merged
680         // capabilities for each signer shared between the packages. This test verifies if one
681         // package revokes a capability from a previous signer, but subsequently restores that
682         // capability, then since all packages have granted the capability, it is restored to the
683         // previous signer in the shared lineage.
684 
685         // Install a package with the SHARED_USER_ID capability revoked for the original signer
686         // in the lineage; verify that a package signed with only the original signer cannot join
687         // the sharedUserId.
688         assertInstallFromBuildSucceeds(
689                 "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
690         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
691         assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
692 
693         // Update the package that revoked the SHARED_USER_ID with an updated lineage that restores
694         // this capability to the original signer; verify the package signed with the original
695         // signing key can now join the sharedUserId since all existing packages in the UID grant
696         // this capability to the original signer.
697         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps-sharedUid.apk");
698         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid-companion2.apk");
699     }
700 
testInstallV3WithRevokedCapabilityInSharedUserId()701     public void testInstallV3WithRevokedCapabilityInSharedUserId() throws Exception {
702         // While a capability can be restored to a common signer in the shared signing lineage, if
703         // one package has revoked a capability from a common signer and another package is
704         // installed / updated which restores the capability to that signer, the revocation of
705         // the capability by the existing package should take precedence. A capability can only
706         // be restored to a common signer if all packages in the sharedUserId have granted this
707         // capability to the signer.
708 
709         // Install a package with the SHARED_USER_ID capability revoked from the original signer,
710         // then install another package in the sharedUserId that grants this capability to the
711         // original signer. Since a package exists in the sharedUserId that has revoked this
712         // capability, another package signed with this capability shouldn't be able to join the
713         // sharedUserId.
714         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid.apk");
715         assertInstallFromBuildSucceeds(
716                 "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
717         assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
718 
719         // Install the same package that grants the SHARED_USER_ID capability to the original
720         // signer; when iterating over the existing packages in the packages in the sharedUserId,
721         // the original version of this package should be skipped since the lineage from the
722         // updated package is used when merging with the shared lineage.
723         assertInstallFromBuildSucceeds(
724                 "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion.apk");
725         assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
726 
727         // Install another package that has granted the SHARED_USER_ID to the original signer; this
728         // should trigger another merge with all packages in the sharedUserId. Since one still
729         // remains that revokes the capability, the capability should be revoked in the shared
730         // lineage.
731         assertInstallFromBuildSucceeds(
732                 "v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion3.apk");
733         assertInstallFromBuildFails("v3-ec-p256-1-sharedUid-companion2.apk");
734     }
735 
testInstallV3UpdateAfterRotation()736     public void testInstallV3UpdateAfterRotation() throws Exception {
737         // This test performs an end to end verification of the update of an app with a rotated
738         // key. The app under test exports a bound service that performs its own PackageManager key
739         // rotation API verification, and the instrumentation test binds to the service and invokes
740         // the verifySignatures method to verify that the key rotation APIs return the expected
741         // results. The instrumentation test app is signed with the same key and lineage as the
742         // app under test to also provide a second app that can be used for the checkSignatures
743         // verification.
744 
745         // Install the initial versions of the apps; the test method verifies the app under test is
746         // signed with the original signing key.
747         assertInstallFromBuildSucceeds("CtsSignatureQueryService.apk");
748         assertInstallFromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
749         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
750                 "verifySignatures_noRotation_succeeds");
751 
752         // Install the second version of the app signed with the rotated key. This test verifies the
753         // app still functions as expected after the update with the rotated key. The
754         // instrumentation test app is not updated here to allow verification of the pre-key
755         // rotation behavior for the checkSignatures APIs. These APIs should behave similar to the
756         // GET_SIGNATURES flag in that if one or both apps have a signing lineage if the oldest
757         // signers in the lineage match then the methods should return that the signatures match
758         // even if one is signed with a newer key in the lineage.
759         assertInstallFromBuildSucceeds("CtsSignatureQueryService_v2.apk");
760         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
761                 "verifySignatures_withRotation_succeeds");
762 
763         // Installs the third version of the app under test and the instrumentation test, both
764         // signed with the same rotated key and lineage. This test is intended to verify that the
765         // app can still be updated and function as expected after an update with a rotated key.
766         assertInstallFromBuildSucceeds("CtsSignatureQueryService_v3.apk");
767         assertInstallFromBuildSucceeds("CtsSignatureQueryServiceTest_v2.apk");
768         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
769                 "verifySignatures_withRotation_succeeds");
770     }
771 
772     @CddTest(requirement="4/C-0-2")
testInstallV31UpdateAfterRotation()773     public void testInstallV31UpdateAfterRotation() throws Exception {
774         // This test is the same as above, but using the v3.1 signature scheme for rotation.
775         assertInstallFromBuildSucceeds("CtsSignatureQueryService.apk");
776         assertInstallFromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
777         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
778                 "verifySignatures_noRotation_succeeds");
779 
780         assertInstallFromBuildSucceeds("CtsSignatureQueryService_v2-tgt-33.apk");
781         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
782                 "verifySignatures_withRotation_succeeds");
783 
784         assertInstallFromBuildSucceeds("CtsSignatureQueryService_v3-tgt-33.apk");
785         assertInstallFromBuildSucceeds("CtsSignatureQueryServiceTest_v2-tgt-33.apk");
786         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
787                 "verifySignatures_withRotation_succeeds");
788     }
789 
790     @CddTest(requirement="4/C-0-9")
testInstallV41UpdateAfterRotation()791     public void testInstallV41UpdateAfterRotation() throws Exception {
792         // V4 is only enabled on devices with Incremental feature
793         if (!hasIncrementalFeature()) {
794             return;
795         }
796 
797         // This test is the same as above, but using the v4.1 signature scheme for rotation.
798         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService.apk");
799         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
800         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
801                 "verifySignatures_noRotation_succeeds");
802 
803         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService_v2-tgt-33.apk");
804         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
805                 "verifySignatures_withRotation_succeeds");
806 
807         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService_v3-tgt-33.apk");
808         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest_v2-tgt-33.apk");
809         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
810                 "verifySignatures_withRotation_succeeds");
811     }
812 
813     @CddTest(requirement="4/C-0-9")
testInstallV41WrongBlockId()814     public void testInstallV41WrongBlockId() throws Exception {
815         // V4 is only enabled on devices with Incremental feature
816         if (!hasIncrementalFeature()) {
817             return;
818         }
819 
820         // This test is the same as above, but using the v4.1 signature scheme for rotation.
821         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService.apk");
822         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
823         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
824                 "verifySignatures_noRotation_succeeds");
825 
826         assertInstallV4FailsWithError("CtsSignatureQueryService_v2-tgt-33-wrongV41Block.apk",
827                 "Failed to find V4 signature block corresponding to V3 blockId: 462663009");
828     }
829 
830     @CddTest(requirement="4/C-0-9")
testInstallV41LegacyV4()831     public void testInstallV41LegacyV4() throws Exception {
832         // V4 is only enabled on devices with Incremental feature
833         if (!hasIncrementalFeature()) {
834             return;
835         }
836 
837         // This test is the same as above, but using the v4.1 signature scheme for rotation.
838         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService.apk");
839         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
840         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
841                 "verifySignatures_noRotation_succeeds");
842 
843         assertInstallV4FailsWithError("CtsSignatureQueryService_v2-tgt-33-legacyV4.apk",
844                 "Failed to find V4 signature block corresponding to V3 blockId: 462663009");
845     }
846 
847     @CddTest(requirement="4/C-0-9")
testInstallV41WrongDigest()848     public void testInstallV41WrongDigest() throws Exception {
849         // V4 is only enabled on devices with Incremental feature
850         if (!hasIncrementalFeature()) {
851             return;
852         }
853 
854         // This test is the same as above, but using the v4.1 signature scheme for rotation.
855         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService.apk");
856         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
857         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
858                 "verifySignatures_noRotation_succeeds");
859 
860         assertInstallV4FailsWithError("CtsSignatureQueryService_v2-tgt-33-wrongDigest.apk",
861                 "APK digest in V4 signature does not match V2/V3");
862     }
863 
testInstallV3KeyRotationSigPerm()864     public void testInstallV3KeyRotationSigPerm() throws Exception {
865         // tests that a v3 signed APK can still get a signature permission from an app with its
866         // older signing certificate.
867         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
868         assertInstallSucceeds(
869                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-permcli-companion.apk");
870         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
871     }
872 
testInstallV3KeyRotationOlderSigPerm()873     public void testInstallV3KeyRotationOlderSigPerm() throws Exception {
874         // tests that an apk with an older signing certificate than the one which defines a
875         // signature permission it wants gets the permission if the defining APK grants the
876         // capability
877         assertInstallSucceeds(
878                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-permdef.apk");
879         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permcli-companion.apk");
880         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
881     }
882 
testInstallV3KeyRotationSigPermNoCap()883     public void testInstallV3KeyRotationSigPermNoCap() throws Exception {
884         // tests that an APK signed by an older signing certificate is unable to get a requested
885         // signature permission when the defining APK has rotated to a newer signing certificiate
886         // and does not grant the permission capability to the older cert
887         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-perm-cap-permdef.apk");
888         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permcli-companion.apk");
889         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
890     }
891 
testInstallV3KeyRotationOlderSigPermNoCap()892     public void testInstallV3KeyRotationOlderSigPermNoCap() throws Exception {
893         // tests that an APK signed by a newer signing certificate than the APK which defines a
894         // signature permission is able to get that permission, even if the newer APK does not
895         // grant the permission capability to the older signing certificate.
896         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
897         assertInstallSucceeds(
898                 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-perm-cap-permcli-companion.apk");
899         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
900     }
901 
testInstallV3NoRotationSigPerm()902     public void testInstallV3NoRotationSigPerm() throws Exception {
903         // make sure that an APK, which wants to use a signature permission defined by an APK, which
904         // has not granted that capability to older signing certificates, can still install
905         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-perm-cap-permdef.apk");
906         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-permcli-companion.apk");
907         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
908     }
909 
testInstallV3CommonSignerInLineageWithPermCap()910     public void testInstallV3CommonSignerInLineageWithPermCap() throws Exception {
911         // If an APK requesting a signature permission has a common signer in the lineage with the
912         // APK declaring the permission, and that signer is granted the permission capability in
913         // the declaring APK, then the permission should be granted to the requesting app even
914         // if their signers have diverged.
915         assertInstallFromBuildSucceeds(
916                 "v3-ec-p256-with-por_1_2_3-1-no-caps-2-default-declperm.apk");
917         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2_4-companion-usesperm.apk");
918         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
919     }
920 
testInstallV3CommonSignerInLineageNoCaps()921     public void testInstallV3CommonSignerInLineageNoCaps() throws Exception {
922         // If an APK requesting a signature permission has a common signer in the lineage with the
923         // APK declaring the permission, but the signer in the lineage has not been granted the
924         // permission capability the permission should not be granted to the requesting app.
925         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2_3-no-caps-declperm.apk");
926         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2_4-companion-usesperm.apk");
927         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
928     }
929 
testKnownSignerPermGrantedWhenCurrentSignerInResource()930     public void testKnownSignerPermGrantedWhenCurrentSignerInResource() throws Exception {
931         // The knownSigner protection flag allows an app to declare other trusted signing
932         // certificates in an array resource; if a requesting app's current signer is in this array
933         // of trusted certificates then the permission should be granted.
934         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-ec-p256-1-3.apk");
935         assertInstallFromBuildSucceeds("v3-ec-p256_3-companion-uses-knownSigner.apk");
936         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
937 
938         // If the declaring app changes the trusted certificates on an update any requesting app
939         // that no longer meets the requirements based on its signing identity should have the
940         // permission revoked. This app update only trusts ec-p256_1 but the app that was previously
941         // granted the permission based on its signing identity is signed by ec-p256_3.
942         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-str-res-ec-p256-1.apk");
943         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
944     }
945 
testKnownSignerPermCurrentSignerNotInResource()946     public void testKnownSignerPermCurrentSignerNotInResource() throws Exception {
947         // If an app requesting a knownSigner permission does not meet the requirements for a
948         // signature permission and is not signed by any of the trusted certificates then the
949         // permission should not be granted.
950         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-ec-p256-1-3.apk");
951         assertInstallFromBuildSucceeds("v3-ec-p256_2-companion-uses-knownSigner.apk");
952         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
953     }
954 
testKnownSignerPermGrantedWhenSignerInLineageInResource()955     public void testKnownSignerPermGrantedWhenSignerInLineageInResource() throws Exception {
956         // If an app requesting a knownSigner permission was previously signed by a certificate
957         // that is trusted by the declaring app then the permission should be granted.
958         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-ec-p256-1-3.apk");
959         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-companion-uses-knownSigner.apk");
960         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
961 
962         // If the declaring app changes the permission to no longer use the knownSigner flag then
963         // any app granted the permission based on a signing identity from the set of trusted
964         // certificates should have the permission revoked.
965         assertInstallFromBuildSucceeds("v3-rsa-2048-declperm.apk");
966         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm");
967     }
968 
testKnownSignerPermSignerInLineageMatchesStringResource()969     public void testKnownSignerPermSignerInLineageMatchesStringResource() throws Exception {
970         // The knownSigner protection flag allows an app to declare a single known trusted
971         // certificate digest using a string resource instead of a string-array resource. This test
972         // verifies the knownSigner permission is granted to a requesting app if the single trusted
973         // cert is in the requesting app's lineage.
974         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-str-res-ec-p256-1.apk");
975         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-companion-uses-knownSigner.apk");
976         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
977     }
978 
testKnownSignerPermSignerInLineageMatchesStringConst()979     public void testKnownSignerPermSignerInLineageMatchesStringConst() throws Exception {
980         // The knownSigner protection flag allows an app to declare a single known trusted
981         // certificate digest using a string constant as the knownCerts attribute value instead of a
982         // resource. This test verifies the knownSigner permission is granted to a requesting app if
983         // the single trusted cert is in the requesting app's lineage.
984         assertInstallFromBuildSucceeds("v3-rsa-2048-decl-knownSigner-str-const-ec-p256-1.apk");
985         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-companion-uses-knownSigner.apk");
986         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
987     }
988 
testInstallV3SigPermDoubleDefNewerSucceeds()989     public void testInstallV3SigPermDoubleDefNewerSucceeds() throws Exception {
990         // make sure that if an app defines a signature permission already defined by another app,
991         // it successfully installs if the other app's signing cert is in its past signing certs and
992         // the signature permission capability is granted
993         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
994         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-permdef-companion.apk");
995     }
996 
testInstallV3SigPermDoubleDefOlderSucceeds()997     public void testInstallV3SigPermDoubleDefOlderSucceeds() throws Exception {
998         // make sure that if an app defines a signature permission already defined by another app,
999         // it successfully installs if it is in the other app's past signing certs and the signature
1000         // permission capability is granted
1001         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-permdef-companion.apk");
1002         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
1003     }
1004 
testInstallV3SigPermDoubleDefNewerNoCapFails()1005     public void testInstallV3SigPermDoubleDefNewerNoCapFails() throws Exception {
1006         // make sure that if an app defines a signature permission already defined by another app,
1007         // it fails to install if the other app's signing cert is in its past signing certs but the
1008         // signature permission capability is not granted
1009         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
1010         assertInstallFails(
1011                 "v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-no-perm-cap-permdef-companion.apk");
1012     }
1013 
testInstallV3SigPermDoubleDefOlderNoCapFails()1014     public void testInstallV3SigPermDoubleDefOlderNoCapFails() throws Exception {
1015         // make sure that if an app defines a signature permission already defined by another app,
1016         // it fails to install if it is in the other app's past signing certs but the signature
1017         // permission capability is not granted
1018         assertInstallSucceeds(
1019                 "v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-no-perm-cap-permdef-companion.apk");
1020         assertInstallFails("v3-rsa-pkcs1-sha256-2048-1-permdef.apk");
1021     }
1022 
testInstallV3SigPermDoubleDefSameNoCapSucceeds()1023     public void testInstallV3SigPermDoubleDefSameNoCapSucceeds() throws Exception {
1024         // make sure that if an app defines a signature permission already defined by another app,
1025         // it installs successfully when signed by the same certificate, even if the original app
1026         // does not grant signature capabilities to its past certs
1027         assertInstallSucceeds(
1028                 "v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-no-perm-cap-permdef-companion.apk");
1029         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-permdef.apk");
1030     }
1031 
testInstallV3KeyRotationGetSignatures()1032     public void testInstallV3KeyRotationGetSignatures() throws Exception {
1033         // tests that a PackageInfo w/GET_SIGNATURES flag returns the older cert
1034         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
1035         Utils.runDeviceTests(
1036                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testGetSignaturesShowsOld");
1037     }
1038 
testInstallV3KeyRotationGetSigningCertificates()1039     public void testInstallV3KeyRotationGetSigningCertificates() throws Exception {
1040         // tests that a PackageInfo w/GET_SIGNING_CERTIFICATES flag returns the old and new certs
1041         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
1042         Utils.runDeviceTests(
1043                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1044                 "testGetSigningCertificatesShowsAll");
1045     }
1046 
testInstallV3KeyRotationGetApkContentsSigners()1047     public void testInstallV3KeyRotationGetApkContentsSigners() throws Exception {
1048         // The GET_SIGNING_CERTIFICATES flag results in a PackageInfo object returned with a
1049         // SigningInfo instance that can be used to query all certificates in the lineage or only
1050         // the current signer(s) via getApkContentsSigners. This test verifies when a V3 signed
1051         // package with a rotated key is queried getApkContentsSigners only returns the current
1052         // signer.
1053         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps.apk");
1054         Utils.runDeviceTests(
1055                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1056                 "testGetApkContentsSignersShowsCurrent");
1057     }
1058 
testInstallV2MultipleSignersGetApkContentsSigners()1059     public void testInstallV2MultipleSignersGetApkContentsSigners() throws Exception {
1060         // Similar to the above test, but verifies when an APK is signed with two V2 signers
1061         // getApkContentsSigners returns both of the V2 signers.
1062         assertInstallFromBuildSucceeds("v1v2-ec-p256-two-signers-targetSdk-30.apk");
1063         Utils.runDeviceTests(
1064                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1065                 "testGetApkContentsSignersShowsMultipleSigners");
1066     }
1067 
testInstallV3MultipleSignersInLineageGetSigningCertificateHistory()1068     public void testInstallV3MultipleSignersInLineageGetSigningCertificateHistory()
1069             throws Exception {
1070         // The APK used for this test is signed with a lineage containing 5 keys in the signing
1071         // history; this test verifies SigningInfo#getSigningCertificateHistory returns all of an
1072         // APKs signers in their order of rotation.
1073         assertInstallFromBuildSucceeds("v3-ec-p256-with-por-1_2_3_4_5-default-caps.apk");
1074         Utils.runDeviceTests(
1075                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1076                 "testGetSigningCertificateHistoryReturnsSignersInOrder");
1077     }
1078 
testInstallV3KeyRotationHasSigningCertificate()1079     public void testInstallV3KeyRotationHasSigningCertificate() throws Exception {
1080         // tests that hasSigningCertificate() recognizes past and current signing certs
1081         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
1082         Utils.runDeviceTests(
1083                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1084                 "testHasSigningCertificate");
1085     }
1086 
testInstallV3KeyRotationHasSigningCertificateSha256()1087     public void testInstallV3KeyRotationHasSigningCertificateSha256() throws Exception {
1088         // tests that hasSigningCertificate() recognizes past and current signing certs by sha256
1089         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
1090         Utils.runDeviceTests(
1091                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1092                 "testHasSigningCertificateSha256");
1093     }
1094 
testInstallV3KeyRotationHasSigningCertificateByUid()1095     public void testInstallV3KeyRotationHasSigningCertificateByUid() throws Exception {
1096         // tests that hasSigningCertificate() recognizes past and current signing certs by uid
1097         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
1098         Utils.runDeviceTests(
1099                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1100                 "testHasSigningCertificateByUid");
1101     }
1102 
testInstallV3KeyRotationHasSigningCertificateByUidSha256()1103     public void testInstallV3KeyRotationHasSigningCertificateByUidSha256() throws Exception {
1104         // tests that hasSigningCertificate() recognizes past and current signing certs by uid
1105         // and sha256
1106         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
1107         Utils.runDeviceTests(
1108                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1109                 "testHasSigningCertificateByUidSha256");
1110     }
1111 
testInstallV3KeyRotationHasDuplicateSigningCertificateHistory()1112     public void testInstallV3KeyRotationHasDuplicateSigningCertificateHistory() throws Exception {
1113         // tests that an app's proof-of-rotation signing history cannot contain the same certificate
1114         // more than once.
1115         assertInstallFails("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2_2-full-caps.apk");
1116     }
1117 
testInstallV3HasMultipleSigners()1118     public void testInstallV3HasMultipleSigners() throws Exception {
1119         // tests that an app can't be signed by multiple signers when using v3 signature scheme
1120         assertInstallFails("v3-rsa-pkcs1-sha256-2048-1_and_2.apk");
1121     }
1122 
testInstallV3HasMultiplePlatformSigners()1123     public void testInstallV3HasMultiplePlatformSigners() throws Exception {
1124         // tests that an app can be signed by multiple v3 signers if they target different platform
1125         // versions
1126         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1_P_and_2_Qplus.apk");
1127     }
1128 
testSharedKeyInSeparateLineageRetainsDeclaredCapabilities()1129     public void testSharedKeyInSeparateLineageRetainsDeclaredCapabilities() throws Exception {
1130         // This test verifies when a key is used in the signing lineage of multiple apps each
1131         // instance of the key retains its declared capabilities.
1132 
1133         // This app has granted the PERMISSION capability to the previous signer in the lineage
1134         // but has revoked the SHARED_USER_ID capability.
1135         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-shUid-cap-declperm2.apk");
1136         // This app has granted the SHARED_USER_ID capability to the previous signer in the lineage
1137         // but has revoked the PERMISSION capability.
1138         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-no-perm-cap-sharedUid.apk");
1139 
1140         // Reboot the device to ensure that the capabilities written to packages.xml are properly
1141         // assigned to the packages installed above; it's possible immediately after a package
1142         // install the capabilities are as declared, but then during the reboot shared signing
1143         // keys also share the initial declared capabilities.
1144         getDevice().reboot();
1145 
1146         // This app is signed with the original shared signing key in the lineage and is part of the
1147         // sharedUserId; since the other app in this sharedUserId has granted the required
1148         // capability in the lineage the install should succeed.
1149         assertInstallFromBuildSucceeds("v3-ec-p256-1-sharedUid-companion2.apk");
1150         // This app is signed with the original shared signing key in the lineage and requests the
1151         // signature permission declared by the test app above. Since that app granted the
1152         // PERMISSION capability to the previous signer in the lineage this app should have the
1153         // permission granted.
1154         assertInstallFromBuildSucceeds("v3-ec-p256-1-companion-usesperm.apk");
1155         Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm");
1156     }
1157 
1158     @CddTest(requirement="4/C-0-2")
testV31TargetTPlatformUsesRotatedKey()1159     public void testV31TargetTPlatformUsesRotatedKey() throws Exception {
1160         // The v3.1 signature block is intended to allow applications to target T+ for APK signing
1161         // key rotation without needing multi-targeting APKs. This test verifies a standard APK
1162         // install with the rotated key in the v3.1 signing block targeting T is recognized by the
1163         // platform, and this rotated key is used as the signing identity.
1164         assertInstallSucceeds("v31-ec-p256_2-tgt-33.apk");
1165         Utils.runDeviceTests(
1166                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1167                 "testUsingRotatedSigner");
1168     }
1169 
1170     @CddTest(requirement="4/C-0-2")
testV31TargetLaterThanDevicePlatformUsesOriginalKey()1171     public void testV31TargetLaterThanDevicePlatformUsesOriginalKey() throws Exception {
1172         // The v3.1 signature block allows targeting SDK versions later than T for rotation; for
1173         // this test a target of 100001 is used assuming it will be beyond the platform's version.
1174         // Since the target version for rotation is beyond the platform's version the original
1175         // signer from the v3.0 block should be used.
1176         assertInstallSucceeds("v31-ec-p256_2-tgt-100001.apk");
1177         Utils.runDeviceTests(
1178                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1179                 "testUsingOriginalSigner");
1180     }
1181 
1182     @CddTest(requirement="4/C-0-2")
testV31BlockStrippedWithV3StrippingProtectionAttrSet()1183     public void testV31BlockStrippedWithV3StrippingProtectionAttrSet() throws Exception {
1184         // With the introduction of the v3.1 signature scheme, a new stripping protection attribute
1185         // has been added to the v3.0 signer to protect against stripping and modification of the
1186         // v3.1 signing block. This test verifies a stripped v3.1 block is detected when the v3.0
1187         // stripping protection attribute is set.
1188         assertInstallFails("v31-block-stripped-v3-attr-value-33.apk");
1189     }
1190 
1191     @CddTest(requirement="4/C-0-2")
testV31BlockWithMultipleSignersUsesCorrectSigner()1192     public void testV31BlockWithMultipleSignersUsesCorrectSigner() throws Exception {
1193         // All of the APKs for this test use multiple v3.1 signers; those targeting SDK versions
1194         // expected to be outside the version of a device under test use the original signer, and
1195         // those targeting an expected range for a device use the rotated key. This test is
1196         // intended to ensure the signer with the min / max SDK version that matches the device
1197         // SDK version is used.
1198 
1199         // The APK used for this test contains two signers in the v3.1 signing block. The first
1200         // has a range from 100001 to Integer.MAX_VALUE and is using the original signing key;
1201         // the second targets 33 to 100000 using the rotated key.
1202         assertInstallSucceeds("v31-ec-p256_2-tgt-33-ec-p256-tgt-100001.apk");
1203         Utils.runDeviceTests(
1204                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1205                 "testUsingRotatedSigner");
1206         uninstallPackage();
1207 
1208         // The APK for this test contains two signers in the v3.1 block, one targeting SDK versions
1209         // 1 to 27 using the original signer, and the other targeting 33+ using the rotated signer.
1210         assertInstallSucceeds("v31-ec-p256_2-tgt-33-ec-p256-tgt-1-27.apk");
1211         Utils.runDeviceTests(
1212                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1213                 "testUsingRotatedSigner");
1214         uninstallPackage();
1215 
1216         // This APK combines the extra signers from the APKs above, one targeting 1 to 27 with the
1217         // original signing key, another targeting 100001+ with the original signing key, and the
1218         // last targeting 33 to 100000 with the rotated key.
1219         assertInstallSucceeds("v31-ec-p256_2-tgt-33-ec-p256-tgt-1-27-and-100001.apk");
1220         Utils.runDeviceTests(
1221                 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS,
1222                 "testUsingRotatedSigner");
1223     }
1224 
1225     @CddTest(requirement="4/C-0-2")
testV31UpdateV3ToFromV31Succeeds()1226     public void testV31UpdateV3ToFromV31Succeeds() throws Exception {
1227         // Since the v3.1 block is just intended to allow targeting SDK versions T and later for
1228         // rotation, an APK signed with the rotated key in a v3.0 signing block should support
1229         // updates to an APK signed with the same signing key in a v3.1 signing block.
1230         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps.apk");
1231         assertInstallSucceeds("v31-ec-p256_2-tgt-33.apk");
1232         uninstallPackage();
1233 
1234         // Similarly an APK signed with the rotated key in a v3.1 signing block should support
1235         // updates to an APK signed with the same signing key in a v3.0 signing block.
1236         assertInstallSucceeds("v31-ec-p256_2-tgt-33.apk");
1237         assertInstallFromBuildSucceeds("v3-ec-p256-with-por_1_2-default-caps.apk");
1238         uninstallPackage();
1239     }
1240 
1241     @CddTest(requirement="4/C-0-2")
testV31RotationTargetModifiedReportedByV3()1242     public void testV31RotationTargetModifiedReportedByV3() throws Exception {
1243         // When determining if a signer in the v3.1 signing block should be applied, the min / max
1244         // SDK versions from the signer are compared against the device's SDK version; if the device
1245         // is not within the signer's range then the block is skipped, other v3.1 blocks are
1246         // checked, and finally the v3.0 block is used. The v3.0 signer block contains an additional
1247         // attribute with the rotation-min-sdk-version that was expected in the v3.1 signing
1248         // block; if this attribute's value does not match what was found in the v3.1 block the
1249         // APK should fail to install.
1250         assertInstallFails("v31-ec-p256_2-tgt-33-modified.apk");
1251     }
1252 
1253     @CddTest(requirement="4/C-0-2")
testV31RotationTargetsDevRelease()1254     public void testV31RotationTargetsDevRelease() throws Exception {
1255         // The v3.1 signature scheme allows targeting a platform release under development through
1256         // the use of a rotation-targets-dev-release additional attribute. Since a platform under
1257         // development shares the same SDK version as the most recently released platform, the
1258         // attribute is used by the platform to determine if a signer block should be applied. If
1259         // the signer's minSdkVersion is the same as the device's SDK version and this attribute
1260         // is set, then the platform will check the value of ro.build.version.codename; a value of
1261         // "REL" indicates the platform is a release platform, so the current signer block will not
1262         // be used. During T's development, the SDK version is 31 and the codename is not "REL", so
1263         // this test APK will install on T during development as well as after its release since
1264         // the SDK version will be bumped at that point.
1265         assertInstallSucceeds("v31-ec-p256_2-tgt-31-dev-release.apk");
1266     }
1267 
1268 
testInstallTargetSdk30WithV1Signers()1269     public void testInstallTargetSdk30WithV1Signers() throws Exception {
1270         // An app targeting SDK version >= 30 must have at least a V2 signature; this test verifies
1271         // an app targeting SDK version 30 with only a V1 signature fails to install.
1272         assertInstallFails("v1-ec-p256-two-signers-targetSdk-30.apk");
1273     }
1274 
testInstallTargetSdk30WithV1V2Signers()1275     public void testInstallTargetSdk30WithV1V2Signers() throws Exception {
1276         // An app targeting SDK version >= 30 must have at least a V2 signature; this test verifies
1277         // that an app targeting SDK version 30 with both a V1 and V2 signature installs
1278         // successfully.
1279         installApkFromBuild("v1v2-ec-p256-two-signers-targetSdk-30.apk");
1280     }
1281 
testInstallV4WithV2Signer()1282     public void testInstallV4WithV2Signer() throws Exception {
1283         // V4 is only enabled on devices with Incremental feature
1284         if (!hasIncrementalFeature()) {
1285             return;
1286         }
1287 
1288         // APK generated with:
1289         // apksigner sign --v2-signing-enabled true --v3-signing-enabled false --v4-signing-enabled
1290         assertInstallV4Succeeds("v4-digest-v2.apk");
1291     }
1292 
testInstallV4WithV3Signer()1293     public void testInstallV4WithV3Signer() throws Exception {
1294         // V4 is only enabled on devices with Incremental feature
1295         if (!hasIncrementalFeature()) {
1296             return;
1297         }
1298 
1299         // APK generated with:
1300         // apksigner sign --v2-signing-enabled false --v3-signing-enabled true --v4-signing-enabled
1301         assertInstallV4Succeeds("v4-digest-v3.apk");
1302     }
1303 
testInstallV4WithV2V3Signer()1304     public void testInstallV4WithV2V3Signer() throws Exception {
1305         // V4 is only enabled on devices with Incremental feature
1306         if (!hasIncrementalFeature()) {
1307             return;
1308         }
1309 
1310         // APK generated with:
1311         // apksigner sign --v2-signing-enabled true --v3-signing-enabled true --v4-signing-enabled
1312         assertInstallV4Succeeds("v4-digest-v2v3.apk");
1313     }
1314 
testInstallV4WithV2NoVeritySigner()1315     public void testInstallV4WithV2NoVeritySigner() throws Exception {
1316         // V4 is only enabled on devices with Incremental feature
1317         if (!hasIncrementalFeature()) {
1318             return;
1319         }
1320 
1321         // APK generated with:
1322         // --v2-signing-enabled true --v3-signing-enabled false --v4-signing-enabled
1323         // Full commands in generate-apks.sh
1324         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withDSA.apk");
1325         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withEC.apk");
1326         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withRSA.apk");
1327         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha512withEC.apk");
1328         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha512withRSA.apk");
1329     }
1330 
testInstallV4WithV2VeritySigner()1331     public void testInstallV4WithV2VeritySigner() throws Exception {
1332         // V4 is only enabled on devices with Incremental feature
1333         if (!hasIncrementalFeature()) {
1334             return;
1335         }
1336 
1337         // APK generated with:
1338         // --v2-signing-enabled true --v3-signing-enabled false
1339         // --v4-signing-enabled --verity-enabled
1340         // Full commands in generate-apks.sh
1341         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withDSA-Verity.apk");
1342         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withEC-Verity.apk");
1343         assertInstallV4SucceedsAndUninstall("v4-digest-v2-Sha256withRSA-Verity.apk");
1344     }
1345 
testInstallV4WithV3NoVeritySigner()1346     public void testInstallV4WithV3NoVeritySigner() throws Exception {
1347         // V4 is only enabled on devices with Incremental feature
1348         if (!hasIncrementalFeature()) {
1349             return;
1350         }
1351 
1352         // APK generated with:
1353         // --v2-signing-enabled false --v3-signing-enabled true --v4-signing-enabled
1354         // Full commands in generate-apks.sh
1355         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withDSA.apk");
1356         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withEC.apk");
1357         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withRSA.apk");
1358         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha512withEC.apk");
1359         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha512withRSA.apk");
1360     }
1361 
testInstallV4WithV3VeritySigner()1362     public void testInstallV4WithV3VeritySigner() throws Exception {
1363         // V4 is only enabled on devices with Incremental feature
1364         if (!hasIncrementalFeature()) {
1365             return;
1366         }
1367 
1368         // APK generated with:
1369         // --v2-signing-enabled false --v3-signing-enabled true
1370         // --v4-signing-enabled --verity-enabled
1371         // Full commands in generate-apks.sh
1372         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withDSA-Verity.apk");
1373         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withEC-Verity.apk");
1374         assertInstallV4SucceedsAndUninstall("v4-digest-v3-Sha256withRSA-Verity.apk");
1375     }
1376 
testInstallV4WithV2SignerDoesNotVerify()1377     public void testInstallV4WithV2SignerDoesNotVerify() throws Exception {
1378         // V4 is only enabled on devices with Incremental feature
1379         if (!hasIncrementalFeature()) {
1380             return;
1381         }
1382 
1383         // APKs generated with:
1384         // apksigner sign -v2-signing-enabled true --v3-signing-enabled false --v4-signing-enabled
1385 
1386         // Malformed v4 signature - first byte of v4 signing_info.signature is flipped
1387         assertInstallV4FailsWithError("v4-digest-v2-badv4signature.apk", "did not verify");
1388         // Malformed digest - first byte of v4 signing_info.apk_digest is flipped
1389         assertInstallV4FailsWithError("v4-digest-v2-badv2digest.apk", "did not verify");
1390     }
1391 
testInstallV4WithV3SignerDoesNotVerify()1392     public void testInstallV4WithV3SignerDoesNotVerify() throws Exception {
1393         // V4 is only enabled on devices with Incremental feature
1394         if (!hasIncrementalFeature()) {
1395             return;
1396         }
1397 
1398         // APKs generated with:
1399         // apksigner sign -v2-signing-enabled false --v3-signing-enabled true --v4-signing-enabled
1400 
1401         // Malformed v4 signature - first byte of v4 signing_info.signature is flipped
1402         assertInstallV4FailsWithError("v4-digest-v3-badv4signature.apk", "did not verify");
1403 
1404         // Malformed digest - first byte of v4 signing_info.apk_digest is flipped
1405         assertInstallV4FailsWithError("v4-digest-v3-badv3digest.apk", "did not verify");
1406 
1407     }
1408 
testInstallV4WithV2V3SignerDoesNotVerify()1409     public void testInstallV4WithV2V3SignerDoesNotVerify() throws Exception {
1410         // V4 is only enabled on devices with Incremental feature
1411         if (!hasIncrementalFeature()) {
1412             return;
1413         }
1414 
1415         // APKs generated with:
1416         // apksigner sign -v2-signing-enabled true --v3-signing-enabled true --v4-signing-enabled
1417 
1418         // Malformed v4 signature - first byte of v4 signing_info.signature is flipped
1419         assertInstallV4FailsWithError("v4-digest-v2v3-badv4signature.apk", "did not verify");
1420 
1421         // Malformed digest - first byte of v4 signing_info.apk_digest is flipped
1422         assertInstallV4FailsWithError("v4-digest-v2v3-badv2v3digest.apk", "did not verify");
1423     }
1424 
testInstallV4With128BytesAdditionalDataSucceeds()1425     public void testInstallV4With128BytesAdditionalDataSucceeds() throws Exception {
1426         // V4 is only enabled on devices with Incremental feature
1427         if (!hasIncrementalFeature()) {
1428             return;
1429         }
1430 
1431         // Editing apksigner to fill additional data of size 128 bytes.
1432         assertInstallV4Succeeds("v4-digest-v3-128bytes-additional-data.apk");
1433     }
1434 
testInstallV4With256BytesAdditionalDataFails()1435     public void testInstallV4With256BytesAdditionalDataFails() throws Exception {
1436         // V4 is only enabled on devices with Incremental feature
1437         if (!hasIncrementalFeature()) {
1438             return;
1439         }
1440 
1441         // Editing apksigner to fill additional data of size 256 bytes.
1442         assertInstallV4FailsWithError("v4-digest-v3-256bytes-additional-data.apk",
1443                 "additionalData has to be at most 128 bytes");
1444     }
1445 
testInstallV4With10MBytesAdditionalDataFails()1446     public void testInstallV4With10MBytesAdditionalDataFails() throws Exception {
1447         // V4 is only enabled on devices with Incremental feature
1448         if (!hasIncrementalFeature()) {
1449             return;
1450         }
1451 
1452         // Editing apksigner to fill additional data of size 10 * 1024 * 1024 bytes.
1453         assertInstallV4FailsWithError("v4-digest-v3-10mbytes-additional-data.apk",
1454                 "Failure");
1455     }
1456 
testInstallV4WithWrongBlockSize()1457     public void testInstallV4WithWrongBlockSize() throws Exception {
1458         // V4 is only enabled on devices with Incremental feature
1459         if (!hasIncrementalFeature()) {
1460             return;
1461         }
1462 
1463         // Editing apksigner with the wrong block size in the v4 signature.
1464         assertInstallV4FailsWithError("v4-digest-v3-wrong-block-size.apk",
1465                 "did not verify");
1466     }
1467 
testInstallV4WithDifferentBlockSize()1468     public void testInstallV4WithDifferentBlockSize() throws Exception {
1469         // V4 is only enabled on devices with Incremental feature
1470         if (!hasIncrementalFeature()) {
1471             return;
1472         }
1473 
1474         // Editing apksigner with the different block size (2048 instead of 4096).
1475         assertInstallV4FailsWithError("v4-digest-v3-merkle-tree-different-block-size.apk",
1476                 "Unsupported log2BlockSize: 11");
1477     }
1478 
testInstallV4WithWrongRawRootHash()1479     public void testInstallV4WithWrongRawRootHash() throws Exception {
1480         // V4 is only enabled on devices with Incremental feature
1481         if (!hasIncrementalFeature()) {
1482             return;
1483         }
1484 
1485         // Editing apksigner with the wrong raw root hash in the v4 signature.
1486         assertInstallV4FailsWithError("v4-digest-v3-wrong-raw-root-hash.apk", "Failure");
1487     }
1488 
testInstallV4WithWrongSignatureBytes()1489     public void testInstallV4WithWrongSignatureBytes() throws Exception {
1490         // V4 is only enabled on devices with Incremental feature
1491         if (!hasIncrementalFeature()) {
1492             return;
1493         }
1494 
1495         // Editing apksigner with the wrong signature bytes in the v4 signature.
1496         assertInstallV4FailsWithError("v4-digest-v3-wrong-sig-bytes.apk",
1497                 "did not verify");
1498     }
1499 
testInstallV4WithWrongSignatureBytesSize()1500     public void testInstallV4WithWrongSignatureBytesSize() throws Exception {
1501         // V4 is only enabled on devices with Incremental feature
1502         if (!hasIncrementalFeature()) {
1503             return;
1504         }
1505 
1506         // Editing apksigner with the wrong signature byte size in the v4 signature.
1507         assertInstallV4FailsWithError("v4-digest-v3-wrong-sig-bytes-size.apk",
1508                 "Failure");
1509     }
1510 
testInstallV4WithNoMerkleTree()1511     public void testInstallV4WithNoMerkleTree() throws Exception {
1512         // V4 is only enabled on devices with Incremental feature
1513         if (!hasIncrementalFeature()) {
1514             return;
1515         }
1516 
1517         // Editing apksigner to not include the Merkle tree.
1518         assertInstallV4FailsWithError("v4-digest-v3-no-merkle-tree.apk",
1519                 "Failure");
1520     }
1521 
testInstallV4WithWithTrailingDataInMerkleTree()1522     public void testInstallV4WithWithTrailingDataInMerkleTree() throws Exception {
1523         // V4 is only enabled on devices with Incremental feature
1524         if (!hasIncrementalFeature()) {
1525             return;
1526         }
1527 
1528         // Editing apksigner to add trailing data after the Merkle tree
1529         assertInstallV4FailsWithError("v4-digest-v3-merkle-tree-1mb-trailing-data.apk",
1530                 "Failure");
1531     }
1532 
testInstallV4WithMerkleTreeBitsFlipped()1533     public void testInstallV4WithMerkleTreeBitsFlipped() throws Exception {
1534         // V4 is only enabled on devices with Incremental feature
1535         if (!hasIncrementalFeature()) {
1536             return;
1537         }
1538 
1539         // Editing apksigner to flip few bits in the only node of the Merkle tree of a small app.
1540         assertInstallV4FailsWithError("v4-digest-v3-merkle-tree-bit-flipped.apk",
1541                 "Failed to parse");
1542     }
1543 
testV4IncToV3NonIncSameKeyUpgradeSucceeds()1544     public void testV4IncToV3NonIncSameKeyUpgradeSucceeds() throws Exception {
1545         // V4 is only enabled on devices with Incremental feature
1546         if (!hasIncrementalFeature()) {
1547             return;
1548         }
1549 
1550         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1551         // to generate the apks
1552         assertInstallV4Succeeds("v4-inc-to-v3-noninc-ec-p256-appv1.apk");
1553 
1554         // non-incremental upgrade with the same key.
1555         assertInstallSucceeds("v4-inc-to-v3-noninc-ec-p256-appv2.apk");
1556     }
1557 
testV4IncToV3NonIncMismatchingKeyUpgradeFails()1558     public void testV4IncToV3NonIncMismatchingKeyUpgradeFails() throws Exception {
1559         // V4 is only enabled on devices with Incremental feature
1560         if (!hasIncrementalFeature()) {
1561             return;
1562         }
1563 
1564         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1565         // to generate the apks
1566         assertInstallV4Succeeds("v4-inc-to-v3-noninc-ec-p256-appv1.apk");
1567 
1568         // non-incremental upgrade with a mismatching key.
1569         assertInstallFailsWithError("v4-inc-to-v3-noninc-ec-p384-appv2.apk",
1570                 "signatures do not match newer version");
1571     }
1572 
testV4IncToV3NonIncRotatedKeyUpgradeSucceeds()1573     public void testV4IncToV3NonIncRotatedKeyUpgradeSucceeds() throws Exception {
1574         // V4 is only enabled on devices with Incremental feature
1575         if (!hasIncrementalFeature()) {
1576             return;
1577         }
1578 
1579         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1580         // to generate the apks
1581         assertInstallV4Succeeds("v4-inc-to-v3-noninc-ec-p256-appv1.apk");
1582 
1583         // non-incremental upgrade with key rotation.
1584         assertInstallSucceeds("v4-inc-to-v3-noninc-ec-p384-rotated-ec-p256-appv2.apk");
1585     }
1586 
testV4IncToV3NonIncMismatchedRotatedKeyUpgradeFails()1587     public void testV4IncToV3NonIncMismatchedRotatedKeyUpgradeFails() throws Exception {
1588         // V4 is only enabled on devices with Incremental feature
1589         if (!hasIncrementalFeature()) {
1590             return;
1591         }
1592 
1593         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1594         // to generate the apks
1595         assertInstallV4Succeeds("v4-inc-to-v3-noninc-dsa-3072-appv1.apk");
1596 
1597         // non-incremental upgrade with key rotation mismatch with key used in app v1.
1598         assertInstallFailsWithError("v4-inc-to-v3-noninc-ec-p384-rotated-ec-p256-appv2.apk",
1599                 "signatures do not match newer version");
1600     }
1601 
testV4IncToV2NonIncSameKeyUpgradeSucceeds()1602     public void testV4IncToV2NonIncSameKeyUpgradeSucceeds() throws Exception {
1603         // V4 is only enabled on devices with Incremental feature
1604         if (!hasIncrementalFeature()) {
1605             return;
1606         }
1607 
1608         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1609         // to generate the apks
1610         assertInstallV4Succeeds("v4-inc-to-v2-noninc-ec-p256-appv1.apk");
1611 
1612         // non-incremental upgrade with the same key.
1613         assertInstallSucceeds("v4-inc-to-v2-noninc-ec-p256-appv2.apk");
1614     }
1615 
testV4IncToV2NonIncMismatchingKeyUpgradeFails()1616     public void testV4IncToV2NonIncMismatchingKeyUpgradeFails() throws Exception {
1617         // V4 is only enabled on devices with Incremental feature
1618         if (!hasIncrementalFeature()) {
1619             return;
1620         }
1621 
1622         // See cts/hostsidetests/appsecurity/res/pkgsigverify/generate-apks.sh for the command
1623         // to generate the apks
1624         assertInstallV4Succeeds("v4-inc-to-v2-noninc-ec-p256-appv1.apk");
1625 
1626         // non-incremental upgrade with a mismatching key.
1627         assertInstallFailsWithError("v4-inc-to-v2-noninc-ec-p384-appv2.apk",
1628                 "signatures do not match newer version");
1629     }
1630 
testInstallV4UpdateAfterRotation()1631     public void testInstallV4UpdateAfterRotation() throws Exception {
1632         // V4 is only enabled on devices with Incremental feature
1633         if (!hasIncrementalFeature()) {
1634             return;
1635         }
1636 
1637         // This test performs an end to end verification of the update of an app with a rotated
1638         // key. The app under test exports a bound service that performs its own PackageManager key
1639         // rotation API verification, and the instrumentation test binds to the service and invokes
1640         // the verifySignatures method to verify that the key rotation APIs return the expected
1641         // results. The instrumentation test app is signed with the same key and lineage as the
1642         // app under test to also provide a second app that can be used for the checkSignatures
1643         // verification.
1644 
1645         // Install the initial versions of the apps; the test method verifies the app under test is
1646         // signed with the original signing key.
1647         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService.apk");
1648         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest.apk");
1649         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
1650                 "verifySignatures_noRotation_succeeds");
1651 
1652         // Install the second version of the app signed with the rotated key. This test verifies the
1653         // app still functions as expected after the update with the rotated key. The
1654         // instrumentation test app is not updated here to allow verification of the pre-key
1655         // rotation behavior for the checkSignatures APIs. These APIs should behave similar to the
1656         // GET_SIGNATURES flag in that if one or both apps have a signing lineage if the oldest
1657         // signers in the lineage match then the methods should return that the signatures match
1658         // even if one is signed with a newer key in the lineage.
1659         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService_v2.apk");
1660         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
1661                 "verifySignatures_withRotation_succeeds");
1662 
1663         // Installs the third version of the app under test and the instrumentation test, both
1664         // signed with the same rotated key and lineage. This test is intended to verify that the
1665         // app can still be updated and function as expected after an update with a rotated key.
1666         assertInstallV4FromBuildSucceeds("CtsSignatureQueryService_v3.apk");
1667         assertInstallV4FromBuildSucceeds("CtsSignatureQueryServiceTest_v2.apk");
1668         Utils.runDeviceTests(getDevice(), SERVICE_TEST_PKG, SERVICE_TEST_CLASS,
1669                 "verifySignatures_withRotation_succeeds");
1670     }
1671 
hasIncrementalFeature()1672     private boolean hasIncrementalFeature() throws Exception {
1673         return "true\n".equals(getDevice().executeShellCommand(
1674                 "pm has-feature android.software.incremental_delivery"));
1675     }
1676 
assertInstallSucceeds(String apkFilenameInResources)1677     private void assertInstallSucceeds(String apkFilenameInResources) throws Exception {
1678         String installResult = installPackageFromResource(apkFilenameInResources);
1679         if (installResult != null) {
1680             fail("Failed to install " + apkFilenameInResources + ": " + installResult);
1681         }
1682     }
1683 
assertInstallEphemeralSucceeds(String apkFilenameInResources)1684     private void assertInstallEphemeralSucceeds(String apkFilenameInResources) throws Exception {
1685         String installResult = installEphemeralPackageFromResource(apkFilenameInResources);
1686         if (installResult != null) {
1687             fail("Failed to install " + apkFilenameInResources + ": " + installResult);
1688         }
1689     }
1690 
assertInstallSucceedsForEach( String apkFilenamePatternInResources, String[] args)1691     private void assertInstallSucceedsForEach(
1692             String apkFilenamePatternInResources, String[] args) throws Exception {
1693         for (String arg : args) {
1694             String apkFilenameInResources =
1695                     String.format(Locale.US, apkFilenamePatternInResources, arg);
1696             String installResult = installPackageFromResource(apkFilenameInResources);
1697             if (installResult != null) {
1698                 fail("Failed to install " + apkFilenameInResources + ": " + installResult);
1699             }
1700             try {
1701                 uninstallPackage();
1702             } catch (Exception e) {
1703                 throw new RuntimeException(
1704                         "Failed to uninstall after installing " + apkFilenameInResources, e);
1705             }
1706         }
1707     }
1708 
assertInstallV4Succeeds(String apkFilenameInResources)1709     private void assertInstallV4Succeeds(String apkFilenameInResources) throws Exception {
1710         String installResult = installV4PackageFromResource(apkFilenameInResources);
1711         if (!installResult.equals("Success\n")) {
1712             fail("Failed to install " + apkFilenameInResources + ": " + installResult);
1713         }
1714     }
1715 
assertInstallV4FromBuildSucceeds(String apkName)1716     private void assertInstallV4FromBuildSucceeds(String apkName) throws Exception {
1717         String installResult = installV4PackageFromBuild(apkName);
1718         if (!installResult.equals("Success\n")) {
1719             fail("Failed to install " + apkName + ": " + installResult);
1720         }
1721     }
1722 
assertInstallV4SucceedsAndUninstall(String apkFilenameInResources)1723     private void assertInstallV4SucceedsAndUninstall(String apkFilenameInResources)
1724             throws Exception {
1725         assertInstallV4Succeeds(apkFilenameInResources);
1726         try {
1727             uninstallPackage();
1728         } catch (Exception e) {
1729             throw new RuntimeException(
1730                     "Failed to uninstall after installing " + apkFilenameInResources, e);
1731         }
1732     }
1733 
assertInstallV4FailsWithError(String apkFilenameInResources, String errorSubstring)1734     private void assertInstallV4FailsWithError(String apkFilenameInResources, String errorSubstring)
1735             throws Exception {
1736         String installResult = installV4PackageFromResource(apkFilenameInResources);
1737         if (installResult.equals("Success\n")) {
1738             fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail"
1739                     + " with \"" + errorSubstring + "\"");
1740         }
1741         assertContains(
1742                 "Install failure message of " + apkFilenameInResources,
1743                 errorSubstring,
1744                 installResult);
1745     }
1746 
assertInstallFailsWithError( String apkFilenameInResources, String errorSubstring)1747     private void assertInstallFailsWithError(
1748             String apkFilenameInResources, String errorSubstring) throws Exception {
1749         String installResult = installPackageFromResource(apkFilenameInResources);
1750         if (installResult == null) {
1751             fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail"
1752                     + " with \"" + errorSubstring + "\"");
1753         }
1754         assertContains(
1755                 "Install failure message of " + apkFilenameInResources,
1756                 errorSubstring,
1757                 installResult);
1758     }
1759 
assertInstallEphemeralFailsWithError( String apkFilenameInResources, String errorSubstring)1760     private void assertInstallEphemeralFailsWithError(
1761             String apkFilenameInResources, String errorSubstring) throws Exception {
1762         String installResult = installEphemeralPackageFromResource(apkFilenameInResources);
1763         if (installResult == null) {
1764             fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail"
1765                     + " with \"" + errorSubstring + "\"");
1766         }
1767         assertContains(
1768                 "Install failure message of " + apkFilenameInResources,
1769                 errorSubstring,
1770                 installResult);
1771     }
1772 
assertInstallFails(String apkFilenameInResources)1773     private void assertInstallFails(String apkFilenameInResources) throws Exception {
1774         String installResult = installPackageFromResource(apkFilenameInResources);
1775         if (installResult == null) {
1776             fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail");
1777         }
1778     }
1779 
assertContains(String message, String expectedSubstring, String actual)1780     private static void assertContains(String message, String expectedSubstring, String actual) {
1781         String errorPrefix = ((message != null) && (message.length() > 0)) ? (message + ": ") : "";
1782         if (actual == null) {
1783             fail(errorPrefix + "Expected to contain \"" + expectedSubstring + "\", but was null");
1784         }
1785         if (!actual.contains(expectedSubstring)) {
1786             fail(errorPrefix + "Expected to contain \"" + expectedSubstring + "\", but was \""
1787                     + actual + "\"");
1788         }
1789     }
1790 
installDeviceTestPkg()1791     private void installDeviceTestPkg() throws Exception {
1792         assertInstallFromBuildSucceeds(DEVICE_TESTS_APK);
1793     }
1794 
assertInstallFromBuildSucceeds(String apkName)1795     private void assertInstallFromBuildSucceeds(String apkName) throws Exception {
1796         String result = installApkFromBuild(apkName);
1797         assertNull("failed to install " + apkName + ", Reason: " + result, result);
1798     }
1799 
assertInstallFromBuildFails(String apkName)1800     private void assertInstallFromBuildFails(String apkName) throws Exception {
1801         String result = installApkFromBuild(apkName);
1802         assertNotNull("Successfully installed " + apkName + " when failure was expected", result);
1803     }
1804 
installApkFromBuild(String apkName)1805     private String installApkFromBuild(String apkName) throws Exception {
1806         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
1807         File apk = buildHelper.getTestFile(apkName);
1808         return getDevice().installPackage(apk, true, INSTALL_ARG_FORCE_QUERYABLE);
1809     }
1810 
installPackageFromResource(String apkFilenameInResources, boolean ephemeral)1811     private String installPackageFromResource(String apkFilenameInResources, boolean ephemeral)
1812             throws IOException, DeviceNotAvailableException {
1813         // ITestDevice.installPackage API requires the APK to be install to be a File. We thus
1814         // copy the requested resource into a temporary file, attempt to install it, and delete the
1815         // file during cleanup.
1816         File apkFile = null;
1817         try {
1818             apkFile = getFileFromResource(apkFilenameInResources);
1819             if (ephemeral) {
1820                 return getDevice().installPackage(apkFile, true, "--ephemeral",
1821                         INSTALL_ARG_FORCE_QUERYABLE);
1822             } else {
1823                 return getDevice().installPackage(apkFile, true, INSTALL_ARG_FORCE_QUERYABLE);
1824             }
1825         } finally {
1826             cleanUpFile(apkFile);
1827         }
1828     }
1829 
installV4PackageFromResource(String apkFilenameInResources)1830     private String installV4PackageFromResource(String apkFilenameInResources)
1831             throws IOException, DeviceNotAvailableException {
1832         File apkFile = null;
1833         File v4SignatureFile = null;
1834         try {
1835             apkFile = getFileFromResource(apkFilenameInResources);
1836             v4SignatureFile = getFileFromResource(apkFilenameInResources + ".idsig");
1837             String remoteApkFilePath = pushFileToRemote(apkFile);
1838             pushFileToRemote(v4SignatureFile);
1839             return installV4Package(remoteApkFilePath);
1840         } finally {
1841             cleanUpFile(apkFile);
1842             cleanUpFile(v4SignatureFile);
1843         }
1844     }
1845 
installV4PackageFromBuild(String apkName)1846     private String installV4PackageFromBuild(String apkName)
1847             throws IOException, DeviceNotAvailableException {
1848         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
1849         File apkFile = buildHelper.getTestFile(apkName);
1850         File v4SignatureFile = buildHelper.getTestFile(apkName + ".idsig");
1851         String remoteApkFilePath = pushFileToRemote(apkFile);
1852         pushFileToRemote(v4SignatureFile);
1853         return installV4Package(remoteApkFilePath);
1854     }
1855 
pushFileToRemote(File localFile)1856     private String pushFileToRemote(File localFile) throws DeviceNotAvailableException {
1857         String remotePath = "/data/local/tmp/pkginstalltest-" + localFile.getName();
1858         getDevice().pushFile(localFile, remotePath);
1859         return remotePath;
1860     }
1861 
installV4Package(String remoteApkPath)1862     private String installV4Package(String remoteApkPath)
1863             throws DeviceNotAvailableException {
1864         String command = "pm install-incremental --force-queryable -t -g " + remoteApkPath;
1865         return getDevice().executeShellCommand(command);
1866     }
1867 
getFileFromResource(String filenameInResources)1868     private File getFileFromResource(String filenameInResources)
1869             throws IOException, IllegalArgumentException {
1870         String fullResourceName = TEST_APK_RESOURCE_PREFIX + filenameInResources;
1871         File tempDir = FileUtil.createTempDir("pkginstalltest");
1872         File file = new File(tempDir, filenameInResources);
1873         InputStream in = getClass().getResourceAsStream(fullResourceName);
1874         if (in == null) {
1875             throw new IllegalArgumentException("Resource not found: " + fullResourceName);
1876         }
1877         OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
1878         byte[] buf = new byte[65536];
1879         int chunkSize;
1880         while ((chunkSize = in.read(buf)) != -1) {
1881             out.write(buf, 0, chunkSize);
1882         }
1883         out.close();
1884         return file;
1885     }
1886 
cleanUpFile(File file)1887     private void cleanUpFile(File file) {
1888         if (file != null && file.exists()) {
1889             file.delete();
1890         }
1891     }
1892 
installPackageFromResource(String apkFilenameInResources)1893     private String installPackageFromResource(String apkFilenameInResources)
1894             throws IOException, DeviceNotAvailableException {
1895         return installPackageFromResource(apkFilenameInResources, false);
1896     }
1897 
installEphemeralPackageFromResource(String apkFilenameInResources)1898     private String installEphemeralPackageFromResource(String apkFilenameInResources)
1899             throws IOException, DeviceNotAvailableException {
1900         return installPackageFromResource(apkFilenameInResources, true);
1901     }
1902 
uninstallPackage()1903     private String uninstallPackage() throws DeviceNotAvailableException {
1904         String result1 = getDevice().uninstallPackage(TEST_PKG);
1905         String result2 = getDevice().uninstallPackage(TEST_PKG2);
1906         return result1 != null ? result1 : result2;
1907     }
1908 
uninstallCompanionPackages()1909     private String uninstallCompanionPackages() throws DeviceNotAvailableException {
1910         String result1 = getDevice().uninstallPackage(COMPANION_TEST_PKG);
1911         String result2 = getDevice().uninstallPackage(COMPANION2_TEST_PKG);
1912         String result3 = getDevice().uninstallPackage(COMPANION3_TEST_PKG);
1913         return Stream.of(result1, result2, result3)
1914                 .filter(Objects::nonNull)
1915                 .findFirst()
1916                 .orElse(null);
1917     }
1918 
uninstallDeviceTestPackage()1919     private String uninstallDeviceTestPackage() throws DeviceNotAvailableException {
1920         return getDevice().uninstallPackage(DEVICE_TESTS_PKG);
1921     }
1922 
uninstallServicePackages()1923     private void uninstallServicePackages() throws DeviceNotAvailableException {
1924         getDevice().uninstallPackage(SERVICE_PKG);
1925         getDevice().uninstallPackage(SERVICE_TEST_PKG);
1926     }
1927 
uninstallPackages()1928     private void uninstallPackages() throws DeviceNotAvailableException {
1929         uninstallPackage();
1930         uninstallCompanionPackages();
1931         uninstallDeviceTestPackage();
1932         uninstallServicePackages();
1933     }
1934 }
1935