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