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