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