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.apk.ApkUtils;
23 import com.android.apksig.internal.apk.ApkSigningBlockUtils;
24 import com.android.apksig.internal.apk.SignatureAlgorithm;
25 import com.android.apksig.internal.apk.SignatureInfo;
26 import com.android.apksig.internal.apk.v3.V3SchemeConstants;
27 import com.android.apksig.internal.apk.v3.V3SchemeSigner;
28 import com.android.apksig.internal.apk.v3.V3SigningCertificateLineage;
29 import com.android.apksig.internal.apk.v3.V3SigningCertificateLineage.SigningCertificateNode;
30 import com.android.apksig.internal.util.AndroidSdkVersion;
31 import com.android.apksig.internal.util.ByteBufferUtils;
32 import com.android.apksig.internal.util.Pair;
33 import com.android.apksig.internal.util.RandomAccessFileDataSink;
34 import com.android.apksig.util.DataSink;
35 import com.android.apksig.util.DataSource;
36 import com.android.apksig.util.DataSources;
37 import com.android.apksig.zip.ZipFormatException;
38 
39 import java.io.File;
40 import java.io.IOException;
41 import java.io.RandomAccessFile;
42 import java.nio.ByteBuffer;
43 import java.nio.ByteOrder;
44 import java.security.InvalidKeyException;
45 import java.security.NoSuchAlgorithmException;
46 import java.security.PrivateKey;
47 import java.security.PublicKey;
48 import java.security.SignatureException;
49 import java.security.cert.CertificateEncodingException;
50 import java.security.cert.X509Certificate;
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.Collections;
54 import java.util.List;
55 
56 /**
57  * APK Signer Lineage.
58  *
59  * <p>The signer lineage contains a history of signing certificates with each ancestor attesting to
60  * the validity of its descendant.  Each additional descendant represents a new identity that can be
61  * used to sign an APK, and each generation has accompanying attributes which represent how the
62  * APK would like to view the older signing certificates, specifically how they should be trusted in
63  * certain situations.
64  *
65  * <p> Its primary use is to enable APK Signing Certificate Rotation.  The Android platform verifies
66  * the APK Signer Lineage, and if the current signing certificate for the APK is in the Signer
67  * Lineage, and the Lineage contains the certificate the platform associates with the APK, it will
68  * allow upgrades to the new certificate.
69  *
70  * @see <a href="https://source.android.com/security/apksigning/index.html">Application Signing</a>
71  */
72 public class SigningCertificateLineage {
73 
74     public final static int MAGIC = 0x3eff39d1;
75 
76     private final static int FIRST_VERSION = 1;
77 
78     private static final int CURRENT_VERSION = FIRST_VERSION;
79 
80     /** accept data from already installed pkg with this cert */
81     private static final int PAST_CERT_INSTALLED_DATA = 1;
82 
83     /** accept sharedUserId with pkg with this cert */
84     private static final int PAST_CERT_SHARED_USER_ID = 2;
85 
86     /** grant SIGNATURE permissions to pkgs with this cert */
87     private static final int PAST_CERT_PERMISSION = 4;
88 
89     /**
90      * Enable updates back to this certificate.  WARNING: this effectively removes any benefit of
91      * signing certificate changes, since a compromised key could retake control of an app even
92      * after change, and should only be used if there is a problem encountered when trying to ditch
93      * an older cert.
94      */
95     private static final int PAST_CERT_ROLLBACK = 8;
96 
97     /**
98      * Preserve authenticator module-based access in AccountManager gated by signing certificate.
99      */
100     private static final int PAST_CERT_AUTH = 16;
101 
102     private final int mMinSdkVersion;
103 
104     /**
105      * The signing lineage is just a list of nodes, with the first being the original signing
106      * certificate and the most recent being the one with which the APK is to actually be signed.
107      */
108     private final List<SigningCertificateNode> mSigningLineage;
109 
SigningCertificateLineage(int minSdkVersion, List<SigningCertificateNode> list)110     private SigningCertificateLineage(int minSdkVersion, List<SigningCertificateNode> list) {
111         mMinSdkVersion = minSdkVersion;
112         mSigningLineage = list;
113     }
114 
115     /**
116      * Creates a {@code SigningCertificateLineage} with a single signer in the lineage.
117      */
createSigningLineage(int minSdkVersion, SignerConfig signer, SignerCapabilities capabilities)118     private static SigningCertificateLineage createSigningLineage(int minSdkVersion,
119             SignerConfig signer, SignerCapabilities capabilities) {
120         SigningCertificateLineage signingCertificateLineage = new SigningCertificateLineage(
121                 minSdkVersion, new ArrayList<>());
122         return signingCertificateLineage.spawnFirstDescendant(signer, capabilities);
123     }
124 
createSigningLineage( int minSdkVersion, SignerConfig parent, SignerCapabilities parentCapabilities, SignerConfig child, SignerCapabilities childCapabilities)125     private static SigningCertificateLineage createSigningLineage(
126             int minSdkVersion, SignerConfig parent, SignerCapabilities parentCapabilities,
127             SignerConfig child, SignerCapabilities childCapabilities)
128             throws CertificateEncodingException, InvalidKeyException, NoSuchAlgorithmException,
129             SignatureException {
130         SigningCertificateLineage signingCertificateLineage =
131                 new SigningCertificateLineage(minSdkVersion, new ArrayList<>());
132         signingCertificateLineage =
133                 signingCertificateLineage.spawnFirstDescendant(parent, parentCapabilities);
134         return signingCertificateLineage.spawnDescendant(parent, child, childCapabilities);
135     }
136 
readFromBytes(byte[] lineageBytes)137     public static SigningCertificateLineage readFromBytes(byte[] lineageBytes)
138             throws IOException {
139         return readFromDataSource(DataSources.asDataSource(ByteBuffer.wrap(lineageBytes)));
140     }
141 
readFromFile(File file)142     public static SigningCertificateLineage readFromFile(File file)
143             throws IOException {
144         if (file == null) {
145             throw new NullPointerException("file == null");
146         }
147         RandomAccessFile inputFile = new RandomAccessFile(file, "r");
148         return readFromDataSource(DataSources.asDataSource(inputFile));
149     }
150 
readFromDataSource(DataSource dataSource)151     public static SigningCertificateLineage readFromDataSource(DataSource dataSource)
152             throws IOException {
153         if (dataSource == null) {
154             throw new NullPointerException("dataSource == null");
155         }
156         ByteBuffer inBuff = dataSource.getByteBuffer(0, (int) dataSource.size());
157         inBuff.order(ByteOrder.LITTLE_ENDIAN);
158         return read(inBuff);
159     }
160 
161     /**
162      * Extracts a Signing Certificate Lineage from a v3 signer proof-of-rotation attribute.
163      *
164      * <note>
165      *     this may not give a complete representation of an APK's signing certificate history,
166      *     since the APK may have multiple signers corresponding to different platform versions.
167      *     Use <code> readFromApkFile</code> to handle this case.
168      * </note>
169      * @param attrValue
170      */
readFromV3AttributeValue(byte[] attrValue)171     public static SigningCertificateLineage readFromV3AttributeValue(byte[] attrValue)
172             throws IOException {
173         List<SigningCertificateNode> parsedLineage =
174                 V3SigningCertificateLineage.readSigningCertificateLineage(ByteBuffer.wrap(
175                         attrValue).order(ByteOrder.LITTLE_ENDIAN));
176         int minSdkVersion = calculateMinSdkVersion(parsedLineage);
177         return  new SigningCertificateLineage(minSdkVersion, parsedLineage);
178     }
179 
180     /**
181      * Extracts a Signing Certificate Lineage from the proof-of-rotation attribute in the V3
182      * signature block of the provided APK File.
183      *
184      * @throws IllegalArgumentException if the provided APK does not contain a V3 signature block,
185      * or if the V3 signature block does not contain a valid lineage.
186      */
readFromApkFile(File apkFile)187     public static SigningCertificateLineage readFromApkFile(File apkFile)
188             throws IOException, ApkFormatException {
189         try (RandomAccessFile f = new RandomAccessFile(apkFile, "r")) {
190             DataSource apk = DataSources.asDataSource(f, 0, f.length());
191             return readFromApkDataSource(apk);
192         }
193     }
194 
195     /**
196      * Extracts a Signing Certificate Lineage from the proof-of-rotation attribute in the V3 and
197      * V3.1 signature blocks of the provided APK DataSource.
198      *
199      * @throws IllegalArgumentException if the provided APK does not contain a V3 nor V3.1
200      * signature block, or if the V3 and V3.1 signature blocks do not contain a valid lineage.
201      */
202 
readFromApkDataSource(DataSource apk)203     public static SigningCertificateLineage readFromApkDataSource(DataSource apk)
204             throws IOException, ApkFormatException {
205         return readFromApkDataSource(apk, /* readV31Lineage= */ true,  /* readV3Lineage= */true);
206     }
207 
208     /**
209      * Extracts a Signing Certificate Lineage from the proof-of-rotation attribute in the V3.1
210      * signature blocks of the provided APK DataSource.
211      *
212      * @throws IllegalArgumentException if the provided APK does not contain a V3.1 signature block,
213      * or if the V3.1 signature block does not contain a valid lineage.
214      */
215 
readV31FromApkDataSource(DataSource apk)216     public static SigningCertificateLineage readV31FromApkDataSource(DataSource apk)
217             throws IOException, ApkFormatException {
218             return readFromApkDataSource(apk, /* readV31Lineage= */ true,
219                         /* readV3Lineage= */ false);
220     }
221 
readFromApkDataSource( DataSource apk, boolean readV31Lineage, boolean readV3Lineage)222     private static SigningCertificateLineage readFromApkDataSource(
223             DataSource apk,
224             boolean readV31Lineage,
225             boolean readV3Lineage)
226             throws IOException, ApkFormatException {
227         ApkUtils.ZipSections zipSections;
228         try {
229             zipSections = ApkUtils.findZipSections(apk);
230         } catch (ZipFormatException e) {
231             throw new ApkFormatException(e.getMessage());
232         }
233 
234         List<SignatureInfo> signatureInfoList = new ArrayList<>();
235         if (readV31Lineage) {
236             try {
237                 ApkSigningBlockUtils.Result result = new ApkSigningBlockUtils.Result(
238                     ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V31);
239                 signatureInfoList.add(
240                     ApkSigningBlockUtils.findSignature(apk, zipSections,
241                         V3SchemeConstants.APK_SIGNATURE_SCHEME_V31_BLOCK_ID, result));
242             } catch (ApkSigningBlockUtils.SignatureNotFoundException ignored) {
243                 // This could be expected if there's only a V3 signature block.
244             }
245         }
246         if (readV3Lineage) {
247             try {
248                 ApkSigningBlockUtils.Result result = new ApkSigningBlockUtils.Result(
249                     ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3);
250                 signatureInfoList.add(
251                     ApkSigningBlockUtils.findSignature(apk, zipSections,
252                         V3SchemeConstants.APK_SIGNATURE_SCHEME_V3_BLOCK_ID, result));
253             } catch (ApkSigningBlockUtils.SignatureNotFoundException ignored) {
254                 // This could be expected if the provided APK is not signed with the V3 signature
255                 // scheme
256             }
257         }
258         if (signatureInfoList.isEmpty()) {
259             String message;
260             if (readV31Lineage && readV3Lineage) {
261                 message = "The provided APK does not contain a valid V3 nor V3.1 signature block.";
262             } else if (readV31Lineage) {
263                 message = "The provided APK does not contain a valid V3.1 signature block.";
264             } else if (readV3Lineage) {
265                 message = "The provided APK does not contain a valid V3 signature block.";
266             } else {
267                 message = "No signature blocks were requested.";
268             }
269             throw new IllegalArgumentException(message);
270         }
271 
272         List<SigningCertificateLineage> lineages = new ArrayList<>(1);
273         for (SignatureInfo signatureInfo : signatureInfoList) {
274             // FORMAT:
275             // * length-prefixed sequence of length-prefixed signers:
276             //   * length-prefixed signed data
277             //   * minSDK
278             //   * maxSDK
279             //   * length-prefixed sequence of length-prefixed signatures
280             //   * length-prefixed public key
281             ByteBuffer signers = getLengthPrefixedSlice(signatureInfo.signatureBlock);
282             while (signers.hasRemaining()) {
283                 ByteBuffer signer = getLengthPrefixedSlice(signers);
284                 ByteBuffer signedData = getLengthPrefixedSlice(signer);
285                 try {
286                     SigningCertificateLineage lineage = readFromSignedData(signedData);
287                     lineages.add(lineage);
288                 } catch (IllegalArgumentException ignored) {
289                     // The current signer block does not contain a valid lineage, but it is possible
290                     // another block will.
291                 }
292             }
293         }
294 
295         SigningCertificateLineage result;
296         if (lineages.isEmpty()) {
297             throw new IllegalArgumentException(
298                     "The provided APK does not contain a valid lineage.");
299         } else if (lineages.size() > 1) {
300             result = consolidateLineages(lineages);
301         } else {
302             result = lineages.get(0);
303         }
304         return result;
305     }
306 
307     /**
308      * Extracts a Signing Certificate Lineage from the proof-of-rotation attribute in the provided
309      * signed data portion of a signer in a V3 signature block.
310      *
311      * @throws IllegalArgumentException if the provided signed data does not contain a valid
312      * lineage.
313      */
readFromSignedData(ByteBuffer signedData)314     public static SigningCertificateLineage readFromSignedData(ByteBuffer signedData)
315             throws IOException, ApkFormatException {
316         // FORMAT:
317         //   * length-prefixed sequence of length-prefixed digests:
318         //   * length-prefixed sequence of certificates:
319         //     * length-prefixed bytes: X.509 certificate (ASN.1 DER encoded).
320         //   * uint-32: minSdkVersion
321         //   * uint-32: maxSdkVersion
322         //   * length-prefixed sequence of length-prefixed additional attributes:
323         //     * uint32: ID
324         //     * (length - 4) bytes: value
325         //     * uint32: Proof-of-rotation ID: 0x3ba06f8c
326         //     * length-prefixed proof-of-rotation structure
327         // consume the digests through the maxSdkVersion to reach the lineage in the attributes
328         getLengthPrefixedSlice(signedData);
329         getLengthPrefixedSlice(signedData);
330         signedData.getInt();
331         signedData.getInt();
332         // iterate over the additional attributes adding any lineages to the List
333         ByteBuffer additionalAttributes = getLengthPrefixedSlice(signedData);
334         List<SigningCertificateLineage> lineages = new ArrayList<>(1);
335         while (additionalAttributes.hasRemaining()) {
336             ByteBuffer attribute = getLengthPrefixedSlice(additionalAttributes);
337             int id = attribute.getInt();
338             if (id == V3SchemeConstants.PROOF_OF_ROTATION_ATTR_ID) {
339                 byte[] value = ByteBufferUtils.toByteArray(attribute);
340                 SigningCertificateLineage lineage = readFromV3AttributeValue(value);
341                 lineages.add(lineage);
342             }
343         }
344         SigningCertificateLineage result;
345         // There should only be a single attribute with the lineage, but if there are multiple then
346         // attempt to consolidate the lineages.
347         if (lineages.isEmpty()) {
348             throw new IllegalArgumentException("The signed data does not contain a valid lineage.");
349         } else if (lineages.size() > 1) {
350             result = consolidateLineages(lineages);
351         } else {
352             result = lineages.get(0);
353         }
354         return result;
355     }
356 
getBytes()357     public byte[] getBytes() {
358         return write().array();
359     }
360 
writeToFile(File file)361     public void writeToFile(File file) throws IOException {
362         if (file == null) {
363             throw new NullPointerException("file == null");
364         }
365         RandomAccessFile outputFile = new RandomAccessFile(file, "rw");
366         writeToDataSink(new RandomAccessFileDataSink(outputFile));
367     }
368 
writeToDataSink(DataSink dataSink)369     public void writeToDataSink(DataSink dataSink) throws IOException {
370         if (dataSink == null) {
371             throw new NullPointerException("dataSink == null");
372         }
373         dataSink.consume(write());
374     }
375 
376     /**
377      * Add a new signing certificate to the lineage.  This effectively creates a signing certificate
378      * rotation event, forcing APKs which include this lineage to be signed by the new signer. The
379      * flags associated with the new signer are set to a default value.
380      *
381      * @param parent current signing certificate of the containing APK
382      * @param child new signing certificate which will sign the APK contents
383      */
spawnDescendant(SignerConfig parent, SignerConfig child)384     public SigningCertificateLineage spawnDescendant(SignerConfig parent, SignerConfig child)
385             throws CertificateEncodingException, InvalidKeyException, NoSuchAlgorithmException,
386             SignatureException {
387         if (parent == null || child == null) {
388             throw new NullPointerException("can't add new descendant to lineage with null inputs");
389         }
390         SignerCapabilities signerCapabilities = new SignerCapabilities.Builder().build();
391         return spawnDescendant(parent, child, signerCapabilities);
392     }
393 
394     /**
395      * Add a new signing certificate to the lineage.  This effectively creates a signing certificate
396      * rotation event, forcing APKs which include this lineage to be signed by the new signer.
397      *
398      * @param parent current signing certificate of the containing APK
399      * @param child new signing certificate which will sign the APK contents
400      * @param childCapabilities flags
401      */
spawnDescendant( SignerConfig parent, SignerConfig child, SignerCapabilities childCapabilities)402     public SigningCertificateLineage spawnDescendant(
403             SignerConfig parent, SignerConfig child, SignerCapabilities childCapabilities)
404             throws CertificateEncodingException, InvalidKeyException,
405             NoSuchAlgorithmException, SignatureException {
406         if (parent == null) {
407             throw new NullPointerException("parent == null");
408         }
409         if (child == null) {
410             throw new NullPointerException("child == null");
411         }
412         if (childCapabilities == null) {
413             throw new NullPointerException("childCapabilities == null");
414         }
415         if (mSigningLineage.isEmpty()) {
416             throw new IllegalArgumentException("Cannot spawn descendant signing certificate on an"
417                     + " empty SigningCertificateLineage: no parent node");
418         }
419 
420         // make sure that the parent matches our newest generation (leaf node/sink)
421         SigningCertificateNode currentGeneration = mSigningLineage.get(mSigningLineage.size() - 1);
422         if (!Arrays.equals(currentGeneration.signingCert.getEncoded(),
423                 parent.getCertificate().getEncoded())) {
424             throw new IllegalArgumentException("SignerConfig Certificate containing private key"
425                     + " to sign the new SigningCertificateLineage record does not match the"
426                     + " existing most recent record");
427         }
428 
429         // create data to be signed, including the algorithm we're going to use
430         SignatureAlgorithm signatureAlgorithm = getSignatureAlgorithm(parent);
431         ByteBuffer prefixedSignedData = ByteBuffer.wrap(
432                 V3SigningCertificateLineage.encodeSignedData(
433                         child.getCertificate(), signatureAlgorithm.getId()));
434         prefixedSignedData.position(4);
435         ByteBuffer signedDataBuffer = ByteBuffer.allocate(prefixedSignedData.remaining());
436         signedDataBuffer.put(prefixedSignedData);
437         byte[] signedData = signedDataBuffer.array();
438 
439         // create SignerConfig to do the signing
440         List<X509Certificate> certificates = new ArrayList<>(1);
441         certificates.add(parent.getCertificate());
442         ApkSigningBlockUtils.SignerConfig newSignerConfig =
443                 new ApkSigningBlockUtils.SignerConfig();
444         newSignerConfig.keyConfig = parent.getKeyConfig();
445         newSignerConfig.certificates = certificates;
446         newSignerConfig.signatureAlgorithms = Collections.singletonList(signatureAlgorithm);
447 
448         // sign it
449         List<Pair<Integer, byte[]>> signatures =
450                 ApkSigningBlockUtils.generateSignaturesOverData(newSignerConfig, signedData);
451 
452         // finally, add it to our lineage
453         SignatureAlgorithm sigAlgorithm = SignatureAlgorithm.findById(signatures.get(0).getFirst());
454         byte[] signature = signatures.get(0).getSecond();
455         currentGeneration.sigAlgorithm = sigAlgorithm;
456         SigningCertificateNode childNode =
457                 new SigningCertificateNode(
458                         child.getCertificate(), sigAlgorithm, null,
459                         signature, childCapabilities.getFlags());
460         List<SigningCertificateNode> lineageCopy = new ArrayList<>(mSigningLineage);
461         lineageCopy.add(childNode);
462         return new SigningCertificateLineage(mMinSdkVersion, lineageCopy);
463     }
464 
465     /**
466      * The number of signing certificates in the lineage, including the current signer, which means
467      * this value can also be used to V2determine the number of signing certificate rotations by
468      * subtracting 1.
469      */
size()470     public int size() {
471         return mSigningLineage.size();
472     }
473 
getSignatureAlgorithm(SignerConfig parent)474     private SignatureAlgorithm getSignatureAlgorithm(SignerConfig parent)
475             throws InvalidKeyException {
476         PublicKey publicKey = parent.getCertificate().getPublicKey();
477 
478         // TODO switch to one signature algorithm selection, or add support for multiple algorithms
479         List<SignatureAlgorithm> algorithms = V3SchemeSigner.getSuggestedSignatureAlgorithms(
480                 publicKey, mMinSdkVersion, false /* verityEnabled */,
481                 false /* deterministicDsaSigning */);
482         return algorithms.get(0);
483     }
484 
spawnFirstDescendant( SignerConfig parent, SignerCapabilities signerCapabilities)485     private SigningCertificateLineage spawnFirstDescendant(
486             SignerConfig parent, SignerCapabilities signerCapabilities) {
487         if (!mSigningLineage.isEmpty()) {
488             throw new IllegalStateException("SigningCertificateLineage already has its first node");
489         }
490 
491         // check to make sure that the public key for the first node is acceptable for our minSdk
492         try {
493             getSignatureAlgorithm(parent);
494         } catch (InvalidKeyException e) {
495             throw new IllegalArgumentException("Algorithm associated with first signing certificate"
496                     + " invalid on desired platform versions", e);
497         }
498 
499         // create "fake" signed data (there will be no signature over it, since there is no parent
500         SigningCertificateNode firstNode = new SigningCertificateNode(
501                 parent.getCertificate(), null, null, new byte[0], signerCapabilities.getFlags());
502         return new SigningCertificateLineage(mMinSdkVersion, Collections.singletonList(firstNode));
503     }
504 
read(ByteBuffer inputByteBuffer)505     private static SigningCertificateLineage read(ByteBuffer inputByteBuffer)
506             throws IOException {
507         ApkSigningBlockUtils.checkByteOrderLittleEndian(inputByteBuffer);
508         if (inputByteBuffer.remaining() < 8) {
509             throw new IllegalArgumentException(
510                     "Improper SigningCertificateLineage format: insufficient data for header.");
511         }
512 
513         if (inputByteBuffer.getInt() != MAGIC) {
514             throw new IllegalArgumentException(
515                     "Improper SigningCertificateLineage format: MAGIC header mismatch.");
516         }
517         return read(inputByteBuffer, inputByteBuffer.getInt());
518     }
519 
read(ByteBuffer inputByteBuffer, int version)520     private static SigningCertificateLineage read(ByteBuffer inputByteBuffer, int version)
521             throws IOException {
522         switch (version) {
523             case FIRST_VERSION:
524                 try {
525                     List<SigningCertificateNode> nodes =
526                             V3SigningCertificateLineage.readSigningCertificateLineage(
527                                     getLengthPrefixedSlice(inputByteBuffer));
528                     int minSdkVersion = calculateMinSdkVersion(nodes);
529                     return new SigningCertificateLineage(minSdkVersion, nodes);
530                 } catch (ApkFormatException e) {
531                     // unable to get a proper length-prefixed lineage slice
532                     throw new IOException("Unable to read list of signing certificate nodes in "
533                             + "SigningCertificateLineage", e);
534                 }
535             default:
536                 throw new IllegalArgumentException(
537                         "Improper SigningCertificateLineage format: unrecognized version.");
538         }
539     }
540 
calculateMinSdkVersion(List<SigningCertificateNode> nodes)541     private static int calculateMinSdkVersion(List<SigningCertificateNode> nodes) {
542         if (nodes == null) {
543             throw new IllegalArgumentException("Can't calculate minimum SDK version of null nodes");
544         }
545         int minSdkVersion = AndroidSdkVersion.P; // lineage introduced in P
546         for (SigningCertificateNode node : nodes) {
547             if (node.sigAlgorithm != null) {
548                 int nodeMinSdkVersion = node.sigAlgorithm.getMinSdkVersion();
549                 if (nodeMinSdkVersion > minSdkVersion) {
550                     minSdkVersion = nodeMinSdkVersion;
551                 }
552             }
553         }
554         return minSdkVersion;
555     }
556 
write()557     private ByteBuffer write() {
558         byte[] encodedLineage =
559                 V3SigningCertificateLineage.encodeSigningCertificateLineage(mSigningLineage);
560         int payloadSize = 4 + 4 + 4 + encodedLineage.length;
561         ByteBuffer result = ByteBuffer.allocate(payloadSize);
562         result.order(ByteOrder.LITTLE_ENDIAN);
563         result.putInt(MAGIC);
564         result.putInt(CURRENT_VERSION);
565         result.putInt(encodedLineage.length);
566         result.put(encodedLineage);
567         result.flip();
568         return result;
569     }
570 
encodeSigningCertificateLineage()571     public byte[] encodeSigningCertificateLineage() {
572         return V3SigningCertificateLineage.encodeSigningCertificateLineage(mSigningLineage);
573     }
574 
sortSignerConfigs( List<DefaultApkSignerEngine.SignerConfig> signerConfigs)575     public List<DefaultApkSignerEngine.SignerConfig> sortSignerConfigs(
576             List<DefaultApkSignerEngine.SignerConfig> signerConfigs) {
577         if (signerConfigs == null) {
578             throw new NullPointerException("signerConfigs == null");
579         }
580 
581         // not the most elegant sort, but we expect signerConfigs to be quite small (1 or 2 signers
582         // in most cases) and likely already sorted, so not worth the overhead of doing anything
583         // fancier
584         List<DefaultApkSignerEngine.SignerConfig> sortedSignerConfigs =
585                 new ArrayList<>(signerConfigs.size());
586         for (int i = 0; i < mSigningLineage.size(); i++) {
587             for (int j = 0; j < signerConfigs.size(); j++) {
588                 DefaultApkSignerEngine.SignerConfig config = signerConfigs.get(j);
589                 if (mSigningLineage.get(i).signingCert.equals(config.getCertificates().get(0))) {
590                     sortedSignerConfigs.add(config);
591                     break;
592                 }
593             }
594         }
595         if (sortedSignerConfigs.size() != signerConfigs.size()) {
596             throw new IllegalArgumentException("SignerConfigs supplied which are not present in the"
597                     + " SigningCertificateLineage");
598         }
599         return sortedSignerConfigs;
600     }
601 
602     /**
603      * Returns the SignerCapabilities for the signer in the lineage that matches the provided
604      * config.
605      */
getSignerCapabilities(SignerConfig config)606     public SignerCapabilities getSignerCapabilities(SignerConfig config) {
607         if (config == null) {
608             throw new NullPointerException("config == null");
609         }
610 
611         X509Certificate cert = config.getCertificate();
612         return getSignerCapabilities(cert);
613     }
614 
615     /**
616      * Returns the SignerCapabilities for the signer in the lineage that matches the provided
617      * certificate.
618      */
getSignerCapabilities(X509Certificate cert)619     public SignerCapabilities getSignerCapabilities(X509Certificate cert) {
620         if (cert == null) {
621             throw new NullPointerException("cert == null");
622         }
623 
624         for (int i = 0; i < mSigningLineage.size(); i++) {
625             SigningCertificateNode lineageNode = mSigningLineage.get(i);
626             if (lineageNode.signingCert.equals(cert)) {
627                 int flags = lineageNode.flags;
628                 return new SignerCapabilities.Builder(flags).build();
629             }
630         }
631 
632         // the provided signer certificate was not found in the lineage
633         throw new IllegalArgumentException("Certificate (" + cert.getSubjectDN()
634                 + ") not found in the SigningCertificateLineage");
635     }
636 
637     /**
638      * Updates the SignerCapabilities for the signer in the lineage that matches the provided
639      * config. Only those capabilities that have been modified through the setXX methods will be
640      * updated for the signer to prevent unset default values from being applied.
641      */
updateSignerCapabilities(SignerConfig config, SignerCapabilities capabilities)642     public void updateSignerCapabilities(SignerConfig config, SignerCapabilities capabilities) {
643         if (config == null) {
644             throw new NullPointerException("config == null");
645         }
646         updateSignerCapabilities(config.getCertificate(), capabilities);
647     }
648 
649     /**
650      * Updates the {@code capabilities} for the signer with the provided {@code certificate} in the
651      * lineage. Only those capabilities that have been modified through the setXX methods will be
652      * updated for the signer to prevent unset default values from being applied.
653      */
updateSignerCapabilities(X509Certificate certificate, SignerCapabilities capabilities)654     public void updateSignerCapabilities(X509Certificate certificate,
655             SignerCapabilities capabilities) {
656         if (certificate == null) {
657             throw new NullPointerException("config == null");
658         }
659 
660         for (int i = 0; i < mSigningLineage.size(); i++) {
661             SigningCertificateNode lineageNode = mSigningLineage.get(i);
662             if (lineageNode.signingCert.equals(certificate)) {
663                 int flags = lineageNode.flags;
664                 SignerCapabilities newCapabilities = new SignerCapabilities.Builder(
665                         flags).setCallerConfiguredCapabilities(capabilities).build();
666                 lineageNode.flags = newCapabilities.getFlags();
667                 return;
668             }
669         }
670 
671         // the provided signer config was not found in the lineage
672         throw new IllegalArgumentException("Certificate (" + certificate.getSubjectDN()
673                 + ") not found in the SigningCertificateLineage");
674     }
675 
676     /**
677      * Returns a list containing all of the certificates in the lineage.
678      */
getCertificatesInLineage()679     public List<X509Certificate> getCertificatesInLineage() {
680         List<X509Certificate> certs = new ArrayList<>();
681         for (int i = 0; i < mSigningLineage.size(); i++) {
682             X509Certificate cert = mSigningLineage.get(i).signingCert;
683             certs.add(cert);
684         }
685         return certs;
686     }
687 
688     /**
689      * Returns {@code true} if the specified config is in the lineage.
690      */
isSignerInLineage(SignerConfig config)691     public boolean isSignerInLineage(SignerConfig config) {
692         if (config == null) {
693             throw new NullPointerException("config == null");
694         }
695 
696         X509Certificate cert = config.getCertificate();
697         return isCertificateInLineage(cert);
698     }
699 
700     /**
701      * Returns {@code true} if the specified certificate is in the lineage.
702      */
isCertificateInLineage(X509Certificate cert)703     public boolean isCertificateInLineage(X509Certificate cert) {
704         if (cert == null) {
705             throw new NullPointerException("cert == null");
706         }
707 
708         for (int i = 0; i < mSigningLineage.size(); i++) {
709             if (mSigningLineage.get(i).signingCert.equals(cert)) {
710                 return true;
711             }
712         }
713         return false;
714     }
715 
716     /**
717      * Returns whether the provided {@code cert} is the latest signing certificate in the lineage.
718      *
719      * <p>This method will only compare the provided {@code cert} against the latest signing
720      * certificate in the lineage; if a certificate that is not in the lineage is provided, this
721      * method will return false.
722      */
isCertificateLatestInLineage(X509Certificate cert)723     public boolean isCertificateLatestInLineage(X509Certificate cert) {
724         if (cert == null) {
725             throw new NullPointerException("cert == null");
726         }
727 
728         return mSigningLineage.get(mSigningLineage.size() - 1).signingCert.equals(cert);
729     }
730 
calculateDefaultFlags()731     private static int calculateDefaultFlags() {
732         return PAST_CERT_INSTALLED_DATA | PAST_CERT_PERMISSION
733                 | PAST_CERT_SHARED_USER_ID | PAST_CERT_AUTH;
734     }
735 
736     /**
737      * Returns a new SigningCertificateLineage which terminates at the node corresponding to the
738      * given certificate.  This is useful in the event of rotating to a new signing algorithm that
739      * is only supported on some platform versions.  It enables a v3 signature to be generated using
740      * this signing certificate and the shortened proof-of-rotation record from this sub lineage in
741      * conjunction with the appropriate SDK version values.
742      *
743      * @param x509Certificate the signing certificate for which to search
744      * @return A new SigningCertificateLineage if the given certificate is present.
745      *
746      * @throws IllegalArgumentException if the provided certificate is not in the lineage.
747      */
getSubLineage(X509Certificate x509Certificate)748     public SigningCertificateLineage getSubLineage(X509Certificate x509Certificate) {
749         if (x509Certificate == null) {
750             throw new NullPointerException("x509Certificate == null");
751         }
752         for (int i = 0; i < mSigningLineage.size(); i++) {
753             if (mSigningLineage.get(i).signingCert.equals(x509Certificate)) {
754                 return new SigningCertificateLineage(
755                         mMinSdkVersion, new ArrayList<>(mSigningLineage.subList(0, i + 1)));
756             }
757         }
758 
759         // looks like we didn't find the cert,
760         throw new IllegalArgumentException("Certificate not found in SigningCertificateLineage");
761     }
762 
763     /**
764      * Consolidates all of the lineages found in an APK into one lineage. In so doing, it also
765      * checks that all of the lineages are contained in one common lineage.
766      *
767      * An APK may contain multiple lineages, one for each signer, which correspond to different
768      * supported platform versions.  In this event, the lineage(s) from the earlier platform
769      * version(s) should be present in the most recent, either directly or via a sublineage
770      * that would allow the earlier lineages to merge with the most recent.
771      *
772      * <note> This does not verify that the largest lineage corresponds to the most recent supported
773      * platform version.  That check is performed during v3 verification. </note>
774      */
consolidateLineages( List<SigningCertificateLineage> lineages)775     public static SigningCertificateLineage consolidateLineages(
776             List<SigningCertificateLineage> lineages) {
777         if (lineages == null || lineages.isEmpty()) {
778             return null;
779         }
780         SigningCertificateLineage consolidatedLineage = lineages.get(0);
781         for (int i = 1; i < lineages.size(); i++) {
782             consolidatedLineage = consolidatedLineage.mergeLineageWith(lineages.get(i));
783         }
784         return consolidatedLineage;
785     }
786 
787     /**
788      * Merges this lineage with the provided {@code otherLineage}.
789      *
790      * <p>The merged lineage does not currently handle merging capabilities of common signers and
791      * should only be used to determine the full signing history of a collection of lineages.
792      */
mergeLineageWith(SigningCertificateLineage otherLineage)793     public SigningCertificateLineage mergeLineageWith(SigningCertificateLineage otherLineage) {
794         // Determine the ancestor and descendant lineages; if the original signer is in the other
795         // lineage, then it is considered a descendant.
796         SigningCertificateLineage ancestorLineage;
797         SigningCertificateLineage descendantLineage;
798         X509Certificate signerCert = mSigningLineage.get(0).signingCert;
799         if (otherLineage.isCertificateInLineage(signerCert)) {
800             descendantLineage = this;
801             ancestorLineage = otherLineage;
802         } else {
803             descendantLineage = otherLineage;
804             ancestorLineage = this;
805         }
806 
807         int ancestorIndex = 0;
808         int descendantIndex = 0;
809         SigningCertificateNode ancestorNode;
810         SigningCertificateNode descendantNode = descendantLineage.mSigningLineage.get(
811                 descendantIndex++);
812         List<SigningCertificateNode> mergedLineage = new ArrayList<>();
813         // Iterate through the ancestor lineage and add the current node to the resulting lineage
814         // until the first node of the descendant is found.
815         while (ancestorIndex < ancestorLineage.size()) {
816             ancestorNode = ancestorLineage.mSigningLineage.get(ancestorIndex++);
817             if (ancestorNode.signingCert.equals(descendantNode.signingCert)) {
818                 break;
819             }
820             mergedLineage.add(ancestorNode);
821         }
822         // If all of the nodes in the ancestor lineage have been added to the merged lineage, then
823         // there is no overlap between this and the provided lineage.
824         if (ancestorIndex == mergedLineage.size()) {
825             throw new IllegalArgumentException(
826                     "The provided lineage is not a descendant or an ancestor of this lineage");
827         }
828         // The descendant lineage's first node was in the ancestor's lineage above; add it to the
829         // merged lineage.
830         mergedLineage.add(descendantNode);
831         while (ancestorIndex < ancestorLineage.size()
832                 && descendantIndex < descendantLineage.size()) {
833             ancestorNode = ancestorLineage.mSigningLineage.get(ancestorIndex++);
834             descendantNode = descendantLineage.mSigningLineage.get(descendantIndex++);
835             if (!ancestorNode.signingCert.equals(descendantNode.signingCert)) {
836                 throw new IllegalArgumentException(
837                         "The provided lineage diverges from this lineage");
838             }
839             mergedLineage.add(descendantNode);
840         }
841         // At this point, one or both of the lineages have been exhausted and all signers to this
842         // point were a match between the two lineages; add any remaining elements from either
843         // lineage to the merged lineage.
844         while (ancestorIndex < ancestorLineage.size()) {
845             mergedLineage.add(ancestorLineage.mSigningLineage.get(ancestorIndex++));
846         }
847         while (descendantIndex < descendantLineage.size()) {
848             mergedLineage.add(descendantLineage.mSigningLineage.get(descendantIndex++));
849         }
850         return new SigningCertificateLineage(Math.min(mMinSdkVersion, otherLineage.mMinSdkVersion),
851                 mergedLineage);
852     }
853 
854     /**
855      * Checks whether given lineages are compatible. Returns {@code true} if an installed APK with
856      * the oldLineage could be updated with an APK with the newLineage.
857      */
checkLineagesCompatibility( SigningCertificateLineage oldLineage, SigningCertificateLineage newLineage)858     public static boolean checkLineagesCompatibility(
859         SigningCertificateLineage oldLineage, SigningCertificateLineage newLineage) {
860 
861         final ArrayList<X509Certificate> oldCertificates = oldLineage == null ?
862                 new ArrayList<X509Certificate>()
863                 : new ArrayList(oldLineage.getCertificatesInLineage());
864         final ArrayList<X509Certificate> newCertificates = newLineage == null ?
865                 new ArrayList<X509Certificate>()
866                 : new ArrayList(newLineage.getCertificatesInLineage());
867 
868         if (oldCertificates.isEmpty()) {
869             return true;
870         }
871         if (newCertificates.isEmpty()) {
872             return false;
873         }
874 
875         // Both lineages contain exactly the same certificates or the new lineage extends
876         // the old one. The capabilities of particular certificates may have changed though but it
877         // does not matter in terms of current compatibility.
878         if (newCertificates.size() >= oldCertificates.size()
879                 && newCertificates.subList(0, oldCertificates.size()).equals(oldCertificates)) {
880             return true;
881         }
882 
883         ArrayList<X509Certificate> newCertificatesArray = new ArrayList(newCertificates);
884         ArrayList<X509Certificate> oldCertificatesArray = new ArrayList(oldCertificates);
885 
886         int lastOldCertIndexInNew = newCertificatesArray.lastIndexOf(
887                     oldCertificatesArray.get(oldCertificatesArray.size()-1));
888 
889         // The new lineage trims some nodes from the beginning of the old lineage and possibly
890         // extends it at the end. The new lineage must contain the old signing certificate and
891         // the nodes up until the node with signing certificate must be in the same order.
892         // Good example 1:
893         //    old: A -> B -> C
894         //    new: B -> C -> D
895         // Good example 2:
896         //    old: A -> B -> C
897         //    new: C
898         // Bad example 1:
899         //    old: A -> B -> C
900         //    new: A -> C
901         // Bad example 1:
902         //    old: A -> B
903         //    new: C -> B
904         if (lastOldCertIndexInNew >= 0) {
905             return newCertificatesArray.subList(0, lastOldCertIndexInNew+1).equals(
906                     oldCertificatesArray.subList(
907                             oldCertificates.size()-1-lastOldCertIndexInNew,
908                             oldCertificatesArray.size()));
909         }
910 
911 
912         // The new lineage can be shorter than the old one only if the last certificate of the new
913         // lineage exists in the old lineage and has a rollback capability there.
914         // Good example:
915         //    old: A -> B_withRollbackCapability -> C
916         //    new: A -> B
917         // Bad example 1:
918         //    old: A -> B -> C
919         //    new: A -> B
920         // Bad example 2:
921         //    old: A -> B_withRollbackCapability -> C
922         //    new: A -> B -> D
923         return  oldCertificates.subList(0, newCertificates.size()).equals(newCertificates)
924                 && oldLineage.getSignerCapabilities(
925                         oldCertificates.get(newCertificates.size()-1)).hasRollback();
926     }
927 
928     /**
929      * Representation of the capabilities the APK would like to grant to its old signing
930      * certificates.  The {@code SigningCertificateLineage} provides two conceptual data structures.
931      *   1) proof of rotation - Evidence that other parties can trust an APK's current signing
932      *      certificate if they trust an older one in this lineage
933      *   2) self-trust - certain capabilities may have been granted by an APK to other parties based
934      *      on its own signing certificate.  When it changes its signing certificate it may want to
935      *      allow the other parties to retain those capabilities.
936      * {@code SignerCapabilties} provides a representation of the second structure.
937      *
938      * <p>Use {@link Builder} to obtain configuration instances.
939      */
940     public static class SignerCapabilities {
941         private final int mFlags;
942 
943         private final int mCallerConfiguredFlags;
944 
SignerCapabilities(int flags)945         private SignerCapabilities(int flags) {
946             this(flags, 0);
947         }
948 
SignerCapabilities(int flags, int callerConfiguredFlags)949         private SignerCapabilities(int flags, int callerConfiguredFlags) {
950             mFlags = flags;
951             mCallerConfiguredFlags = callerConfiguredFlags;
952         }
953 
getFlags()954         private int getFlags() {
955             return mFlags;
956         }
957 
958         /**
959          * Returns {@code true} if the capabilities of this object match those of the provided
960          * object.
961          */
962         @Override
equals(Object other)963         public boolean equals(Object other) {
964             if (this == other) return true;
965             if (!(other instanceof SignerCapabilities)) return false;
966 
967             return this.mFlags == ((SignerCapabilities) other).mFlags;
968         }
969 
970         @Override
hashCode()971         public int hashCode() {
972             return 31 * mFlags;
973         }
974 
975         /**
976          * Returns {@code true} if this object has the installed data capability.
977          */
hasInstalledData()978         public boolean hasInstalledData() {
979             return (mFlags & PAST_CERT_INSTALLED_DATA) != 0;
980         }
981 
982         /**
983          * Returns {@code true} if this object has the shared UID capability.
984          */
hasSharedUid()985         public boolean hasSharedUid() {
986             return (mFlags & PAST_CERT_SHARED_USER_ID) != 0;
987         }
988 
989         /**
990          * Returns {@code true} if this object has the permission capability.
991          */
hasPermission()992         public boolean hasPermission() {
993             return (mFlags & PAST_CERT_PERMISSION) != 0;
994         }
995 
996         /**
997          * Returns {@code true} if this object has the rollback capability.
998          */
hasRollback()999         public boolean hasRollback() {
1000             return (mFlags & PAST_CERT_ROLLBACK) != 0;
1001         }
1002 
1003         /**
1004          * Returns {@code true} if this object has the auth capability.
1005          */
hasAuth()1006         public boolean hasAuth() {
1007             return (mFlags & PAST_CERT_AUTH) != 0;
1008         }
1009 
1010         /**
1011          * Builder of {@link SignerCapabilities} instances.
1012          */
1013         public static class Builder {
1014             private int mFlags;
1015 
1016             private int mCallerConfiguredFlags;
1017 
1018             /**
1019              * Constructs a new {@code Builder}.
1020              */
Builder()1021             public Builder() {
1022                 mFlags = calculateDefaultFlags();
1023             }
1024 
1025             /**
1026              * Constructs a new {@code Builder} with the initial capabilities set to the provided
1027              * flags.
1028              */
Builder(int flags)1029             public Builder(int flags) {
1030                 mFlags = flags;
1031             }
1032 
1033             /**
1034              * Set the {@code PAST_CERT_INSTALLED_DATA} flag in this capabilities object.  This flag
1035              * is used by the platform to determine if installed data associated with previous
1036              * signing certificate should be trusted.  In particular, this capability is required to
1037              * perform signing certificate rotation during an upgrade on-device.  Without it, the
1038              * platform will not permit the app data from the old signing certificate to
1039              * propagate to the new version.  Typically, this flag should be set to enable signing
1040              * certificate rotation, and may be unset later when the app developer is satisfied that
1041              * their install base is as migrated as it will be.
1042              */
setInstalledData(boolean enabled)1043             public Builder setInstalledData(boolean enabled) {
1044                 mCallerConfiguredFlags |= PAST_CERT_INSTALLED_DATA;
1045                 if (enabled) {
1046                     mFlags |= PAST_CERT_INSTALLED_DATA;
1047                 } else {
1048                     mFlags &= ~PAST_CERT_INSTALLED_DATA;
1049                 }
1050                 return this;
1051             }
1052 
1053             /**
1054              * Set the {@code PAST_CERT_SHARED_USER_ID} flag in this capabilities object.  This flag
1055              * is used by the platform to determine if this app is willing to be sharedUid with
1056              * other apps which are still signed with the associated signing certificate.  This is
1057              * useful in situations where sharedUserId apps would like to change their signing
1058              * certificate, but can't guarantee the order of updates to those apps.
1059              */
setSharedUid(boolean enabled)1060             public Builder setSharedUid(boolean enabled) {
1061                 mCallerConfiguredFlags |= PAST_CERT_SHARED_USER_ID;
1062                 if (enabled) {
1063                     mFlags |= PAST_CERT_SHARED_USER_ID;
1064                 } else {
1065                     mFlags &= ~PAST_CERT_SHARED_USER_ID;
1066                 }
1067                 return this;
1068             }
1069 
1070             /**
1071              * Set the {@code PAST_CERT_PERMISSION} flag in this capabilities object.  This flag
1072              * is used by the platform to determine if this app is willing to grant SIGNATURE
1073              * permissions to apps signed with the associated signing certificate.  Without this
1074              * capability, an application signed with the older certificate will not be granted the
1075              * SIGNATURE permissions defined by this app.  In addition, if multiple apps define the
1076              * same SIGNATURE permission, the second one the platform sees will not be installable
1077              * if this capability is not set and the signing certificates differ.
1078              */
setPermission(boolean enabled)1079             public Builder setPermission(boolean enabled) {
1080                 mCallerConfiguredFlags |= PAST_CERT_PERMISSION;
1081                 if (enabled) {
1082                     mFlags |= PAST_CERT_PERMISSION;
1083                 } else {
1084                     mFlags &= ~PAST_CERT_PERMISSION;
1085                 }
1086                 return this;
1087             }
1088 
1089             /**
1090              * Set the {@code PAST_CERT_ROLLBACK} flag in this capabilities object.  This flag
1091              * is used by the platform to determine if this app is willing to upgrade to a new
1092              * version that is signed by one of its past signing certificates.
1093              *
1094              * <note> WARNING: this effectively removes any benefit of signing certificate changes,
1095              * since a compromised key could retake control of an app even after change, and should
1096              * only be used if there is a problem encountered when trying to ditch an older cert
1097              * </note>
1098              */
setRollback(boolean enabled)1099             public Builder setRollback(boolean enabled) {
1100                 mCallerConfiguredFlags |= PAST_CERT_ROLLBACK;
1101                 if (enabled) {
1102                     mFlags |= PAST_CERT_ROLLBACK;
1103                 } else {
1104                     mFlags &= ~PAST_CERT_ROLLBACK;
1105                 }
1106                 return this;
1107             }
1108 
1109             /**
1110              * Set the {@code PAST_CERT_AUTH} flag in this capabilities object.  This flag
1111              * is used by the platform to determine whether or not privileged access based on
1112              * authenticator module signing certificates should be granted.
1113              */
setAuth(boolean enabled)1114             public Builder setAuth(boolean enabled) {
1115                 mCallerConfiguredFlags |= PAST_CERT_AUTH;
1116                 if (enabled) {
1117                     mFlags |= PAST_CERT_AUTH;
1118                 } else {
1119                     mFlags &= ~PAST_CERT_AUTH;
1120                 }
1121                 return this;
1122             }
1123 
1124             /**
1125              * Applies the capabilities that were explicitly set in the provided capabilities object
1126              * to this builder. Any values that were not set will not be applied to this builder
1127              * to prevent unintentinoally setting a capability back to a default value.
1128              */
setCallerConfiguredCapabilities(SignerCapabilities capabilities)1129             public Builder setCallerConfiguredCapabilities(SignerCapabilities capabilities) {
1130                 // The mCallerConfiguredFlags should have a bit set for each capability that was
1131                 // set by a caller. If a capability was explicitly set then the corresponding bit
1132                 // in mCallerConfiguredFlags should be set. This allows the provided capabilities
1133                 // to take effect for those set by the caller while those that were not set will
1134                 // be cleared by the bitwise and and the initial value for the builder will remain.
1135                 mFlags = (mFlags & ~capabilities.mCallerConfiguredFlags) |
1136                         (capabilities.mFlags & capabilities.mCallerConfiguredFlags);
1137                 return this;
1138             }
1139 
1140             /**
1141              * Returns a new {@code SignerConfig} instance configured based on the configuration of
1142              * this builder.
1143              */
build()1144             public SignerCapabilities build() {
1145                 return new SignerCapabilities(mFlags, mCallerConfiguredFlags);
1146             }
1147         }
1148     }
1149 
1150     /**
1151      * Configuration of a signer. Used to add a new entry to the {@link SigningCertificateLineage}
1152      *
1153      * <p>Use {@link Builder} to obtain configuration instances.
1154      */
1155     public static class SignerConfig {
1156         private final KeyConfig mKeyConfig;
1157         private final X509Certificate mCertificate;
1158 
SignerConfig(KeyConfig keyConfig, X509Certificate certificate)1159         private SignerConfig(KeyConfig keyConfig, X509Certificate certificate) {
1160             mKeyConfig = keyConfig;
1161             mCertificate = certificate;
1162         }
1163 
1164         /**
1165          * Returns the signing key of this signer.
1166          *
1167          * @deprecated Use {@link #getKeyConfig()} instead of accessing a {@link PrivateKey}
1168          *     directly. If the user of ApkSigner is signing with a KMS instead of JCA, this method
1169          *     will return null.
1170          */
1171         @Deprecated
getPrivateKey()1172         public PrivateKey getPrivateKey() {
1173             return mKeyConfig.match(jca -> jca.privateKey, kms -> null);
1174         }
1175 
getKeyConfig()1176         public KeyConfig getKeyConfig() {
1177             return mKeyConfig;
1178         }
1179 
1180         /**
1181          * Returns the certificate(s) of this signer. The first certificate's public key corresponds
1182          * to this signer's private key.
1183          */
getCertificate()1184         public X509Certificate getCertificate() {
1185             return mCertificate;
1186         }
1187 
1188         /**
1189          * Builder of {@link SignerConfig} instances.
1190          */
1191         public static class Builder {
1192             private final KeyConfig mKeyConfig;
1193             private final X509Certificate mCertificate;
1194 
1195             /**
1196              * Constructs a new {@code Builder}.
1197              *
1198              * @deprecated use {@link #Builder(KeyConfig, X509Certificate)} instead
1199              * @param privateKey signing key
1200              * @param certificate the X.509 certificate with a subject public key of the {@code
1201              *     privateKey}.
1202              */
1203             @Deprecated
Builder(PrivateKey privateKey, X509Certificate certificate)1204             public Builder(PrivateKey privateKey, X509Certificate certificate) {
1205                 mKeyConfig = new KeyConfig.Jca(privateKey);
1206                 mCertificate = certificate;
1207             }
1208 
1209             /**
1210              * Constructs a new {@code Builder}.
1211              *
1212              * @param keyConfig signing key configuration
1213              * @param certificate the X.509 certificate with a subject public key of the {@code
1214              *     privateKey}.
1215              */
Builder(KeyConfig keyConfig, X509Certificate certificate)1216             public Builder(KeyConfig keyConfig, X509Certificate certificate) {
1217                 mKeyConfig = keyConfig;
1218                 mCertificate = certificate;
1219             }
1220 
1221             /**
1222              * Returns a new {@code SignerConfig} instance configured based on the configuration of
1223              * this builder.
1224              */
build()1225             public SignerConfig build() {
1226                 return new SignerConfig(mKeyConfig, mCertificate);
1227             }
1228         }
1229     }
1230 
1231     /**
1232      * Builder of {@link SigningCertificateLineage} instances.
1233      */
1234     public static class Builder {
1235         private final SignerConfig mOriginalSignerConfig;
1236         private final SignerConfig mNewSignerConfig;
1237         private SignerCapabilities mOriginalCapabilities;
1238         private SignerCapabilities mNewCapabilities;
1239         private int mMinSdkVersion;
1240         /**
1241          * Constructs a new {@code Builder}.
1242          *
1243          * @param originalSignerConfig first signer in this lineage, parent of the next
1244          * @param newSignerConfig new signer in the lineage; the new signing key that the APK will
1245          *                        use
1246          */
Builder( SignerConfig originalSignerConfig, SignerConfig newSignerConfig)1247         public Builder(
1248                 SignerConfig originalSignerConfig,
1249                 SignerConfig newSignerConfig) {
1250             if (originalSignerConfig == null || newSignerConfig == null) {
1251                 throw new NullPointerException("Can't pass null SignerConfigs when constructing a "
1252                         + "new SigningCertificateLineage");
1253             }
1254             mOriginalSignerConfig = originalSignerConfig;
1255             mNewSignerConfig = newSignerConfig;
1256         }
1257 
1258         /**
1259          * Constructs a new {@code Builder} that is intended to create a {@code
1260          * SigningCertificateLineage} with a single signer in the signing history.
1261          *
1262          * @param originalSignerConfig first signer in this lineage
1263          */
Builder(SignerConfig originalSignerConfig)1264         public Builder(SignerConfig originalSignerConfig) {
1265             if (originalSignerConfig == null) {
1266                 throw new NullPointerException("Can't pass null SignerConfigs when constructing a "
1267                         + "new SigningCertificateLineage");
1268             }
1269             mOriginalSignerConfig = originalSignerConfig;
1270             mNewSignerConfig = null;
1271         }
1272 
1273         /**
1274          * Sets the minimum Android platform version (API Level) on which this lineage is expected
1275          * to validate.  It is possible that newer signers in the lineage may not be recognized on
1276          * the given platform, but as long as an older signer is, the lineage can still be used to
1277          * sign an APK for the given platform.
1278          *
1279          * <note> By default, this value is set to the value for the
1280          * P release, since this structure was created for that release, and will also be set to
1281          * that value if a smaller one is specified. </note>
1282          */
setMinSdkVersion(int minSdkVersion)1283         public Builder setMinSdkVersion(int minSdkVersion) {
1284             mMinSdkVersion = minSdkVersion;
1285             return this;
1286         }
1287 
1288         /**
1289          * Sets capabilities to give {@code mOriginalSignerConfig}. These capabilities allow an
1290          * older signing certificate to still be used in some situations on the platform even though
1291          * the APK is now being signed by a newer signing certificate.
1292          */
setOriginalCapabilities(SignerCapabilities signerCapabilities)1293         public Builder setOriginalCapabilities(SignerCapabilities signerCapabilities) {
1294             if (signerCapabilities == null) {
1295                 throw new NullPointerException("signerCapabilities == null");
1296             }
1297             mOriginalCapabilities = signerCapabilities;
1298             return this;
1299         }
1300 
1301         /**
1302          * Sets capabilities to give {@code mNewSignerConfig}. These capabilities allow an
1303          * older signing certificate to still be used in some situations on the platform even though
1304          * the APK is now being signed by a newer signing certificate.  By default, the new signer
1305          * will have all capabilities, so when first switching to a new signing certificate, these
1306          * capabilities have no effect, but they will act as the default level of trust when moving
1307          * to a new signing certificate.
1308          */
setNewCapabilities(SignerCapabilities signerCapabilities)1309         public Builder setNewCapabilities(SignerCapabilities signerCapabilities) {
1310             if (signerCapabilities == null) {
1311                 throw new NullPointerException("signerCapabilities == null");
1312             }
1313             mNewCapabilities = signerCapabilities;
1314             return this;
1315         }
1316 
build()1317         public SigningCertificateLineage build()
1318                 throws CertificateEncodingException, InvalidKeyException, NoSuchAlgorithmException,
1319                 SignatureException {
1320             if (mMinSdkVersion < AndroidSdkVersion.P) {
1321                 mMinSdkVersion = AndroidSdkVersion.P;
1322             }
1323 
1324             if (mOriginalCapabilities == null) {
1325                 mOriginalCapabilities = new SignerCapabilities.Builder().build();
1326             }
1327 
1328             if (mNewSignerConfig == null) {
1329                 return createSigningLineage(mMinSdkVersion, mOriginalSignerConfig,
1330                         mOriginalCapabilities);
1331             }
1332 
1333             if (mNewCapabilities == null) {
1334                 mNewCapabilities = new SignerCapabilities.Builder().build();
1335             }
1336 
1337             return createSigningLineage(
1338                     mMinSdkVersion, mOriginalSignerConfig, mOriginalCapabilities,
1339                     mNewSignerConfig, mNewCapabilities);
1340         }
1341     }
1342 }
1343