• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, int callerConfiguredFlags)945         private SignerCapabilities(int flags, int callerConfiguredFlags) {
946             mFlags = flags;
947             mCallerConfiguredFlags = callerConfiguredFlags;
948         }
949 
getFlags()950         private int getFlags() {
951             return mFlags;
952         }
953 
954         /**
955          * Returns {@code true} if the capabilities of this object match those of the provided
956          * object.
957          */
958         @Override
equals(Object other)959         public boolean equals(Object other) {
960             if (this == other) return true;
961             if (!(other instanceof SignerCapabilities)) return false;
962 
963             return this.mFlags == ((SignerCapabilities) other).mFlags;
964         }
965 
966         @Override
hashCode()967         public int hashCode() {
968             return 31 * mFlags;
969         }
970 
971         /**
972          * Returns {@code true} if this object has the installed data capability.
973          */
hasInstalledData()974         public boolean hasInstalledData() {
975             return (mFlags & PAST_CERT_INSTALLED_DATA) != 0;
976         }
977 
978         /**
979          * Returns {@code true} if this object has the shared UID capability.
980          */
hasSharedUid()981         public boolean hasSharedUid() {
982             return (mFlags & PAST_CERT_SHARED_USER_ID) != 0;
983         }
984 
985         /**
986          * Returns {@code true} if this object has the permission capability.
987          */
hasPermission()988         public boolean hasPermission() {
989             return (mFlags & PAST_CERT_PERMISSION) != 0;
990         }
991 
992         /**
993          * Returns {@code true} if this object has the rollback capability.
994          */
hasRollback()995         public boolean hasRollback() {
996             return (mFlags & PAST_CERT_ROLLBACK) != 0;
997         }
998 
999         /**
1000          * Returns {@code true} if this object has the auth capability.
1001          */
hasAuth()1002         public boolean hasAuth() {
1003             return (mFlags & PAST_CERT_AUTH) != 0;
1004         }
1005 
1006         /**
1007          * Builder of {@link SignerCapabilities} instances.
1008          */
1009         public static class Builder {
1010             private int mFlags;
1011 
1012             private int mCallerConfiguredFlags;
1013 
1014             /**
1015              * Constructs a new {@code Builder}.
1016              */
Builder()1017             public Builder() {
1018                 mFlags = calculateDefaultFlags();
1019             }
1020 
1021             /**
1022              * Constructs a new {@code Builder} with the initial capabilities set to the provided
1023              * flags.
1024              */
Builder(int flags)1025             public Builder(int flags) {
1026                 mFlags = flags;
1027             }
1028 
1029             /**
1030              * Set the {@code PAST_CERT_INSTALLED_DATA} flag in this capabilities object.  This flag
1031              * is used by the platform to determine if installed data associated with previous
1032              * signing certificate should be trusted.  In particular, this capability is required to
1033              * perform signing certificate rotation during an upgrade on-device.  Without it, the
1034              * platform will not permit the app data from the old signing certificate to
1035              * propagate to the new version.  Typically, this flag should be set to enable signing
1036              * certificate rotation, and may be unset later when the app developer is satisfied that
1037              * their install base is as migrated as it will be.
1038              */
setInstalledData(boolean enabled)1039             public Builder setInstalledData(boolean enabled) {
1040                 mCallerConfiguredFlags |= PAST_CERT_INSTALLED_DATA;
1041                 if (enabled) {
1042                     mFlags |= PAST_CERT_INSTALLED_DATA;
1043                 } else {
1044                     mFlags &= ~PAST_CERT_INSTALLED_DATA;
1045                 }
1046                 return this;
1047             }
1048 
1049             /**
1050              * Set the {@code PAST_CERT_SHARED_USER_ID} flag in this capabilities object.  This flag
1051              * is used by the platform to determine if this app is willing to be sharedUid with
1052              * other apps which are still signed with the associated signing certificate.  This is
1053              * useful in situations where sharedUserId apps would like to change their signing
1054              * certificate, but can't guarantee the order of updates to those apps.
1055              */
setSharedUid(boolean enabled)1056             public Builder setSharedUid(boolean enabled) {
1057                 mCallerConfiguredFlags |= PAST_CERT_SHARED_USER_ID;
1058                 if (enabled) {
1059                     mFlags |= PAST_CERT_SHARED_USER_ID;
1060                 } else {
1061                     mFlags &= ~PAST_CERT_SHARED_USER_ID;
1062                 }
1063                 return this;
1064             }
1065 
1066             /**
1067              * Set the {@code PAST_CERT_PERMISSION} flag in this capabilities object.  This flag
1068              * is used by the platform to determine if this app is willing to grant SIGNATURE
1069              * permissions to apps signed with the associated signing certificate.  Without this
1070              * capability, an application signed with the older certificate will not be granted the
1071              * SIGNATURE permissions defined by this app.  In addition, if multiple apps define the
1072              * same SIGNATURE permission, the second one the platform sees will not be installable
1073              * if this capability is not set and the signing certificates differ.
1074              */
setPermission(boolean enabled)1075             public Builder setPermission(boolean enabled) {
1076                 mCallerConfiguredFlags |= PAST_CERT_PERMISSION;
1077                 if (enabled) {
1078                     mFlags |= PAST_CERT_PERMISSION;
1079                 } else {
1080                     mFlags &= ~PAST_CERT_PERMISSION;
1081                 }
1082                 return this;
1083             }
1084 
1085             /**
1086              * Set the {@code PAST_CERT_ROLLBACK} flag in this capabilities object.  This flag
1087              * is used by the platform to determine if this app is willing to upgrade to a new
1088              * version that is signed by one of its past signing certificates.
1089              *
1090              * <note> WARNING: this effectively removes any benefit of signing certificate changes,
1091              * since a compromised key could retake control of an app even after change, and should
1092              * only be used if there is a problem encountered when trying to ditch an older cert
1093              * </note>
1094              */
setRollback(boolean enabled)1095             public Builder setRollback(boolean enabled) {
1096                 mCallerConfiguredFlags |= PAST_CERT_ROLLBACK;
1097                 if (enabled) {
1098                     mFlags |= PAST_CERT_ROLLBACK;
1099                 } else {
1100                     mFlags &= ~PAST_CERT_ROLLBACK;
1101                 }
1102                 return this;
1103             }
1104 
1105             /**
1106              * Set the {@code PAST_CERT_AUTH} flag in this capabilities object.  This flag
1107              * is used by the platform to determine whether or not privileged access based on
1108              * authenticator module signing certificates should be granted.
1109              */
setAuth(boolean enabled)1110             public Builder setAuth(boolean enabled) {
1111                 mCallerConfiguredFlags |= PAST_CERT_AUTH;
1112                 if (enabled) {
1113                     mFlags |= PAST_CERT_AUTH;
1114                 } else {
1115                     mFlags &= ~PAST_CERT_AUTH;
1116                 }
1117                 return this;
1118             }
1119 
1120             /**
1121              * Applies the capabilities that were explicitly set in the provided capabilities object
1122              * to this builder. Any values that were not set will not be applied to this builder
1123              * to prevent unintentinoally setting a capability back to a default value.
1124              */
setCallerConfiguredCapabilities(SignerCapabilities capabilities)1125             public Builder setCallerConfiguredCapabilities(SignerCapabilities capabilities) {
1126                 // The mCallerConfiguredFlags should have a bit set for each capability that was
1127                 // set by a caller. If a capability was explicitly set then the corresponding bit
1128                 // in mCallerConfiguredFlags should be set. This allows the provided capabilities
1129                 // to take effect for those set by the caller while those that were not set will
1130                 // be cleared by the bitwise and and the initial value for the builder will remain.
1131                 mFlags = (mFlags & ~capabilities.mCallerConfiguredFlags) |
1132                         (capabilities.mFlags & capabilities.mCallerConfiguredFlags);
1133                 return this;
1134             }
1135 
1136             /**
1137              * Returns a new {@code SignerConfig} instance configured based on the configuration of
1138              * this builder.
1139              */
build()1140             public SignerCapabilities build() {
1141                 return new SignerCapabilities(mFlags, mCallerConfiguredFlags);
1142             }
1143         }
1144     }
1145 
1146     /**
1147      * Configuration of a signer. Used to add a new entry to the {@link SigningCertificateLineage}
1148      *
1149      * <p>Use {@link Builder} to obtain configuration instances.
1150      */
1151     public static class SignerConfig {
1152         private final KeyConfig mKeyConfig;
1153         private final X509Certificate mCertificate;
1154 
SignerConfig(KeyConfig keyConfig, X509Certificate certificate)1155         private SignerConfig(KeyConfig keyConfig, X509Certificate certificate) {
1156             mKeyConfig = keyConfig;
1157             mCertificate = certificate;
1158         }
1159 
1160         /**
1161          * Returns the signing key of this signer.
1162          *
1163          * @deprecated Use {@link #getKeyConfig()} instead of accessing a {@link PrivateKey}
1164          *     directly. If the user of ApkSigner is signing with a KMS instead of JCA, this method
1165          *     will return null.
1166          */
1167         @Deprecated
getPrivateKey()1168         public PrivateKey getPrivateKey() {
1169             return mKeyConfig.match(jca -> jca.privateKey, kms -> null);
1170         }
1171 
getKeyConfig()1172         public KeyConfig getKeyConfig() {
1173             return mKeyConfig;
1174         }
1175 
1176         /**
1177          * Returns the certificate(s) of this signer. The first certificate's public key corresponds
1178          * to this signer's private key.
1179          */
getCertificate()1180         public X509Certificate getCertificate() {
1181             return mCertificate;
1182         }
1183 
1184         /**
1185          * Builder of {@link SignerConfig} instances.
1186          */
1187         public static class Builder {
1188             private final KeyConfig mKeyConfig;
1189             private final X509Certificate mCertificate;
1190 
1191             /**
1192              * Constructs a new {@code Builder}.
1193              *
1194              * @deprecated use {@link #Builder(KeyConfig, X509Certificate)} instead
1195              * @param privateKey signing key
1196              * @param certificate the X.509 certificate with a subject public key of the {@code
1197              *     privateKey}.
1198              */
1199             @Deprecated
Builder(PrivateKey privateKey, X509Certificate certificate)1200             public Builder(PrivateKey privateKey, X509Certificate certificate) {
1201                 mKeyConfig = new KeyConfig.Jca(privateKey);
1202                 mCertificate = certificate;
1203             }
1204 
1205             /**
1206              * Constructs a new {@code Builder}.
1207              *
1208              * @param keyConfig signing key configuration
1209              * @param certificate the X.509 certificate with a subject public key of the {@code
1210              *     privateKey}.
1211              */
Builder(KeyConfig keyConfig, X509Certificate certificate)1212             public Builder(KeyConfig keyConfig, X509Certificate certificate) {
1213                 mKeyConfig = keyConfig;
1214                 mCertificate = certificate;
1215             }
1216 
1217             /**
1218              * Returns a new {@code SignerConfig} instance configured based on the configuration of
1219              * this builder.
1220              */
build()1221             public SignerConfig build() {
1222                 return new SignerConfig(mKeyConfig, mCertificate);
1223             }
1224         }
1225     }
1226 
1227     /**
1228      * Builder of {@link SigningCertificateLineage} instances.
1229      */
1230     public static class Builder {
1231         private final SignerConfig mOriginalSignerConfig;
1232         private final SignerConfig mNewSignerConfig;
1233         private SignerCapabilities mOriginalCapabilities;
1234         private SignerCapabilities mNewCapabilities;
1235         private int mMinSdkVersion;
1236         /**
1237          * Constructs a new {@code Builder}.
1238          *
1239          * @param originalSignerConfig first signer in this lineage, parent of the next
1240          * @param newSignerConfig new signer in the lineage; the new signing key that the APK will
1241          *                        use
1242          */
Builder( SignerConfig originalSignerConfig, SignerConfig newSignerConfig)1243         public Builder(
1244                 SignerConfig originalSignerConfig,
1245                 SignerConfig newSignerConfig) {
1246             if (originalSignerConfig == null || newSignerConfig == null) {
1247                 throw new NullPointerException("Can't pass null SignerConfigs when constructing a "
1248                         + "new SigningCertificateLineage");
1249             }
1250             mOriginalSignerConfig = originalSignerConfig;
1251             mNewSignerConfig = newSignerConfig;
1252         }
1253 
1254         /**
1255          * Constructs a new {@code Builder} that is intended to create a {@code
1256          * SigningCertificateLineage} with a single signer in the signing history.
1257          *
1258          * @param originalSignerConfig first signer in this lineage
1259          */
Builder(SignerConfig originalSignerConfig)1260         public Builder(SignerConfig originalSignerConfig) {
1261             if (originalSignerConfig == null) {
1262                 throw new NullPointerException("Can't pass null SignerConfigs when constructing a "
1263                         + "new SigningCertificateLineage");
1264             }
1265             mOriginalSignerConfig = originalSignerConfig;
1266             mNewSignerConfig = null;
1267         }
1268 
1269         /**
1270          * Sets the minimum Android platform version (API Level) on which this lineage is expected
1271          * to validate.  It is possible that newer signers in the lineage may not be recognized on
1272          * the given platform, but as long as an older signer is, the lineage can still be used to
1273          * sign an APK for the given platform.
1274          *
1275          * <note> By default, this value is set to the value for the
1276          * P release, since this structure was created for that release, and will also be set to
1277          * that value if a smaller one is specified. </note>
1278          */
setMinSdkVersion(int minSdkVersion)1279         public Builder setMinSdkVersion(int minSdkVersion) {
1280             mMinSdkVersion = minSdkVersion;
1281             return this;
1282         }
1283 
1284         /**
1285          * Sets capabilities to give {@code mOriginalSignerConfig}. These capabilities allow an
1286          * older signing certificate to still be used in some situations on the platform even though
1287          * the APK is now being signed by a newer signing certificate.
1288          */
setOriginalCapabilities(SignerCapabilities signerCapabilities)1289         public Builder setOriginalCapabilities(SignerCapabilities signerCapabilities) {
1290             if (signerCapabilities == null) {
1291                 throw new NullPointerException("signerCapabilities == null");
1292             }
1293             mOriginalCapabilities = signerCapabilities;
1294             return this;
1295         }
1296 
1297         /**
1298          * Sets capabilities to give {@code mNewSignerConfig}. These capabilities allow an
1299          * older signing certificate to still be used in some situations on the platform even though
1300          * the APK is now being signed by a newer signing certificate.  By default, the new signer
1301          * will have all capabilities, so when first switching to a new signing certificate, these
1302          * capabilities have no effect, but they will act as the default level of trust when moving
1303          * to a new signing certificate.
1304          */
setNewCapabilities(SignerCapabilities signerCapabilities)1305         public Builder setNewCapabilities(SignerCapabilities signerCapabilities) {
1306             if (signerCapabilities == null) {
1307                 throw new NullPointerException("signerCapabilities == null");
1308             }
1309             mNewCapabilities = signerCapabilities;
1310             return this;
1311         }
1312 
build()1313         public SigningCertificateLineage build()
1314                 throws CertificateEncodingException, InvalidKeyException, NoSuchAlgorithmException,
1315                 SignatureException {
1316             if (mMinSdkVersion < AndroidSdkVersion.P) {
1317                 mMinSdkVersion = AndroidSdkVersion.P;
1318             }
1319 
1320             if (mOriginalCapabilities == null) {
1321                 mOriginalCapabilities = new SignerCapabilities.Builder().build();
1322             }
1323 
1324             if (mNewSignerConfig == null) {
1325                 return createSigningLineage(mMinSdkVersion, mOriginalSignerConfig,
1326                         mOriginalCapabilities);
1327             }
1328 
1329             if (mNewCapabilities == null) {
1330                 mNewCapabilities = new SignerCapabilities.Builder().build();
1331             }
1332 
1333             return createSigningLineage(
1334                     mMinSdkVersion, mOriginalSignerConfig, mOriginalCapabilities,
1335                     mNewSignerConfig, mNewCapabilities);
1336         }
1337     }
1338 }
1339