Home | History | Annotate | Download | only in apksig
      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 com.android.apksig.apk.ApkFormatException;
     20 import com.android.apksig.apk.ApkUtils;
     21 import com.android.apksig.internal.apk.ApkSigningBlockUtils;
     22 import com.android.apksig.internal.apk.SignatureAlgorithm;
     23 import com.android.apksig.internal.apk.v1.DigestAlgorithm;
     24 import com.android.apksig.internal.apk.v1.V1SchemeSigner;
     25 import com.android.apksig.internal.apk.v2.V2SchemeSigner;
     26 import com.android.apksig.internal.apk.v3.V3SchemeSigner;
     27 import com.android.apksig.internal.util.AndroidSdkVersion;
     28 import com.android.apksig.internal.util.Pair;
     29 import com.android.apksig.internal.util.TeeDataSink;
     30 import com.android.apksig.util.DataSink;
     31 import com.android.apksig.util.DataSinks;
     32 import com.android.apksig.util.DataSource;
     33 
     34 import java.io.ByteArrayOutputStream;
     35 import java.io.IOException;
     36 import java.nio.ByteBuffer;
     37 import java.security.InvalidKeyException;
     38 import java.security.MessageDigest;
     39 import java.security.NoSuchAlgorithmException;
     40 import java.security.PrivateKey;
     41 import java.security.PublicKey;
     42 import java.security.SignatureException;
     43 import java.security.cert.CertificateException;
     44 import java.security.cert.X509Certificate;
     45 import java.util.ArrayList;
     46 import java.util.Arrays;
     47 import java.util.Collections;
     48 import java.util.HashMap;
     49 import java.util.List;
     50 import java.util.Map;
     51 import java.util.Set;
     52 
     53 /**
     54  * Default implementation of {@link ApkSignerEngine}.
     55  *
     56  * <p>Use {@link Builder} to obtain instances of this engine.
     57  */
     58 public class DefaultApkSignerEngine implements ApkSignerEngine {
     59 
     60     // IMPLEMENTATION NOTE: This engine generates a signed APK as follows:
     61     // 1. The engine asks its client to output input JAR entries which are not part of JAR
     62     //    signature.
     63     // 2. If JAR signing (v1 signing) is enabled, the engine inspects the output JAR entries to
     64     //    compute their digests, to be placed into output META-INF/MANIFEST.MF. It also inspects
     65     //    the contents of input and output META-INF/MANIFEST.MF to borrow the main section of the
     66     //    file. It does not care about individual (i.e., JAR entry-specific) sections. It then
     67     //    emits the v1 signature (a set of JAR entries) and asks the client to output them.
     68     // 3. If APK Signature Scheme v2 (v2 signing) is enabled, the engine emits an APK Signing Block
     69     //    from outputZipSections() and asks its client to insert this block into the output.
     70     // 4. If APK Signature Scheme v3 (v3 signing) is enabled, the engine includes it in the APK
     71     //    Signing BLock output from outputZipSections() and asks its client to insert this block
     72     //    into the output.  If both v2 and v3 signing is enabled, they are both added to the APK
     73     //    Signing Block before asking the client to insert it into the output.
     74 
     75     private final boolean mV1SigningEnabled;
     76     private final boolean mV2SigningEnabled;
     77     private final boolean mV3SigningEnabled;
     78     private final boolean mDebuggableApkPermitted;
     79     private final boolean mOtherSignersSignaturesPreserved;
     80     private final String mCreatedBy;
     81     private final List<SignerConfig> mSignerConfigs;
     82     private final int mMinSdkVersion;
     83     private final SigningCertificateLineage mSigningCertificateLineage;
     84 
     85     private List<V1SchemeSigner.SignerConfig> mV1SignerConfigs = Collections.emptyList();
     86     private DigestAlgorithm mV1ContentDigestAlgorithm;
     87 
     88     private boolean mClosed;
     89 
     90     private boolean mV1SignaturePending;
     91 
     92     /**
     93      * Names of JAR entries which this engine is expected to output as part of v1 signing.
     94      */
     95     private Set<String> mSignatureExpectedOutputJarEntryNames = Collections.emptySet();
     96 
     97     /** Requests for digests of output JAR entries. */
     98     private final Map<String, GetJarEntryDataDigestRequest> mOutputJarEntryDigestRequests =
     99             new HashMap<>();
    100 
    101     /** Digests of output JAR entries. */
    102     private final Map<String, byte[]> mOutputJarEntryDigests = new HashMap<>();
    103 
    104     /** Data of JAR entries emitted by this engine as v1 signature. */
    105     private final Map<String, byte[]> mEmittedSignatureJarEntryData = new HashMap<>();
    106 
    107     /** Requests for data of output JAR entries which comprise the v1 signature. */
    108     private final Map<String, GetJarEntryDataRequest> mOutputSignatureJarEntryDataRequests =
    109             new HashMap<>();
    110     /**
    111      * Request to obtain the data of MANIFEST.MF or {@code null} if the request hasn't been issued.
    112      */
    113     private GetJarEntryDataRequest mInputJarManifestEntryDataRequest;
    114 
    115     /**
    116      * Request to obtain the data of AndroidManifest.xml or {@code null} if the request hasn't been
    117      * issued.
    118      */
    119     private GetJarEntryDataRequest mOutputAndroidManifestEntryDataRequest;
    120 
    121     /**
    122      * Whether the package being signed is marked as {@code android:debuggable} or {@code null}
    123      * if this is not yet known.
    124      */
    125     private Boolean mDebuggable;
    126 
    127     /**
    128      * Request to output the emitted v1 signature or {@code null} if the request hasn't been issued.
    129      */
    130     private OutputJarSignatureRequestImpl mAddV1SignatureRequest;
    131 
    132     private boolean mV2SignaturePending;
    133     private boolean mV3SignaturePending;
    134 
    135     /**
    136      * Request to output the emitted v2 and/or v3 signature(s) {@code null} if the request hasn't
    137      * been issued.
    138      */
    139     private OutputApkSigningBlockRequestImpl mAddSigningBlockRequest;
    140 
    141     private DefaultApkSignerEngine(
    142             List<SignerConfig> signerConfigs,
    143             int minSdkVersion,
    144             boolean v1SigningEnabled,
    145             boolean v2SigningEnabled,
    146             boolean v3SigningEnabled,
    147             boolean debuggableApkPermitted,
    148             boolean otherSignersSignaturesPreserved,
    149             String createdBy,
    150             SigningCertificateLineage signingCertificateLineage) throws InvalidKeyException {
    151         if (signerConfigs.isEmpty()) {
    152             throw new IllegalArgumentException("At least one signer config must be provided");
    153         }
    154         if (otherSignersSignaturesPreserved) {
    155             throw new UnsupportedOperationException(
    156                     "Preserving other signer's signatures is not yet implemented");
    157         }
    158 
    159         mV1SigningEnabled = v1SigningEnabled;
    160         mV2SigningEnabled = v2SigningEnabled;
    161         mV3SigningEnabled = v3SigningEnabled;
    162         mV1SignaturePending = v1SigningEnabled;
    163         mV2SignaturePending = v2SigningEnabled;
    164         mV3SignaturePending = v3SigningEnabled;
    165         mDebuggableApkPermitted = debuggableApkPermitted;
    166         mOtherSignersSignaturesPreserved = otherSignersSignaturesPreserved;
    167         mCreatedBy = createdBy;
    168         mSignerConfigs = signerConfigs;
    169         mMinSdkVersion = minSdkVersion;
    170         mSigningCertificateLineage = signingCertificateLineage;
    171 
    172         if (v1SigningEnabled) {
    173             if (v3SigningEnabled) {
    174 
    175                 // v3 signing only supports single signers, of which the oldest (first) will be the
    176                 // one to use for v1 and v2 signing
    177                 SignerConfig oldestConfig = signerConfigs.get(0);
    178 
    179                 // in the event of signing certificate changes, make sure we have the oldest in the
    180                 // signing history to sign with v1
    181                 if (signingCertificateLineage != null) {
    182                     SigningCertificateLineage subLineage =
    183                             signingCertificateLineage.getSubLineage(
    184                                     oldestConfig.mCertificates.get(0));
    185                     if (subLineage.size() != 1) {
    186                         throw new IllegalArgumentException(
    187                                 "v1 signing enabled but the oldest signer in the "
    188                                 + "SigningCertificateLineage is missing.  Please provide the oldest"
    189                                 + " signer to enable v1 signing");
    190                     }
    191                 }
    192                 createV1SignerConfigs(
    193                         Collections.singletonList(oldestConfig), minSdkVersion);
    194             } else {
    195                 createV1SignerConfigs(signerConfigs, minSdkVersion);
    196             }
    197         }
    198     }
    199 
    200     private void createV1SignerConfigs(List<SignerConfig> signerConfigs, int minSdkVersion)
    201             throws InvalidKeyException {
    202         mV1SignerConfigs = new ArrayList<>(signerConfigs.size());
    203         Map<String, Integer> v1SignerNameToSignerIndex = new HashMap<>(signerConfigs.size());
    204         DigestAlgorithm v1ContentDigestAlgorithm = null;
    205         for (int i = 0; i < signerConfigs.size(); i++) {
    206             SignerConfig signerConfig = signerConfigs.get(i);
    207             List<X509Certificate> certificates = signerConfig.getCertificates();
    208             PublicKey publicKey = certificates.get(0).getPublicKey();
    209 
    210             String v1SignerName = V1SchemeSigner.getSafeSignerName(signerConfig.getName());
    211             // Check whether the signer's name is unique among all v1 signers
    212             Integer indexOfOtherSignerWithSameName =
    213                     v1SignerNameToSignerIndex.put(v1SignerName, i);
    214             if (indexOfOtherSignerWithSameName != null) {
    215                 throw new IllegalArgumentException(
    216                         "Signers #" + (indexOfOtherSignerWithSameName + 1)
    217                         + " and #" + (i + 1)
    218                         + " have the same name: " + v1SignerName
    219                         + ". v1 signer names must be unique");
    220             }
    221 
    222             DigestAlgorithm v1SignatureDigestAlgorithm =
    223                     V1SchemeSigner.getSuggestedSignatureDigestAlgorithm(
    224                             publicKey, minSdkVersion);
    225             V1SchemeSigner.SignerConfig v1SignerConfig = new V1SchemeSigner.SignerConfig();
    226             v1SignerConfig.name = v1SignerName;
    227             v1SignerConfig.privateKey = signerConfig.getPrivateKey();
    228             v1SignerConfig.certificates = certificates;
    229             v1SignerConfig.signatureDigestAlgorithm = v1SignatureDigestAlgorithm;
    230             // For digesting contents of APK entries and of MANIFEST.MF, pick the algorithm
    231             // of comparable strength to the digest algorithm used for computing the signature.
    232             // When there are multiple signers, pick the strongest digest algorithm out of their
    233             // signature digest algorithms. This avoids reducing the digest strength used by any
    234             // of the signers to protect APK contents.
    235             if (v1ContentDigestAlgorithm == null) {
    236                 v1ContentDigestAlgorithm = v1SignatureDigestAlgorithm;
    237             } else {
    238                 if (DigestAlgorithm.BY_STRENGTH_COMPARATOR.compare(
    239                         v1SignatureDigestAlgorithm, v1ContentDigestAlgorithm) > 0) {
    240                     v1ContentDigestAlgorithm = v1SignatureDigestAlgorithm;
    241                 }
    242             }
    243             mV1SignerConfigs.add(v1SignerConfig);
    244         }
    245         mV1ContentDigestAlgorithm = v1ContentDigestAlgorithm;
    246         mSignatureExpectedOutputJarEntryNames =
    247                 V1SchemeSigner.getOutputEntryNames(mV1SignerConfigs);
    248     }
    249 
    250     private List<ApkSigningBlockUtils.SignerConfig> createV2SignerConfigs(
    251             boolean apkSigningBlockPaddingSupported) throws InvalidKeyException {
    252         if (mV3SigningEnabled) {
    253 
    254             // v3 signing only supports single signers, of which the oldest (first) will be the one
    255             // to use for v1 and v2 signing
    256             List<ApkSigningBlockUtils.SignerConfig> signerConfig =
    257                     new ArrayList<>();
    258 
    259             SignerConfig oldestConfig = mSignerConfigs.get(0);
    260 
    261             // first make sure that if we have signing certificate history that the oldest signer
    262             // corresponds to the oldest ancestor
    263             if (mSigningCertificateLineage != null) {
    264                 SigningCertificateLineage subLineage =
    265                         mSigningCertificateLineage.getSubLineage(oldestConfig.mCertificates.get(0));
    266                 if (subLineage.size() != 1) {
    267                     throw new IllegalArgumentException("v2 signing enabled but the oldest signer in"
    268                                     + " the SigningCertificateLineage is missing.  Please provide"
    269                                     + " the oldest signer to enable v2 signing.");
    270                 }
    271             }
    272             signerConfig.add(
    273                     createSigningBlockSignerConfig(
    274                             mSignerConfigs.get(0), apkSigningBlockPaddingSupported,
    275                             ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2));
    276             return signerConfig;
    277         } else {
    278             return createSigningBlockSignerConfigs(apkSigningBlockPaddingSupported,
    279                     ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2);
    280         }
    281     }
    282 
    283     private List<ApkSigningBlockUtils.SignerConfig> createV3SignerConfigs(
    284             boolean apkSigningBlockPaddingSupported) throws InvalidKeyException {
    285         List<ApkSigningBlockUtils.SignerConfig> rawConfigs =
    286                 createSigningBlockSignerConfigs(apkSigningBlockPaddingSupported,
    287                         ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3);
    288 
    289         List<ApkSigningBlockUtils.SignerConfig> processedConfigs = new ArrayList<>();
    290 
    291         // we have our configs, now touch them up to appropriately cover all SDK levels since APK
    292         // signature scheme v3 was introduced
    293         int currentMinSdk = Integer.MAX_VALUE;
    294         for (int i = rawConfigs.size() - 1; i >= 0; i--) {
    295             ApkSigningBlockUtils.SignerConfig config = rawConfigs.get(i);
    296             if (config.signatureAlgorithms == null) {
    297                 // no valid algorithm was found for this signer, and we haven't yet covered all
    298                 // platform versions, something's wrong
    299                 String keyAlgorithm = config.certificates.get(0).getPublicKey().getAlgorithm();
    300                 throw new InvalidKeyException("Unsupported key algorithm " + keyAlgorithm + " is "
    301                         + "not supported for APK Signature Scheme v3 signing");
    302             }
    303             if (i == rawConfigs.size() - 1) {
    304                 // first go through the loop, config should support all future platform versions.
    305                 // this assumes we don't deprecate support for signers in the future.  If we do,
    306                 // this needs to change
    307                 config.maxSdkVersion = Integer.MAX_VALUE;
    308             } else {
    309                 // otherwise, we only want to use this signer up to the minimum platform version
    310                 // on which a newer one is acceptable
    311                 config.maxSdkVersion = currentMinSdk - 1;
    312             }
    313             config.minSdkVersion = getMinSdkFromV3SignatureAlgorithms(config.signatureAlgorithms);
    314             if (mSigningCertificateLineage != null) {
    315                 config.mSigningCertificateLineage =
    316                         mSigningCertificateLineage.getSubLineage(config.certificates.get(0));
    317             }
    318             // we know that this config will be used, so add it to our result, order doesn't matter
    319             // at this point (and likely only one will be needed
    320             processedConfigs.add(config);
    321             currentMinSdk = config.minSdkVersion;
    322             if (currentMinSdk <= mMinSdkVersion || currentMinSdk <= AndroidSdkVersion.P) {
    323                 // this satisfies all we need, stop here
    324                 break;
    325             }
    326         }
    327         if (currentMinSdk > AndroidSdkVersion.P && currentMinSdk > mMinSdkVersion) {
    328             // we can't cover all desired SDK versions, abort
    329             throw new InvalidKeyException("Provided key algorithms not supported on all desired "
    330                     + "Android SDK versions");
    331         }
    332         return processedConfigs;
    333     }
    334 
    335     private int getMinSdkFromV3SignatureAlgorithms(List<SignatureAlgorithm> algorithms) {
    336         int min = Integer.MAX_VALUE;
    337         for (SignatureAlgorithm algorithm : algorithms) {
    338             int current = algorithm.getMinSdkVersion();
    339             if (current < min) {
    340                 if (current <= mMinSdkVersion || current <= AndroidSdkVersion.P) {
    341                     // this algorithm satisfies all of our needs, no need to keep looking
    342                     return current;
    343                 } else {
    344                     min = current;
    345                 }
    346             }
    347         }
    348         return min;
    349     }
    350 
    351     private List<ApkSigningBlockUtils.SignerConfig> createSigningBlockSignerConfigs(
    352             boolean apkSigningBlockPaddingSupported, int schemeId) throws InvalidKeyException {
    353         List<ApkSigningBlockUtils.SignerConfig> signerConfigs =
    354                 new ArrayList<>(mSignerConfigs.size());
    355         for (int i = 0; i < mSignerConfigs.size(); i++) {
    356             SignerConfig signerConfig = mSignerConfigs.get(i);
    357             signerConfigs.add(
    358                     createSigningBlockSignerConfig(
    359                             signerConfig, apkSigningBlockPaddingSupported, schemeId));
    360         }
    361         return signerConfigs;
    362     }
    363 
    364     private ApkSigningBlockUtils.SignerConfig createSigningBlockSignerConfig(
    365             SignerConfig signerConfig, boolean apkSigningBlockPaddingSupported, int schemeId)
    366                     throws InvalidKeyException {
    367         List<X509Certificate> certificates = signerConfig.getCertificates();
    368         PublicKey publicKey = certificates.get(0).getPublicKey();
    369 
    370         ApkSigningBlockUtils.SignerConfig newSignerConfig =
    371                 new ApkSigningBlockUtils.SignerConfig();
    372         newSignerConfig.privateKey = signerConfig.getPrivateKey();
    373         newSignerConfig.certificates = certificates;
    374 
    375         switch (schemeId) {
    376             case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2:
    377                 newSignerConfig.signatureAlgorithms =
    378                         V2SchemeSigner.getSuggestedSignatureAlgorithms(publicKey, mMinSdkVersion,
    379                                 apkSigningBlockPaddingSupported);
    380                 break;
    381             case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3:
    382                 try {
    383                     newSignerConfig.signatureAlgorithms =
    384                             V3SchemeSigner.getSuggestedSignatureAlgorithms(
    385                                     publicKey, mMinSdkVersion, apkSigningBlockPaddingSupported);
    386                 } catch (InvalidKeyException e) {
    387 
    388                     // It is possible for a signer used for v1/v2 signing to not be allowed for use
    389                     // with v3 signing.  This is ok as long as there exists a more recent v3 signer
    390                     // that covers all supported platform versions.  Populate signatureAlgorithm
    391                     // with null, it will be cleaned-up in a later step.
    392                     newSignerConfig.signatureAlgorithms = null;
    393                 }
    394                 break;
    395             default:
    396                 throw new IllegalArgumentException("Unknown APK Signature Scheme ID requested");
    397         }
    398         return newSignerConfig;
    399     }
    400 
    401     @Override
    402     public void inputApkSigningBlock(DataSource apkSigningBlock) {
    403         checkNotClosed();
    404 
    405         if ((apkSigningBlock == null) || (apkSigningBlock.size() == 0)) {
    406             return;
    407         }
    408 
    409         if (mOtherSignersSignaturesPreserved) {
    410             // TODO: Preserve blocks other than APK Signature Scheme v2 blocks of signers configured
    411             // in this engine.
    412             return;
    413         }
    414         // TODO: Preserve blocks other than APK Signature Scheme v2 blocks.
    415     }
    416 
    417     @Override
    418     public InputJarEntryInstructions inputJarEntry(String entryName) {
    419         checkNotClosed();
    420 
    421         InputJarEntryInstructions.OutputPolicy outputPolicy =
    422                 getInputJarEntryOutputPolicy(entryName);
    423         switch (outputPolicy) {
    424             case SKIP:
    425                 return new InputJarEntryInstructions(InputJarEntryInstructions.OutputPolicy.SKIP);
    426             case OUTPUT:
    427                 return new InputJarEntryInstructions(InputJarEntryInstructions.OutputPolicy.OUTPUT);
    428             case OUTPUT_BY_ENGINE:
    429                 if (V1SchemeSigner.MANIFEST_ENTRY_NAME.equals(entryName)) {
    430                     // We copy the main section of the JAR manifest from input to output. Thus, this
    431                     // invalidates v1 signature and we need to see the entry's data.
    432                     mInputJarManifestEntryDataRequest = new GetJarEntryDataRequest(entryName);
    433                     return new InputJarEntryInstructions(
    434                             InputJarEntryInstructions.OutputPolicy.OUTPUT_BY_ENGINE,
    435                             mInputJarManifestEntryDataRequest);
    436                 }
    437                 return new InputJarEntryInstructions(
    438                         InputJarEntryInstructions.OutputPolicy.OUTPUT_BY_ENGINE);
    439             default:
    440                 throw new RuntimeException("Unsupported output policy: " + outputPolicy);
    441         }
    442     }
    443 
    444     @Override
    445     public InspectJarEntryRequest outputJarEntry(String entryName) {
    446         checkNotClosed();
    447         invalidateV2Signature();
    448 
    449         if ((!mDebuggableApkPermitted)
    450                 && (ApkUtils.ANDROID_MANIFEST_ZIP_ENTRY_NAME.equals(entryName))) {
    451             forgetOutputApkDebuggableStatus();
    452         }
    453 
    454         if (!mV1SigningEnabled) {
    455             // No need to inspect JAR entries when v1 signing is not enabled.
    456             if ((!mDebuggableApkPermitted)
    457                     && (ApkUtils.ANDROID_MANIFEST_ZIP_ENTRY_NAME.equals(entryName))) {
    458                 // To reject debuggable APKs we need to inspect the APK's AndroidManifest.xml to
    459                 // check whether it declares that the APK is debuggable
    460                 mOutputAndroidManifestEntryDataRequest = new GetJarEntryDataRequest(entryName);
    461                 return mOutputAndroidManifestEntryDataRequest;
    462             }
    463             return null;
    464         }
    465         // v1 signing is enabled
    466 
    467         if (V1SchemeSigner.isJarEntryDigestNeededInManifest(entryName)) {
    468             // This entry is covered by v1 signature. We thus need to inspect the entry's data to
    469             // compute its digest(s) for v1 signature.
    470 
    471             // TODO: Handle the case where other signer's v1 signatures are present and need to be
    472             // preserved. In that scenario we can't modify MANIFEST.MF and add/remove JAR entries
    473             // covered by v1 signature.
    474             invalidateV1Signature();
    475             GetJarEntryDataDigestRequest dataDigestRequest =
    476                     new GetJarEntryDataDigestRequest(
    477                             entryName,
    478                             V1SchemeSigner.getJcaMessageDigestAlgorithm(mV1ContentDigestAlgorithm));
    479             mOutputJarEntryDigestRequests.put(entryName, dataDigestRequest);
    480             mOutputJarEntryDigests.remove(entryName);
    481 
    482             if ((!mDebuggableApkPermitted)
    483                     && (ApkUtils.ANDROID_MANIFEST_ZIP_ENTRY_NAME.equals(entryName))) {
    484                 // To reject debuggable APKs we need to inspect the APK's AndroidManifest.xml to
    485                 // check whether it declares that the APK is debuggable
    486                 mOutputAndroidManifestEntryDataRequest = new GetJarEntryDataRequest(entryName);
    487                 return new CompoundInspectJarEntryRequest(
    488                         entryName, mOutputAndroidManifestEntryDataRequest, dataDigestRequest);
    489             }
    490 
    491             return dataDigestRequest;
    492         }
    493 
    494         if (mSignatureExpectedOutputJarEntryNames.contains(entryName)) {
    495             // This entry is part of v1 signature generated by this engine. We need to check whether
    496             // the entry's data is as output by the engine.
    497             invalidateV1Signature();
    498             GetJarEntryDataRequest dataRequest;
    499             if (V1SchemeSigner.MANIFEST_ENTRY_NAME.equals(entryName)) {
    500                 dataRequest = new GetJarEntryDataRequest(entryName);
    501                 mInputJarManifestEntryDataRequest = dataRequest;
    502             } else {
    503                 // If this entry is part of v1 signature which has been emitted by this engine,
    504                 // check whether the output entry's data matches what the engine emitted.
    505                 dataRequest =
    506                         (mEmittedSignatureJarEntryData.containsKey(entryName))
    507                                 ? new GetJarEntryDataRequest(entryName) : null;
    508             }
    509 
    510             if (dataRequest != null) {
    511                 mOutputSignatureJarEntryDataRequests.put(entryName, dataRequest);
    512             }
    513             return dataRequest;
    514         }
    515 
    516         // This entry is not covered by v1 signature and isn't part of v1 signature.
    517         return null;
    518     }
    519 
    520     @Override
    521     public InputJarEntryInstructions.OutputPolicy inputJarEntryRemoved(String entryName) {
    522         checkNotClosed();
    523         return getInputJarEntryOutputPolicy(entryName);
    524     }
    525 
    526     @Override
    527     public void outputJarEntryRemoved(String entryName) {
    528         checkNotClosed();
    529         invalidateV2Signature();
    530         if (!mV1SigningEnabled) {
    531             return;
    532         }
    533 
    534         if (V1SchemeSigner.isJarEntryDigestNeededInManifest(entryName)) {
    535             // This entry is covered by v1 signature.
    536             invalidateV1Signature();
    537             mOutputJarEntryDigests.remove(entryName);
    538             mOutputJarEntryDigestRequests.remove(entryName);
    539             mOutputSignatureJarEntryDataRequests.remove(entryName);
    540             return;
    541         }
    542 
    543         if (mSignatureExpectedOutputJarEntryNames.contains(entryName)) {
    544             // This entry is part of the v1 signature generated by this engine.
    545             invalidateV1Signature();
    546             return;
    547         }
    548     }
    549 
    550     @Override
    551     public OutputJarSignatureRequest outputJarEntries()
    552             throws ApkFormatException, InvalidKeyException, SignatureException,
    553                     NoSuchAlgorithmException {
    554         checkNotClosed();
    555 
    556         if (!mV1SignaturePending) {
    557             return null;
    558         }
    559 
    560         if ((mInputJarManifestEntryDataRequest != null)
    561                 && (!mInputJarManifestEntryDataRequest.isDone())) {
    562             throw new IllegalStateException(
    563                     "Still waiting to inspect input APK's "
    564                             + mInputJarManifestEntryDataRequest.getEntryName());
    565         }
    566 
    567         for (GetJarEntryDataDigestRequest digestRequest
    568                 : mOutputJarEntryDigestRequests.values()) {
    569             String entryName = digestRequest.getEntryName();
    570             if (!digestRequest.isDone()) {
    571                 throw new IllegalStateException(
    572                         "Still waiting to inspect output APK's " + entryName);
    573             }
    574             mOutputJarEntryDigests.put(entryName, digestRequest.getDigest());
    575         }
    576         mOutputJarEntryDigestRequests.clear();
    577 
    578         for (GetJarEntryDataRequest dataRequest : mOutputSignatureJarEntryDataRequests.values()) {
    579             if (!dataRequest.isDone()) {
    580                 throw new IllegalStateException(
    581                         "Still waiting to inspect output APK's " + dataRequest.getEntryName());
    582             }
    583         }
    584 
    585         List<Integer> apkSigningSchemeIds = new ArrayList<>();
    586         if (mV2SigningEnabled) {
    587             apkSigningSchemeIds.add(ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2);
    588         }
    589         if (mV3SigningEnabled) {
    590             apkSigningSchemeIds.add(ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3);
    591         }
    592         byte[] inputJarManifest =
    593                 (mInputJarManifestEntryDataRequest != null)
    594                     ? mInputJarManifestEntryDataRequest.getData() : null;
    595 
    596         // Check whether the most recently used signature (if present) is still fine.
    597         checkOutputApkNotDebuggableIfDebuggableMustBeRejected();
    598         List<Pair<String, byte[]>> signatureZipEntries;
    599         if ((mAddV1SignatureRequest == null) || (!mAddV1SignatureRequest.isDone())) {
    600             try {
    601                 signatureZipEntries =
    602                         V1SchemeSigner.sign(
    603                                 mV1SignerConfigs,
    604                                 mV1ContentDigestAlgorithm,
    605                                 mOutputJarEntryDigests,
    606                                 apkSigningSchemeIds,
    607                                 inputJarManifest,
    608                                 mCreatedBy);
    609             } catch (CertificateException e) {
    610                 throw new SignatureException("Failed to generate v1 signature", e);
    611             }
    612         } else {
    613             V1SchemeSigner.OutputManifestFile newManifest =
    614                     V1SchemeSigner.generateManifestFile(
    615                             mV1ContentDigestAlgorithm,
    616                             mOutputJarEntryDigests,
    617                             inputJarManifest);
    618             byte[] emittedSignatureManifest =
    619                     mEmittedSignatureJarEntryData.get(V1SchemeSigner.MANIFEST_ENTRY_NAME);
    620             if (!Arrays.equals(newManifest.contents, emittedSignatureManifest)) {
    621                 // Emitted v1 signature is no longer valid.
    622                 try {
    623                     signatureZipEntries =
    624                             V1SchemeSigner.signManifest(
    625                                     mV1SignerConfigs,
    626                                     mV1ContentDigestAlgorithm,
    627                                     apkSigningSchemeIds,
    628                                     mCreatedBy,
    629                                     newManifest);
    630                 } catch (CertificateException e) {
    631                     throw new SignatureException("Failed to generate v1 signature", e);
    632                 }
    633             } else {
    634                 // Emitted v1 signature is still valid. Check whether the signature is there in the
    635                 // output.
    636                 signatureZipEntries = new ArrayList<>();
    637                 for (Map.Entry<String, byte[]> expectedOutputEntry
    638                         : mEmittedSignatureJarEntryData.entrySet()) {
    639                     String entryName = expectedOutputEntry.getKey();
    640                     byte[] expectedData = expectedOutputEntry.getValue();
    641                     GetJarEntryDataRequest actualDataRequest =
    642                             mOutputSignatureJarEntryDataRequests.get(entryName);
    643                     if (actualDataRequest == null) {
    644                         // This signature entry hasn't been output.
    645                         signatureZipEntries.add(Pair.of(entryName, expectedData));
    646                         continue;
    647                     }
    648                     byte[] actualData = actualDataRequest.getData();
    649                     if (!Arrays.equals(expectedData, actualData)) {
    650                         signatureZipEntries.add(Pair.of(entryName, expectedData));
    651                     }
    652                 }
    653                 if (signatureZipEntries.isEmpty()) {
    654                     // v1 signature in the output is valid
    655                     return null;
    656                 }
    657                 // v1 signature in the output is not valid.
    658             }
    659         }
    660 
    661         if (signatureZipEntries.isEmpty()) {
    662             // v1 signature in the output is valid
    663             mV1SignaturePending = false;
    664             return null;
    665         }
    666 
    667         List<OutputJarSignatureRequest.JarEntry> sigEntries =
    668                 new ArrayList<>(signatureZipEntries.size());
    669         for (Pair<String, byte[]> entry : signatureZipEntries) {
    670             String entryName = entry.getFirst();
    671             byte[] entryData = entry.getSecond();
    672             sigEntries.add(new OutputJarSignatureRequest.JarEntry(entryName, entryData));
    673             mEmittedSignatureJarEntryData.put(entryName, entryData);
    674         }
    675         mAddV1SignatureRequest = new OutputJarSignatureRequestImpl(sigEntries);
    676         return mAddV1SignatureRequest;
    677     }
    678 
    679     @Deprecated
    680     @Override
    681     public OutputApkSigningBlockRequest outputZipSections(
    682             DataSource zipEntries,
    683             DataSource zipCentralDirectory,
    684             DataSource zipEocd)
    685                     throws IOException, InvalidKeyException, SignatureException,
    686                             NoSuchAlgorithmException {
    687         return outputZipSectionsInternal(zipEntries, zipCentralDirectory, zipEocd, false);
    688     }
    689 
    690     @Override
    691     public OutputApkSigningBlockRequest2 outputZipSections2(
    692             DataSource zipEntries,
    693             DataSource zipCentralDirectory,
    694             DataSource zipEocd)
    695                     throws IOException, InvalidKeyException, SignatureException,
    696                             NoSuchAlgorithmException {
    697         return outputZipSectionsInternal(zipEntries, zipCentralDirectory, zipEocd, true);
    698     }
    699 
    700     private OutputApkSigningBlockRequestImpl outputZipSectionsInternal(
    701             DataSource zipEntries,
    702             DataSource zipCentralDirectory,
    703             DataSource zipEocd,
    704             boolean apkSigningBlockPaddingSupported)
    705                     throws IOException, InvalidKeyException, SignatureException,
    706                             NoSuchAlgorithmException {
    707         checkNotClosed();
    708         checkV1SigningDoneIfEnabled();
    709         if (!mV2SigningEnabled && !mV3SigningEnabled) {
    710             return null;
    711         }
    712         checkOutputApkNotDebuggableIfDebuggableMustBeRejected();
    713 
    714         // adjust to proper padding
    715         Pair<DataSource, Integer> paddingPair =
    716                 ApkSigningBlockUtils.generateApkSigningBlockPadding(zipEntries,
    717                         apkSigningBlockPaddingSupported);
    718         DataSource beforeCentralDir = paddingPair.getFirst();
    719         int padSizeBeforeApkSigningBlock  = paddingPair.getSecond();
    720         DataSource eocd =
    721                 ApkSigningBlockUtils.copyWithModifiedCDOffset(beforeCentralDir, zipEocd);
    722 
    723         List<Pair<byte[], Integer>> signingSchemeBlocks = new ArrayList<>();
    724 
    725         // create APK Signature Scheme V2 Signature if requested
    726         if (mV2SigningEnabled) {
    727             invalidateV2Signature();
    728             List<ApkSigningBlockUtils.SignerConfig> v2SignerConfigs =
    729                     createV2SignerConfigs(apkSigningBlockPaddingSupported);
    730             signingSchemeBlocks.add(
    731                     V2SchemeSigner.generateApkSignatureSchemeV2Block(beforeCentralDir,
    732                             zipCentralDirectory, eocd, v2SignerConfigs, mV3SigningEnabled));
    733         }
    734         if (mV3SigningEnabled) {
    735             invalidateV3Signature();
    736             List<ApkSigningBlockUtils.SignerConfig> v3SignerConfigs =
    737                     createV3SignerConfigs(apkSigningBlockPaddingSupported);
    738             signingSchemeBlocks.add(
    739                     V3SchemeSigner.generateApkSignatureSchemeV3Block(beforeCentralDir,
    740                             zipCentralDirectory, eocd, v3SignerConfigs));
    741         }
    742 
    743         // create APK Signing Block with v2 and/or v3 blocks
    744         byte[] apkSigningBlock =
    745                 ApkSigningBlockUtils.generateApkSigningBlock(signingSchemeBlocks);
    746 
    747         mAddSigningBlockRequest = new OutputApkSigningBlockRequestImpl(apkSigningBlock,
    748                 padSizeBeforeApkSigningBlock);
    749         return mAddSigningBlockRequest;
    750     }
    751 
    752     @Override
    753     public void outputDone() {
    754         checkNotClosed();
    755         checkV1SigningDoneIfEnabled();
    756         checkSigningBlockDoneIfEnabled();
    757     }
    758 
    759     @Override
    760     public void close() {
    761         mClosed = true;
    762 
    763         mAddV1SignatureRequest = null;
    764         mInputJarManifestEntryDataRequest = null;
    765         mOutputAndroidManifestEntryDataRequest = null;
    766         mDebuggable = null;
    767         mOutputJarEntryDigestRequests.clear();
    768         mOutputJarEntryDigests.clear();
    769         mEmittedSignatureJarEntryData.clear();
    770         mOutputSignatureJarEntryDataRequests.clear();
    771 
    772         mAddSigningBlockRequest = null;
    773     }
    774 
    775     private void invalidateV1Signature() {
    776         if (mV1SigningEnabled) {
    777             mV1SignaturePending = true;
    778         }
    779         invalidateV2Signature();
    780     }
    781 
    782     private void invalidateV2Signature() {
    783         if (mV2SigningEnabled) {
    784             mV2SignaturePending = true;
    785             mAddSigningBlockRequest = null;
    786         }
    787     }
    788 
    789     private void invalidateV3Signature() {
    790         if (mV3SigningEnabled) {
    791             mV3SignaturePending = true;
    792             mAddSigningBlockRequest = null;
    793         }
    794     }
    795 
    796     private void checkNotClosed() {
    797         if (mClosed) {
    798             throw new IllegalStateException("Engine closed");
    799         }
    800     }
    801 
    802     private void checkV1SigningDoneIfEnabled() {
    803         if (!mV1SignaturePending) {
    804             return;
    805         }
    806 
    807         if (mAddV1SignatureRequest == null) {
    808             throw new IllegalStateException(
    809                     "v1 signature (JAR signature) not yet generated. Skipped outputJarEntries()?");
    810         }
    811         if (!mAddV1SignatureRequest.isDone()) {
    812             throw new IllegalStateException(
    813                     "v1 signature (JAR signature) addition requested by outputJarEntries() hasn't"
    814                             + " been fulfilled");
    815         }
    816         for (Map.Entry<String, byte[]> expectedOutputEntry
    817                 : mEmittedSignatureJarEntryData.entrySet()) {
    818             String entryName = expectedOutputEntry.getKey();
    819             byte[] expectedData = expectedOutputEntry.getValue();
    820             GetJarEntryDataRequest actualDataRequest =
    821                     mOutputSignatureJarEntryDataRequests.get(entryName);
    822             if (actualDataRequest == null) {
    823                 throw new IllegalStateException(
    824                         "APK entry " + entryName + " not yet output despite this having been"
    825                                 + " requested");
    826             } else if (!actualDataRequest.isDone()) {
    827                 throw new IllegalStateException(
    828                         "Still waiting to inspect output APK's " + entryName);
    829             }
    830             byte[] actualData = actualDataRequest.getData();
    831             if (!Arrays.equals(expectedData, actualData)) {
    832                 throw new IllegalStateException(
    833                         "Output APK entry " + entryName + " data differs from what was requested");
    834             }
    835         }
    836         mV1SignaturePending = false;
    837     }
    838 
    839     private void checkSigningBlockDoneIfEnabled() {
    840         if (!mV2SignaturePending && !mV3SignaturePending) {
    841             return;
    842         }
    843         if (mAddSigningBlockRequest == null) {
    844             throw new IllegalStateException(
    845                     "Signed APK Signing BLock not yet generated. Skipped outputZipSections()?");
    846         }
    847         if (!mAddSigningBlockRequest.isDone()) {
    848             throw new IllegalStateException(
    849                     "APK Signing Block addition of signature(s) requested by"
    850                             + " outputZipSections() hasn't been fulfilled yet");
    851         }
    852         mAddSigningBlockRequest = null;
    853         mV2SignaturePending = false;
    854         mV3SignaturePending = false;
    855     }
    856 
    857     private void checkOutputApkNotDebuggableIfDebuggableMustBeRejected()
    858             throws SignatureException {
    859         if (mDebuggableApkPermitted) {
    860             return;
    861         }
    862 
    863         try {
    864             if (isOutputApkDebuggable()) {
    865                 throw new SignatureException(
    866                         "APK is debuggable (see android:debuggable attribute) and this engine is"
    867                                 + " configured to refuse to sign debuggable APKs");
    868             }
    869         } catch (ApkFormatException e) {
    870             throw new SignatureException("Failed to determine whether the APK is debuggable", e);
    871         }
    872     }
    873 
    874     /**
    875      * Returns whether the output APK is debuggable according to its
    876      * {@code android:debuggable} declaration.
    877      */
    878     private boolean isOutputApkDebuggable() throws ApkFormatException {
    879         if (mDebuggable != null) {
    880             return mDebuggable;
    881         }
    882 
    883         if (mOutputAndroidManifestEntryDataRequest == null) {
    884             throw new IllegalStateException(
    885                     "Cannot determine debuggable status of output APK because "
    886                             + ApkUtils.ANDROID_MANIFEST_ZIP_ENTRY_NAME
    887                             + " entry contents have not yet been requested");
    888         }
    889 
    890         if (!mOutputAndroidManifestEntryDataRequest.isDone()) {
    891             throw new IllegalStateException(
    892                     "Still waiting to inspect output APK's "
    893                             + mOutputAndroidManifestEntryDataRequest.getEntryName());
    894         }
    895         mDebuggable =
    896                 ApkUtils.getDebuggableFromBinaryAndroidManifest(
    897                         ByteBuffer.wrap(mOutputAndroidManifestEntryDataRequest.getData()));
    898         return mDebuggable;
    899     }
    900 
    901     private void forgetOutputApkDebuggableStatus() {
    902         mDebuggable = null;
    903     }
    904 
    905     /**
    906      * Returns the output policy for the provided input JAR entry.
    907      */
    908     private InputJarEntryInstructions.OutputPolicy getInputJarEntryOutputPolicy(String entryName) {
    909         if (mSignatureExpectedOutputJarEntryNames.contains(entryName)) {
    910             return InputJarEntryInstructions.OutputPolicy.OUTPUT_BY_ENGINE;
    911         }
    912         if ((mOtherSignersSignaturesPreserved)
    913                 || (V1SchemeSigner.isJarEntryDigestNeededInManifest(entryName))) {
    914             return InputJarEntryInstructions.OutputPolicy.OUTPUT;
    915         }
    916         return InputJarEntryInstructions.OutputPolicy.SKIP;
    917     }
    918 
    919     private static class OutputJarSignatureRequestImpl implements OutputJarSignatureRequest {
    920         private final List<JarEntry> mAdditionalJarEntries;
    921         private volatile boolean mDone;
    922 
    923         private OutputJarSignatureRequestImpl(List<JarEntry> additionalZipEntries) {
    924             mAdditionalJarEntries =
    925                     Collections.unmodifiableList(new ArrayList<>(additionalZipEntries));
    926         }
    927 
    928         @Override
    929         public List<JarEntry> getAdditionalJarEntries() {
    930             return mAdditionalJarEntries;
    931         }
    932 
    933         @Override
    934         public void done() {
    935             mDone = true;
    936         }
    937 
    938         private boolean isDone() {
    939             return mDone;
    940         }
    941     }
    942 
    943     @SuppressWarnings("deprecation")
    944     private static class OutputApkSigningBlockRequestImpl
    945             implements OutputApkSigningBlockRequest, OutputApkSigningBlockRequest2 {
    946         private final byte[] mApkSigningBlock;
    947         private final int mPaddingBeforeApkSigningBlock;
    948         private volatile boolean mDone;
    949 
    950         private OutputApkSigningBlockRequestImpl(byte[] apkSigingBlock, int paddingBefore) {
    951             mApkSigningBlock = apkSigingBlock.clone();
    952             mPaddingBeforeApkSigningBlock = paddingBefore;
    953         }
    954 
    955         @Override
    956         public byte[] getApkSigningBlock() {
    957             return mApkSigningBlock.clone();
    958         }
    959 
    960         @Override
    961         public void done() {
    962             mDone = true;
    963         }
    964 
    965         private boolean isDone() {
    966             return mDone;
    967         }
    968 
    969         @Override
    970         public int getPaddingSizeBeforeApkSigningBlock() {
    971             return mPaddingBeforeApkSigningBlock;
    972         }
    973     }
    974 
    975     /**
    976      * JAR entry inspection request which obtain the entry's uncompressed data.
    977      */
    978     private static class GetJarEntryDataRequest implements InspectJarEntryRequest {
    979         private final String mEntryName;
    980         private final Object mLock = new Object();
    981 
    982         private boolean mDone;
    983         private DataSink mDataSink;
    984         private ByteArrayOutputStream mDataSinkBuf;
    985 
    986         private GetJarEntryDataRequest(String entryName) {
    987             mEntryName = entryName;
    988         }
    989 
    990         @Override
    991         public String getEntryName() {
    992             return mEntryName;
    993         }
    994 
    995         @Override
    996         public DataSink getDataSink() {
    997             synchronized (mLock) {
    998                 checkNotDone();
    999                 if (mDataSinkBuf == null) {
   1000                     mDataSinkBuf = new ByteArrayOutputStream();
   1001                 }
   1002                 if (mDataSink == null) {
   1003                     mDataSink = DataSinks.asDataSink(mDataSinkBuf);
   1004                 }
   1005                 return mDataSink;
   1006             }
   1007         }
   1008 
   1009         @Override
   1010         public void done() {
   1011             synchronized (mLock) {
   1012                 if (mDone) {
   1013                     return;
   1014                 }
   1015                 mDone = true;
   1016             }
   1017         }
   1018 
   1019         private boolean isDone() {
   1020             synchronized (mLock) {
   1021                 return mDone;
   1022             }
   1023         }
   1024 
   1025         private void checkNotDone() throws IllegalStateException {
   1026             synchronized (mLock) {
   1027                 if (mDone) {
   1028                     throw new IllegalStateException("Already done");
   1029                 }
   1030             }
   1031         }
   1032 
   1033         private byte[] getData() {
   1034             synchronized (mLock) {
   1035                 if (!mDone) {
   1036                     throw new IllegalStateException("Not yet done");
   1037                 }
   1038                 return (mDataSinkBuf != null) ? mDataSinkBuf.toByteArray() : new byte[0];
   1039             }
   1040         }
   1041     }
   1042 
   1043     /**
   1044      * JAR entry inspection request which obtains the digest of the entry's uncompressed data.
   1045      */
   1046     private static class GetJarEntryDataDigestRequest implements InspectJarEntryRequest {
   1047         private final String mEntryName;
   1048         private final String mJcaDigestAlgorithm;
   1049         private final Object mLock = new Object();
   1050 
   1051         private boolean mDone;
   1052         private DataSink mDataSink;
   1053         private MessageDigest mMessageDigest;
   1054         private byte[] mDigest;
   1055 
   1056         private GetJarEntryDataDigestRequest(String entryName, String jcaDigestAlgorithm) {
   1057             mEntryName = entryName;
   1058             mJcaDigestAlgorithm = jcaDigestAlgorithm;
   1059         }
   1060 
   1061         @Override
   1062         public String getEntryName() {
   1063             return mEntryName;
   1064         }
   1065 
   1066         @Override
   1067         public DataSink getDataSink() {
   1068             synchronized (mLock) {
   1069                 checkNotDone();
   1070                 if (mDataSink == null) {
   1071                     mDataSink = DataSinks.asDataSink(getMessageDigest());
   1072                 }
   1073                 return mDataSink;
   1074             }
   1075         }
   1076 
   1077         private MessageDigest getMessageDigest() {
   1078             synchronized (mLock) {
   1079                 if (mMessageDigest == null) {
   1080                     try {
   1081                         mMessageDigest = MessageDigest.getInstance(mJcaDigestAlgorithm);
   1082                     } catch (NoSuchAlgorithmException e) {
   1083                         throw new RuntimeException(
   1084                                 mJcaDigestAlgorithm + " MessageDigest not available", e);
   1085                     }
   1086                 }
   1087                 return mMessageDigest;
   1088             }
   1089         }
   1090 
   1091         @Override
   1092         public void done() {
   1093             synchronized (mLock) {
   1094                 if (mDone) {
   1095                     return;
   1096                 }
   1097                 mDone = true;
   1098                 mDigest = getMessageDigest().digest();
   1099                 mMessageDigest = null;
   1100                 mDataSink = null;
   1101             }
   1102         }
   1103 
   1104         private boolean isDone() {
   1105             synchronized (mLock) {
   1106                 return mDone;
   1107             }
   1108         }
   1109 
   1110         private void checkNotDone() throws IllegalStateException {
   1111             synchronized (mLock) {
   1112                 if (mDone) {
   1113                     throw new IllegalStateException("Already done");
   1114                 }
   1115             }
   1116         }
   1117 
   1118         private byte[] getDigest() {
   1119             synchronized (mLock) {
   1120                 if (!mDone) {
   1121                     throw new IllegalStateException("Not yet done");
   1122                 }
   1123                 return mDigest.clone();
   1124             }
   1125         }
   1126     }
   1127 
   1128     /**
   1129      * JAR entry inspection request which transparently satisfies multiple such requests.
   1130      */
   1131     private static class CompoundInspectJarEntryRequest implements InspectJarEntryRequest {
   1132         private final String mEntryName;
   1133         private final InspectJarEntryRequest[] mRequests;
   1134         private final Object mLock = new Object();
   1135 
   1136         private DataSink mSink;
   1137 
   1138         private CompoundInspectJarEntryRequest(
   1139                 String entryName, InspectJarEntryRequest... requests) {
   1140             mEntryName = entryName;
   1141             mRequests = requests;
   1142         }
   1143 
   1144         @Override
   1145         public String getEntryName() {
   1146             return mEntryName;
   1147         }
   1148 
   1149         @Override
   1150         public DataSink getDataSink() {
   1151             synchronized (mLock) {
   1152                 if (mSink == null) {
   1153                     DataSink[] sinks = new DataSink[mRequests.length];
   1154                     for (int i = 0; i < sinks.length; i++) {
   1155                         sinks[i] = mRequests[i].getDataSink();
   1156                     }
   1157                     mSink = new TeeDataSink(sinks);
   1158                 }
   1159                 return mSink;
   1160             }
   1161         }
   1162 
   1163         @Override
   1164         public void done() {
   1165             for (InspectJarEntryRequest request : mRequests) {
   1166                 request.done();
   1167             }
   1168         }
   1169     }
   1170 
   1171     /**
   1172      * Configuration of a signer.
   1173      *
   1174      * <p>Use {@link Builder} to obtain configuration instances.
   1175      */
   1176     public static class SignerConfig {
   1177         private final String mName;
   1178         private final PrivateKey mPrivateKey;
   1179         private final List<X509Certificate> mCertificates;
   1180 
   1181         private SignerConfig(
   1182                 String name,
   1183                 PrivateKey privateKey,
   1184                 List<X509Certificate> certificates) {
   1185             mName = name;
   1186             mPrivateKey = privateKey;
   1187             mCertificates = Collections.unmodifiableList(new ArrayList<>(certificates));
   1188         }
   1189 
   1190         /**
   1191          * Returns the name of this signer.
   1192          */
   1193         public String getName() {
   1194             return mName;
   1195         }
   1196 
   1197         /**
   1198          * Returns the signing key of this signer.
   1199          */
   1200         public PrivateKey getPrivateKey() {
   1201             return mPrivateKey;
   1202         }
   1203 
   1204         /**
   1205          * Returns the certificate(s) of this signer. The first certificate's public key corresponds
   1206          * to this signer's private key.
   1207          */
   1208         public List<X509Certificate> getCertificates() {
   1209             return mCertificates;
   1210         }
   1211 
   1212         /**
   1213          * Builder of {@link SignerConfig} instances.
   1214          */
   1215         public static class Builder {
   1216             private final String mName;
   1217             private final PrivateKey mPrivateKey;
   1218             private final List<X509Certificate> mCertificates;
   1219 
   1220             /**
   1221              * Constructs a new {@code Builder}.
   1222              *
   1223              * @param name signer's name. The name is reflected in the name of files comprising the
   1224              *        JAR signature of the APK.
   1225              * @param privateKey signing key
   1226              * @param certificates list of one or more X.509 certificates. The subject public key of
   1227              *        the first certificate must correspond to the {@code privateKey}.
   1228              */
   1229             public Builder(
   1230                     String name,
   1231                     PrivateKey privateKey,
   1232                     List<X509Certificate> certificates) {
   1233                 if (name.isEmpty()) {
   1234                     throw new IllegalArgumentException("Empty name");
   1235                 }
   1236                 mName = name;
   1237                 mPrivateKey = privateKey;
   1238                 mCertificates = new ArrayList<>(certificates);
   1239             }
   1240 
   1241             /**
   1242              * Returns a new {@code SignerConfig} instance configured based on the configuration of
   1243              * this builder.
   1244              */
   1245             public SignerConfig build() {
   1246                 return new SignerConfig(
   1247                         mName,
   1248                         mPrivateKey,
   1249                         mCertificates);
   1250             }
   1251         }
   1252     }
   1253 
   1254     /**
   1255      * Builder of {@link DefaultApkSignerEngine} instances.
   1256      */
   1257     public static class Builder {
   1258         private List<SignerConfig> mSignerConfigs;
   1259         private final int mMinSdkVersion;
   1260 
   1261         private boolean mV1SigningEnabled = true;
   1262         private boolean mV2SigningEnabled = true;
   1263         private boolean mV3SigningEnabled = true;
   1264         private boolean mDebuggableApkPermitted = true;
   1265         private boolean mOtherSignersSignaturesPreserved;
   1266         private String mCreatedBy = "1.0 (Android)";
   1267 
   1268         private SigningCertificateLineage mSigningCertificateLineage;
   1269 
   1270         // APK Signature Scheme v3 only supports a single signing certificate, so to move to v3
   1271         // signing by default, but not require prior clients to update to explicitly disable v3
   1272         // signing for multiple signers, we modify the mV3SigningEnabled depending on the provided
   1273         // inputs (multiple signers and mSigningCertificateLineage in particular).  Maintain two
   1274         // extra variables to record whether or not mV3SigningEnabled has been set directly by a
   1275         // client and so should override the default behavior.
   1276         private boolean mV3SigningExplicitlyDisabled = false;
   1277         private boolean mV3SigningExplicitlyEnabled = false;
   1278 
   1279         /**
   1280          * Constructs a new {@code Builder}.
   1281          *
   1282          * @param signerConfigs information about signers with which the APK will be signed. At
   1283          *        least one signer configuration must be provided.
   1284          * @param minSdkVersion API Level of the oldest Android platform on which the APK is
   1285          *        supposed to be installed. See {@code minSdkVersion} attribute in the APK's
   1286          *        {@code AndroidManifest.xml}. The higher the version, the stronger signing features
   1287          *        will be enabled.
   1288          */
   1289         public Builder(
   1290                 List<SignerConfig> signerConfigs,
   1291                 int minSdkVersion) {
   1292             if (signerConfigs.isEmpty()) {
   1293                 throw new IllegalArgumentException("At least one signer config must be provided");
   1294             }
   1295             if (signerConfigs.size() > 1) {
   1296                 // APK Signature Scheme v3 only supports single signer, unless a
   1297                 // SigningCertificateLineage is provided, in which case this will be reset to true,
   1298                 // since we don't yet have a v4 scheme about which to worry
   1299                 mV3SigningEnabled = false;
   1300             }
   1301             mSignerConfigs = new ArrayList<>(signerConfigs);
   1302             mMinSdkVersion = minSdkVersion;
   1303         }
   1304 
   1305         /**
   1306          * Returns a new {@code DefaultApkSignerEngine} instance configured based on the
   1307          * configuration of this builder.
   1308          */
   1309         public DefaultApkSignerEngine build() throws InvalidKeyException {
   1310 
   1311             if (mV3SigningExplicitlyDisabled && mV3SigningExplicitlyEnabled) {
   1312                 throw new IllegalStateException("Builder configured to both enable and disable APK "
   1313                         + "Signature Scheme v3 signing");
   1314             }
   1315             if (mV3SigningExplicitlyDisabled) {
   1316                 mV3SigningEnabled = false;
   1317             } else if (mV3SigningExplicitlyEnabled) {
   1318                 mV3SigningEnabled = true;
   1319             }
   1320 
   1321             // make sure our signers are appropriately setup
   1322             if (mSigningCertificateLineage != null) {
   1323                 try {
   1324                     mSignerConfigs = mSigningCertificateLineage.sortSignerConfigs(mSignerConfigs);
   1325                     if (!mV3SigningEnabled && mSignerConfigs.size() > 1) {
   1326 
   1327                         // this is a strange situation: we've provided a valid rotation history, but
   1328                         // are only signing with v1/v2.  blow up, since we don't know for sure with
   1329                         // which signer the user intended to sign
   1330                         throw new IllegalStateException("Provided multiple signers which are part "
   1331                                 + "of the SigningCertificateLineage, but not signing with APK "
   1332                                 + "Signature Scheme v3");
   1333                     }
   1334                 } catch (IllegalArgumentException e) {
   1335                     throw new IllegalStateException("Provided signer configs do not match the "
   1336                             + "provided SigningCertificateLineage", e);
   1337                 }
   1338             } else if (mV3SigningEnabled && mSignerConfigs.size() > 1) {
   1339                 throw new IllegalStateException("Multiple signing certificates provided for use "
   1340                 + "with APK Signature Scheme v3 without an accompanying SigningCertificateLineage");
   1341             }
   1342 
   1343             return new DefaultApkSignerEngine(
   1344                     mSignerConfigs,
   1345                     mMinSdkVersion,
   1346                     mV1SigningEnabled,
   1347                     mV2SigningEnabled,
   1348                     mV3SigningEnabled,
   1349                     mDebuggableApkPermitted,
   1350                     mOtherSignersSignaturesPreserved,
   1351                     mCreatedBy,
   1352                     mSigningCertificateLineage);
   1353         }
   1354 
   1355         /**
   1356          * Sets whether the APK should be signed using JAR signing (aka v1 signature scheme).
   1357          *
   1358          * <p>By default, the APK will be signed using this scheme.
   1359          */
   1360         public Builder setV1SigningEnabled(boolean enabled) {
   1361             mV1SigningEnabled = enabled;
   1362             return this;
   1363         }
   1364 
   1365         /**
   1366          * Sets whether the APK should be signed using APK Signature Scheme v2 (aka v2 signature
   1367          * scheme).
   1368          *
   1369          * <p>By default, the APK will be signed using this scheme.
   1370          */
   1371         public Builder setV2SigningEnabled(boolean enabled) {
   1372             mV2SigningEnabled = enabled;
   1373             return this;
   1374         }
   1375 
   1376         /**
   1377          * Sets whether the APK should be signed using APK Signature Scheme v3 (aka v3 signature
   1378          * scheme).
   1379          *
   1380          * <p>By default, the APK will be signed using this scheme.
   1381          */
   1382         public Builder setV3SigningEnabled(boolean enabled) {
   1383             mV3SigningEnabled = enabled;
   1384             if (enabled) {
   1385                 mV3SigningExplicitlyEnabled = true;
   1386             } else {
   1387                 mV3SigningExplicitlyDisabled = true;
   1388             }
   1389             return this;
   1390         }
   1391 
   1392         /**
   1393          * Sets whether the APK should be signed even if it is marked as debuggable
   1394          * ({@code android:debuggable="true"} in its {@code AndroidManifest.xml}). For backward
   1395          * compatibility reasons, the default value of this setting is {@code true}.
   1396          *
   1397          * <p>It is dangerous to sign debuggable APKs with production/release keys because Android
   1398          * platform loosens security checks for such APKs. For example, arbitrary unauthorized code
   1399          * may be executed in the context of such an app by anybody with ADB shell access.
   1400          */
   1401         public Builder setDebuggableApkPermitted(boolean permitted) {
   1402             mDebuggableApkPermitted = permitted;
   1403             return this;
   1404         }
   1405 
   1406         /**
   1407          * Sets whether signatures produced by signers other than the ones configured in this engine
   1408          * should be copied from the input APK to the output APK.
   1409          *
   1410          * <p>By default, signatures of other signers are omitted from the output APK.
   1411          */
   1412         public Builder setOtherSignersSignaturesPreserved(boolean preserved) {
   1413             mOtherSignersSignaturesPreserved = preserved;
   1414             return this;
   1415         }
   1416 
   1417         /**
   1418          * Sets the value of the {@code Created-By} field in JAR signature files.
   1419          */
   1420         public Builder setCreatedBy(String createdBy) {
   1421             if (createdBy == null) {
   1422                 throw new NullPointerException();
   1423             }
   1424             mCreatedBy = createdBy;
   1425             return this;
   1426         }
   1427 
   1428         /**
   1429          * Sets the {@link SigningCertificateLineage} to use with the v3 signature scheme.  This
   1430          * structure provides proof of signing certificate rotation linking {@link SignerConfig}
   1431          * objects to previous ones.
   1432          */
   1433         public Builder setSigningCertificateLineage(
   1434                 SigningCertificateLineage signingCertificateLineage) {
   1435             if (signingCertificateLineage != null) {
   1436                 mV3SigningEnabled = true;
   1437                 mSigningCertificateLineage = signingCertificateLineage;
   1438             }
   1439             return this;
   1440         }
   1441     }
   1442 }
   1443