Home | History | Annotate | Download | only in apksig
      1 /*
      2  * Copyright (C) 2018 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.internal.apk.ApkSigningBlockUtils.getLengthPrefixedSlice;
     20 
     21 import com.android.apksig.apk.ApkFormatException;
     22 import com.android.apksig.internal.apk.ApkSigningBlockUtils;
     23 import com.android.apksig.internal.apk.SignatureAlgorithm;
     24 import com.android.apksig.internal.apk.v3.V3SchemeSigner;
     25 import com.android.apksig.internal.apk.v3.V3SigningCertificateLineage;
     26 import com.android.apksig.internal.apk.v3.V3SigningCertificateLineage.SigningCertificateNode;
     27 import com.android.apksig.internal.util.AndroidSdkVersion;
     28 import com.android.apksig.internal.util.Pair;
     29 import com.android.apksig.internal.util.RandomAccessFileDataSink;
     30 import com.android.apksig.util.DataSink;
     31 import com.android.apksig.util.DataSource;
     32 import com.android.apksig.util.DataSources;
     33 
     34 import java.io.File;
     35 import java.io.IOException;
     36 import java.io.RandomAccessFile;
     37 import java.nio.ByteBuffer;
     38 import java.nio.ByteOrder;
     39 import java.security.InvalidKeyException;
     40 import java.security.NoSuchAlgorithmException;
     41 import java.security.PrivateKey;
     42 import java.security.PublicKey;
     43 import java.security.SignatureException;
     44 import java.security.cert.CertificateEncodingException;
     45 import java.security.cert.X509Certificate;
     46 import java.util.ArrayList;
     47 import java.util.Arrays;
     48 import java.util.Collections;
     49 import java.util.List;
     50 
     51 /**
     52  * APK Signer Lineage.
     53  *
     54  * <p>The signer lineage contains a history of signing certificates with each ancestor attesting to
     55  * the validity of its descendant.  Each additional descendant represents a new identity that can be
     56  * used to sign an APK, and each generation has accompanying attributes which represent how the
     57  * APK would like to view the older signing certificates, specifically how they should be trusted in
     58  * certain situations.
     59  *
     60  * <p> Its primary use is to enable APK Signing Certificate Rotation.  The Android platform verifies
     61  * the APK Signer Lineage, and if the current signing certificate for the APK is in the Signer
     62  * Lineage, and the Lineage contains the certificate the platform associates with the APK, it will
     63  * allow upgrades to the new certificate.
     64  *
     65  * @see <a href="https://source.android.com/security/apksigning/index.html">Application Signing</a>
     66  */
     67 public class SigningCertificateLineage {
     68 
     69     private final static int MAGIC = 0x3eff39d1;
     70 
     71     private final static int FIRST_VERSION = 1;
     72 
     73     private static final int CURRENT_VERSION = FIRST_VERSION;
     74 
     75     /** accept data from already installed pkg with this cert */
     76     private static final int PAST_CERT_INSTALLED_DATA = 1;
     77 
     78     /** accept sharedUserId with pkg with this cert */
     79     private static final int PAST_CERT_SHARED_USER_ID = 2;
     80 
     81     /** grant SIGNATURE permissions to pkgs with this cert */
     82     private static final int PAST_CERT_PERMISSION = 4;
     83 
     84     /**
     85      * Enable updates back to this certificate.  WARNING: this effectively removes any benefit of
     86      * signing certificate changes, since a compromised key could retake control of an app even
     87      * after change, and should only be used if there is a problem encountered when trying to ditch
     88      * an older cert.
     89      */
     90     private static final int PAST_CERT_ROLLBACK = 8;
     91 
     92     /**
     93      * Preserve authenticator module-based access in AccountManager gated by signing certificate.
     94      */
     95     private static final int PAST_CERT_AUTH = 16;
     96 
     97     private final int mMinSdkVersion;
     98 
     99     /**
    100      * The signing lineage is just a list of nodes, with the first being the original signing
    101      * certificate and the most recent being the one with which the APK is to actually be signed.
    102      */
    103     private final List<SigningCertificateNode> mSigningLineage;
    104 
    105     private SigningCertificateLineage(int minSdkVersion, List<SigningCertificateNode> list) {
    106         mMinSdkVersion = minSdkVersion;
    107         mSigningLineage = list;
    108     }
    109 
    110     private static SigningCertificateLineage createSigningLineage(
    111             int minSdkVersion, SignerConfig parent, SignerCapabilities parentCapabilities,
    112             SignerConfig child, SignerCapabilities childCapabilities)
    113             throws CertificateEncodingException, InvalidKeyException, NoSuchAlgorithmException,
    114             SignatureException {
    115         SigningCertificateLineage signingCertificateLineage =
    116                 new SigningCertificateLineage(minSdkVersion, new ArrayList<>());
    117         signingCertificateLineage =
    118                 signingCertificateLineage.spawnFirstDescendant(parent, parentCapabilities);
    119         return signingCertificateLineage.spawnDescendant(parent, child, childCapabilities);
    120     }
    121 
    122     public static SigningCertificateLineage readFromFile(File file)
    123             throws IOException {
    124         if (file == null) {
    125             throw new NullPointerException("file == null");
    126         }
    127         RandomAccessFile inputFile = new RandomAccessFile(file, "r");
    128         return readFromDataSource(DataSources.asDataSource(inputFile));
    129     }
    130 
    131     public static SigningCertificateLineage readFromDataSource(DataSource dataSource)
    132             throws IOException {
    133         if (dataSource == null) {
    134             throw new NullPointerException("dataSource == null");
    135         }
    136         ByteBuffer inBuff = dataSource.getByteBuffer(0, (int) dataSource.size());
    137         inBuff.order(ByteOrder.LITTLE_ENDIAN);
    138         return read(inBuff);
    139     }
    140 
    141     /**
    142      * Extracts a Signing Certificate Lineage from a v3 signer proof-of-rotation attribute.
    143      *
    144      * <note>
    145      *     this may not give a complete representation of an APK's signing certificate history,
    146      *     since the APK may have multiple signers corresponding to different platform versions.
    147      *     Use <code> readFromApkFile</code> to handle this case.
    148      * </note>
    149      * @param attrValue
    150      */
    151     public static SigningCertificateLineage readFromV3AttributeValue(byte[] attrValue)
    152             throws IOException {
    153         List<SigningCertificateNode> parsedLineage =
    154                 V3SigningCertificateLineage.readSigningCertificateLineage(ByteBuffer.wrap(
    155                         attrValue));
    156         int minSdkVersion = calculateMinSdkVersion(parsedLineage);
    157         return  new SigningCertificateLineage(minSdkVersion, parsedLineage);
    158     }
    159 
    160     public static SigningCertificateLineage readFromApkFile(File apkFile) {
    161         throw new UnsupportedOperationException("Not yet implemented");
    162     }
    163 
    164     public void writeToFile(File file) throws IOException {
    165         if (file == null) {
    166             throw new NullPointerException("file == null");
    167         }
    168         RandomAccessFile outputFile = new RandomAccessFile(file, "rw");
    169         writeToDataSink(new RandomAccessFileDataSink(outputFile));
    170     }
    171 
    172     public void writeToDataSink(DataSink dataSink) throws IOException {
    173         if (dataSink == null) {
    174             throw new NullPointerException("dataSink == null");
    175         }
    176         dataSink.consume(write());
    177     }
    178 
    179     /**
    180      * Add a new signing certificate to the lineage.  This effectively creates a signing certificate
    181      * rotation event, forcing APKs which include this lineage to be signed by the new signer. The
    182      * flags associated with the new signer are set to a default value.
    183      *
    184      * @param parent current signing certificate of the containing APK
    185      * @param child new signing certificate which will sign the APK contents
    186      */
    187     public SigningCertificateLineage spawnDescendant(SignerConfig parent, SignerConfig child)
    188             throws CertificateEncodingException, InvalidKeyException, NoSuchAlgorithmException,
    189             SignatureException {
    190         if (parent == null || child == null) {
    191             throw new NullPointerException("can't add new descendant to lineage with null inputs");
    192         }
    193         SignerCapabilities signerCapabilities = new SignerCapabilities.Builder().build();
    194         return spawnDescendant(parent, child, signerCapabilities);
    195     }
    196 
    197     /**
    198      * Add a new signing certificate to the lineage.  This effectively creates a signing certificate
    199      * rotation event, forcing APKs which include this lineage to be signed by the new signer.
    200      *
    201      * @param parent current signing certificate of the containing APK
    202      * @param child new signing certificate which will sign the APK contents
    203      * @param childCapabilities flags
    204      */
    205     public SigningCertificateLineage spawnDescendant(
    206             SignerConfig parent, SignerConfig child, SignerCapabilities childCapabilities)
    207             throws CertificateEncodingException, InvalidKeyException,
    208             NoSuchAlgorithmException, SignatureException {
    209         if (parent == null) {
    210             throw new NullPointerException("parent == null");
    211         }
    212         if (child == null) {
    213             throw new NullPointerException("child == null");
    214         }
    215         if (childCapabilities == null) {
    216             throw new NullPointerException("childCapabilities == null");
    217         }
    218         if (mSigningLineage.isEmpty()) {
    219             throw new IllegalArgumentException("Cannot spawn descendant signing certificate on an"
    220                     + " empty SigningCertificateLineage: no parent node");
    221         }
    222 
    223         // make sure that the parent matches our newest generation (leaf node/sink)
    224         SigningCertificateNode currentGeneration = mSigningLineage.get(mSigningLineage.size() - 1);
    225         if (!Arrays.equals(currentGeneration.signingCert.getEncoded(),
    226                 parent.getCertificate().getEncoded())) {
    227             throw new IllegalArgumentException("SignerConfig Certificate containing private key"
    228                     + " to sign the new SigningCertificateLineage record does not match the"
    229                     + " existing most recent record");
    230         }
    231 
    232         // create data to be signed, including the algorithm we're going to use
    233         SignatureAlgorithm signatureAlgorithm = getSignatureAlgorithm(parent);
    234         ByteBuffer prefixedSignedData = ByteBuffer.wrap(
    235                 V3SigningCertificateLineage.encodeSignedData(
    236                         child.getCertificate(), signatureAlgorithm.getId()));
    237         prefixedSignedData.position(4);
    238         ByteBuffer signedDataBuffer = ByteBuffer.allocate(prefixedSignedData.remaining());
    239         signedDataBuffer.put(prefixedSignedData);
    240         byte[] signedData = signedDataBuffer.array();
    241 
    242         // create SignerConfig to do the signing
    243         List<X509Certificate> certificates = new ArrayList<>(1);
    244         certificates.add(parent.getCertificate());
    245         ApkSigningBlockUtils.SignerConfig newSignerConfig =
    246                 new ApkSigningBlockUtils.SignerConfig();
    247         newSignerConfig.privateKey = parent.getPrivateKey();
    248         newSignerConfig.certificates = certificates;
    249         newSignerConfig.signatureAlgorithms = Collections.singletonList(signatureAlgorithm);
    250 
    251         // sign it
    252         List<Pair<Integer, byte[]>> signatures =
    253                 ApkSigningBlockUtils.generateSignaturesOverData(newSignerConfig, signedData);
    254 
    255         // finally, add it to our lineage
    256         SignatureAlgorithm sigAlgorithm = SignatureAlgorithm.findById(signatures.get(0).getFirst());
    257         byte[] signature = signatures.get(0).getSecond();
    258         currentGeneration.sigAlgorithm = sigAlgorithm;
    259         SigningCertificateNode childNode =
    260                 new SigningCertificateNode(
    261                         child.getCertificate(), sigAlgorithm, null,
    262                         signature, childCapabilities.getFlags());
    263         List<SigningCertificateNode> lineageCopy = new ArrayList<>(mSigningLineage);
    264         lineageCopy.add(childNode);
    265         return new SigningCertificateLineage(mMinSdkVersion, lineageCopy);
    266     }
    267 
    268     /**
    269      * The number of signing certificates in the lineage, including the current signer, which means
    270      * this value can also be used to V2determine the number of signing certificate rotations by
    271      * subtracting 1.
    272      */
    273     public int size() {
    274         return mSigningLineage.size();
    275     }
    276 
    277     private SignatureAlgorithm getSignatureAlgorithm(SignerConfig parent)
    278             throws InvalidKeyException {
    279         PublicKey publicKey = parent.getCertificate().getPublicKey();
    280 
    281         // TODO switch to one signature algorithm selection, or add support for multiple algorithms
    282         List<SignatureAlgorithm> algorithms = V3SchemeSigner.getSuggestedSignatureAlgorithms(
    283                 publicKey, mMinSdkVersion, false /* padding support */);
    284         return algorithms.get(0);
    285     }
    286 
    287     private SigningCertificateLineage spawnFirstDescendant(
    288             SignerConfig parent, SignerCapabilities signerCapabilities) {
    289         if (!mSigningLineage.isEmpty()) {
    290             throw new IllegalStateException("SigningCertificateLineage already has its first node");
    291         }
    292 
    293         // check to make sure that the public key for the first node is acceptable for our minSdk
    294         try {
    295             getSignatureAlgorithm(parent);
    296         } catch (InvalidKeyException e) {
    297             throw new IllegalArgumentException("Algorithm associated with first signing certificate"
    298                     + " invalid on desired platform versions", e);
    299         }
    300 
    301         // create "fake" signed data (there will be no signature over it, since there is no parent
    302         SigningCertificateNode firstNode = new SigningCertificateNode(
    303                 parent.getCertificate(), null, null, new byte[0], signerCapabilities.getFlags());
    304         return new SigningCertificateLineage(mMinSdkVersion, Collections.singletonList(firstNode));
    305     }
    306 
    307     private static SigningCertificateLineage read(ByteBuffer inputByteBuffer)
    308             throws IOException {
    309         ApkSigningBlockUtils.checkByteOrderLittleEndian(inputByteBuffer);
    310         if (inputByteBuffer.remaining() < 8) {
    311             throw new IllegalArgumentException(
    312                     "Improper SigningCertificateLineage format: insufficient data for header.");
    313         }
    314 
    315         if (inputByteBuffer.getInt() != MAGIC) {
    316             throw new IllegalArgumentException(
    317                     "Improper SigningCertificateLineage format: MAGIC header mismatch.");
    318         }
    319         return read(inputByteBuffer, inputByteBuffer.getInt());
    320     }
    321 
    322     private static SigningCertificateLineage read(ByteBuffer inputByteBuffer, int version)
    323             throws IOException {
    324         switch (version) {
    325             case FIRST_VERSION:
    326                 try {
    327                     List<SigningCertificateNode> nodes =
    328                             V3SigningCertificateLineage.readSigningCertificateLineage(
    329                                     getLengthPrefixedSlice(inputByteBuffer));
    330                     int minSdkVersion = calculateMinSdkVersion(nodes);
    331                     return new SigningCertificateLineage(minSdkVersion, nodes);
    332                 } catch (ApkFormatException e) {
    333                     // unable to get a proper length-prefixed lineage slice
    334                     throw new IOException("Unable to read list of signing certificate nodes in "
    335                             + "SigningCertificateLineage", e);
    336                 }
    337             default:
    338                 throw new IllegalArgumentException(
    339                         "Improper SigningCertificateLineage format: unrecognized version.");
    340         }
    341     }
    342 
    343     private static int calculateMinSdkVersion(List<SigningCertificateNode> nodes) {
    344         if (nodes == null) {
    345             throw new IllegalArgumentException("Can't calculate minimum SDK version of null nodes");
    346         }
    347         int minSdkVersion = AndroidSdkVersion.P; // lineage introduced in P
    348         for (SigningCertificateNode node : nodes) {
    349             if (node.sigAlgorithm != null) {
    350                 int nodeMinSdkVersion = node.sigAlgorithm.getMinSdkVersion();
    351                 if (nodeMinSdkVersion > minSdkVersion) {
    352                     minSdkVersion = nodeMinSdkVersion;
    353                 }
    354             }
    355         }
    356         return minSdkVersion;
    357     }
    358 
    359     private ByteBuffer write() {
    360         byte[] encodedLineage =
    361                 V3SigningCertificateLineage.encodeSigningCertificateLineage(mSigningLineage);
    362         int payloadSize = 4 + 4 + 4 + encodedLineage.length;
    363         ByteBuffer result = ByteBuffer.allocate(payloadSize);
    364         result.order(ByteOrder.LITTLE_ENDIAN);
    365         result.putInt(MAGIC);
    366         result.putInt(CURRENT_VERSION);
    367         result.putInt(encodedLineage.length);
    368         result.put(encodedLineage);
    369         return result;
    370     }
    371 
    372     public byte[] generateV3SignerAttribute() {
    373         // FORMAT (little endian):
    374         // * length-prefixed bytes: attribute pair
    375         //   * uint32: ID
    376         //   * bytes: value - encoded V3 SigningCertificateLineage
    377         byte[] encodedLineage =
    378                 V3SigningCertificateLineage.encodeSigningCertificateLineage(mSigningLineage);
    379         int payloadSize = 4 + 4 + encodedLineage.length;
    380         ByteBuffer result = ByteBuffer.allocate(payloadSize);
    381         result.order(ByteOrder.LITTLE_ENDIAN);
    382         result.putInt(4 + encodedLineage.length);
    383         result.putInt(V3SchemeSigner.PROOF_OF_ROTATION_ATTR_ID);
    384         result.put(encodedLineage);
    385         return result.array();
    386     }
    387 
    388     public List<DefaultApkSignerEngine.SignerConfig> sortSignerConfigs(
    389             List<DefaultApkSignerEngine.SignerConfig> signerConfigs) {
    390         if (signerConfigs == null) {
    391             throw new NullPointerException("signerConfigs == null");
    392         }
    393 
    394         // not the most elegant sort, but we expect signerConfigs to be quite small (1 or 2 signers
    395         // in most cases) and likely already sorted, so not worth the overhead of doing anything
    396         // fancier
    397         List<DefaultApkSignerEngine.SignerConfig> sortedSignerConfigs =
    398                 new ArrayList<>(signerConfigs.size());
    399         for (int i = 0; i < mSigningLineage.size(); i++) {
    400             for (int j = 0; j < signerConfigs.size(); j++) {
    401                 DefaultApkSignerEngine.SignerConfig config = signerConfigs.get(j);
    402                 if (mSigningLineage.get(i).signingCert.equals(config.getCertificates().get(0))) {
    403                     sortedSignerConfigs.add(config);
    404                     break;
    405                 }
    406             }
    407         }
    408         if (sortedSignerConfigs.size() != signerConfigs.size()) {
    409             throw new IllegalArgumentException("SignerConfigs supplied which are not present in the"
    410                     + " SigningCertificateLineage");
    411         }
    412         return sortedSignerConfigs;
    413     }
    414 
    415     // TODO add API to return all signing certificate(s)
    416 
    417     // TODO add API to query if given signing certificate is in set of signing certificates
    418 
    419     // TODO add API to modify flags corresponding to a given signing certificate
    420 
    421     private static int calculateDefaultFlags() {
    422         return PAST_CERT_INSTALLED_DATA | PAST_CERT_PERMISSION
    423                 | PAST_CERT_SHARED_USER_ID | PAST_CERT_AUTH;
    424     }
    425 
    426     /**
    427      * Returns a new SigingCertificateLineage which terminates at the node corresponding to the
    428      * given certificate.  This is useful in the event of rotating to a new signing algorithm that
    429      * is only supported on some platform versions.  It enables a v3 signature to be generated using
    430      * this signing certificate and the shortened proof-of-rotation record from this sub lineage in
    431      * conjunction with the appropriate SDK version values.
    432      *
    433      * @param x509Certificate the signing certificate for which to search
    434      * @return A new SigningCertificateLineage if present, or null otherwise.
    435      */
    436     public SigningCertificateLineage getSubLineage(X509Certificate x509Certificate) {
    437         if (x509Certificate == null) {
    438             throw new NullPointerException("x509Certificate == null");
    439         }
    440         for (int i = 0; i < mSigningLineage.size(); i++) {
    441             if (mSigningLineage.get(i).signingCert.equals(x509Certificate)) {
    442                 return new SigningCertificateLineage(
    443                         mMinSdkVersion, new ArrayList<>(mSigningLineage.subList(0, i + 1)));
    444             }
    445         }
    446 
    447         // looks like we didn't find the cert,
    448         throw new IllegalArgumentException("Certificate not found in SigningCertificateLineage");
    449     }
    450 
    451     /**
    452      * Consolidates all of the lineages found in an APK into one lineage, which is the longest one.
    453      * In so doing, it also checks that all of the smaller lineages are contained in the largest,
    454      * and that they properly cover the desired platform ranges.
    455      *
    456      * An APK may contain multiple lineages, one for each signer, which correspond to different
    457      * supported platform versions.  In this event, the lineage(s) from the earlier platform
    458      * version(s) need to be present in the most recent (longest) one to make sure that when a
    459      * platform version changes.
    460      *
    461      * <note> This does not verify that the largest lineage corresponds to the most recent supported
    462      * platform version.  That check requires is performed during v3 verification. </note>
    463      */
    464     public static SigningCertificateLineage consolidateLineages(
    465             List<SigningCertificateLineage> lineages) {
    466         if (lineages == null || lineages.isEmpty()) {
    467             return null;
    468         }
    469         int largestIndex = 0;
    470         int maxSize = 0;
    471 
    472         // determine the longest chain
    473         for (int i = 0; i < lineages.size(); i++) {
    474             int curSize = lineages.get(i).size();
    475             if (curSize > maxSize) {
    476                 largestIndex = i;
    477                 maxSize = curSize;
    478             }
    479         }
    480 
    481         List<SigningCertificateNode> largestList = lineages.get(largestIndex).mSigningLineage;
    482         // make sure all other lineages fit into this one, with the same capabilities
    483         for (int i = 0; i < lineages.size(); i++) {
    484             if (i == largestIndex) {
    485                 continue;
    486             }
    487             List<SigningCertificateNode> underTest = lineages.get(i).mSigningLineage;
    488             if (!underTest.equals(largestList.subList(0, underTest.size()))) {
    489                 throw new IllegalArgumentException("Inconsistent SigningCertificateLineages. "
    490                         + "Not all lineages are subsets of each other.");
    491             }
    492         }
    493 
    494         // if we've made it this far, they all check out, so just return the largest
    495         return lineages.get(largestIndex);
    496     }
    497 
    498     /**
    499      * Representation of the capabilities the APK would like to grant to its old signing
    500      * certificates.  The {@code SigningCertificateLineage} provides two conceptual data structures.
    501      *   1) proof of rotation - Evidence that other parties can trust an APK's current signing
    502      *      certificate if they trust an older one in this lineage
    503      *   2) self-trust - certain capabilities may have been granted by an APK to other parties based
    504      *      on its own signing certificate.  When it changes its signing certificate it may want to
    505      *      allow the other parties to retain those capabilities.
    506      * {@code SignerCapabilties} provides a representation of the second structure.
    507      *
    508      * <p>Use {@link Builder} to obtain configuration instances.
    509      */
    510     public static class SignerCapabilities {
    511         private final int mFlags;
    512 
    513         private SignerCapabilities(int flags) {
    514             mFlags = flags;
    515         }
    516 
    517         private int getFlags() {
    518             return mFlags;
    519         }
    520 
    521         /**
    522          * Builder of {@link SignerCapabilities} instances.
    523          */
    524         public static class Builder {
    525             private int mFlags;
    526 
    527             /**
    528              * Constructs a new {@code Builder}.
    529              */
    530             public Builder() {
    531                 mFlags = calculateDefaultFlags();
    532             }
    533 
    534             /**
    535              * Set the {@code PAST_CERT_INSTALLED_DATA} flag in this capabilities object.  This flag
    536              * is used by the platform to determine if installed data associated with previous
    537              * signing certificate should be trusted.  In particular, this capability is required to
    538              * perform signing certificate rotation during an upgrade on-device.  Without it, the
    539              * platform will not permit the app data from the old signing certificate to
    540              * propagate to the new version.  Typically, this flag should be set to enable signing
    541              * certificate rotation, and may be unset later when the app developer is satisfied that
    542              * their install base is as migrated as it will be.
    543              */
    544             public Builder setInstalledData(boolean enabled) {
    545                 if (enabled) {
    546                     mFlags |= PAST_CERT_INSTALLED_DATA;
    547                 } else {
    548                     mFlags &= ~PAST_CERT_INSTALLED_DATA;
    549                 }
    550                 return this;
    551             }
    552 
    553             /**
    554              * Set the {@code PAST_CERT_SHARED_USER_ID} flag in this capabilities object.  This flag
    555              * is used by the platform to determine if this app is willing to be sharedUid with
    556              * other apps which are still signed with the associated signing certificate.  This is
    557              * useful in situations where sharedUserId apps would like to change their signing
    558              * certificate, but can't guarantee the order of updates to those apps.
    559              */
    560             public Builder setSharedUid(boolean enabled) {
    561                 if (enabled) {
    562                     mFlags |= PAST_CERT_SHARED_USER_ID;
    563                 } else {
    564                     mFlags &= ~PAST_CERT_SHARED_USER_ID;
    565                 }
    566                 return this;
    567             }
    568 
    569             /**
    570              * Set the {@code PAST_CERT_PERMISSION} flag in this capabilities object.  This flag
    571              * is used by the platform to determine if this app is willing to grant SIGNATURE
    572              * permissions to apps signed with the associated signing certificate.  Without this
    573              * capability, an application signed with the older certificate will not be granted the
    574              * SIGNATURE permissions defined by this app.  In addition, if multiple apps define the
    575              * same SIGNATURE permission, the second one the platform sees will not be installable
    576              * if this capability is not set and the signing certificates differ.
    577              */
    578             public Builder setPermission(boolean enabled) {
    579                 if (enabled) {
    580                     mFlags |= PAST_CERT_PERMISSION;
    581                 } else {
    582                     mFlags &= ~PAST_CERT_PERMISSION;
    583                 }
    584                 return this;
    585             }
    586 
    587             /**
    588              * Set the {@code PAST_CERT_ROLLBACK} flag in this capabilities object.  This flag
    589              * is used by the platform to determine if this app is willing to upgrade to a new
    590              * version that is signed by one of its past signing certificates.
    591              *
    592              * <note> WARNING: this effectively removes any benefit of signing certificate changes,
    593              * since a compromised key could retake control of an app even after change, and should
    594              * only be used if there is a problem encountered when trying to ditch an older cert
    595              * </note>
    596              */
    597             public Builder setRollback(boolean enabled) {
    598                 if (enabled) {
    599                     mFlags |= PAST_CERT_ROLLBACK;
    600                 } else {
    601                     mFlags &= ~PAST_CERT_ROLLBACK;
    602                 }
    603                 return this;
    604             }
    605 
    606             /**
    607              * Set the {@code PAST_CERT_AUTH} flag in this capabilities object.  This flag
    608              * is used by the platform to determine whether or not privileged access based on
    609              * authenticator module signing certificates should be granted.
    610              */
    611             public Builder setAuth(boolean enabled) {
    612                 if (enabled) {
    613                     mFlags |= PAST_CERT_AUTH;
    614                 } else {
    615                     mFlags &= ~PAST_CERT_AUTH;
    616                 }
    617                 return this;
    618             }
    619 
    620             /**
    621              * Returns a new {@code SignerConfig} instance configured based on the configuration of
    622              * this builder.
    623              */
    624             public SignerCapabilities build() {
    625                 return new SignerCapabilities(mFlags);
    626             }
    627         }
    628     }
    629 
    630     /**
    631      * Configuration of a signer.  Used to add a new entry to the {@link SigningCertificateLineage}
    632      *
    633      * <p>Use {@link Builder} to obtain configuration instances.
    634      */
    635     public static class SignerConfig {
    636         private final PrivateKey mPrivateKey;
    637         private final X509Certificate mCertificate;
    638 
    639         private SignerConfig(
    640                 PrivateKey privateKey,
    641                 X509Certificate certificate) {
    642             mPrivateKey = privateKey;
    643             mCertificate = certificate;
    644         }
    645 
    646         /**
    647          * Returns the signing key of this signer.
    648          */
    649         public PrivateKey getPrivateKey() {
    650             return mPrivateKey;
    651         }
    652 
    653         /**
    654          * Returns the certificate(s) of this signer. The first certificate's public key corresponds
    655          * to this signer's private key.
    656          */
    657         public X509Certificate getCertificate() {
    658             return mCertificate;
    659         }
    660 
    661         /**
    662          * Builder of {@link SignerConfig} instances.
    663          */
    664         public static class Builder {
    665             private final PrivateKey mPrivateKey;
    666             private final X509Certificate mCertificate;
    667 
    668             /**
    669              * Constructs a new {@code Builder}.
    670              *
    671              * @param privateKey signing key
    672              * @param certificate the X.509 certificate with a subject public key of the
    673              * {@code privateKey}.
    674              */
    675             public Builder(
    676                     PrivateKey privateKey,
    677                     X509Certificate certificate) {
    678                 mPrivateKey = privateKey;
    679                 mCertificate = certificate;
    680             }
    681 
    682             /**
    683              * Returns a new {@code SignerConfig} instance configured based on the configuration of
    684              * this builder.
    685              */
    686             public SignerConfig build() {
    687                 return new SignerConfig(
    688                         mPrivateKey,
    689                         mCertificate);
    690             }
    691         }
    692     }
    693 
    694     /**
    695      * Builder of {@link SigningCertificateLineage} instances.
    696      */
    697     public static class Builder {
    698         private final SignerConfig mOriginalSignerConfig;
    699         private final SignerConfig mNewSignerConfig;
    700         private SignerCapabilities mOriginalCapabilities;
    701         private SignerCapabilities mNewCapabilities;
    702         private int mMinSdkVersion;
    703         /**
    704          * Constructs a new {@code Builder}.
    705          *
    706          * @param originalSignerConfig first signer in this lineage, parent of the next
    707          * @param newSignerConfig new signer in the lineage; the new signing key that the APK will
    708          *                        use
    709          */
    710         public Builder(
    711                 SignerConfig originalSignerConfig,
    712                 SignerConfig newSignerConfig) {
    713             if (originalSignerConfig == null || newSignerConfig == null) {
    714                 throw new NullPointerException("Can't pass null SignerConfigs when constructing a "
    715                         + "new SigningCertificateLineage");
    716             }
    717             mOriginalSignerConfig = originalSignerConfig;
    718             mNewSignerConfig = newSignerConfig;
    719         }
    720 
    721         /**
    722          * Sets the minimum Android platform version (API Level) on which this lineage is expected
    723          * to validate.  It is possible that newer signers in the lineage may not be recognized on
    724          * the given platform, but as long as an older signer is, the lineage can still be used to
    725          * sign an APK for the given platform.
    726          *
    727          * <note> By default, this value is set to the value for the
    728          * P release, since this structure was created for that release, and will also be set to
    729          * that value if a smaller one is specified. </note>
    730          */
    731         public Builder setMinSdkVersion(int minSdkVersion) {
    732             mMinSdkVersion = minSdkVersion;
    733             return this;
    734         }
    735 
    736         /**
    737          * Sets capabilities to give {@code mOriginalSignerConfig}. These capabilities allow an
    738          * older signing certificate to still be used in some situations on the platform even though
    739          * the APK is now being signed by a newer signing certificate.
    740          */
    741         public Builder setOriginalCapabilities(SignerCapabilities signerCapabilities) {
    742             if (signerCapabilities == null) {
    743                 throw new NullPointerException("signerCapabilities == null");
    744             }
    745             mOriginalCapabilities = signerCapabilities;
    746             return this;
    747         }
    748 
    749         /**
    750          * Sets capabilities to give {@code mNewSignerConfig}. These capabilities allow an
    751          * older signing certificate to still be used in some situations on the platform even though
    752          * the APK is now being signed by a newer signing certificate.  By default, the new signer
    753          * will have all capabilities, so when first switching to a new signing certificate, these
    754          * capabilities have no effect, but they will act as the default level of trust when moving
    755          * to a new signing certificate.
    756          */
    757         public Builder setNewCapabilities(SignerCapabilities signerCapabilities) {
    758             if (signerCapabilities == null) {
    759                 throw new NullPointerException("signerCapabilities == null");
    760             }
    761             mNewCapabilities = signerCapabilities;
    762             return this;
    763         }
    764 
    765         public SigningCertificateLineage build()
    766                 throws CertificateEncodingException, InvalidKeyException, NoSuchAlgorithmException,
    767                 SignatureException {
    768             if (mMinSdkVersion < AndroidSdkVersion.P) {
    769                 mMinSdkVersion = AndroidSdkVersion.P;
    770             }
    771 
    772             if (mOriginalCapabilities == null) {
    773                 mOriginalCapabilities = new SignerCapabilities.Builder().build();
    774             }
    775 
    776             if (mNewCapabilities == null) {
    777                 mNewCapabilities = new SignerCapabilities.Builder().build();
    778             }
    779 
    780             return createSigningLineage(
    781                     mMinSdkVersion, mOriginalSignerConfig, mOriginalCapabilities,
    782                     mNewSignerConfig, mNewCapabilities);
    783         }
    784     }
    785 }
    786