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 
SigningCertificateLineage(int minSdkVersion, List<SigningCertificateNode> list)105     private SigningCertificateLineage(int minSdkVersion, List<SigningCertificateNode> list) {
106         mMinSdkVersion = minSdkVersion;
107         mSigningLineage = list;
108     }
109 
createSigningLineage( int minSdkVersion, SignerConfig parent, SignerCapabilities parentCapabilities, SignerConfig child, SignerCapabilities childCapabilities)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 
readFromFile(File file)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 
readFromDataSource(DataSource dataSource)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      */
readFromV3AttributeValue(byte[] attrValue)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 
readFromApkFile(File apkFile)160     public static SigningCertificateLineage readFromApkFile(File apkFile) {
161         throw new UnsupportedOperationException("Not yet implemented");
162     }
163 
writeToFile(File file)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 
writeToDataSink(DataSink dataSink)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      */
spawnDescendant(SignerConfig parent, SignerConfig child)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      */
spawnDescendant( SignerConfig parent, SignerConfig child, SignerCapabilities childCapabilities)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      */
size()273     public int size() {
274         return mSigningLineage.size();
275     }
276 
getSignatureAlgorithm(SignerConfig parent)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 
spawnFirstDescendant( SignerConfig parent, SignerCapabilities signerCapabilities)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 
read(ByteBuffer inputByteBuffer)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 
read(ByteBuffer inputByteBuffer, int version)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 
calculateMinSdkVersion(List<SigningCertificateNode> nodes)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 
write()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 
generateV3SignerAttribute()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 
sortSignerConfigs( List<DefaultApkSignerEngine.SignerConfig> signerConfigs)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 
calculateDefaultFlags()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      */
getSubLineage(X509Certificate x509Certificate)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      */
consolidateLineages( List<SigningCertificateLineage> lineages)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 
SignerCapabilities(int flags)513         private SignerCapabilities(int flags) {
514             mFlags = flags;
515         }
516 
getFlags()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              */
Builder()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              */
setInstalledData(boolean enabled)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              */
setSharedUid(boolean enabled)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              */
setPermission(boolean enabled)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              */
setRollback(boolean enabled)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              */
setAuth(boolean enabled)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              */
build()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 
SignerConfig( PrivateKey privateKey, X509Certificate certificate)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          */
getPrivateKey()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          */
getCertificate()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              */
Builder( PrivateKey privateKey, X509Certificate certificate)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              */
build()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          */
Builder( SignerConfig originalSignerConfig, SignerConfig newSignerConfig)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          */
setMinSdkVersion(int minSdkVersion)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          */
setOriginalCapabilities(SignerCapabilities signerCapabilities)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          */
setNewCapabilities(SignerCapabilities signerCapabilities)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 
build()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