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.SecurityTest; 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 27 import java.io.BufferedOutputStream; 28 import java.io.File; 29 import java.io.FileNotFoundException; 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 DEVICE_TESTS_APK = "CtsV3SigningSchemeRotationTest.apk"; 44 private static final String DEVICE_TESTS_PKG = "android.appsecurity.cts.v3rotationtests"; 45 private static final String DEVICE_TESTS_CLASS = DEVICE_TESTS_PKG + ".V3RotationTest"; 46 private static final String TEST_APK_RESOURCE_PREFIX = "/pkgsigverify/"; 47 48 private static final String[] DSA_KEY_NAMES = {"1024", "2048", "3072"}; 49 private static final String[] EC_KEY_NAMES = {"p256", "p384", "p521"}; 50 private static final String[] RSA_KEY_NAMES = {"1024", "2048", "3072", "4096", "8192", "16384"}; 51 private static final String[] RSA_KEY_NAMES_2048_AND_LARGER = 52 {"2048", "3072", "4096", "8192", "16384"}; 53 54 private IBuildInfo mCtsBuild; 55 56 @Override setBuild(IBuildInfo buildInfo)57 public void setBuild(IBuildInfo buildInfo) { 58 mCtsBuild = buildInfo; 59 } 60 61 @Override setUp()62 protected void setUp() throws Exception { 63 super.setUp(); 64 65 Utils.prepareSingleUser(getDevice()); 66 assertNotNull(mCtsBuild); 67 uninstallPackage(); 68 uninstallCompanionPackage(); 69 installDeviceTestPkg(); 70 } 71 72 @Override tearDown()73 protected void tearDown() throws Exception { 74 try { 75 uninstallPackages(); 76 } catch (DeviceNotAvailableException ignored) { 77 } finally { 78 super.tearDown(); 79 } 80 } 81 testInstallOriginalSucceeds()82 public void testInstallOriginalSucceeds() throws Exception { 83 // APK signed with v1 and v2 schemes. Obtained by building 84 // cts/hostsidetests/appsecurity/test-apps/tinyapp. 85 assertInstallSucceeds("original.apk"); 86 } 87 testInstallV1OneSignerMD5withRSA()88 public void testInstallV1OneSignerMD5withRSA() throws Exception { 89 // APK signed with v1 scheme only, one signer. 90 assertInstallSucceedsForEach( 91 "v1-only-with-rsa-pkcs1-md5-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES); 92 assertInstallSucceedsForEach( 93 "v1-only-with-rsa-pkcs1-md5-1.2.840.113549.1.1.4-%s.apk", RSA_KEY_NAMES); 94 } 95 testInstallV1OneSignerSHA1withRSA()96 public void testInstallV1OneSignerSHA1withRSA() throws Exception { 97 // APK signed with v1 scheme only, one signer. 98 assertInstallSucceedsForEach( 99 "v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES); 100 assertInstallSucceedsForEach( 101 "v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.5-%s.apk", RSA_KEY_NAMES); 102 } 103 testInstallV1OneSignerSHA224withRSA()104 public void testInstallV1OneSignerSHA224withRSA() throws Exception { 105 // APK signed with v1 scheme only, one signer. 106 assertInstallSucceedsForEach( 107 "v1-only-with-rsa-pkcs1-sha224-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES); 108 assertInstallSucceedsForEach( 109 "v1-only-with-rsa-pkcs1-sha224-1.2.840.113549.1.1.14-%s.apk", RSA_KEY_NAMES); 110 } 111 testInstallV1OneSignerSHA256withRSA()112 public void testInstallV1OneSignerSHA256withRSA() throws Exception { 113 // APK signed with v1 scheme only, one signer. 114 assertInstallSucceedsForEach( 115 "v1-only-with-rsa-pkcs1-sha256-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES); 116 assertInstallSucceedsForEach( 117 "v1-only-with-rsa-pkcs1-sha256-1.2.840.113549.1.1.11-%s.apk", RSA_KEY_NAMES); 118 } 119 testInstallV1OneSignerSHA384withRSA()120 public void testInstallV1OneSignerSHA384withRSA() throws Exception { 121 // APK signed with v1 scheme only, one signer. 122 assertInstallSucceedsForEach( 123 "v1-only-with-rsa-pkcs1-sha384-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES); 124 assertInstallSucceedsForEach( 125 "v1-only-with-rsa-pkcs1-sha384-1.2.840.113549.1.1.12-%s.apk", RSA_KEY_NAMES); 126 } 127 testInstallV1OneSignerSHA512withRSA()128 public void testInstallV1OneSignerSHA512withRSA() throws Exception { 129 // APK signed with v1 scheme only, one signer. 130 assertInstallSucceedsForEach( 131 "v1-only-with-rsa-pkcs1-sha512-1.2.840.113549.1.1.1-%s.apk", RSA_KEY_NAMES); 132 assertInstallSucceedsForEach( 133 "v1-only-with-rsa-pkcs1-sha512-1.2.840.113549.1.1.13-%s.apk", RSA_KEY_NAMES); 134 } 135 testInstallV1OneSignerSHA1withECDSA()136 public void testInstallV1OneSignerSHA1withECDSA() throws Exception { 137 // APK signed with v1 scheme only, one signer. 138 assertInstallSucceedsForEach( 139 "v1-only-with-ecdsa-sha1-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES); 140 assertInstallSucceedsForEach( 141 "v1-only-with-ecdsa-sha1-1.2.840.10045.4.1-%s.apk", EC_KEY_NAMES); 142 } 143 testInstallV1OneSignerSHA224withECDSA()144 public void testInstallV1OneSignerSHA224withECDSA() throws Exception { 145 // APK signed with v1 scheme only, one signer. 146 assertInstallSucceedsForEach( 147 "v1-only-with-ecdsa-sha224-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES); 148 assertInstallSucceedsForEach( 149 "v1-only-with-ecdsa-sha224-1.2.840.10045.4.3.1-%s.apk", EC_KEY_NAMES); 150 } 151 testInstallV1OneSignerSHA256withECDSA()152 public void testInstallV1OneSignerSHA256withECDSA() throws Exception { 153 // APK signed with v1 scheme only, one signer. 154 assertInstallSucceedsForEach( 155 "v1-only-with-ecdsa-sha256-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES); 156 assertInstallSucceedsForEach( 157 "v1-only-with-ecdsa-sha256-1.2.840.10045.4.3.2-%s.apk", EC_KEY_NAMES); 158 } 159 testInstallV1OneSignerSHA384withECDSA()160 public void testInstallV1OneSignerSHA384withECDSA() throws Exception { 161 // APK signed with v1 scheme only, one signer. 162 assertInstallSucceedsForEach( 163 "v1-only-with-ecdsa-sha384-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES); 164 assertInstallSucceedsForEach( 165 "v1-only-with-ecdsa-sha384-1.2.840.10045.4.3.3-%s.apk", EC_KEY_NAMES); 166 } 167 testInstallV1OneSignerSHA512withECDSA()168 public void testInstallV1OneSignerSHA512withECDSA() throws Exception { 169 // APK signed with v1 scheme only, one signer. 170 assertInstallSucceedsForEach( 171 "v1-only-with-ecdsa-sha512-1.2.840.10045.2.1-%s.apk", EC_KEY_NAMES); 172 assertInstallSucceedsForEach( 173 "v1-only-with-ecdsa-sha512-1.2.840.10045.4.3.4-%s.apk", EC_KEY_NAMES); 174 } 175 testInstallV1OneSignerSHA1withDSA()176 public void testInstallV1OneSignerSHA1withDSA() throws Exception { 177 // APK signed with v1 scheme only, one signer. 178 assertInstallSucceedsForEach( 179 "v1-only-with-dsa-sha1-1.2.840.10040.4.1-%s.apk", DSA_KEY_NAMES); 180 assertInstallSucceedsForEach( 181 "v1-only-with-dsa-sha1-1.2.840.10040.4.3-%s.apk", DSA_KEY_NAMES); 182 } 183 testInstallV1OneSignerSHA224withDSA()184 public void testInstallV1OneSignerSHA224withDSA() throws Exception { 185 // APK signed with v1 scheme only, one signer. 186 assertInstallSucceedsForEach( 187 "v1-only-with-dsa-sha224-1.2.840.10040.4.1-%s.apk", DSA_KEY_NAMES); 188 assertInstallSucceedsForEach( 189 "v1-only-with-dsa-sha224-2.16.840.1.101.3.4.3.1-%s.apk", DSA_KEY_NAMES); 190 } 191 testInstallV1OneSignerSHA256withDSA()192 public void testInstallV1OneSignerSHA256withDSA() throws Exception { 193 // APK signed with v1 scheme only, one signer. 194 assertInstallSucceedsForEach( 195 "v1-only-with-dsa-sha256-1.2.840.10040.4.1-%s.apk", DSA_KEY_NAMES); 196 assertInstallSucceedsForEach( 197 "v1-only-with-dsa-sha256-2.16.840.1.101.3.4.3.2-%s.apk", DSA_KEY_NAMES); 198 } 199 200 // Android platform doesn't support DSA with SHA-384 and SHA-512. 201 // public void testInstallV1OneSignerSHA384withDSA() throws Exception { 202 // // APK signed with v1 scheme only, one signer. 203 // assertInstallSucceedsForEach( 204 // "v1-only-with-dsa-sha384-2.16.840.1.101.3.4.3.3-%s.apk", DSA_KEY_NAMES); 205 // } 206 // 207 // public void testInstallV1OneSignerSHA512withDSA() throws Exception { 208 // // APK signed with v1 scheme only, one signer. 209 // assertInstallSucceedsForEach( 210 // "v1-only-with-dsa-sha512-2.16.840.1.101.3.4.3.3-%s.apk", DSA_KEY_NAMES); 211 // } 212 testInstallV2StrippedFails()213 public void testInstallV2StrippedFails() throws Exception { 214 // APK signed with v1 and v2 schemes, but v2 signature was stripped from the file (by using 215 // zipalign). 216 // This should fail because the v1 signature indicates that the APK was supposed to be 217 // signed with v2 scheme as well, making the platform's anti-stripping protections reject 218 // the APK. 219 assertInstallFailsWithError("v2-stripped.apk", "Signature stripped"); 220 221 // Similar to above, but the X-Android-APK-Signed anti-stripping header in v1 signature 222 // lists unknown signature schemes in addition to APK Signature Scheme v2. Unknown schemes 223 // should be ignored. 224 assertInstallFailsWithError( 225 "v2-stripped-with-ignorable-signing-schemes.apk", "Signature stripped"); 226 } 227 testInstallV2OneSignerOneSignature()228 public void testInstallV2OneSignerOneSignature() throws Exception { 229 // APK signed with v2 scheme only, one signer, one signature. 230 assertInstallSucceedsForEach("v2-only-with-dsa-sha256-%s.apk", DSA_KEY_NAMES); 231 assertInstallSucceedsForEach("v2-only-with-ecdsa-sha256-%s.apk", EC_KEY_NAMES); 232 assertInstallSucceedsForEach("v2-only-with-rsa-pkcs1-sha256-%s.apk", RSA_KEY_NAMES); 233 assertInstallSucceedsForEach("v2-only-with-rsa-pss-sha256-%s.apk", RSA_KEY_NAMES); 234 235 // DSA with SHA-512 is not supported by Android platform and thus APK Signature Scheme v2 236 // does not support that either 237 // assertInstallSucceedsForEach("v2-only-with-dsa-sha512-%s.apk", DSA_KEY_NAMES); 238 assertInstallSucceedsForEach("v2-only-with-ecdsa-sha512-%s.apk", EC_KEY_NAMES); 239 assertInstallSucceedsForEach("v2-only-with-rsa-pkcs1-sha512-%s.apk", RSA_KEY_NAMES); 240 assertInstallSucceedsForEach( 241 "v2-only-with-rsa-pss-sha512-%s.apk", 242 RSA_KEY_NAMES_2048_AND_LARGER // 1024-bit key is too short for PSS with SHA-512 243 ); 244 } 245 testInstallV1SignatureOnlyDoesNotVerify()246 public void testInstallV1SignatureOnlyDoesNotVerify() throws Exception { 247 // APK signed with v1 scheme only, but not all digests match those recorded in 248 // META-INF/MANIFEST.MF. 249 String error = "META-INF/MANIFEST.MF has invalid digest"; 250 251 // Bitflip in classes.dex of otherwise good file. 252 assertInstallFailsWithError( 253 "v1-only-with-tampered-classes-dex.apk", error); 254 } 255 testInstallV2SignatureDoesNotVerify()256 public void testInstallV2SignatureDoesNotVerify() throws Exception { 257 // APK signed with v2 scheme only, but the signature over signed-data does not verify. 258 String error = "signature did not verify"; 259 260 // Bitflip in certificate field inside signed-data. Based on 261 // v2-only-with-dsa-sha256-1024.apk. 262 assertInstallFailsWithError("v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk", error); 263 264 // Signature claims to be RSA PKCS#1 v1.5 with SHA-256, but is actually using SHA-512. 265 // Based on v2-only-with-rsa-pkcs1-sha256-2048.apk. 266 assertInstallFailsWithError( 267 "v2-only-with-rsa-pkcs1-sha256-2048-sig-does-not-verify.apk", error); 268 269 // Signature claims to be RSA PSS with SHA-256 and 32 bytes of salt, but is actually using 0 270 // bytes of salt. Based on v2-only-with-rsa-pkcs1-sha256-2048.apk. Obtained by modifying APK 271 // signer to use the wrong amount of salt. 272 assertInstallFailsWithError( 273 "v2-only-with-rsa-pss-sha256-2048-sig-does-not-verify.apk", error); 274 275 // Bitflip in the ECDSA signature. Based on v2-only-with-ecdsa-sha256-p256.apk. 276 assertInstallFailsWithError( 277 "v2-only-with-ecdsa-sha256-p256-sig-does-not-verify.apk", error); 278 } 279 testInstallV2ContentDigestMismatch()280 public void testInstallV2ContentDigestMismatch() throws Exception { 281 // APK signed with v2 scheme only, but the digest of contents does not match the digest 282 // stored in signed-data. 283 String error = "digest of contents did not verify"; 284 285 // Based on v2-only-with-rsa-pkcs1-sha512-4096.apk. Obtained by modifying APK signer to 286 // flip the leftmost bit in content digest before signing signed-data. 287 assertInstallFailsWithError( 288 "v2-only-with-rsa-pkcs1-sha512-4096-digest-mismatch.apk", error); 289 290 // Based on v2-only-with-ecdsa-sha256-p256.apk. Obtained by modifying APK signer to flip the 291 // leftmost bit in content digest before signing signed-data. 292 assertInstallFailsWithError( 293 "v2-only-with-ecdsa-sha256-p256-digest-mismatch.apk", error); 294 } 295 testInstallNoApkSignatureSchemeBlock()296 public void testInstallNoApkSignatureSchemeBlock() throws Exception { 297 // APK signed with v2 scheme only, but the rules for verifying APK Signature Scheme v2 298 // signatures say that this APK must not be verified using APK Signature Scheme v2. 299 300 // Obtained from v2-only-with-rsa-pkcs1-sha512-4096.apk by flipping a bit in the magic 301 // field in the footer of APK Signing Block. This makes the APK Signing Block disappear. 302 assertInstallFails("v2-only-wrong-apk-sig-block-magic.apk"); 303 304 // Obtained by modifying APK signer to insert "GARBAGE" between ZIP Central Directory and 305 // End of Central Directory. The APK is otherwise fine and is signed with APK Signature 306 // Scheme v2. Based on v2-only-with-rsa-pkcs1-sha256.apk. 307 assertInstallFails("v2-only-garbage-between-cd-and-eocd.apk"); 308 309 // Obtained by modifying APK signer to truncate the ZIP Central Directory by one byte. The 310 // APK is otherwise fine and is signed with APK Signature Scheme v2. Based on 311 // v2-only-with-rsa-pkcs1-sha256.apk 312 assertInstallFails("v2-only-truncated-cd.apk"); 313 314 // Obtained by modifying the size in APK Signature Block header. Based on 315 // v2-only-with-ecdsa-sha512-p521.apk. 316 assertInstallFails("v2-only-apk-sig-block-size-mismatch.apk"); 317 318 // Obtained by modifying the ID under which APK Signature Scheme v2 Block is stored in 319 // APK Signing Block and by modifying the APK signer to not insert anti-stripping 320 // protections into JAR Signature. The APK should appear as having no APK Signature Scheme 321 // v2 Block and should thus successfully verify using JAR Signature Scheme. 322 assertInstallSucceeds("v1-with-apk-sig-block-but-without-apk-sig-scheme-v2-block.apk"); 323 } 324 testInstallV2UnknownPairIgnoredInApkSigningBlock()325 public void testInstallV2UnknownPairIgnoredInApkSigningBlock() throws Exception { 326 // Obtained by modifying APK signer to emit an unknown ID-value pair into APK Signing Block 327 // before the ID-value pair containing the APK Signature Scheme v2 Block. The unknown 328 // ID-value should be ignored. 329 assertInstallSucceeds("v2-only-unknown-pair-in-apk-sig-block.apk"); 330 } 331 testInstallV2IgnoresUnknownSignatureAlgorithms()332 public void testInstallV2IgnoresUnknownSignatureAlgorithms() throws Exception { 333 // APK is signed with a known signature algorithm and with a couple of unknown ones. 334 // Obtained by modifying APK signer to use "unknown" signature algorithms in addition to 335 // known ones. 336 assertInstallSucceeds("v2-only-with-ignorable-unsupported-sig-algs.apk"); 337 } 338 testInstallV2RejectsMismatchBetweenSignaturesAndDigestsBlocks()339 public void testInstallV2RejectsMismatchBetweenSignaturesAndDigestsBlocks() throws Exception { 340 // APK is signed with a single signature algorithm, but the digests block claims that it is 341 // signed with two different signature algorithms. Obtained by modifying APK Signer to 342 // emit an additional digest record with signature algorithm 0x12345678. 343 assertInstallFailsWithError( 344 "v2-only-signatures-and-digests-block-mismatch.apk", 345 "Signature algorithms don't match between digests and signatures records"); 346 } 347 testInstallV2RejectsMismatchBetweenPublicKeyAndCertificate()348 public void testInstallV2RejectsMismatchBetweenPublicKeyAndCertificate() throws Exception { 349 // APK is signed with v2 only. The public key field does not match the public key in the 350 // leaf certificate. Obtained by modifying APK signer to write out a modified leaf 351 // certificate where the RSA modulus has a bitflip. 352 assertInstallFailsWithError( 353 "v2-only-cert-and-public-key-mismatch.apk", 354 "Public key mismatch between certificate and signature record"); 355 } 356 testInstallV2RejectsSignerBlockWithNoCertificates()357 public void testInstallV2RejectsSignerBlockWithNoCertificates() throws Exception { 358 // APK is signed with v2 only. There are no certificates listed in the signer block. 359 // Obtained by modifying APK signer to output no certificates. 360 assertInstallFailsWithError("v2-only-no-certs-in-sig.apk", "No certificates listed"); 361 } 362 testInstallTwoSigners()363 public void testInstallTwoSigners() throws Exception { 364 // APK signed by two different signers. 365 assertInstallSucceeds("two-signers.apk"); 366 // Because the install attempt below is an update, it also tests that the signing 367 // certificates exposed by v2 signatures above are the same as the one exposed by v1 368 // signatures in this APK. 369 assertInstallSucceeds("v1-only-two-signers.apk"); 370 assertInstallSucceeds("v2-only-two-signers.apk"); 371 } 372 testInstallNegativeModulus()373 public void testInstallNegativeModulus() throws Exception { 374 // APK signed with a certificate that has a negative RSA modulus. 375 assertInstallSucceeds("v1-only-negative-modulus.apk"); 376 assertInstallSucceeds("v2-only-negative-modulus.apk"); 377 assertInstallSucceeds("v3-only-negative-modulus.apk"); 378 } 379 testInstallV2TwoSignersRejectsWhenOneBroken()380 public void testInstallV2TwoSignersRejectsWhenOneBroken() throws Exception { 381 // Bitflip in the ECDSA signature of second signer. Based on two-signers.apk. 382 // This asserts that breakage in any signer leads to rejection of the APK. 383 assertInstallFailsWithError( 384 "two-signers-second-signer-v2-broken.apk", "signature did not verify"); 385 } 386 testInstallV2TwoSignersRejectsWhenOneWithoutSignatures()387 public void testInstallV2TwoSignersRejectsWhenOneWithoutSignatures() throws Exception { 388 // APK v2-signed by two different signers. However, there are no signatures for the second 389 // signer. 390 assertInstallFailsWithError( 391 "v2-only-two-signers-second-signer-no-sig.apk", "No signatures"); 392 } 393 testInstallV2TwoSignersRejectsWhenOneWithoutSupportedSignatures()394 public void testInstallV2TwoSignersRejectsWhenOneWithoutSupportedSignatures() throws Exception { 395 // APK v2-signed by two different signers. However, there are no supported signatures for 396 // the second signer. 397 assertInstallFailsWithError( 398 "v2-only-two-signers-second-signer-no-supported-sig.apk", 399 "No supported signatures"); 400 } 401 testInstallV2RejectsWhenMissingCode()402 public void testInstallV2RejectsWhenMissingCode() throws Exception { 403 // Obtained by removing classes.dex from original.apk and then signing with v2 only. 404 // Although this has nothing to do with v2 signature verification, package manager wants 405 // signature verification / certificate collection to reject APKs with missing code 406 // (classes.dex) unless requested otherwise. 407 assertInstallFailsWithError("v2-only-missing-classes.dex.apk", "code is missing"); 408 } 409 testCorrectCertUsedFromPkcs7SignedDataCertsSet()410 public void testCorrectCertUsedFromPkcs7SignedDataCertsSet() throws Exception { 411 // Obtained by prepending the rsa-1024 certificate to the PKCS#7 SignedData certificates set 412 // of v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.1-2048.apk META-INF/CERT.RSA. The certs 413 // (in the order of appearance in the file) are thus: rsa-1024, rsa-2048. The package's 414 // signing cert is rsa-2048. 415 assertInstallSucceeds("v1-only-pkcs7-cert-bag-first-cert-not-used.apk"); 416 417 // Check that rsa-1024 was not used as the previously installed package's signing cert. 418 assertInstallFailsWithError( 419 "v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.1-1024.apk", 420 "signatures do not match"); 421 422 // Check that rsa-2048 was used as the previously installed package's signing cert. 423 assertInstallSucceeds("v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.1-2048.apk"); 424 } 425 testV1SchemeSignatureCertNotReencoded()426 public void testV1SchemeSignatureCertNotReencoded() throws Exception { 427 // Regression test for b/30148997 and b/18228011. When PackageManager does not preserve the 428 // original encoded form of signing certificates, bad things happen, such as rejection of 429 // completely valid updates to apps. The issue in b/30148997 and b/18228011 was that 430 // PackageManager started re-encoding signing certs into DER. This normally produces exactly 431 // the original form because X.509 certificates are supposed to be DER-encoded. However, a 432 // small fraction of Android apps uses X.509 certificates which are not DER-encoded. For 433 // such apps, re-encoding into DER changes the serialized form of the certificate, creating 434 // a mismatch with the serialized form stored in the PackageManager database, leading to the 435 // rejection of updates for the app. 436 // 437 // The signing certs of the two APKs differ only in how the cert's signature is encoded. 438 // From Android's perspective, these two APKs are signed by different entities and thus 439 // cannot be used to update one another. If signature verification code re-encodes certs 440 // into DER, both certs will be exactly the same and Android will accept these APKs as 441 // updates of each other. This test is thus asserting that the two APKs are not accepted as 442 // updates of each other. 443 // 444 // * v1-only-with-rsa-1024.apk cert's signature is DER-encoded 445 // * v1-only-with-rsa-1024-cert-not-der.apk cert's signature is not DER-encoded. It is 446 // BER-encoded, with length encoded as two bytes instead of just one. 447 // v1-only-with-rsa-1024-cert-not-der.apk META-INF/CERT.RSA was obtained from 448 // v1-only-with-rsa-1024.apk META-INF/CERT.RSA by manually modifying the ASN.1 structure. 449 assertInstallSucceeds("v1-only-with-rsa-1024.apk"); 450 assertInstallFailsWithError( 451 "v1-only-with-rsa-1024-cert-not-der.apk", "signatures do not match"); 452 453 uninstallPackage(); 454 assertInstallSucceeds("v1-only-with-rsa-1024-cert-not-der.apk"); 455 assertInstallFailsWithError("v1-only-with-rsa-1024.apk", "signatures do not match"); 456 } 457 testV2SchemeSignatureCertNotReencoded()458 public void testV2SchemeSignatureCertNotReencoded() throws Exception { 459 // This test is here to catch something like b/30148997 and b/18228011 happening to the 460 // handling of APK Signature Scheme v2 signatures by PackageManager. When PackageManager 461 // does not preserve the original encoded form of signing certificates, bad things happen, 462 // such as rejection of completely valid updates to apps. The issue in b/30148997 and 463 // b/18228011 was that PackageManager started re-encoding signing certs into DER. This 464 // normally produces exactly the original form because X.509 certificates are supposed to be 465 // DER-encoded. However, a small fraction of Android apps uses X.509 certificates which are 466 // not DER-encoded. For such apps, re-encoding into DER changes the serialized form of the 467 // certificate, creating a mismatch with the serialized form stored in the PackageManager 468 // database, leading to the rejection of updates for the app. 469 // 470 // The signing certs of the two APKs differ only in how the cert's signature is encoded. 471 // From Android's perspective, these two APKs are signed by different entities and thus 472 // cannot be used to update one another. If signature verification code re-encodes certs 473 // into DER, both certs will be exactly the same and Android will accept these APKs as 474 // updates of each other. This test is thus asserting that the two APKs are not accepted as 475 // updates of each other. 476 // 477 // * v2-only-with-rsa-pkcs1-sha256-1024.apk cert's signature is DER-encoded 478 // * v2-only-with-rsa-pkcs1-sha256-1024-cert-not-der.apk cert's signature is not DER-encoded 479 // It is BER-encoded, with length encoded as two bytes instead of just one. 480 assertInstallSucceeds("v2-only-with-rsa-pkcs1-sha256-1024.apk"); 481 assertInstallFailsWithError( 482 "v2-only-with-rsa-pkcs1-sha256-1024-cert-not-der.apk", "signatures do not match"); 483 484 uninstallPackage(); 485 assertInstallSucceeds("v2-only-with-rsa-pkcs1-sha256-1024-cert-not-der.apk"); 486 assertInstallFailsWithError( 487 "v2-only-with-rsa-pkcs1-sha256-1024.apk", "signatures do not match"); 488 } 489 testInstallMaxSizedZipEocdComment()490 public void testInstallMaxSizedZipEocdComment() throws Exception { 491 // Obtained by modifying apksigner to produce a max-sized (0xffff bytes long) ZIP End of 492 // Central Directory comment, and signing the original.apk using the modified apksigner. 493 assertInstallSucceeds("v1-only-max-sized-eocd-comment.apk"); 494 assertInstallSucceeds("v2-only-max-sized-eocd-comment.apk"); 495 } 496 testInstallEphemeralRequiresV2Signature()497 public void testInstallEphemeralRequiresV2Signature() throws Exception { 498 assertInstallEphemeralFailsWithError("unsigned-ephemeral.apk", 499 "Failed to collect certificates"); 500 assertInstallEphemeralFailsWithError("v1-only-ephemeral.apk", 501 "must be signed with APK Signature Scheme v2 or greater"); 502 assertInstallEphemeralSucceeds("v2-only-ephemeral.apk"); 503 assertInstallEphemeralSucceeds("v1-v2-ephemeral.apk"); // signed with both schemes 504 } 505 testInstallEmpty()506 public void testInstallEmpty() throws Exception { 507 assertInstallFailsWithError("empty-unsigned.apk", "Unknown failure"); 508 assertInstallFailsWithError("v1-only-empty.apk", "Unknown failure"); 509 assertInstallFailsWithError("v2-only-empty.apk", "Unknown failure"); 510 } 511 512 @SecurityTest testInstallApkWhichDoesNotStartWithZipLocalFileHeaderMagic()513 public void testInstallApkWhichDoesNotStartWithZipLocalFileHeaderMagic() throws Exception { 514 // The APKs below are competely fine except they don't start with ZIP Local File Header 515 // magic. Thus, these APKs will install just fine unless Package Manager requires that APKs 516 // start with ZIP Local File Header magic. 517 String error = "Unknown failure"; 518 519 // Obtained by modifying apksigner to output four unused 0x00 bytes at the start of the APK 520 assertInstallFailsWithError("v1-only-starts-with-00000000-magic.apk", error); 521 assertInstallFailsWithError("v2-only-starts-with-00000000-magic.apk", error); 522 523 // Obtained by modifying apksigner to output 8 unused bytes (DEX magic and version) at the 524 // start of the APK 525 assertInstallFailsWithError("v1-only-starts-with-dex-magic.apk", error); 526 assertInstallFailsWithError("v2-only-starts-with-dex-magic.apk", error); 527 } 528 testInstallV3KeyRotation()529 public void testInstallV3KeyRotation() throws Exception { 530 // tests that a v3 signed APK with RSA key can rotate to a new key 531 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1.apk"); 532 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk"); 533 } 534 testInstallV3KeyRotationToAncestor()535 public void testInstallV3KeyRotationToAncestor() throws Exception { 536 // tests that a v3 signed APK with RSA key cannot be upgraded by one of its past certs 537 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk"); 538 assertInstallFails("v3-rsa-pkcs1-sha256-2048-1.apk"); 539 } 540 testInstallV3KeyRotationToAncestorWithRollback()541 public void testInstallV3KeyRotationToAncestorWithRollback() throws Exception { 542 // tests that a v3 signed APK with RSA key can be upgraded by one of its past certs if it 543 // has granted that cert the rollback capability 544 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-and-roll-caps.apk"); 545 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1.apk"); 546 } 547 testInstallV3KeyRotationMultipleHops()548 public void testInstallV3KeyRotationMultipleHops() throws Exception { 549 // tests that a v3 signed APK with RSA key can rotate to a new key which is the result of 550 // multiple rotations from the original: APK signed with key 1 can be updated by key 3, when 551 // keys were: 1 -> 2 -> 3 552 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1.apk"); 553 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-3-with-por_1_2_3-full-caps.apk"); 554 } 555 testInstallV3PorSignerMismatch()556 public void testInstallV3PorSignerMismatch() throws Exception { 557 // tests that an APK with a proof-of-rotation struct that doesn't include the current 558 // signing certificate fails to install 559 assertInstallFails("v3-rsa-pkcs1-sha256-2048-3-with-por_1_2-full-caps.apk"); 560 } 561 testInstallV3KeyRotationWrongPor()562 public void testInstallV3KeyRotationWrongPor() throws Exception { 563 // tests that a valid APK with a proof-of-rotation record can't upgrade an APK with a 564 // signing certificate that isn't in the proof-of-rotation record 565 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1.apk"); 566 assertInstallFails("v3-rsa-pkcs1-sha256-2048-3-with-por_2_3-full-caps.apk"); 567 } 568 testInstallV3KeyRotationSharedUid()569 public void testInstallV3KeyRotationSharedUid() throws Exception { 570 // tests that a v3 signed sharedUid APK can still be sharedUid with apps with its older 571 // signing certificate, if it so desires 572 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-sharedUid.apk"); 573 assertInstallSucceeds( 574 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-sharedUid-companion.apk"); 575 } 576 testInstallV3KeyRotationOlderSharedUid()577 public void testInstallV3KeyRotationOlderSharedUid() throws Exception { 578 579 // tests that a sharedUid APK can still install with another app that is signed by a newer 580 // signing certificate, but which allows sharedUid with the older one 581 assertInstallSucceeds( 582 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-sharedUid-companion.apk"); 583 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-sharedUid.apk"); 584 } 585 testInstallV3KeyRotationSharedUidNoCap()586 public void testInstallV3KeyRotationSharedUidNoCap() throws Exception { 587 // tests that a v3 signed sharedUid APK cannot be sharedUid with apps with its older 588 // signing certificate, when it has not granted that certificate the sharedUid capability 589 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-sharedUid.apk"); 590 assertInstallFails( 591 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-shUid-cap-sharedUid-companion.apk"); 592 } 593 testInstallV3KeyRotationOlderSharedUidNoCap()594 public void testInstallV3KeyRotationOlderSharedUidNoCap() throws Exception { 595 // tests that a sharedUid APK signed with an old certificate cannot install with 596 // an app having a proof-of-rotation structure that hasn't granted the older 597 // certificate the sharedUid capability 598 assertInstallSucceeds( 599 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-shUid-cap-sharedUid-companion.apk"); 600 assertInstallFails("v3-rsa-pkcs1-sha256-2048-1-sharedUid.apk"); 601 } 602 testInstallV3NoRotationSharedUid()603 public void testInstallV3NoRotationSharedUid() throws Exception { 604 // tests that a sharedUid APK signed with a new certificate installs with 605 // an app having a proof-of-rotation structure that hasn't granted an older 606 // certificate the sharedUid capability 607 assertInstallSucceeds( 608 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-shUid-cap-sharedUid-companion.apk"); 609 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-sharedUid.apk"); 610 } 611 testInstallV3KeyRotationSigPerm()612 public void testInstallV3KeyRotationSigPerm() throws Exception { 613 // tests that a v3 signed APK can still get a signature permission from an app with its 614 // older signing certificate. 615 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk"); 616 assertInstallSucceeds( 617 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-permcli-companion.apk"); 618 Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm"); 619 } 620 testInstallV3KeyRotationOlderSigPerm()621 public void testInstallV3KeyRotationOlderSigPerm() throws Exception { 622 // tests that an apk with an older signing certificate than the one which defines a 623 // signature permission it wants gets the permission if the defining APK grants the 624 // capability 625 assertInstallSucceeds( 626 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps-permdef.apk"); 627 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permcli-companion.apk"); 628 Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm"); 629 } 630 testInstallV3KeyRotationSigPermNoCap()631 public void testInstallV3KeyRotationSigPermNoCap() throws Exception { 632 // tests that an APK signed by an older signing certificate is unable to get a requested 633 // signature permission when the defining APK has rotated to a newer signing certificiate 634 // and does not grant the permission capability to the older cert 635 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-perm-cap-permdef.apk"); 636 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permcli-companion.apk"); 637 Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasNoPerm"); 638 } 639 testInstallV3KeyRotationOlderSigPermNoCap()640 public void testInstallV3KeyRotationOlderSigPermNoCap() throws Exception { 641 // tests that an APK signed by a newer signing certificate than the APK which defines a 642 // signature permission is able to get that permission, even if the newer APK does not 643 // grant the permission capability to the older signing certificate. 644 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk"); 645 assertInstallSucceeds( 646 "v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-perm-cap-permcli-companion.apk"); 647 Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm"); 648 } 649 testInstallV3NoRotationSigPerm()650 public void testInstallV3NoRotationSigPerm() throws Exception { 651 // make sure that an APK, which wants to use a signature permission defined by an APK, which 652 // has not granted that capability to older signing certificates, can still install 653 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-no-perm-cap-permdef.apk"); 654 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-permcli-companion.apk"); 655 Utils.runDeviceTests(getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testHasPerm"); 656 } 657 testInstallV3SigPermDoubleDefNewerSucceeds()658 public void testInstallV3SigPermDoubleDefNewerSucceeds() throws Exception { 659 // make sure that if an app defines a signature permission already defined by another app, 660 // it successfully installs if the other app's signing cert is in its past signing certs and 661 // the signature permission capability is granted 662 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk"); 663 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-permdef-companion.apk"); 664 } 665 testInstallV3SigPermDoubleDefOlderSucceeds()666 public void testInstallV3SigPermDoubleDefOlderSucceeds() throws Exception { 667 // make sure that if an app defines a signature permission already defined by another app, 668 // it successfully installs if it is in the other app's past signing certs and the signature 669 // permission capability is granted 670 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-permdef-companion.apk"); 671 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk"); 672 } 673 testInstallV3SigPermDoubleDefNewerNoCapFails()674 public void testInstallV3SigPermDoubleDefNewerNoCapFails() throws Exception { 675 // make sure that if an app defines a signature permission already defined by another app, 676 // it fails to install if the other app's signing cert is in its past signing certs but the 677 // signature permission capability is not granted 678 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1-permdef.apk"); 679 assertInstallFails( 680 "v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-no-perm-cap-permdef-companion.apk"); 681 } 682 testInstallV3SigPermDoubleDefOlderNoCapFails()683 public void testInstallV3SigPermDoubleDefOlderNoCapFails() throws Exception { 684 // make sure that if an app defines a signature permission already defined by another app, 685 // it fails to install if it is in the other app's past signing certs but the signature 686 // permission capability is not granted 687 assertInstallSucceeds( 688 "v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-no-perm-cap-permdef-companion.apk"); 689 assertInstallFails("v3-rsa-pkcs1-sha256-2048-1-permdef.apk"); 690 } 691 testInstallV3SigPermDoubleDefSameNoCapSucceeds()692 public void testInstallV3SigPermDoubleDefSameNoCapSucceeds() throws Exception { 693 // make sure that if an app defines a signature permission already defined by another app, 694 // it installs successfully when signed by the same certificate, even if the original app 695 // does not grant signature capabilities to its past certs 696 assertInstallSucceeds( 697 "v3-rsa-pkcs1-sha256-2048-2-with_por_1_2-no-perm-cap-permdef-companion.apk"); 698 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-permdef.apk"); 699 } 700 testInstallV3KeyRotationGetSignatures()701 public void testInstallV3KeyRotationGetSignatures() throws Exception { 702 // tests that a PackageInfo w/GET_SIGNATURES flag returns the older cert 703 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk"); 704 Utils.runDeviceTests( 705 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, "testGetSignaturesShowsOld"); 706 } 707 testInstallV3KeyRotationGetSigningCertificates()708 public void testInstallV3KeyRotationGetSigningCertificates() throws Exception { 709 // tests that a PackageInfo w/GET_SIGNING_CERTIFICATES flag returns the old and new certs 710 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk"); 711 Utils.runDeviceTests( 712 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, 713 "testGetSigningCertificatesShowsAll"); 714 } 715 testInstallV3KeyRotationHasSigningCertificate()716 public void testInstallV3KeyRotationHasSigningCertificate() throws Exception { 717 // tests that hasSigningCertificate() recognizes past and current signing certs 718 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk"); 719 Utils.runDeviceTests( 720 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, 721 "testHasSigningCertificate"); 722 } 723 testInstallV3KeyRotationHasSigningCertificateSha256()724 public void testInstallV3KeyRotationHasSigningCertificateSha256() throws Exception { 725 // tests that hasSigningCertificate() recognizes past and current signing certs by sha256 726 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk"); 727 Utils.runDeviceTests( 728 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, 729 "testHasSigningCertificateSha256"); 730 } 731 testInstallV3KeyRotationHasSigningCertificateByUid()732 public void testInstallV3KeyRotationHasSigningCertificateByUid() throws Exception { 733 // tests that hasSigningCertificate() recognizes past and current signing certs by uid 734 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk"); 735 Utils.runDeviceTests( 736 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, 737 "testHasSigningCertificateByUid"); 738 } 739 testInstallV3KeyRotationHasSigningCertificateByUidSha256()740 public void testInstallV3KeyRotationHasSigningCertificateByUidSha256() throws Exception { 741 // tests that hasSigningCertificate() recognizes past and current signing certs by uid 742 // and sha256 743 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk"); 744 Utils.runDeviceTests( 745 getDevice(), DEVICE_TESTS_PKG, DEVICE_TESTS_CLASS, 746 "testHasSigningCertificateByUidSha256"); 747 } 748 testInstallV3KeyRotationHasDuplicateSigningCertificateHistory()749 public void testInstallV3KeyRotationHasDuplicateSigningCertificateHistory() throws Exception { 750 // tests that an app's proof-of-rotation signing history cannot contain the same certificate 751 // more than once. 752 assertInstallFails("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2_2-full-caps.apk"); 753 } 754 testInstallV3HasMultipleSigners()755 public void testInstallV3HasMultipleSigners() throws Exception { 756 // tests that an app can't be signed by multiple signers when using v3 signature scheme 757 assertInstallFails("v3-rsa-pkcs1-sha256-2048-1_and_2.apk"); 758 } 759 testInstallV3HasMultiplePlatformSigners()760 public void testInstallV3HasMultiplePlatformSigners() throws Exception { 761 // tests that an app can be signed by multiple v3 signers if they target different platform 762 // versions 763 assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1_P_and_2_Qplus.apk"); 764 } 765 assertInstallSucceeds(String apkFilenameInResources)766 private void assertInstallSucceeds(String apkFilenameInResources) throws Exception { 767 String installResult = installPackageFromResource(apkFilenameInResources); 768 if (installResult != null) { 769 fail("Failed to install " + apkFilenameInResources + ": " + installResult); 770 } 771 } 772 assertInstallEphemeralSucceeds(String apkFilenameInResources)773 private void assertInstallEphemeralSucceeds(String apkFilenameInResources) throws Exception { 774 String installResult = installEphemeralPackageFromResource(apkFilenameInResources); 775 if (installResult != null) { 776 fail("Failed to install " + apkFilenameInResources + ": " + installResult); 777 } 778 } 779 assertInstallSucceedsForEach( String apkFilenamePatternInResources, String[] args)780 private void assertInstallSucceedsForEach( 781 String apkFilenamePatternInResources, String[] args) throws Exception { 782 for (String arg : args) { 783 String apkFilenameInResources = 784 String.format(Locale.US, apkFilenamePatternInResources, arg); 785 String installResult = installPackageFromResource(apkFilenameInResources); 786 if (installResult != null) { 787 fail("Failed to install " + apkFilenameInResources + ": " + installResult); 788 } 789 try { 790 uninstallPackage(); 791 } catch (Exception e) { 792 throw new RuntimeException( 793 "Failed to uninstall after installing " + apkFilenameInResources, e); 794 } 795 } 796 } 797 assertInstallFailsWithError( String apkFilenameInResources, String errorSubstring)798 private void assertInstallFailsWithError( 799 String apkFilenameInResources, String errorSubstring) throws Exception { 800 String installResult = installPackageFromResource(apkFilenameInResources); 801 if (installResult == null) { 802 fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail" 803 + " with \"" + errorSubstring + "\""); 804 } 805 assertContains( 806 "Install failure message of " + apkFilenameInResources, 807 errorSubstring, 808 installResult); 809 } 810 assertInstallEphemeralFailsWithError( String apkFilenameInResources, String errorSubstring)811 private void assertInstallEphemeralFailsWithError( 812 String apkFilenameInResources, String errorSubstring) throws Exception { 813 String installResult = installEphemeralPackageFromResource(apkFilenameInResources); 814 if (installResult == null) { 815 fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail" 816 + " with \"" + errorSubstring + "\""); 817 } 818 assertContains( 819 "Install failure message of " + apkFilenameInResources, 820 errorSubstring, 821 installResult); 822 } 823 assertInstallFails(String apkFilenameInResources)824 private void assertInstallFails(String apkFilenameInResources) throws Exception { 825 String installResult = installPackageFromResource(apkFilenameInResources); 826 if (installResult == null) { 827 fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail"); 828 } 829 } 830 assertContains(String message, String expectedSubstring, String actual)831 private static void assertContains(String message, String expectedSubstring, String actual) { 832 String errorPrefix = ((message != null) && (message.length() > 0)) ? (message + ": ") : ""; 833 if (actual == null) { 834 fail(errorPrefix + "Expected to contain \"" + expectedSubstring + "\", but was null"); 835 } 836 if (!actual.contains(expectedSubstring)) { 837 fail(errorPrefix + "Expected to contain \"" + expectedSubstring + "\", but was \"" 838 + actual + "\""); 839 } 840 } 841 installDeviceTestPkg()842 private void installDeviceTestPkg() throws Exception { 843 CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild); 844 File apk = buildHelper.getTestFile(DEVICE_TESTS_APK); 845 String result = getDevice().installPackage(apk, true); 846 assertNull("failed to install " + DEVICE_TESTS_APK + ", Reason: " + result, result); 847 } 848 installPackageFromResource(String apkFilenameInResources, boolean ephemeral)849 private String installPackageFromResource(String apkFilenameInResources, boolean ephemeral) 850 throws IOException, DeviceNotAvailableException { 851 // ITestDevice.installPackage API requires the APK to be install to be a File. We thus 852 // copy the requested resource into a temporary file, attempt to install it, and delete the 853 // file during cleanup. 854 855 String fullResourceName = TEST_APK_RESOURCE_PREFIX + apkFilenameInResources; 856 File apkFile = File.createTempFile("pkginstalltest", ".apk"); 857 try { 858 try (InputStream in = getClass().getResourceAsStream(fullResourceName); 859 OutputStream out = new BufferedOutputStream(new FileOutputStream(apkFile))) { 860 if (in == null) { 861 throw new IllegalArgumentException("Resource not found: " + fullResourceName); 862 } 863 byte[] buf = new byte[65536]; 864 int chunkSize; 865 while ((chunkSize = in.read(buf)) != -1) { 866 out.write(buf, 0, chunkSize); 867 } 868 } 869 if (ephemeral) { 870 return getDevice().installPackage(apkFile, true, "--ephemeral"); 871 } else { 872 return getDevice().installPackage(apkFile, true); 873 } 874 } finally { 875 apkFile.delete(); 876 } 877 } 878 installPackageFromResource(String apkFilenameInResources)879 private String installPackageFromResource(String apkFilenameInResources) 880 throws IOException, DeviceNotAvailableException { 881 return installPackageFromResource(apkFilenameInResources, false); 882 } 883 installEphemeralPackageFromResource(String apkFilenameInResources)884 private String installEphemeralPackageFromResource(String apkFilenameInResources) 885 throws IOException, DeviceNotAvailableException { 886 return installPackageFromResource(apkFilenameInResources, true); 887 } 888 uninstallPackage()889 private String uninstallPackage() throws DeviceNotAvailableException { 890 return getDevice().uninstallPackage(TEST_PKG); 891 } 892 uninstallCompanionPackage()893 private String uninstallCompanionPackage() throws DeviceNotAvailableException { 894 return getDevice().uninstallPackage(COMPANION_TEST_PKG); 895 } 896 uninstallDeviceTestPackage()897 private String uninstallDeviceTestPackage() throws DeviceNotAvailableException { 898 return getDevice().uninstallPackage(DEVICE_TESTS_PKG); 899 } 900 uninstallPackages()901 private void uninstallPackages() throws DeviceNotAvailableException { 902 uninstallPackage(); 903 uninstallCompanionPackage(); 904 uninstallDeviceTestPackage(); 905 } 906 } 907