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