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 com.android.apksig; 18 19 import static com.android.apksig.apk.ApkUtils.SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME; 20 import static com.android.apksig.apk.ApkUtils.computeSha256DigestBytes; 21 import static com.android.apksig.internal.apk.ApkSigningBlockUtils.VERITY_PADDING_BLOCK_ID; 22 import static com.android.apksig.internal.apk.ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2; 23 import static com.android.apksig.internal.apk.ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3; 24 import static com.android.apksig.internal.apk.ApkSigningBlockUtils.VERSION_JAR_SIGNATURE_SCHEME; 25 import static com.android.apksig.internal.apk.v3.V3SchemeConstants.MIN_SDK_WITH_V31_SUPPORT; 26 import static com.android.apksig.internal.apk.v3.V3SchemeConstants.MIN_SDK_WITH_V3_SUPPORT; 27 28 import com.android.apksig.apk.ApkFormatException; 29 import com.android.apksig.apk.ApkUtils; 30 import com.android.apksig.internal.apk.ApkSigningBlockUtils; 31 import com.android.apksig.internal.apk.ContentDigestAlgorithm; 32 import com.android.apksig.internal.apk.SignatureAlgorithm; 33 import com.android.apksig.internal.apk.stamp.V2SourceStampSigner; 34 import com.android.apksig.internal.apk.v1.DigestAlgorithm; 35 import com.android.apksig.internal.apk.v1.V1SchemeConstants; 36 import com.android.apksig.internal.apk.v1.V1SchemeSigner; 37 import com.android.apksig.internal.apk.v1.V1SchemeVerifier; 38 import com.android.apksig.internal.apk.v2.V2SchemeSigner; 39 import com.android.apksig.internal.apk.v3.V3SchemeConstants; 40 import com.android.apksig.internal.apk.v3.V3SchemeSigner; 41 import com.android.apksig.internal.apk.v4.V4SchemeSigner; 42 import com.android.apksig.internal.apk.v4.V4Signature; 43 import com.android.apksig.internal.jar.ManifestParser; 44 import com.android.apksig.internal.util.AndroidSdkVersion; 45 import com.android.apksig.internal.util.Pair; 46 import com.android.apksig.internal.util.TeeDataSink; 47 import com.android.apksig.util.DataSink; 48 import com.android.apksig.util.DataSinks; 49 import com.android.apksig.util.DataSource; 50 import com.android.apksig.util.RunnablesExecutor; 51 52 import java.io.ByteArrayOutputStream; 53 import java.io.File; 54 import java.io.IOException; 55 import java.io.OutputStream; 56 import java.nio.ByteBuffer; 57 import java.security.InvalidKeyException; 58 import java.security.MessageDigest; 59 import java.security.NoSuchAlgorithmException; 60 import java.security.PrivateKey; 61 import java.security.PublicKey; 62 import java.security.SignatureException; 63 import java.security.cert.CertificateEncodingException; 64 import java.security.cert.CertificateException; 65 import java.security.cert.X509Certificate; 66 import java.util.ArrayList; 67 import java.util.Arrays; 68 import java.util.Collection; 69 import java.util.Collections; 70 import java.util.HashMap; 71 import java.util.HashSet; 72 import java.util.Iterator; 73 import java.util.List; 74 import java.util.Map; 75 import java.util.Set; 76 77 /** 78 * Default implementation of {@link ApkSignerEngine}. 79 * 80 * <p>Use {@link Builder} to obtain instances of this engine. 81 */ 82 public class DefaultApkSignerEngine implements ApkSignerEngine { 83 84 // IMPLEMENTATION NOTE: This engine generates a signed APK as follows: 85 // 1. The engine asks its client to output input JAR entries which are not part of JAR 86 // signature. 87 // 2. If JAR signing (v1 signing) is enabled, the engine inspects the output JAR entries to 88 // compute their digests, to be placed into output META-INF/MANIFEST.MF. It also inspects 89 // the contents of input and output META-INF/MANIFEST.MF to borrow the main section of the 90 // file. It does not care about individual (i.e., JAR entry-specific) sections. It then 91 // emits the v1 signature (a set of JAR entries) and asks the client to output them. 92 // 3. If APK Signature Scheme v2 (v2 signing) is enabled, the engine emits an APK Signing Block 93 // from outputZipSections() and asks its client to insert this block into the output. 94 // 4. If APK Signature Scheme v3 (v3 signing) is enabled, the engine includes it in the APK 95 // Signing BLock output from outputZipSections() and asks its client to insert this block 96 // into the output. If both v2 and v3 signing is enabled, they are both added to the APK 97 // Signing Block before asking the client to insert it into the output. 98 99 private final boolean mV1SigningEnabled; 100 private final boolean mV2SigningEnabled; 101 private final boolean mV3SigningEnabled; 102 private final boolean mVerityEnabled; 103 private final boolean mDebuggableApkPermitted; 104 private final boolean mOtherSignersSignaturesPreserved; 105 private final String mCreatedBy; 106 private final List<SignerConfig> mSignerConfigs; 107 private final List<SignerConfig> mTargetedSignerConfigs; 108 private final SignerConfig mSourceStampSignerConfig; 109 private final SigningCertificateLineage mSourceStampSigningCertificateLineage; 110 private final boolean mSourceStampTimestampEnabled; 111 private final int mMinSdkVersion; 112 private final SigningCertificateLineage mSigningCertificateLineage; 113 114 private List<byte[]> mPreservedV2Signers = Collections.emptyList(); 115 private List<Pair<byte[], Integer>> mPreservedSignatureBlocks = Collections.emptyList(); 116 117 private List<V1SchemeSigner.SignerConfig> mV1SignerConfigs = Collections.emptyList(); 118 private DigestAlgorithm mV1ContentDigestAlgorithm; 119 120 private boolean mClosed; 121 122 private boolean mV1SignaturePending; 123 124 /** Names of JAR entries which this engine is expected to output as part of v1 signing. */ 125 private Set<String> mSignatureExpectedOutputJarEntryNames = Collections.emptySet(); 126 127 /** Requests for digests of output JAR entries. */ 128 private final Map<String, GetJarEntryDataDigestRequest> mOutputJarEntryDigestRequests = 129 new HashMap<>(); 130 131 /** Digests of output JAR entries. */ 132 private final Map<String, byte[]> mOutputJarEntryDigests = new HashMap<>(); 133 134 /** Data of JAR entries emitted by this engine as v1 signature. */ 135 private final Map<String, byte[]> mEmittedSignatureJarEntryData = new HashMap<>(); 136 137 /** Requests for data of output JAR entries which comprise the v1 signature. */ 138 private final Map<String, GetJarEntryDataRequest> mOutputSignatureJarEntryDataRequests = 139 new HashMap<>(); 140 /** 141 * Request to obtain the data of MANIFEST.MF or {@code null} if the request hasn't been issued. 142 */ 143 private GetJarEntryDataRequest mInputJarManifestEntryDataRequest; 144 145 /** 146 * Request to obtain the data of AndroidManifest.xml or {@code null} if the request hasn't been 147 * issued. 148 */ 149 private GetJarEntryDataRequest mOutputAndroidManifestEntryDataRequest; 150 151 /** 152 * Whether the package being signed is marked as {@code android:debuggable} or {@code null} if 153 * this is not yet known. 154 */ 155 private Boolean mDebuggable; 156 157 /** 158 * Request to output the emitted v1 signature or {@code null} if the request hasn't been issued. 159 */ 160 private OutputJarSignatureRequestImpl mAddV1SignatureRequest; 161 162 private boolean mV2SignaturePending; 163 private boolean mV3SignaturePending; 164 165 /** 166 * Request to output the emitted v2 and/or v3 signature(s) {@code null} if the request hasn't 167 * been issued. 168 */ 169 private OutputApkSigningBlockRequestImpl mAddSigningBlockRequest; 170 171 private RunnablesExecutor mExecutor = RunnablesExecutor.MULTI_THREADED; 172 173 /** 174 * A Set of block IDs to be discarded when requesting to preserve the original signatures. 175 */ 176 private static final Set<Integer> DISCARDED_SIGNATURE_BLOCK_IDS; 177 static { 178 DISCARDED_SIGNATURE_BLOCK_IDS = new HashSet<>(3); 179 // The verity padding block is recomputed on an 180 // ApkSigningBlockUtils.ANDROID_COMMON_PAGE_ALIGNMENT_BYTES boundary. 181 DISCARDED_SIGNATURE_BLOCK_IDS.add(VERITY_PADDING_BLOCK_ID); 182 // The source stamp block is not currently preserved; appending a new signature scheme 183 // block will invalidate the previous source stamp. 184 DISCARDED_SIGNATURE_BLOCK_IDS.add(Constants.V1_SOURCE_STAMP_BLOCK_ID); 185 DISCARDED_SIGNATURE_BLOCK_IDS.add(Constants.V2_SOURCE_STAMP_BLOCK_ID); 186 } 187 DefaultApkSignerEngine( List<SignerConfig> signerConfigs, List<SignerConfig> targetedSignerConfigs, SignerConfig sourceStampSignerConfig, SigningCertificateLineage sourceStampSigningCertificateLineage, boolean sourceStampTimestampEnabled, int minSdkVersion, boolean v1SigningEnabled, boolean v2SigningEnabled, boolean v3SigningEnabled, boolean verityEnabled, boolean debuggableApkPermitted, boolean otherSignersSignaturesPreserved, String createdBy, SigningCertificateLineage signingCertificateLineage)188 private DefaultApkSignerEngine( 189 List<SignerConfig> signerConfigs, 190 List<SignerConfig> targetedSignerConfigs, 191 SignerConfig sourceStampSignerConfig, 192 SigningCertificateLineage sourceStampSigningCertificateLineage, 193 boolean sourceStampTimestampEnabled, 194 int minSdkVersion, 195 boolean v1SigningEnabled, 196 boolean v2SigningEnabled, 197 boolean v3SigningEnabled, 198 boolean verityEnabled, 199 boolean debuggableApkPermitted, 200 boolean otherSignersSignaturesPreserved, 201 String createdBy, 202 SigningCertificateLineage signingCertificateLineage) 203 throws InvalidKeyException { 204 if (signerConfigs.isEmpty() && targetedSignerConfigs.isEmpty()) { 205 throw new IllegalArgumentException("At least one signer config must be provided"); 206 } 207 208 mV1SigningEnabled = v1SigningEnabled; 209 mV2SigningEnabled = v2SigningEnabled; 210 mV3SigningEnabled = v3SigningEnabled; 211 mVerityEnabled = verityEnabled; 212 mV1SignaturePending = v1SigningEnabled; 213 mV2SignaturePending = v2SigningEnabled; 214 mV3SignaturePending = v3SigningEnabled; 215 mDebuggableApkPermitted = debuggableApkPermitted; 216 mOtherSignersSignaturesPreserved = otherSignersSignaturesPreserved; 217 mCreatedBy = createdBy; 218 mSignerConfigs = signerConfigs; 219 mTargetedSignerConfigs = targetedSignerConfigs; 220 mSourceStampSignerConfig = sourceStampSignerConfig; 221 mSourceStampSigningCertificateLineage = sourceStampSigningCertificateLineage; 222 mSourceStampTimestampEnabled = sourceStampTimestampEnabled; 223 mMinSdkVersion = minSdkVersion; 224 mSigningCertificateLineage = signingCertificateLineage; 225 226 if (v1SigningEnabled) { 227 if (v3SigningEnabled) { 228 229 // v3 signing only supports single signers, of which the oldest (first) will be the 230 // one to use for v1 and v2 signing 231 SignerConfig oldestConfig = !signerConfigs.isEmpty() ? signerConfigs.get(0) 232 : targetedSignerConfigs.get(0); 233 234 // in the event of signing certificate changes, make sure we have the oldest in the 235 // signing history to sign with v1 236 if (signingCertificateLineage != null) { 237 SigningCertificateLineage subLineage = 238 signingCertificateLineage.getSubLineage( 239 oldestConfig.mCertificates.get(0)); 240 if (subLineage.size() != 1) { 241 throw new IllegalArgumentException( 242 "v1 signing enabled but the oldest signer in the" 243 + " SigningCertificateLineage is missing. Please provide the" 244 + " oldest signer to enable v1 signing"); 245 } 246 } 247 createV1SignerConfigs(Collections.singletonList(oldestConfig), minSdkVersion); 248 } else { 249 createV1SignerConfigs(signerConfigs, minSdkVersion); 250 } 251 } 252 } 253 createV1SignerConfigs(List<SignerConfig> signerConfigs, int minSdkVersion)254 private void createV1SignerConfigs(List<SignerConfig> signerConfigs, int minSdkVersion) 255 throws InvalidKeyException { 256 mV1SignerConfigs = new ArrayList<>(signerConfigs.size()); 257 Map<String, Integer> v1SignerNameToSignerIndex = new HashMap<>(signerConfigs.size()); 258 DigestAlgorithm v1ContentDigestAlgorithm = null; 259 for (int i = 0; i < signerConfigs.size(); i++) { 260 SignerConfig signerConfig = signerConfigs.get(i); 261 List<X509Certificate> certificates = signerConfig.getCertificates(); 262 PublicKey publicKey = certificates.get(0).getPublicKey(); 263 264 String v1SignerName = V1SchemeSigner.getSafeSignerName(signerConfig.getName()); 265 // Check whether the signer's name is unique among all v1 signers 266 Integer indexOfOtherSignerWithSameName = v1SignerNameToSignerIndex.put(v1SignerName, i); 267 if (indexOfOtherSignerWithSameName != null) { 268 throw new IllegalArgumentException( 269 "Signers #" 270 + (indexOfOtherSignerWithSameName + 1) 271 + " and #" 272 + (i + 1) 273 + " have the same name: " 274 + v1SignerName 275 + ". v1 signer names must be unique"); 276 } 277 278 DigestAlgorithm v1SignatureDigestAlgorithm = 279 V1SchemeSigner.getSuggestedSignatureDigestAlgorithm(publicKey, minSdkVersion); 280 V1SchemeSigner.SignerConfig v1SignerConfig = new V1SchemeSigner.SignerConfig(); 281 v1SignerConfig.name = v1SignerName; 282 v1SignerConfig.keyConfig = signerConfig.getKeyConfig(); 283 v1SignerConfig.certificates = certificates; 284 v1SignerConfig.signatureDigestAlgorithm = v1SignatureDigestAlgorithm; 285 v1SignerConfig.deterministicDsaSigning = signerConfig.getDeterministicDsaSigning(); 286 // For digesting contents of APK entries and of MANIFEST.MF, pick the algorithm 287 // of comparable strength to the digest algorithm used for computing the signature. 288 // When there are multiple signers, pick the strongest digest algorithm out of their 289 // signature digest algorithms. This avoids reducing the digest strength used by any 290 // of the signers to protect APK contents. 291 if (v1ContentDigestAlgorithm == null) { 292 v1ContentDigestAlgorithm = v1SignatureDigestAlgorithm; 293 } else { 294 if (DigestAlgorithm.BY_STRENGTH_COMPARATOR.compare( 295 v1SignatureDigestAlgorithm, v1ContentDigestAlgorithm) 296 > 0) { 297 v1ContentDigestAlgorithm = v1SignatureDigestAlgorithm; 298 } 299 } 300 mV1SignerConfigs.add(v1SignerConfig); 301 } 302 mV1ContentDigestAlgorithm = v1ContentDigestAlgorithm; 303 mSignatureExpectedOutputJarEntryNames = 304 V1SchemeSigner.getOutputEntryNames(mV1SignerConfigs); 305 } 306 createV2SignerConfigs( boolean apkSigningBlockPaddingSupported)307 private List<ApkSigningBlockUtils.SignerConfig> createV2SignerConfigs( 308 boolean apkSigningBlockPaddingSupported) throws InvalidKeyException { 309 if (mV3SigningEnabled) { 310 311 // v3 signing only supports single signers, of which the oldest (first) will be the one 312 // to use for v1 and v2 signing 313 List<ApkSigningBlockUtils.SignerConfig> signerConfig = new ArrayList<>(); 314 315 SignerConfig oldestConfig = !mSignerConfigs.isEmpty() ? mSignerConfigs.get(0) 316 : mTargetedSignerConfigs.get(0); 317 318 // first make sure that if we have signing certificate history that the oldest signer 319 // corresponds to the oldest ancestor 320 if (mSigningCertificateLineage != null) { 321 SigningCertificateLineage subLineage = 322 mSigningCertificateLineage.getSubLineage(oldestConfig.mCertificates.get(0)); 323 if (subLineage.size() != 1) { 324 throw new IllegalArgumentException( 325 "v2 signing enabled but the oldest signer in" 326 + " the SigningCertificateLineage is missing. Please provide" 327 + " the oldest signer to enable v2 signing."); 328 } 329 } 330 signerConfig.add( 331 createSigningBlockSignerConfig( 332 oldestConfig, 333 apkSigningBlockPaddingSupported, 334 ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2)); 335 return signerConfig; 336 } else { 337 return createSigningBlockSignerConfigs( 338 apkSigningBlockPaddingSupported, 339 ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2); 340 } 341 } 342 processV3Configs( List<ApkSigningBlockUtils.SignerConfig> rawConfigs)343 private List<ApkSigningBlockUtils.SignerConfig> processV3Configs( 344 List<ApkSigningBlockUtils.SignerConfig> rawConfigs) throws InvalidKeyException { 345 // If the caller only specified targeted signing configs, ensure those configs cover the 346 // full range for V3 support (or the APK's minSdkVersion if > P). 347 int minRequiredV3SdkVersion = Math.max(AndroidSdkVersion.P, mMinSdkVersion); 348 if (mSignerConfigs.isEmpty() && 349 mTargetedSignerConfigs.get(0).getMinSdkVersion() > minRequiredV3SdkVersion) { 350 throw new IllegalArgumentException( 351 "The provided targeted signer configs do not cover the SDK range for V3 " 352 + "support; either provide the original signer or ensure a signer " 353 + "targets SDK version " + minRequiredV3SdkVersion); 354 } 355 356 List<ApkSigningBlockUtils.SignerConfig> processedConfigs = new ArrayList<>(); 357 358 // we have our configs, now touch them up to appropriately cover all SDK levels since APK 359 // signature scheme v3 was introduced 360 int currentMinSdk = Integer.MAX_VALUE; 361 for (int i = rawConfigs.size() - 1; i >= 0; i--) { 362 ApkSigningBlockUtils.SignerConfig config = rawConfigs.get(i); 363 if (config.signatureAlgorithms == null) { 364 // no valid algorithm was found for this signer, and we haven't yet covered all 365 // platform versions, something's wrong 366 String keyAlgorithm = config.certificates.get(0).getPublicKey().getAlgorithm(); 367 throw new InvalidKeyException( 368 "Unsupported key algorithm " 369 + keyAlgorithm 370 + " is " 371 + "not supported for APK Signature Scheme v3 signing"); 372 } 373 if (i == rawConfigs.size() - 1) { 374 // first go through the loop, config should support all future platform versions. 375 // this assumes we don't deprecate support for signers in the future. If we do, 376 // this needs to change 377 config.maxSdkVersion = Integer.MAX_VALUE; 378 } else { 379 // If the previous signer was targeting a development release, then the current 380 // signer's maxSdkVersion should overlap with the previous signer's minSdkVersion 381 // to ensure the current signer applies to the production release. 382 ApkSigningBlockUtils.SignerConfig prevSigner = processedConfigs.get( 383 processedConfigs.size() - 1); 384 if (prevSigner.signerTargetsDevRelease) { 385 config.maxSdkVersion = prevSigner.minSdkVersion; 386 } else { 387 config.maxSdkVersion = currentMinSdk - 1; 388 } 389 } 390 if (config.minSdkVersion == V3SchemeConstants.DEV_RELEASE) { 391 // If the current signer is targeting the current development release, then set 392 // the signer's minSdkVersion to the last production release and the flag indicating 393 // this signer is targeting a dev release. 394 config.minSdkVersion = V3SchemeConstants.PROD_RELEASE; 395 config.signerTargetsDevRelease = true; 396 } else if (config.minSdkVersion == 0) { 397 config.minSdkVersion = getMinSdkFromV3SignatureAlgorithms( 398 config.signatureAlgorithms); 399 } 400 // Truncate the lineage to the current signer if it is not the latest signer. 401 X509Certificate signerCert = config.certificates.get(0); 402 if (config.signingCertificateLineage != null 403 && !config.signingCertificateLineage.isCertificateLatestInLineage(signerCert)) { 404 config.signingCertificateLineage = config.signingCertificateLineage.getSubLineage( 405 signerCert); 406 } 407 // we know that this config will be used, so add it to our result, order doesn't matter 408 // at this point 409 processedConfigs.add(config); 410 currentMinSdk = config.minSdkVersion; 411 if (config.signerTargetsDevRelease ? currentMinSdk < minRequiredV3SdkVersion 412 : currentMinSdk <= minRequiredV3SdkVersion) { 413 // this satisfies all we need, stop here 414 break; 415 } 416 } 417 if (currentMinSdk > AndroidSdkVersion.P && currentMinSdk > mMinSdkVersion) { 418 // we can't cover all desired SDK versions, abort 419 throw new InvalidKeyException( 420 "Provided key algorithms not supported on all desired " 421 + "Android SDK versions"); 422 } 423 424 return processedConfigs; 425 } 426 createV3SignerConfigs( boolean apkSigningBlockPaddingSupported)427 private List<ApkSigningBlockUtils.SignerConfig> createV3SignerConfigs( 428 boolean apkSigningBlockPaddingSupported) throws InvalidKeyException { 429 return processV3Configs(createSigningBlockSignerConfigs(apkSigningBlockPaddingSupported, 430 ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3)); 431 } 432 processV31SignerConfigs( List<ApkSigningBlockUtils.SignerConfig> v3SignerConfigs)433 private List<ApkSigningBlockUtils.SignerConfig> processV31SignerConfigs( 434 List<ApkSigningBlockUtils.SignerConfig> v3SignerConfigs) { 435 // The V3.1 signature scheme supports SDK targeted signing config, but this scheme should 436 // only be used when a separate signing config exists for the V3.0 block. 437 if (v3SignerConfigs.size() == 1) { 438 return null; 439 } 440 441 // When there are multiple signing configs, the signer with the minimum SDK version should 442 // be used for the V3.0 block, and all other signers should be used for the V3.1 block. 443 int signerMinSdkVersion = v3SignerConfigs.stream().mapToInt( 444 signer -> signer.minSdkVersion).min().orElse(AndroidSdkVersion.P); 445 List<ApkSigningBlockUtils.SignerConfig> v31SignerConfigs = new ArrayList<>(); 446 Iterator<ApkSigningBlockUtils.SignerConfig> v3SignerIterator = v3SignerConfigs.iterator(); 447 while (v3SignerIterator.hasNext()) { 448 ApkSigningBlockUtils.SignerConfig signerConfig = v3SignerIterator.next(); 449 // If the signer config's minSdkVersion supports V3.1 and is not the min signer in the 450 // list, then add it to the V3.1 signer configs and remove it from the V3.0 list. If 451 // the signer is targeting the minSdkVersion as a development release, then it should 452 // be included in V3.1 to allow the V3.0 block to target the production release of the 453 // same SDK version. 454 if (signerConfig.minSdkVersion >= MIN_SDK_WITH_V31_SUPPORT 455 && (signerConfig.minSdkVersion > signerMinSdkVersion 456 || (signerConfig.minSdkVersion >= signerMinSdkVersion 457 && signerConfig.signerTargetsDevRelease))) { 458 v31SignerConfigs.add(signerConfig); 459 v3SignerIterator.remove(); 460 } 461 } 462 return v31SignerConfigs; 463 } 464 createV4SignerConfig()465 private V4SchemeSigner.SignerConfig createV4SignerConfig() throws InvalidKeyException { 466 List<ApkSigningBlockUtils.SignerConfig> v4Configs = createSigningBlockSignerConfigs(true, 467 ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V4); 468 if (v4Configs.size() != 1) { 469 // V4 uses signer config to connect back to v3. Use the same filtering logic. 470 v4Configs = processV3Configs(v4Configs); 471 } 472 List<ApkSigningBlockUtils.SignerConfig> v41configs = processV31SignerConfigs(v4Configs); 473 return new V4SchemeSigner.SignerConfig(v4Configs, v41configs); 474 } 475 createSourceStampSignerConfig()476 private ApkSigningBlockUtils.SignerConfig createSourceStampSignerConfig() 477 throws InvalidKeyException { 478 ApkSigningBlockUtils.SignerConfig config = createSigningBlockSignerConfig( 479 mSourceStampSignerConfig, 480 /* apkSigningBlockPaddingSupported= */ false, 481 ApkSigningBlockUtils.VERSION_SOURCE_STAMP); 482 if (mSourceStampSigningCertificateLineage != null) { 483 config.signingCertificateLineage = mSourceStampSigningCertificateLineage.getSubLineage( 484 config.certificates.get(0)); 485 } 486 return config; 487 } 488 getMinSdkFromV3SignatureAlgorithms(List<SignatureAlgorithm> algorithms)489 private int getMinSdkFromV3SignatureAlgorithms(List<SignatureAlgorithm> algorithms) { 490 int min = Integer.MAX_VALUE; 491 for (SignatureAlgorithm algorithm : algorithms) { 492 int current = algorithm.getMinSdkVersion(); 493 if (current < min) { 494 if (current <= mMinSdkVersion || current <= AndroidSdkVersion.P) { 495 // this algorithm satisfies all of our needs, no need to keep looking 496 return current; 497 } else { 498 min = current; 499 } 500 } 501 } 502 return min; 503 } 504 createSigningBlockSignerConfigs( boolean apkSigningBlockPaddingSupported, int schemeId)505 private List<ApkSigningBlockUtils.SignerConfig> createSigningBlockSignerConfigs( 506 boolean apkSigningBlockPaddingSupported, int schemeId) throws InvalidKeyException { 507 List<ApkSigningBlockUtils.SignerConfig> signerConfigs = 508 new ArrayList<>(mSignerConfigs.size() + mTargetedSignerConfigs.size()); 509 for (int i = 0; i < mSignerConfigs.size(); i++) { 510 SignerConfig signerConfig = mSignerConfigs.get(i); 511 signerConfigs.add( 512 createSigningBlockSignerConfig( 513 signerConfig, apkSigningBlockPaddingSupported, schemeId)); 514 } 515 if (schemeId >= VERSION_APK_SIGNATURE_SCHEME_V3) { 516 for (int i = 0; i < mTargetedSignerConfigs.size(); i++) { 517 SignerConfig signerConfig = mTargetedSignerConfigs.get(i); 518 signerConfigs.add( 519 createSigningBlockSignerConfig( 520 signerConfig, apkSigningBlockPaddingSupported, schemeId)); 521 } 522 } 523 return signerConfigs; 524 } 525 createSigningBlockSignerConfig( SignerConfig signerConfig, boolean apkSigningBlockPaddingSupported, int schemeId)526 private ApkSigningBlockUtils.SignerConfig createSigningBlockSignerConfig( 527 SignerConfig signerConfig, boolean apkSigningBlockPaddingSupported, int schemeId) 528 throws InvalidKeyException { 529 List<X509Certificate> certificates = signerConfig.getCertificates(); 530 PublicKey publicKey = certificates.get(0).getPublicKey(); 531 532 ApkSigningBlockUtils.SignerConfig newSignerConfig = new ApkSigningBlockUtils.SignerConfig(); 533 newSignerConfig.keyConfig = signerConfig.getKeyConfig(); 534 newSignerConfig.certificates = certificates; 535 newSignerConfig.minSdkVersion = signerConfig.getMinSdkVersion(); 536 newSignerConfig.signerTargetsDevRelease = signerConfig.getSignerTargetsDevRelease(); 537 newSignerConfig.signingCertificateLineage = signerConfig.getSigningCertificateLineage(); 538 539 switch (schemeId) { 540 case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2: 541 newSignerConfig.signatureAlgorithms = 542 V2SchemeSigner.getSuggestedSignatureAlgorithms( 543 publicKey, 544 mMinSdkVersion, 545 apkSigningBlockPaddingSupported && mVerityEnabled, 546 signerConfig.getDeterministicDsaSigning()); 547 break; 548 case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3: 549 try { 550 newSignerConfig.signatureAlgorithms = 551 V3SchemeSigner.getSuggestedSignatureAlgorithms( 552 publicKey, 553 mMinSdkVersion, 554 apkSigningBlockPaddingSupported && mVerityEnabled, 555 signerConfig.getDeterministicDsaSigning()); 556 } catch (InvalidKeyException e) { 557 558 // It is possible for a signer used for v1/v2 signing to not be allowed for use 559 // with v3 signing. This is ok as long as there exists a more recent v3 signer 560 // that covers all supported platform versions. Populate signatureAlgorithm 561 // with null, it will be cleaned-up in a later step. 562 newSignerConfig.signatureAlgorithms = null; 563 } 564 break; 565 case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V4: 566 try { 567 newSignerConfig.signatureAlgorithms = 568 V4SchemeSigner.getSuggestedSignatureAlgorithms( 569 publicKey, mMinSdkVersion, apkSigningBlockPaddingSupported, 570 signerConfig.getDeterministicDsaSigning()); 571 } catch (InvalidKeyException e) { 572 // V4 is an optional signing schema, ok to proceed without. 573 newSignerConfig.signatureAlgorithms = null; 574 } 575 break; 576 case ApkSigningBlockUtils.VERSION_SOURCE_STAMP: 577 newSignerConfig.signatureAlgorithms = 578 Collections.singletonList( 579 SignatureAlgorithm.RSA_PKCS1_V1_5_WITH_SHA256); 580 break; 581 default: 582 throw new IllegalArgumentException("Unknown APK Signature Scheme ID requested"); 583 } 584 return newSignerConfig; 585 } 586 isDebuggable(String entryName)587 private boolean isDebuggable(String entryName) { 588 return mDebuggableApkPermitted 589 || !ApkUtils.ANDROID_MANIFEST_ZIP_ENTRY_NAME.equals(entryName); 590 } 591 592 /** 593 * Initializes DefaultApkSignerEngine with the existing MANIFEST.MF. This reads existing digests 594 * from the MANIFEST.MF file (they are assumed correct) and stores them for the final signature 595 * without recalculation. This step has a significant performance benefit in case of incremental 596 * build. 597 * 598 * <p>This method extracts and stored computed digest for every entry that it would compute it 599 * for in the {@link #outputJarEntry(String)} method 600 * 601 * @param manifestBytes raw representation of MANIFEST.MF file 602 * @param entryNames a set of expected entries names 603 * @return set of entry names which were processed by the engine during the initialization, a 604 * subset of entryNames 605 */ 606 @Override 607 @SuppressWarnings("AndroidJdkLibsChecker") initWith(byte[] manifestBytes, Set<String> entryNames)608 public Set<String> initWith(byte[] manifestBytes, Set<String> entryNames) { 609 V1SchemeVerifier.Result result = new V1SchemeVerifier.Result(); 610 Pair<ManifestParser.Section, Map<String, ManifestParser.Section>> sections = 611 V1SchemeVerifier.parseManifest(manifestBytes, entryNames, result); 612 String alg = V1SchemeSigner.getJcaMessageDigestAlgorithm(mV1ContentDigestAlgorithm); 613 for (Map.Entry<String, ManifestParser.Section> entry : sections.getSecond().entrySet()) { 614 String entryName = entry.getKey(); 615 if (V1SchemeSigner.isJarEntryDigestNeededInManifest(entry.getKey()) 616 && isDebuggable(entryName)) { 617 618 V1SchemeVerifier.NamedDigest extractedDigest = null; 619 Collection<V1SchemeVerifier.NamedDigest> digestsToVerify = 620 V1SchemeVerifier.getDigestsToVerify( 621 entry.getValue(), "-Digest", mMinSdkVersion, Integer.MAX_VALUE); 622 for (V1SchemeVerifier.NamedDigest digestToVerify : digestsToVerify) { 623 if (digestToVerify.jcaDigestAlgorithm.equals(alg)) { 624 extractedDigest = digestToVerify; 625 break; 626 } 627 } 628 if (extractedDigest != null) { 629 mOutputJarEntryDigests.put(entryName, extractedDigest.digest); 630 } 631 } 632 } 633 return mOutputJarEntryDigests.keySet(); 634 } 635 636 @Override setExecutor(RunnablesExecutor executor)637 public void setExecutor(RunnablesExecutor executor) { 638 mExecutor = executor; 639 } 640 641 @Override inputApkSigningBlock(DataSource apkSigningBlock)642 public void inputApkSigningBlock(DataSource apkSigningBlock) { 643 checkNotClosed(); 644 645 if ((apkSigningBlock == null) || (apkSigningBlock.size() == 0)) { 646 return; 647 } 648 649 if (mOtherSignersSignaturesPreserved) { 650 boolean schemeSignatureBlockPreserved = false; 651 mPreservedSignatureBlocks = new ArrayList<>(); 652 try { 653 List<Pair<byte[], Integer>> signatureBlocks = 654 ApkSigningBlockUtils.getApkSignatureBlocks(apkSigningBlock); 655 for (Pair<byte[], Integer> signatureBlock : signatureBlocks) { 656 if (signatureBlock.getSecond() == Constants.APK_SIGNATURE_SCHEME_V2_BLOCK_ID) { 657 // If a V2 signature block is found and the engine is configured to use V2 658 // then save any of the previous signers that are not part of the current 659 // signing request. 660 if (mV2SigningEnabled) { 661 List<Pair<List<X509Certificate>, byte[]>> v2Signers = 662 ApkSigningBlockUtils.getApkSignatureBlockSigners( 663 signatureBlock.getFirst()); 664 mPreservedV2Signers = new ArrayList<>(v2Signers.size()); 665 for (Pair<List<X509Certificate>, byte[]> v2Signer : v2Signers) { 666 if (!isConfiguredWithSigner(v2Signer.getFirst())) { 667 mPreservedV2Signers.add(v2Signer.getSecond()); 668 schemeSignatureBlockPreserved = true; 669 } 670 } 671 } else { 672 // else V2 signing is not enabled; save the entire signature block to be 673 // added to the final APK signing block. 674 mPreservedSignatureBlocks.add(signatureBlock); 675 schemeSignatureBlockPreserved = true; 676 } 677 } else if (signatureBlock.getSecond() 678 == Constants.APK_SIGNATURE_SCHEME_V3_BLOCK_ID) { 679 // Preserving other signers in the presence of a V3 signature block is only 680 // supported if the engine is configured to resign the APK with the V3 681 // signature scheme, and the V3 signer in the signature block is the same 682 // as the engine is configured to use. 683 if (!mV3SigningEnabled) { 684 throw new IllegalStateException( 685 "Preserving an existing V3 signature is not supported"); 686 } 687 List<Pair<List<X509Certificate>, byte[]>> v3Signers = 688 ApkSigningBlockUtils.getApkSignatureBlockSigners( 689 signatureBlock.getFirst()); 690 if (v3Signers.size() > 1) { 691 throw new IllegalArgumentException( 692 "The provided APK signing block contains " + v3Signers.size() 693 + " V3 signers; the V3 signature scheme only supports" 694 + " one signer"); 695 } 696 // If there is only a single V3 signer then ensure it is the signer 697 // configured to sign the APK. 698 if (v3Signers.size() == 1 699 && !isConfiguredWithSigner(v3Signers.get(0).getFirst())) { 700 throw new IllegalStateException( 701 "The V3 signature scheme only supports one signer; a request " 702 + "was made to preserve the existing V3 signature, " 703 + "but the engine is configured to sign with a " 704 + "different signer"); 705 } 706 } else if (!DISCARDED_SIGNATURE_BLOCK_IDS.contains( 707 signatureBlock.getSecond())) { 708 mPreservedSignatureBlocks.add(signatureBlock); 709 } 710 } 711 } catch (ApkFormatException | CertificateException | IOException e) { 712 throw new IllegalArgumentException("Unable to parse the provided signing block", e); 713 } 714 // Signature scheme V3+ only support a single signer; if the engine is configured to 715 // sign with V3+ then ensure no scheme signature blocks have been preserved. 716 if (mV3SigningEnabled && schemeSignatureBlockPreserved) { 717 throw new IllegalStateException( 718 "Signature scheme V3+ only supports a single signer and cannot be " 719 + "appended to the existing signature scheme blocks"); 720 } 721 return; 722 } 723 } 724 725 /** 726 * Returns whether the engine is configured to sign the APK with a signer using the specified 727 * {@code signerCerts}. 728 */ isConfiguredWithSigner(List<X509Certificate> signerCerts)729 private boolean isConfiguredWithSigner(List<X509Certificate> signerCerts) { 730 for (SignerConfig signerConfig : mSignerConfigs) { 731 if (signerCerts.containsAll(signerConfig.getCertificates())) { 732 return true; 733 } 734 } 735 return false; 736 } 737 738 @Override inputJarEntry(String entryName)739 public InputJarEntryInstructions inputJarEntry(String entryName) { 740 checkNotClosed(); 741 742 InputJarEntryInstructions.OutputPolicy outputPolicy = 743 getInputJarEntryOutputPolicy(entryName); 744 switch (outputPolicy) { 745 case SKIP: 746 return new InputJarEntryInstructions(InputJarEntryInstructions.OutputPolicy.SKIP); 747 case OUTPUT: 748 return new InputJarEntryInstructions(InputJarEntryInstructions.OutputPolicy.OUTPUT); 749 case OUTPUT_BY_ENGINE: 750 if (V1SchemeConstants.MANIFEST_ENTRY_NAME.equals(entryName)) { 751 // We copy the main section of the JAR manifest from input to output. Thus, this 752 // invalidates v1 signature and we need to see the entry's data. 753 mInputJarManifestEntryDataRequest = new GetJarEntryDataRequest(entryName); 754 return new InputJarEntryInstructions( 755 InputJarEntryInstructions.OutputPolicy.OUTPUT_BY_ENGINE, 756 mInputJarManifestEntryDataRequest); 757 } 758 return new InputJarEntryInstructions( 759 InputJarEntryInstructions.OutputPolicy.OUTPUT_BY_ENGINE); 760 default: 761 throw new RuntimeException("Unsupported output policy: " + outputPolicy); 762 } 763 } 764 765 @Override outputJarEntry(String entryName)766 public InspectJarEntryRequest outputJarEntry(String entryName) { 767 checkNotClosed(); 768 invalidateV2Signature(); 769 770 if (!isDebuggable(entryName)) { 771 forgetOutputApkDebuggableStatus(); 772 } 773 774 if (!mV1SigningEnabled) { 775 // No need to inspect JAR entries when v1 signing is not enabled. 776 if (!isDebuggable(entryName)) { 777 // To reject debuggable APKs we need to inspect the APK's AndroidManifest.xml to 778 // check whether it declares that the APK is debuggable 779 mOutputAndroidManifestEntryDataRequest = new GetJarEntryDataRequest(entryName); 780 return mOutputAndroidManifestEntryDataRequest; 781 } 782 return null; 783 } 784 // v1 signing is enabled 785 786 if (V1SchemeSigner.isJarEntryDigestNeededInManifest(entryName)) { 787 // This entry is covered by v1 signature. We thus need to inspect the entry's data to 788 // compute its digest(s) for v1 signature. 789 790 // TODO: Handle the case where other signer's v1 signatures are present and need to be 791 // preserved. In that scenario we can't modify MANIFEST.MF and add/remove JAR entries 792 // covered by v1 signature. 793 invalidateV1Signature(); 794 GetJarEntryDataDigestRequest dataDigestRequest = 795 new GetJarEntryDataDigestRequest( 796 entryName, 797 V1SchemeSigner.getJcaMessageDigestAlgorithm(mV1ContentDigestAlgorithm)); 798 mOutputJarEntryDigestRequests.put(entryName, dataDigestRequest); 799 mOutputJarEntryDigests.remove(entryName); 800 801 if ((!mDebuggableApkPermitted) 802 && (ApkUtils.ANDROID_MANIFEST_ZIP_ENTRY_NAME.equals(entryName))) { 803 // To reject debuggable APKs we need to inspect the APK's AndroidManifest.xml to 804 // check whether it declares that the APK is debuggable 805 mOutputAndroidManifestEntryDataRequest = new GetJarEntryDataRequest(entryName); 806 return new CompoundInspectJarEntryRequest( 807 entryName, mOutputAndroidManifestEntryDataRequest, dataDigestRequest); 808 } 809 810 return dataDigestRequest; 811 } 812 813 if (mSignatureExpectedOutputJarEntryNames.contains(entryName)) { 814 // This entry is part of v1 signature generated by this engine. We need to check whether 815 // the entry's data is as output by the engine. 816 invalidateV1Signature(); 817 GetJarEntryDataRequest dataRequest; 818 if (V1SchemeConstants.MANIFEST_ENTRY_NAME.equals(entryName)) { 819 dataRequest = new GetJarEntryDataRequest(entryName); 820 mInputJarManifestEntryDataRequest = dataRequest; 821 } else { 822 // If this entry is part of v1 signature which has been emitted by this engine, 823 // check whether the output entry's data matches what the engine emitted. 824 dataRequest = 825 (mEmittedSignatureJarEntryData.containsKey(entryName)) 826 ? new GetJarEntryDataRequest(entryName) 827 : null; 828 } 829 830 if (dataRequest != null) { 831 mOutputSignatureJarEntryDataRequests.put(entryName, dataRequest); 832 } 833 return dataRequest; 834 } 835 836 // This entry is not covered by v1 signature and isn't part of v1 signature. 837 return null; 838 } 839 840 @Override inputJarEntryRemoved(String entryName)841 public InputJarEntryInstructions.OutputPolicy inputJarEntryRemoved(String entryName) { 842 checkNotClosed(); 843 return getInputJarEntryOutputPolicy(entryName); 844 } 845 846 @Override outputJarEntryRemoved(String entryName)847 public void outputJarEntryRemoved(String entryName) { 848 checkNotClosed(); 849 invalidateV2Signature(); 850 if (!mV1SigningEnabled) { 851 return; 852 } 853 854 if (V1SchemeSigner.isJarEntryDigestNeededInManifest(entryName)) { 855 // This entry is covered by v1 signature. 856 invalidateV1Signature(); 857 mOutputJarEntryDigests.remove(entryName); 858 mOutputJarEntryDigestRequests.remove(entryName); 859 mOutputSignatureJarEntryDataRequests.remove(entryName); 860 return; 861 } 862 863 if (mSignatureExpectedOutputJarEntryNames.contains(entryName)) { 864 // This entry is part of the v1 signature generated by this engine. 865 invalidateV1Signature(); 866 return; 867 } 868 } 869 870 @Override outputJarEntries()871 public OutputJarSignatureRequest outputJarEntries() 872 throws ApkFormatException, InvalidKeyException, SignatureException, 873 NoSuchAlgorithmException { 874 checkNotClosed(); 875 876 if (!mV1SignaturePending) { 877 return null; 878 } 879 880 if ((mInputJarManifestEntryDataRequest != null) 881 && (!mInputJarManifestEntryDataRequest.isDone())) { 882 throw new IllegalStateException( 883 "Still waiting to inspect input APK's " 884 + mInputJarManifestEntryDataRequest.getEntryName()); 885 } 886 887 for (GetJarEntryDataDigestRequest digestRequest : mOutputJarEntryDigestRequests.values()) { 888 String entryName = digestRequest.getEntryName(); 889 if (!digestRequest.isDone()) { 890 throw new IllegalStateException( 891 "Still waiting to inspect output APK's " + entryName); 892 } 893 mOutputJarEntryDigests.put(entryName, digestRequest.getDigest()); 894 } 895 if (isEligibleForSourceStamp()) { 896 MessageDigest messageDigest = 897 MessageDigest.getInstance( 898 V1SchemeSigner.getJcaMessageDigestAlgorithm(mV1ContentDigestAlgorithm)); 899 messageDigest.update(generateSourceStampCertificateDigest()); 900 mOutputJarEntryDigests.put( 901 SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME, messageDigest.digest()); 902 } 903 mOutputJarEntryDigestRequests.clear(); 904 905 for (GetJarEntryDataRequest dataRequest : mOutputSignatureJarEntryDataRequests.values()) { 906 if (!dataRequest.isDone()) { 907 throw new IllegalStateException( 908 "Still waiting to inspect output APK's " + dataRequest.getEntryName()); 909 } 910 } 911 912 List<Integer> apkSigningSchemeIds = new ArrayList<>(); 913 if (mV2SigningEnabled) { 914 apkSigningSchemeIds.add(ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2); 915 } 916 if (mV3SigningEnabled) { 917 apkSigningSchemeIds.add(ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3); 918 } 919 byte[] inputJarManifest = 920 (mInputJarManifestEntryDataRequest != null) 921 ? mInputJarManifestEntryDataRequest.getData() 922 : null; 923 if (isEligibleForSourceStamp()) { 924 inputJarManifest = 925 V1SchemeSigner.generateManifestFile( 926 mV1ContentDigestAlgorithm, 927 mOutputJarEntryDigests, 928 inputJarManifest) 929 .contents; 930 } 931 932 // Check whether the most recently used signature (if present) is still fine. 933 checkOutputApkNotDebuggableIfDebuggableMustBeRejected(); 934 List<Pair<String, byte[]>> signatureZipEntries; 935 if ((mAddV1SignatureRequest == null) || (!mAddV1SignatureRequest.isDone())) { 936 try { 937 signatureZipEntries = 938 V1SchemeSigner.sign( 939 mV1SignerConfigs, 940 mV1ContentDigestAlgorithm, 941 mOutputJarEntryDigests, 942 apkSigningSchemeIds, 943 inputJarManifest, 944 mCreatedBy); 945 } catch (CertificateException e) { 946 throw new SignatureException("Failed to generate v1 signature", e); 947 } 948 } else { 949 V1SchemeSigner.OutputManifestFile newManifest = 950 V1SchemeSigner.generateManifestFile( 951 mV1ContentDigestAlgorithm, mOutputJarEntryDigests, inputJarManifest); 952 byte[] emittedSignatureManifest = 953 mEmittedSignatureJarEntryData.get(V1SchemeConstants.MANIFEST_ENTRY_NAME); 954 if (!Arrays.equals(newManifest.contents, emittedSignatureManifest)) { 955 // Emitted v1 signature is no longer valid. 956 try { 957 signatureZipEntries = 958 V1SchemeSigner.signManifest( 959 mV1SignerConfigs, 960 mV1ContentDigestAlgorithm, 961 apkSigningSchemeIds, 962 mCreatedBy, 963 newManifest); 964 } catch (CertificateException e) { 965 throw new SignatureException("Failed to generate v1 signature", e); 966 } 967 } else { 968 // Emitted v1 signature is still valid. Check whether the signature is there in the 969 // output. 970 signatureZipEntries = new ArrayList<>(); 971 for (Map.Entry<String, byte[]> expectedOutputEntry : 972 mEmittedSignatureJarEntryData.entrySet()) { 973 String entryName = expectedOutputEntry.getKey(); 974 byte[] expectedData = expectedOutputEntry.getValue(); 975 GetJarEntryDataRequest actualDataRequest = 976 mOutputSignatureJarEntryDataRequests.get(entryName); 977 if (actualDataRequest == null) { 978 // This signature entry hasn't been output. 979 signatureZipEntries.add(Pair.of(entryName, expectedData)); 980 continue; 981 } 982 byte[] actualData = actualDataRequest.getData(); 983 if (!Arrays.equals(expectedData, actualData)) { 984 signatureZipEntries.add(Pair.of(entryName, expectedData)); 985 } 986 } 987 if (signatureZipEntries.isEmpty()) { 988 // v1 signature in the output is valid 989 return null; 990 } 991 // v1 signature in the output is not valid. 992 } 993 } 994 995 if (signatureZipEntries.isEmpty()) { 996 // v1 signature in the output is valid 997 mV1SignaturePending = false; 998 return null; 999 } 1000 1001 List<OutputJarSignatureRequest.JarEntry> sigEntries = 1002 new ArrayList<>(signatureZipEntries.size()); 1003 for (Pair<String, byte[]> entry : signatureZipEntries) { 1004 String entryName = entry.getFirst(); 1005 byte[] entryData = entry.getSecond(); 1006 sigEntries.add(new OutputJarSignatureRequest.JarEntry(entryName, entryData)); 1007 mEmittedSignatureJarEntryData.put(entryName, entryData); 1008 } 1009 mAddV1SignatureRequest = new OutputJarSignatureRequestImpl(sigEntries); 1010 return mAddV1SignatureRequest; 1011 } 1012 1013 @Deprecated 1014 @Override outputZipSections( DataSource zipEntries, DataSource zipCentralDirectory, DataSource zipEocd)1015 public OutputApkSigningBlockRequest outputZipSections( 1016 DataSource zipEntries, DataSource zipCentralDirectory, DataSource zipEocd) 1017 throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException { 1018 return outputZipSectionsInternal(zipEntries, zipCentralDirectory, zipEocd, false); 1019 } 1020 1021 @Override outputZipSections2( DataSource zipEntries, DataSource zipCentralDirectory, DataSource zipEocd)1022 public OutputApkSigningBlockRequest2 outputZipSections2( 1023 DataSource zipEntries, DataSource zipCentralDirectory, DataSource zipEocd) 1024 throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException { 1025 return outputZipSectionsInternal(zipEntries, zipCentralDirectory, zipEocd, true); 1026 } 1027 outputZipSectionsInternal( DataSource zipEntries, DataSource zipCentralDirectory, DataSource zipEocd, boolean apkSigningBlockPaddingSupported)1028 private OutputApkSigningBlockRequestImpl outputZipSectionsInternal( 1029 DataSource zipEntries, 1030 DataSource zipCentralDirectory, 1031 DataSource zipEocd, 1032 boolean apkSigningBlockPaddingSupported) 1033 throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException { 1034 checkNotClosed(); 1035 checkV1SigningDoneIfEnabled(); 1036 if (!mV2SigningEnabled && !mV3SigningEnabled && !isEligibleForSourceStamp()) { 1037 return null; 1038 } 1039 checkOutputApkNotDebuggableIfDebuggableMustBeRejected(); 1040 1041 // adjust to proper padding 1042 Pair<DataSource, Integer> paddingPair = 1043 ApkSigningBlockUtils.generateApkSigningBlockPadding( 1044 zipEntries, apkSigningBlockPaddingSupported); 1045 DataSource beforeCentralDir = paddingPair.getFirst(); 1046 int padSizeBeforeApkSigningBlock = paddingPair.getSecond(); 1047 DataSource eocd = ApkSigningBlockUtils.copyWithModifiedCDOffset(beforeCentralDir, zipEocd); 1048 1049 List<Pair<byte[], Integer>> signingSchemeBlocks = new ArrayList<>(); 1050 ApkSigningBlockUtils.SigningSchemeBlockAndDigests v2SigningSchemeBlockAndDigests = null; 1051 ApkSigningBlockUtils.SigningSchemeBlockAndDigests v3SigningSchemeBlockAndDigests = null; 1052 // If the engine is configured to preserve previous signature blocks and any were found in 1053 // the existing APK signing block then add them to the list to be used to generate the 1054 // new APK signing block. 1055 if (mOtherSignersSignaturesPreserved && mPreservedSignatureBlocks != null 1056 && !mPreservedSignatureBlocks.isEmpty()) { 1057 signingSchemeBlocks.addAll(mPreservedSignatureBlocks); 1058 } 1059 1060 // create APK Signature Scheme V2 Signature if requested 1061 if (mV2SigningEnabled) { 1062 invalidateV2Signature(); 1063 List<ApkSigningBlockUtils.SignerConfig> v2SignerConfigs = 1064 createV2SignerConfigs(apkSigningBlockPaddingSupported); 1065 v2SigningSchemeBlockAndDigests = 1066 V2SchemeSigner.generateApkSignatureSchemeV2Block( 1067 mExecutor, 1068 beforeCentralDir, 1069 zipCentralDirectory, 1070 eocd, 1071 v2SignerConfigs, 1072 mV3SigningEnabled, 1073 mOtherSignersSignaturesPreserved ? mPreservedV2Signers : null); 1074 signingSchemeBlocks.add(v2SigningSchemeBlockAndDigests.signingSchemeBlock); 1075 } 1076 if (mV3SigningEnabled) { 1077 invalidateV3Signature(); 1078 List<ApkSigningBlockUtils.SignerConfig> v3SignerConfigs = 1079 createV3SignerConfigs(apkSigningBlockPaddingSupported); 1080 List<ApkSigningBlockUtils.SignerConfig> v31SignerConfigs = processV31SignerConfigs( 1081 v3SignerConfigs); 1082 if (v31SignerConfigs != null && v31SignerConfigs.size() > 0) { 1083 ApkSigningBlockUtils.SigningSchemeBlockAndDigests 1084 v31SigningSchemeBlockAndDigests = 1085 new V3SchemeSigner.Builder(beforeCentralDir, zipCentralDirectory, eocd, 1086 v31SignerConfigs) 1087 .setRunnablesExecutor(mExecutor) 1088 .setBlockId(V3SchemeConstants.APK_SIGNATURE_SCHEME_V31_BLOCK_ID) 1089 .build() 1090 .generateApkSignatureSchemeV3BlockAndDigests(); 1091 signingSchemeBlocks.add(v31SigningSchemeBlockAndDigests.signingSchemeBlock); 1092 } 1093 V3SchemeSigner.Builder builder = new V3SchemeSigner.Builder(beforeCentralDir, 1094 zipCentralDirectory, eocd, v3SignerConfigs) 1095 .setRunnablesExecutor(mExecutor) 1096 .setBlockId(V3SchemeConstants.APK_SIGNATURE_SCHEME_V3_BLOCK_ID); 1097 if (v31SignerConfigs != null && !v31SignerConfigs.isEmpty()) { 1098 // The V3.1 stripping protection writes the minimum SDK version from the targeted 1099 // signers as an additional attribute in the V3.0 signing block. 1100 int minSdkVersionForV31 = v31SignerConfigs.stream().mapToInt( 1101 signer -> signer.minSdkVersion).min().orElse(MIN_SDK_WITH_V31_SUPPORT); 1102 builder.setMinSdkVersionForV31(minSdkVersionForV31); 1103 } 1104 v3SigningSchemeBlockAndDigests = 1105 builder.build().generateApkSignatureSchemeV3BlockAndDigests(); 1106 signingSchemeBlocks.add(v3SigningSchemeBlockAndDigests.signingSchemeBlock); 1107 } 1108 if (isEligibleForSourceStamp()) { 1109 ApkSigningBlockUtils.SignerConfig sourceStampSignerConfig = 1110 createSourceStampSignerConfig(); 1111 Map<Integer, Map<ContentDigestAlgorithm, byte[]>> signatureSchemeDigestInfos = 1112 new HashMap<>(); 1113 if (mV3SigningEnabled) { 1114 signatureSchemeDigestInfos.put( 1115 VERSION_APK_SIGNATURE_SCHEME_V3, v3SigningSchemeBlockAndDigests.digestInfo); 1116 } 1117 if (mV2SigningEnabled) { 1118 signatureSchemeDigestInfos.put( 1119 VERSION_APK_SIGNATURE_SCHEME_V2, v2SigningSchemeBlockAndDigests.digestInfo); 1120 } 1121 if (mV1SigningEnabled) { 1122 Map<ContentDigestAlgorithm, byte[]> v1SigningSchemeDigests = new HashMap<>(); 1123 try { 1124 // Jar signing related variables must have been already populated at this point 1125 // if V1 signing is enabled since it is happening before computations on the APK 1126 // signing block (V2/V3/V4/SourceStamp signing). 1127 byte[] inputJarManifest = 1128 (mInputJarManifestEntryDataRequest != null) 1129 ? mInputJarManifestEntryDataRequest.getData() 1130 : null; 1131 byte[] jarManifest = 1132 V1SchemeSigner.generateManifestFile( 1133 mV1ContentDigestAlgorithm, 1134 mOutputJarEntryDigests, 1135 inputJarManifest) 1136 .contents; 1137 // The digest of the jar manifest does not need to be computed in chunks due to 1138 // the small size of the manifest. 1139 v1SigningSchemeDigests.put( 1140 ContentDigestAlgorithm.SHA256, computeSha256DigestBytes(jarManifest)); 1141 } catch (ApkFormatException e) { 1142 throw new RuntimeException("Failed to generate manifest file", e); 1143 } 1144 signatureSchemeDigestInfos.put( 1145 VERSION_JAR_SIGNATURE_SCHEME, v1SigningSchemeDigests); 1146 } 1147 V2SourceStampSigner v2SourceStampSigner = 1148 new V2SourceStampSigner.Builder(sourceStampSignerConfig, 1149 signatureSchemeDigestInfos) 1150 .setSourceStampTimestampEnabled(mSourceStampTimestampEnabled) 1151 .build(); 1152 signingSchemeBlocks.add(v2SourceStampSigner.generateSourceStampBlock()); 1153 } 1154 1155 // create APK Signing Block with v2 and/or v3 and/or SourceStamp blocks 1156 byte[] apkSigningBlock = ApkSigningBlockUtils.generateApkSigningBlock(signingSchemeBlocks); 1157 1158 mAddSigningBlockRequest = 1159 new OutputApkSigningBlockRequestImpl(apkSigningBlock, padSizeBeforeApkSigningBlock); 1160 return mAddSigningBlockRequest; 1161 } 1162 1163 @Override outputDone()1164 public void outputDone() { 1165 checkNotClosed(); 1166 checkV1SigningDoneIfEnabled(); 1167 checkSigningBlockDoneIfEnabled(); 1168 } 1169 1170 @Override signV4(DataSource dataSource, File outputFile, boolean ignoreFailures)1171 public void signV4(DataSource dataSource, File outputFile, boolean ignoreFailures) 1172 throws SignatureException { 1173 if (outputFile == null) { 1174 if (ignoreFailures) { 1175 return; 1176 } 1177 throw new SignatureException("Missing V4 output file."); 1178 } 1179 try { 1180 V4SchemeSigner.SignerConfig v4SignerConfig = createV4SignerConfig(); 1181 V4SchemeSigner.generateV4Signature(dataSource, v4SignerConfig, outputFile); 1182 } catch (InvalidKeyException | IOException | NoSuchAlgorithmException e) { 1183 if (ignoreFailures) { 1184 return; 1185 } 1186 throw new SignatureException("V4 signing failed", e); 1187 } 1188 } 1189 1190 /** For external use only to generate V4 & tree separately. */ produceV4Signature(DataSource dataSource, OutputStream sigOutput)1191 public byte[] produceV4Signature(DataSource dataSource, OutputStream sigOutput) 1192 throws SignatureException { 1193 if (sigOutput == null) { 1194 throw new SignatureException("Missing V4 output streams."); 1195 } 1196 try { 1197 V4SchemeSigner.SignerConfig v4SignerConfig = createV4SignerConfig(); 1198 Pair<V4Signature, byte[]> pair = 1199 V4SchemeSigner.generateV4Signature(dataSource, v4SignerConfig); 1200 pair.getFirst().writeTo(sigOutput); 1201 return pair.getSecond(); 1202 } catch (InvalidKeyException | IOException | NoSuchAlgorithmException e) { 1203 throw new SignatureException("V4 signing failed", e); 1204 } 1205 } 1206 1207 @Override isEligibleForSourceStamp()1208 public boolean isEligibleForSourceStamp() { 1209 return mSourceStampSignerConfig != null 1210 && (mV2SigningEnabled || mV3SigningEnabled || mV1SigningEnabled); 1211 } 1212 1213 @Override generateSourceStampCertificateDigest()1214 public byte[] generateSourceStampCertificateDigest() throws SignatureException { 1215 if (mSourceStampSignerConfig.getCertificates().isEmpty()) { 1216 throw new SignatureException("No certificates configured for stamp"); 1217 } 1218 try { 1219 return computeSha256DigestBytes( 1220 mSourceStampSignerConfig.getCertificates().get(0).getEncoded()); 1221 } catch (CertificateEncodingException e) { 1222 throw new SignatureException("Failed to encode source stamp certificate", e); 1223 } 1224 } 1225 1226 @Override close()1227 public void close() { 1228 mClosed = true; 1229 1230 mAddV1SignatureRequest = null; 1231 mInputJarManifestEntryDataRequest = null; 1232 mOutputAndroidManifestEntryDataRequest = null; 1233 mDebuggable = null; 1234 mOutputJarEntryDigestRequests.clear(); 1235 mOutputJarEntryDigests.clear(); 1236 mEmittedSignatureJarEntryData.clear(); 1237 mOutputSignatureJarEntryDataRequests.clear(); 1238 1239 mAddSigningBlockRequest = null; 1240 } 1241 invalidateV1Signature()1242 private void invalidateV1Signature() { 1243 if (mV1SigningEnabled) { 1244 mV1SignaturePending = true; 1245 } 1246 invalidateV2Signature(); 1247 } 1248 invalidateV2Signature()1249 private void invalidateV2Signature() { 1250 if (mV2SigningEnabled) { 1251 mV2SignaturePending = true; 1252 mAddSigningBlockRequest = null; 1253 } 1254 } 1255 invalidateV3Signature()1256 private void invalidateV3Signature() { 1257 if (mV3SigningEnabled) { 1258 mV3SignaturePending = true; 1259 mAddSigningBlockRequest = null; 1260 } 1261 } 1262 checkNotClosed()1263 private void checkNotClosed() { 1264 if (mClosed) { 1265 throw new IllegalStateException("Engine closed"); 1266 } 1267 } 1268 checkV1SigningDoneIfEnabled()1269 private void checkV1SigningDoneIfEnabled() { 1270 if (!mV1SignaturePending) { 1271 return; 1272 } 1273 1274 if (mAddV1SignatureRequest == null) { 1275 throw new IllegalStateException( 1276 "v1 signature (JAR signature) not yet generated. Skipped outputJarEntries()?"); 1277 } 1278 if (!mAddV1SignatureRequest.isDone()) { 1279 throw new IllegalStateException( 1280 "v1 signature (JAR signature) addition requested by outputJarEntries() hasn't" 1281 + " been fulfilled"); 1282 } 1283 for (Map.Entry<String, byte[]> expectedOutputEntry : 1284 mEmittedSignatureJarEntryData.entrySet()) { 1285 String entryName = expectedOutputEntry.getKey(); 1286 byte[] expectedData = expectedOutputEntry.getValue(); 1287 GetJarEntryDataRequest actualDataRequest = 1288 mOutputSignatureJarEntryDataRequests.get(entryName); 1289 if (actualDataRequest == null) { 1290 throw new IllegalStateException( 1291 "APK entry " 1292 + entryName 1293 + " not yet output despite this having been" 1294 + " requested"); 1295 } else if (!actualDataRequest.isDone()) { 1296 throw new IllegalStateException( 1297 "Still waiting to inspect output APK's " + entryName); 1298 } 1299 byte[] actualData = actualDataRequest.getData(); 1300 if (!Arrays.equals(expectedData, actualData)) { 1301 throw new IllegalStateException( 1302 "Output APK entry " + entryName + " data differs from what was requested"); 1303 } 1304 } 1305 mV1SignaturePending = false; 1306 } 1307 checkSigningBlockDoneIfEnabled()1308 private void checkSigningBlockDoneIfEnabled() { 1309 if (!mV2SignaturePending && !mV3SignaturePending) { 1310 return; 1311 } 1312 if (mAddSigningBlockRequest == null) { 1313 throw new IllegalStateException( 1314 "Signed APK Signing BLock not yet generated. Skipped outputZipSections()?"); 1315 } 1316 if (!mAddSigningBlockRequest.isDone()) { 1317 throw new IllegalStateException( 1318 "APK Signing Block addition of signature(s) requested by" 1319 + " outputZipSections() hasn't been fulfilled yet"); 1320 } 1321 mAddSigningBlockRequest = null; 1322 mV2SignaturePending = false; 1323 mV3SignaturePending = false; 1324 } 1325 checkOutputApkNotDebuggableIfDebuggableMustBeRejected()1326 private void checkOutputApkNotDebuggableIfDebuggableMustBeRejected() throws SignatureException { 1327 if (mDebuggableApkPermitted) { 1328 return; 1329 } 1330 1331 try { 1332 if (isOutputApkDebuggable()) { 1333 throw new SignatureException( 1334 "APK is debuggable (see android:debuggable attribute) and this engine is" 1335 + " configured to refuse to sign debuggable APKs"); 1336 } 1337 } catch (ApkFormatException e) { 1338 throw new SignatureException("Failed to determine whether the APK is debuggable", e); 1339 } 1340 } 1341 1342 /** 1343 * Returns whether the output APK is debuggable according to its {@code android:debuggable} 1344 * declaration. 1345 */ isOutputApkDebuggable()1346 private boolean isOutputApkDebuggable() throws ApkFormatException { 1347 if (mDebuggable != null) { 1348 return mDebuggable; 1349 } 1350 1351 if (mOutputAndroidManifestEntryDataRequest == null) { 1352 throw new IllegalStateException( 1353 "Cannot determine debuggable status of output APK because " 1354 + ApkUtils.ANDROID_MANIFEST_ZIP_ENTRY_NAME 1355 + " entry contents have not yet been requested"); 1356 } 1357 1358 if (!mOutputAndroidManifestEntryDataRequest.isDone()) { 1359 throw new IllegalStateException( 1360 "Still waiting to inspect output APK's " 1361 + mOutputAndroidManifestEntryDataRequest.getEntryName()); 1362 } 1363 mDebuggable = 1364 ApkUtils.getDebuggableFromBinaryAndroidManifest( 1365 ByteBuffer.wrap(mOutputAndroidManifestEntryDataRequest.getData())); 1366 return mDebuggable; 1367 } 1368 forgetOutputApkDebuggableStatus()1369 private void forgetOutputApkDebuggableStatus() { 1370 mDebuggable = null; 1371 } 1372 1373 /** Returns the output policy for the provided input JAR entry. */ getInputJarEntryOutputPolicy(String entryName)1374 private InputJarEntryInstructions.OutputPolicy getInputJarEntryOutputPolicy(String entryName) { 1375 if (mSignatureExpectedOutputJarEntryNames.contains(entryName)) { 1376 return InputJarEntryInstructions.OutputPolicy.OUTPUT_BY_ENGINE; 1377 } 1378 if ((mOtherSignersSignaturesPreserved) 1379 || (V1SchemeSigner.isJarEntryDigestNeededInManifest(entryName))) { 1380 return InputJarEntryInstructions.OutputPolicy.OUTPUT; 1381 } 1382 return InputJarEntryInstructions.OutputPolicy.SKIP; 1383 } 1384 1385 private static class OutputJarSignatureRequestImpl implements OutputJarSignatureRequest { 1386 private final List<JarEntry> mAdditionalJarEntries; 1387 private volatile boolean mDone; 1388 OutputJarSignatureRequestImpl(List<JarEntry> additionalZipEntries)1389 private OutputJarSignatureRequestImpl(List<JarEntry> additionalZipEntries) { 1390 mAdditionalJarEntries = 1391 Collections.unmodifiableList(new ArrayList<>(additionalZipEntries)); 1392 } 1393 1394 @Override getAdditionalJarEntries()1395 public List<JarEntry> getAdditionalJarEntries() { 1396 return mAdditionalJarEntries; 1397 } 1398 1399 @Override done()1400 public void done() { 1401 mDone = true; 1402 } 1403 isDone()1404 private boolean isDone() { 1405 return mDone; 1406 } 1407 } 1408 1409 @SuppressWarnings("deprecation") 1410 private static class OutputApkSigningBlockRequestImpl 1411 implements OutputApkSigningBlockRequest, OutputApkSigningBlockRequest2 { 1412 private final byte[] mApkSigningBlock; 1413 private final int mPaddingBeforeApkSigningBlock; 1414 private volatile boolean mDone; 1415 OutputApkSigningBlockRequestImpl(byte[] apkSigingBlock, int paddingBefore)1416 private OutputApkSigningBlockRequestImpl(byte[] apkSigingBlock, int paddingBefore) { 1417 mApkSigningBlock = apkSigingBlock.clone(); 1418 mPaddingBeforeApkSigningBlock = paddingBefore; 1419 } 1420 1421 @Override getApkSigningBlock()1422 public byte[] getApkSigningBlock() { 1423 return mApkSigningBlock.clone(); 1424 } 1425 1426 @Override done()1427 public void done() { 1428 mDone = true; 1429 } 1430 isDone()1431 private boolean isDone() { 1432 return mDone; 1433 } 1434 1435 @Override getPaddingSizeBeforeApkSigningBlock()1436 public int getPaddingSizeBeforeApkSigningBlock() { 1437 return mPaddingBeforeApkSigningBlock; 1438 } 1439 } 1440 1441 /** JAR entry inspection request which obtain the entry's uncompressed data. */ 1442 private static class GetJarEntryDataRequest implements InspectJarEntryRequest { 1443 private final String mEntryName; 1444 private final Object mLock = new Object(); 1445 1446 private boolean mDone; 1447 private DataSink mDataSink; 1448 private ByteArrayOutputStream mDataSinkBuf; 1449 GetJarEntryDataRequest(String entryName)1450 private GetJarEntryDataRequest(String entryName) { 1451 mEntryName = entryName; 1452 } 1453 1454 @Override getEntryName()1455 public String getEntryName() { 1456 return mEntryName; 1457 } 1458 1459 @Override getDataSink()1460 public DataSink getDataSink() { 1461 synchronized (mLock) { 1462 checkNotDone(); 1463 if (mDataSinkBuf == null) { 1464 mDataSinkBuf = new ByteArrayOutputStream(); 1465 } 1466 if (mDataSink == null) { 1467 mDataSink = DataSinks.asDataSink(mDataSinkBuf); 1468 } 1469 return mDataSink; 1470 } 1471 } 1472 1473 @Override done()1474 public void done() { 1475 synchronized (mLock) { 1476 if (mDone) { 1477 return; 1478 } 1479 mDone = true; 1480 } 1481 } 1482 isDone()1483 private boolean isDone() { 1484 synchronized (mLock) { 1485 return mDone; 1486 } 1487 } 1488 checkNotDone()1489 private void checkNotDone() throws IllegalStateException { 1490 synchronized (mLock) { 1491 if (mDone) { 1492 throw new IllegalStateException("Already done"); 1493 } 1494 } 1495 } 1496 getData()1497 private byte[] getData() { 1498 synchronized (mLock) { 1499 if (!mDone) { 1500 throw new IllegalStateException("Not yet done"); 1501 } 1502 return (mDataSinkBuf != null) ? mDataSinkBuf.toByteArray() : new byte[0]; 1503 } 1504 } 1505 } 1506 1507 /** JAR entry inspection request which obtains the digest of the entry's uncompressed data. */ 1508 private static class GetJarEntryDataDigestRequest implements InspectJarEntryRequest { 1509 private final String mEntryName; 1510 private final String mJcaDigestAlgorithm; 1511 private final Object mLock = new Object(); 1512 1513 private boolean mDone; 1514 private DataSink mDataSink; 1515 private MessageDigest mMessageDigest; 1516 private byte[] mDigest; 1517 GetJarEntryDataDigestRequest(String entryName, String jcaDigestAlgorithm)1518 private GetJarEntryDataDigestRequest(String entryName, String jcaDigestAlgorithm) { 1519 mEntryName = entryName; 1520 mJcaDigestAlgorithm = jcaDigestAlgorithm; 1521 } 1522 1523 @Override getEntryName()1524 public String getEntryName() { 1525 return mEntryName; 1526 } 1527 1528 @Override getDataSink()1529 public DataSink getDataSink() { 1530 synchronized (mLock) { 1531 checkNotDone(); 1532 if (mDataSink == null) { 1533 mDataSink = DataSinks.asDataSink(getMessageDigest()); 1534 } 1535 return mDataSink; 1536 } 1537 } 1538 getMessageDigest()1539 private MessageDigest getMessageDigest() { 1540 synchronized (mLock) { 1541 if (mMessageDigest == null) { 1542 try { 1543 mMessageDigest = MessageDigest.getInstance(mJcaDigestAlgorithm); 1544 } catch (NoSuchAlgorithmException e) { 1545 throw new RuntimeException( 1546 mJcaDigestAlgorithm + " MessageDigest not available", e); 1547 } 1548 } 1549 return mMessageDigest; 1550 } 1551 } 1552 1553 @Override done()1554 public void done() { 1555 synchronized (mLock) { 1556 if (mDone) { 1557 return; 1558 } 1559 mDone = true; 1560 mDigest = getMessageDigest().digest(); 1561 mMessageDigest = null; 1562 mDataSink = null; 1563 } 1564 } 1565 isDone()1566 private boolean isDone() { 1567 synchronized (mLock) { 1568 return mDone; 1569 } 1570 } 1571 checkNotDone()1572 private void checkNotDone() throws IllegalStateException { 1573 synchronized (mLock) { 1574 if (mDone) { 1575 throw new IllegalStateException("Already done"); 1576 } 1577 } 1578 } 1579 getDigest()1580 private byte[] getDigest() { 1581 synchronized (mLock) { 1582 if (!mDone) { 1583 throw new IllegalStateException("Not yet done"); 1584 } 1585 return mDigest.clone(); 1586 } 1587 } 1588 } 1589 1590 /** JAR entry inspection request which transparently satisfies multiple such requests. */ 1591 private static class CompoundInspectJarEntryRequest implements InspectJarEntryRequest { 1592 private final String mEntryName; 1593 private final InspectJarEntryRequest[] mRequests; 1594 private final Object mLock = new Object(); 1595 1596 private DataSink mSink; 1597 CompoundInspectJarEntryRequest( String entryName, InspectJarEntryRequest... requests)1598 private CompoundInspectJarEntryRequest( 1599 String entryName, InspectJarEntryRequest... requests) { 1600 mEntryName = entryName; 1601 mRequests = requests; 1602 } 1603 1604 @Override getEntryName()1605 public String getEntryName() { 1606 return mEntryName; 1607 } 1608 1609 @Override getDataSink()1610 public DataSink getDataSink() { 1611 synchronized (mLock) { 1612 if (mSink == null) { 1613 DataSink[] sinks = new DataSink[mRequests.length]; 1614 for (int i = 0; i < sinks.length; i++) { 1615 sinks[i] = mRequests[i].getDataSink(); 1616 } 1617 mSink = new TeeDataSink(sinks); 1618 } 1619 return mSink; 1620 } 1621 } 1622 1623 @Override done()1624 public void done() { 1625 for (InspectJarEntryRequest request : mRequests) { 1626 request.done(); 1627 } 1628 } 1629 } 1630 1631 /** 1632 * Configuration of a signer. 1633 * 1634 * <p>Use {@link Builder} to obtain configuration instances. 1635 */ 1636 public static class SignerConfig { 1637 private final String mName; 1638 private final KeyConfig mKeyConfig; 1639 private final List<X509Certificate> mCertificates; 1640 private final boolean mDeterministicDsaSigning; 1641 private final int mMinSdkVersion; 1642 private final boolean mSignerTargetsDevRelease; 1643 private final SigningCertificateLineage mSigningCertificateLineage; 1644 SignerConfig(Builder builder)1645 private SignerConfig(Builder builder) { 1646 mName = builder.mName; 1647 mKeyConfig = builder.mKeyConfig; 1648 mCertificates = Collections.unmodifiableList(new ArrayList<>(builder.mCertificates)); 1649 mDeterministicDsaSigning = builder.mDeterministicDsaSigning; 1650 mMinSdkVersion = builder.mMinSdkVersion; 1651 mSignerTargetsDevRelease = builder.mSignerTargetsDevRelease; 1652 mSigningCertificateLineage = builder.mSigningCertificateLineage; 1653 } 1654 1655 /** Returns the name of this signer. */ getName()1656 public String getName() { 1657 return mName; 1658 } 1659 1660 /** 1661 * Returns the signing key of this signer. 1662 * 1663 * @deprecated Use {@link #getKeyConfig()} instead of accessing a {@link PrivateKey} 1664 * directly. If the user of ApkSigner is signing with a KMS instead of JCA, this method 1665 * will return null. 1666 */ 1667 @Deprecated getPrivateKey()1668 public PrivateKey getPrivateKey() { 1669 return mKeyConfig.match(jca -> jca.privateKey, kms -> null); 1670 } 1671 getKeyConfig()1672 public KeyConfig getKeyConfig() { 1673 return mKeyConfig; 1674 } 1675 1676 /** 1677 * Returns the certificate(s) of this signer. The first certificate's public key corresponds 1678 * to this signer's private key. 1679 */ getCertificates()1680 public List<X509Certificate> getCertificates() { 1681 return mCertificates; 1682 } 1683 1684 /** 1685 * If this signer is a DSA signer, whether or not the signing is done deterministically. 1686 */ getDeterministicDsaSigning()1687 public boolean getDeterministicDsaSigning() { 1688 return mDeterministicDsaSigning; 1689 } 1690 1691 /** Returns the minimum SDK version for which this signer should be used. */ getMinSdkVersion()1692 public int getMinSdkVersion() { 1693 return mMinSdkVersion; 1694 } 1695 1696 /** Returns whether this signer targets a development release. */ getSignerTargetsDevRelease()1697 public boolean getSignerTargetsDevRelease() { 1698 return mSignerTargetsDevRelease; 1699 } 1700 1701 /** Returns the {@link SigningCertificateLineage} for this signer. */ getSigningCertificateLineage()1702 public SigningCertificateLineage getSigningCertificateLineage() { 1703 return mSigningCertificateLineage; 1704 } 1705 1706 /** Builder of {@link SignerConfig} instances. */ 1707 public static class Builder { 1708 private final String mName; 1709 private final KeyConfig mKeyConfig; 1710 private final List<X509Certificate> mCertificates; 1711 private final boolean mDeterministicDsaSigning; 1712 private int mMinSdkVersion; 1713 private boolean mSignerTargetsDevRelease; 1714 private SigningCertificateLineage mSigningCertificateLineage; 1715 1716 /** 1717 * Constructs a new {@code Builder}. 1718 * 1719 * @deprecated use {@link #Builder(String, KeyConfig, List)} instead 1720 * @param name signer's name. The name is reflected in the name of files comprising the 1721 * JAR signature of the APK. 1722 * @param privateKey signing key 1723 * @param certificates list of one or more X.509 certificates. The subject public key of 1724 * the first certificate must correspond to the {@code privateKey}. 1725 */ 1726 @Deprecated Builder(String name, PrivateKey privateKey, List<X509Certificate> certificates)1727 public Builder(String name, PrivateKey privateKey, List<X509Certificate> certificates) { 1728 this(name, privateKey, certificates, false); 1729 } 1730 1731 /** 1732 * Constructs a new {@code Builder}. 1733 * 1734 * @deprecated use {@link #Builder(String, KeyConfig, List, boolean)} instead 1735 * @param name signer's name. The name is reflected in the name of files comprising the 1736 * JAR signature of the APK. 1737 * @param privateKey signing key 1738 * @param certificates list of one or more X.509 certificates. The subject public key of 1739 * the first certificate must correspond to the {@code privateKey}. 1740 * @param deterministicDsaSigning When signing using DSA, whether or not the 1741 * deterministic signing algorithm variant (RFC6979) should be used. 1742 */ 1743 @Deprecated Builder( String name, PrivateKey privateKey, List<X509Certificate> certificates, boolean deterministicDsaSigning)1744 public Builder( 1745 String name, 1746 PrivateKey privateKey, 1747 List<X509Certificate> certificates, 1748 boolean deterministicDsaSigning) { 1749 if (name.isEmpty()) { 1750 throw new IllegalArgumentException("Empty name"); 1751 } 1752 mName = name; 1753 mKeyConfig = new KeyConfig.Jca(privateKey); 1754 mCertificates = new ArrayList<>(certificates); 1755 mDeterministicDsaSigning = deterministicDsaSigning; 1756 } 1757 1758 /** 1759 * Constructs a new {@code Builder}. 1760 * 1761 * @param name signer's name. The name is reflected in the name of files comprising the 1762 * JAR signature of the APK. 1763 * @param keyConfig signing key configuration. 1764 * @param certificates list of one or more X.509 certificates. The subject public key of 1765 * the first certificate must correspond to the {@code privateKey}. 1766 */ Builder(String name, KeyConfig keyConfig, List<X509Certificate> certificates)1767 public Builder(String name, KeyConfig keyConfig, List<X509Certificate> certificates) { 1768 this(name, keyConfig, certificates, false); 1769 } 1770 1771 /** 1772 * Constructs a new {@code Builder}. 1773 * 1774 * @param name signer's name. The name is reflected in the name of files comprising the 1775 * JAR signature of the APK. 1776 * @param keyConfig signing key configuration 1777 * @param certificates list of one or more X.509 certificates. The subject public key of 1778 * the first certificate must correspond to the {@code privateKey}. 1779 * @param deterministicDsaSigning When signing using DSA, whether or not the 1780 * deterministic signing algorithm variant (RFC6979) should be used. 1781 */ Builder( String name, KeyConfig keyConfig, List<X509Certificate> certificates, boolean deterministicDsaSigning)1782 public Builder( 1783 String name, 1784 KeyConfig keyConfig, 1785 List<X509Certificate> certificates, 1786 boolean deterministicDsaSigning) { 1787 if (name.isEmpty()) { 1788 throw new IllegalArgumentException("Empty name"); 1789 } 1790 mName = name; 1791 mKeyConfig = keyConfig; 1792 mCertificates = new ArrayList<>(certificates); 1793 mDeterministicDsaSigning = deterministicDsaSigning; 1794 } 1795 1796 /** @see #setLineageForMinSdkVersion(SigningCertificateLineage, int) */ setMinSdkVersion(int minSdkVersion)1797 public Builder setMinSdkVersion(int minSdkVersion) { 1798 return setLineageForMinSdkVersion(null, minSdkVersion); 1799 } 1800 1801 /** 1802 * Sets the specified {@code minSdkVersion} as the minimum Android platform version 1803 * (API level) for which the provided {@code lineage} (where applicable) should be used 1804 * to produce the APK's signature. This method is useful if callers want to specify a 1805 * particular rotated signer or lineage with restricted capabilities for later 1806 * platform releases. 1807 * 1808 * <p><em>Note:</em>>The V1 and V2 signature schemes do not support key rotation and 1809 * signing lineages with capabilities; only an app's original signer(s) can be used for 1810 * the V1 and V2 signature blocks. Because of this, only a value of {@code 1811 * minSdkVersion} >= 28 (Android P) where support for the V3 signature scheme was 1812 * introduced can be specified. 1813 * 1814 * <p><em>Note:</em>Due to limitations with platform targeting in the V3.0 signature 1815 * scheme, specifying a {@code minSdkVersion} value <= 32 (Android Sv2) will result in 1816 * the current {@code SignerConfig} being used in the V3.0 signing block and applied to 1817 * Android P through at least Sv2 (and later depending on the {@code minSdkVersion} for 1818 * subsequent {@code SignerConfig} instances). Because of this, only a single {@code 1819 * SignerConfig} can be instantiated with a minimum SDK version <= 32. 1820 * 1821 * @param lineage the {@code SigningCertificateLineage} to target the specified {@code 1822 * minSdkVersion} 1823 * @param minSdkVersion the minimum SDK version for which this {@code SignerConfig} 1824 * should be used 1825 * @return this {@code Builder} instance 1826 * 1827 * @throws IllegalArgumentException if the provided {@code minSdkVersion} < 28 or the 1828 * certificate provided in the constructor is not in the specified {@code lineage}. 1829 */ setLineageForMinSdkVersion(SigningCertificateLineage lineage, int minSdkVersion)1830 public Builder setLineageForMinSdkVersion(SigningCertificateLineage lineage, 1831 int minSdkVersion) { 1832 if (minSdkVersion < AndroidSdkVersion.P) { 1833 throw new IllegalArgumentException( 1834 "SDK targeted signing config is only supported with the V3 signature " 1835 + "scheme on Android P (SDK version " 1836 + AndroidSdkVersion.P + ") and later"); 1837 } 1838 if (minSdkVersion < MIN_SDK_WITH_V31_SUPPORT) { 1839 minSdkVersion = AndroidSdkVersion.P; 1840 } 1841 mMinSdkVersion = minSdkVersion; 1842 // If a lineage is provided, ensure the signing certificate for this signer is in 1843 // the lineage; in the case of multiple signing certificates, the first is always 1844 // used in the lineage. 1845 if (lineage != null && !lineage.isCertificateInLineage(mCertificates.get(0))) { 1846 throw new IllegalArgumentException( 1847 "The provided lineage does not contain the signing certificate, " 1848 + mCertificates.get(0).getSubjectDN() 1849 + ", for this SignerConfig"); 1850 } 1851 mSigningCertificateLineage = lineage; 1852 return this; 1853 } 1854 1855 /** 1856 * Sets whether this signer's min SDK version is intended to target a development 1857 * release. 1858 * 1859 * <p>This is primarily required for a signer testing on a platform's development 1860 * release; however, it is recommended that signer's use the latest development SDK 1861 * version instead of explicitly specifying this boolean. This class will properly 1862 * handle an SDK that is currently targeting a development release and will use the 1863 * finalized SDK version on release. 1864 */ setSignerTargetsDevRelease(boolean signerTargetsDevRelease)1865 private Builder setSignerTargetsDevRelease(boolean signerTargetsDevRelease) { 1866 if (signerTargetsDevRelease && mMinSdkVersion < MIN_SDK_WITH_V31_SUPPORT) { 1867 throw new IllegalArgumentException( 1868 "Rotation can only target a development release for signers targeting " 1869 + MIN_SDK_WITH_V31_SUPPORT + " or later"); 1870 } 1871 mSignerTargetsDevRelease = signerTargetsDevRelease; 1872 return this; 1873 } 1874 1875 1876 /** 1877 * Returns a new {@code SignerConfig} instance configured based on the configuration of 1878 * this builder. 1879 */ build()1880 public SignerConfig build() { 1881 return new SignerConfig(this); 1882 } 1883 } 1884 } 1885 1886 /** Builder of {@link DefaultApkSignerEngine} instances. */ 1887 public static class Builder { 1888 private List<SignerConfig> mSignerConfigs; 1889 private List<SignerConfig> mTargetedSignerConfigs; 1890 private SignerConfig mStampSignerConfig; 1891 private SigningCertificateLineage mSourceStampSigningCertificateLineage; 1892 private boolean mSourceStampTimestampEnabled = true; 1893 private final int mMinSdkVersion; 1894 1895 private boolean mV1SigningEnabled = true; 1896 private boolean mV2SigningEnabled = true; 1897 private boolean mV3SigningEnabled = true; 1898 private int mRotationMinSdkVersion = V3SchemeConstants.DEFAULT_ROTATION_MIN_SDK_VERSION; 1899 private boolean mRotationTargetsDevRelease = false; 1900 private boolean mVerityEnabled = false; 1901 private boolean mDebuggableApkPermitted = true; 1902 private boolean mOtherSignersSignaturesPreserved; 1903 private String mCreatedBy = "1.0 (Android)"; 1904 1905 private SigningCertificateLineage mSigningCertificateLineage; 1906 1907 // APK Signature Scheme v3 only supports a single signing certificate, so to move to v3 1908 // signing by default, but not require prior clients to update to explicitly disable v3 1909 // signing for multiple signers, we modify the mV3SigningEnabled depending on the provided 1910 // inputs (multiple signers and mSigningCertificateLineage in particular). Maintain two 1911 // extra variables to record whether or not mV3SigningEnabled has been set directly by a 1912 // client and so should override the default behavior. 1913 private boolean mV3SigningExplicitlyDisabled = false; 1914 private boolean mV3SigningExplicitlyEnabled = false; 1915 1916 /** 1917 * Constructs a new {@code Builder}. 1918 * 1919 * @param signerConfigs information about signers with which the APK will be signed. At 1920 * least one signer configuration must be provided. 1921 * @param minSdkVersion API Level of the oldest Android platform on which the APK is 1922 * supposed to be installed. See {@code minSdkVersion} attribute in the APK's {@code 1923 * AndroidManifest.xml}. The higher the version, the stronger signing features will be 1924 * enabled. 1925 */ Builder(List<SignerConfig> signerConfigs, int minSdkVersion)1926 public Builder(List<SignerConfig> signerConfigs, int minSdkVersion) { 1927 if (signerConfigs.isEmpty()) { 1928 throw new IllegalArgumentException("At least one signer config must be provided"); 1929 } 1930 if (signerConfigs.size() > 1) { 1931 // APK Signature Scheme v3 only supports single signer, unless a 1932 // SigningCertificateLineage is provided, in which case this will be reset to true, 1933 // since we don't yet have a v4 scheme about which to worry 1934 mV3SigningEnabled = false; 1935 } 1936 mSignerConfigs = new ArrayList<>(signerConfigs); 1937 mMinSdkVersion = minSdkVersion; 1938 } 1939 1940 /** 1941 * Sets the APK signature schemes that should be enabled based on the options provided by 1942 * the caller. 1943 */ setEnabledSignatureSchemes()1944 private void setEnabledSignatureSchemes() { 1945 if (mV3SigningExplicitlyDisabled && mV3SigningExplicitlyEnabled) { 1946 throw new IllegalStateException( 1947 "Builder configured to both enable and disable APK " 1948 + "Signature Scheme v3 signing"); 1949 } 1950 if (mV3SigningExplicitlyDisabled) { 1951 mV3SigningEnabled = false; 1952 } else if (mV3SigningExplicitlyEnabled) { 1953 mV3SigningEnabled = true; 1954 } 1955 } 1956 1957 /** 1958 * Sets the SDK targeted signer configs based on the signing config and rotation options 1959 * provided by the caller. 1960 * 1961 * @throws InvalidKeyException if a {@link SigningCertificateLineage} cannot be created 1962 * from the provided options 1963 */ setTargetedSignerConfigs()1964 private void setTargetedSignerConfigs() throws InvalidKeyException { 1965 // If the caller specified any SDK targeted signer configs, then the min SDK version 1966 // should be set for those configs, all others should have a default 0 min SDK version. 1967 mSignerConfigs.sort(((signerConfig1, signerConfig2) -> signerConfig1.getMinSdkVersion() 1968 - signerConfig2.getMinSdkVersion())); 1969 // With the signer configs sorted, find the first targeted signer config with a min 1970 // SDK version > 0 to create the separate targeted signer configs. 1971 mTargetedSignerConfigs = new ArrayList<>(); 1972 for (int i = 0; i < mSignerConfigs.size(); i++) { 1973 if (mSignerConfigs.get(i).getMinSdkVersion() > 0) { 1974 mTargetedSignerConfigs = mSignerConfigs.subList(i, mSignerConfigs.size()); 1975 mSignerConfigs = mSignerConfigs.subList(0, i); 1976 break; 1977 } 1978 } 1979 1980 // A lineage provided outside a targeted signing config is intended for the original 1981 // rotation; sort the untargeted signing configs based on this lineage and create a new 1982 // targeted signing config for the initial rotation. 1983 if (mSigningCertificateLineage != null) { 1984 if (!mTargetedSignerConfigs.isEmpty()) { 1985 // Only the initial rotation can use the rotation-min-sdk-version; all 1986 // subsequent targeted rotations must use targeted signing configs. 1987 int firstTargetedSdkVersion = mTargetedSignerConfigs.get(0).getMinSdkVersion(); 1988 if (mRotationMinSdkVersion >= firstTargetedSdkVersion) { 1989 throw new IllegalStateException( 1990 "The rotation-min-sdk-version, " + mRotationMinSdkVersion 1991 + ", must be less than the first targeted SDK version, " 1992 + firstTargetedSdkVersion); 1993 } 1994 } 1995 try { 1996 mSignerConfigs = mSigningCertificateLineage.sortSignerConfigs(mSignerConfigs); 1997 } catch (IllegalArgumentException e) { 1998 throw new IllegalStateException( 1999 "Provided signer configs do not match the " 2000 + "provided SigningCertificateLineage", 2001 e); 2002 } 2003 // Get the last signer in the lineage, create a new targeted signer from it, 2004 // and add it as a targeted signer config. 2005 SignerConfig rotatedSignerConfig = mSignerConfigs.remove(mSignerConfigs.size() - 1); 2006 SignerConfig.Builder rotatedConfigBuilder = 2007 new SignerConfig.Builder( 2008 rotatedSignerConfig.getName(), 2009 rotatedSignerConfig.getKeyConfig(), 2010 rotatedSignerConfig.getCertificates(), 2011 rotatedSignerConfig.getDeterministicDsaSigning()); 2012 rotatedConfigBuilder.setLineageForMinSdkVersion(mSigningCertificateLineage, 2013 mRotationMinSdkVersion); 2014 rotatedConfigBuilder.setSignerTargetsDevRelease(mRotationTargetsDevRelease); 2015 mTargetedSignerConfigs.add(0, rotatedConfigBuilder.build()); 2016 } 2017 mSigningCertificateLineage = mergeTargetedSigningConfigLineages(); 2018 } 2019 2020 /** 2021 * Merges and returns the lineages from any caller provided SDK targeted {@link 2022 * SignerConfig} instances with an optional {@code lineage} specified as part of the general 2023 * signing config. 2024 * 2025 * <p>If multiple signing configs target the same SDK version, or if any of the lineages 2026 * cannot be merged, then an {@code IllegalStateException} is thrown. 2027 */ mergeTargetedSigningConfigLineages()2028 private SigningCertificateLineage mergeTargetedSigningConfigLineages() 2029 throws InvalidKeyException { 2030 SigningCertificateLineage mergedLineage = null; 2031 int prevSdkVersion = 0; 2032 for (SignerConfig signerConfig : mTargetedSignerConfigs) { 2033 int signerMinSdkVersion = signerConfig.getMinSdkVersion(); 2034 if (signerMinSdkVersion < AndroidSdkVersion.P) { 2035 throw new IllegalStateException( 2036 "Targeted signing config is not supported prior to SDK version " 2037 + AndroidSdkVersion.P + "; received value " 2038 + signerMinSdkVersion); 2039 } 2040 SigningCertificateLineage signerLineage = 2041 signerConfig.getSigningCertificateLineage(); 2042 // It is possible for a lineage to be null if the user is using one of the 2043 // signers from the lineage as the only signer to target an SDK version; create 2044 // a single element lineage to verify the signer is part of the merged lineage. 2045 if (signerLineage == null) { 2046 try { 2047 signerLineage = 2048 new SigningCertificateLineage.Builder( 2049 new SigningCertificateLineage.SignerConfig.Builder( 2050 signerConfig.mKeyConfig, 2051 signerConfig.mCertificates.get(0)) 2052 .build()) 2053 .build(); 2054 } catch (CertificateEncodingException 2055 | NoSuchAlgorithmException 2056 | SignatureException e) { 2057 throw new IllegalStateException( 2058 "Unable to create a SignerConfig for signer from certificate " 2059 + signerConfig.mCertificates.get(0).getSubjectDN()); 2060 } 2061 } 2062 // The V3.0 signature scheme does not support verified targeted SDK signing 2063 // configs; if a signer is targeting any SDK version < T, then it will 2064 // target P with the V3.0 signature scheme. 2065 if (signerMinSdkVersion < AndroidSdkVersion.T) { 2066 signerMinSdkVersion = AndroidSdkVersion.P; 2067 } 2068 // Ensure there are no SignerConfigs targeting the same SDK version. 2069 if (signerMinSdkVersion == prevSdkVersion) { 2070 throw new IllegalStateException( 2071 "Multiple SignerConfigs were found targeting SDK version " 2072 + signerMinSdkVersion); 2073 } 2074 // If multiple lineages have been provided, then verify each subsequent lineage 2075 // is a valid descendant or ancestor of the previously merged lineages. 2076 if (mergedLineage == null) { 2077 mergedLineage = signerLineage; 2078 } else { 2079 try { 2080 mergedLineage = mergedLineage.mergeLineageWith(signerLineage); 2081 } catch (IllegalArgumentException e) { 2082 throw new IllegalStateException( 2083 "The provided lineage targeting SDK " + signerMinSdkVersion 2084 + " is not in the signing history of the other targeted " 2085 + "signing configs", e); 2086 } 2087 } 2088 prevSdkVersion = signerMinSdkVersion; 2089 } 2090 return mergedLineage; 2091 } 2092 2093 /** 2094 * Returns a new {@code DefaultApkSignerEngine} instance configured based on the 2095 * configuration of this builder. 2096 */ build()2097 public DefaultApkSignerEngine build() throws InvalidKeyException { 2098 setEnabledSignatureSchemes(); 2099 setTargetedSignerConfigs(); 2100 2101 // make sure our signers are appropriately setup 2102 if (mSigningCertificateLineage != null) { 2103 if (!mV3SigningEnabled && mSignerConfigs.size() > 1) { 2104 // this is a strange situation: we've provided a valid rotation history, but 2105 // are only signing with v1/v2. blow up, since we don't know for sure with 2106 // which signer the user intended to sign 2107 throw new IllegalStateException( 2108 "Provided multiple signers which are part of the" 2109 + " SigningCertificateLineage, but not signing with APK" 2110 + " Signature Scheme v3"); 2111 } 2112 } else if (mV3SigningEnabled && mSignerConfigs.size() > 1) { 2113 throw new IllegalStateException( 2114 "Multiple signing certificates provided for use with APK Signature Scheme" 2115 + " v3 without an accompanying SigningCertificateLineage"); 2116 } 2117 2118 return new DefaultApkSignerEngine( 2119 mSignerConfigs, 2120 mTargetedSignerConfigs, 2121 mStampSignerConfig, 2122 mSourceStampSigningCertificateLineage, 2123 mSourceStampTimestampEnabled, 2124 mMinSdkVersion, 2125 mV1SigningEnabled, 2126 mV2SigningEnabled, 2127 mV3SigningEnabled, 2128 mVerityEnabled, 2129 mDebuggableApkPermitted, 2130 mOtherSignersSignaturesPreserved, 2131 mCreatedBy, 2132 mSigningCertificateLineage); 2133 } 2134 2135 /** Sets the signer configuration for the SourceStamp to be embedded in the APK. */ setStampSignerConfig(SignerConfig stampSignerConfig)2136 public Builder setStampSignerConfig(SignerConfig stampSignerConfig) { 2137 mStampSignerConfig = stampSignerConfig; 2138 return this; 2139 } 2140 2141 /** 2142 * Sets the source stamp {@link SigningCertificateLineage}. This structure provides proof of 2143 * signing certificate rotation for certificates previously used to sign source stamps. 2144 */ setSourceStampSigningCertificateLineage( SigningCertificateLineage sourceStampSigningCertificateLineage)2145 public Builder setSourceStampSigningCertificateLineage( 2146 SigningCertificateLineage sourceStampSigningCertificateLineage) { 2147 mSourceStampSigningCertificateLineage = sourceStampSigningCertificateLineage; 2148 return this; 2149 } 2150 2151 /** 2152 * Sets whether the source stamp should contain the timestamp attribute with the time 2153 * at which the source stamp was signed. 2154 */ setSourceStampTimestampEnabled(boolean value)2155 public Builder setSourceStampTimestampEnabled(boolean value) { 2156 mSourceStampTimestampEnabled = value; 2157 return this; 2158 } 2159 2160 /** 2161 * Sets whether the APK should be signed using JAR signing (aka v1 signature scheme). 2162 * 2163 * <p>By default, the APK will be signed using this scheme. 2164 */ setV1SigningEnabled(boolean enabled)2165 public Builder setV1SigningEnabled(boolean enabled) { 2166 mV1SigningEnabled = enabled; 2167 return this; 2168 } 2169 2170 /** 2171 * Sets whether the APK should be signed using APK Signature Scheme v2 (aka v2 signature 2172 * scheme). 2173 * 2174 * <p>By default, the APK will be signed using this scheme. 2175 */ setV2SigningEnabled(boolean enabled)2176 public Builder setV2SigningEnabled(boolean enabled) { 2177 mV2SigningEnabled = enabled; 2178 return this; 2179 } 2180 2181 /** 2182 * Sets whether the APK should be signed using APK Signature Scheme v3 (aka v3 signature 2183 * scheme). 2184 * 2185 * <p>By default, the APK will be signed using this scheme. 2186 */ setV3SigningEnabled(boolean enabled)2187 public Builder setV3SigningEnabled(boolean enabled) { 2188 mV3SigningEnabled = enabled; 2189 if (enabled) { 2190 mV3SigningExplicitlyEnabled = true; 2191 } else { 2192 mV3SigningExplicitlyDisabled = true; 2193 } 2194 return this; 2195 } 2196 2197 /** 2198 * Sets whether the APK should be signed using the verity signature algorithm in the v2 and 2199 * v3 signature blocks. 2200 * 2201 * <p>By default, the APK will be signed using the verity signature algorithm for the v2 and 2202 * v3 signature schemes. 2203 */ setVerityEnabled(boolean enabled)2204 public Builder setVerityEnabled(boolean enabled) { 2205 mVerityEnabled = enabled; 2206 return this; 2207 } 2208 2209 /** 2210 * Sets whether the APK should be signed even if it is marked as debuggable ({@code 2211 * android:debuggable="true"} in its {@code AndroidManifest.xml}). For backward 2212 * compatibility reasons, the default value of this setting is {@code true}. 2213 * 2214 * <p>It is dangerous to sign debuggable APKs with production/release keys because Android 2215 * platform loosens security checks for such APKs. For example, arbitrary unauthorized code 2216 * may be executed in the context of such an app by anybody with ADB shell access. 2217 */ setDebuggableApkPermitted(boolean permitted)2218 public Builder setDebuggableApkPermitted(boolean permitted) { 2219 mDebuggableApkPermitted = permitted; 2220 return this; 2221 } 2222 2223 /** 2224 * Sets whether signatures produced by signers other than the ones configured in this engine 2225 * should be copied from the input APK to the output APK. 2226 * 2227 * <p>By default, signatures of other signers are omitted from the output APK. 2228 */ setOtherSignersSignaturesPreserved(boolean preserved)2229 public Builder setOtherSignersSignaturesPreserved(boolean preserved) { 2230 mOtherSignersSignaturesPreserved = preserved; 2231 return this; 2232 } 2233 2234 /** Sets the value of the {@code Created-By} field in JAR signature files. */ setCreatedBy(String createdBy)2235 public Builder setCreatedBy(String createdBy) { 2236 if (createdBy == null) { 2237 throw new NullPointerException(); 2238 } 2239 mCreatedBy = createdBy; 2240 return this; 2241 } 2242 2243 /** 2244 * Sets the {@link SigningCertificateLineage} to use with the v3 signature scheme. This 2245 * structure provides proof of signing certificate rotation linking {@link SignerConfig} 2246 * objects to previous ones. 2247 */ setSigningCertificateLineage( SigningCertificateLineage signingCertificateLineage)2248 public Builder setSigningCertificateLineage( 2249 SigningCertificateLineage signingCertificateLineage) { 2250 if (signingCertificateLineage != null) { 2251 mV3SigningEnabled = true; 2252 mSigningCertificateLineage = signingCertificateLineage; 2253 } 2254 return this; 2255 } 2256 2257 /** 2258 * Sets the minimum Android platform version (API Level) for which an APK's rotated signing 2259 * key should be used to produce the APK's signature. The original signing key for the APK 2260 * will be used for all previous platform versions. If a rotated key with signing lineage is 2261 * not provided then this method is a noop. 2262 * 2263 * <p>By default, if a signing lineage is specified with {@link 2264 * #setSigningCertificateLineage(SigningCertificateLineage)}, then the APK Signature Scheme 2265 * V3.1 will be used to only apply the rotation on devices running Android T+. 2266 * 2267 * <p><em>Note:</em>Specifying a {@code minSdkVersion} value <= 32 (Android Sv2) will result 2268 * in the original V3 signing block being used without platform targeting. 2269 */ setMinSdkVersionForRotation(int minSdkVersion)2270 public Builder setMinSdkVersionForRotation(int minSdkVersion) { 2271 // If the provided SDK version does not support v3.1, then use the default SDK version 2272 // with rotation support. 2273 if (minSdkVersion < MIN_SDK_WITH_V31_SUPPORT) { 2274 mRotationMinSdkVersion = MIN_SDK_WITH_V3_SUPPORT; 2275 } else { 2276 mRotationMinSdkVersion = minSdkVersion; 2277 } 2278 return this; 2279 } 2280 2281 /** 2282 * Sets whether the rotation-min-sdk-version is intended to target a development release; 2283 * this is primarily required after the T SDK is finalized, and an APK needs to target U 2284 * during its development cycle for rotation. 2285 * 2286 * <p>This is only required after the T SDK is finalized since S and earlier releases do 2287 * not know about the V3.1 block ID, but once T is released and work begins on U, U will 2288 * use the SDK version of T during development. Specifying a rotation-min-sdk-version of T's 2289 * SDK version along with setting {@code enabled} to true will allow an APK to use the 2290 * rotated key on a device running U while causing this to be bypassed for T. 2291 * 2292 * <p><em>Note:</em>If the rotation-min-sdk-version is less than or equal to 32 (Android 2293 * Sv2), then the rotated signing key will be used in the v3.0 signing block and this call 2294 * will be a noop. 2295 */ setRotationTargetsDevRelease(boolean enabled)2296 public Builder setRotationTargetsDevRelease(boolean enabled) { 2297 mRotationTargetsDevRelease = enabled; 2298 return this; 2299 } 2300 } 2301 } 2302