1 /*
2  * Copyright (C) 2021 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 android.content.pm;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.text.TextUtils;
25 import android.util.ArraySet;
26 import android.util.PackageUtils;
27 import android.util.Slog;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.internal.util.DataClass;
31 
32 import libcore.util.HexEncoding;
33 
34 import java.lang.annotation.Retention;
35 import java.lang.annotation.RetentionPolicy;
36 import java.security.PublicKey;
37 import java.security.cert.CertificateException;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collections;
41 import java.util.List;
42 import java.util.Set;
43 
44 /**
45  * A container for signing-related data of an application package.
46  *
47  * @hide
48  */
49 @DataClass(genConstructor = false, genConstDefs = false, genParcelable = true, genAidl = false)
50 public final class SigningDetails implements Parcelable {
51 
52     private static final String TAG = "SigningDetails";
53 
54     @Retention(RetentionPolicy.SOURCE)
55     @IntDef({SignatureSchemeVersion.UNKNOWN,
56             SignatureSchemeVersion.JAR,
57             SignatureSchemeVersion.SIGNING_BLOCK_V2,
58             SignatureSchemeVersion.SIGNING_BLOCK_V3,
59             SignatureSchemeVersion.SIGNING_BLOCK_V4})
60     public @interface SignatureSchemeVersion {
61         int UNKNOWN = 0;
62         int JAR = 1;
63         int SIGNING_BLOCK_V2 = 2;
64         int SIGNING_BLOCK_V3 = 3;
65         int SIGNING_BLOCK_V4 = 4;
66     }
67 
68     /** The signing certificates associated with this application package. */
69     private final @Nullable Signature[] mSignatures;
70 
71     /** The signature scheme version for this application package. */
72     private final @SignatureSchemeVersion int mSignatureSchemeVersion;
73 
74     /** The public keys set for the certificates. */
75     private final @Nullable ArraySet<PublicKey> mPublicKeys;
76 
77     /**
78      * APK Signature Scheme v3 includes support for adding a proof-of-rotation record that
79      * contains two pieces of information:
80      *   1) the past signing certificates
81      *   2) the flags that APK wants to assign to each of the past signing certificates.
82      *
83      * This collection of {@code Signature} objects, each of which is formed from a former
84      * signing certificate of this APK before it was changed by signing certificate rotation,
85      * represents the first piece of information.  It is the APK saying to the rest of the
86      * world: "hey if you trust the old cert, you can trust me!"  This is useful, if for
87      * instance, the platform would like to determine whether or not to allow this APK to do
88      * something it would've allowed it to do under the old cert (like upgrade).
89      */
90     private final @Nullable Signature[] mPastSigningCertificates;
91 
92     /** special value used to see if cert is in package - not exposed to callers */
93     private static final int PAST_CERT_EXISTS = 0;
94 
95     @IntDef(flag = true,
96             value = {CertCapabilities.INSTALLED_DATA,
97                     CertCapabilities.SHARED_USER_ID,
98                     CertCapabilities.PERMISSION,
99                     CertCapabilities.ROLLBACK})
100     public @interface CertCapabilities {
101 
102         /** accept data from already installed pkg with this cert */
103         int INSTALLED_DATA = 1;
104 
105         /** accept sharedUserId with pkg with this cert */
106         int SHARED_USER_ID = 2;
107 
108         /** grant SIGNATURE permissions to pkgs with this cert */
109         int PERMISSION = 4;
110 
111         /** allow pkg to update to one signed by this certificate */
112         int ROLLBACK = 8;
113 
114         /** allow pkg to continue to have auth access gated by this cert */
115         int AUTH = 16;
116     }
117 
118     @IntDef(value = {CapabilityMergeRule.MERGE_SELF_CAPABILITY,
119                     CapabilityMergeRule.MERGE_OTHER_CAPABILITY,
120                     CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY})
121     public @interface CapabilityMergeRule {
122         /**
123          * When capabilities are different for a common signer in the lineage, use the capabilities
124          * from this instance.
125          */
126         int MERGE_SELF_CAPABILITY = 0;
127 
128         /**
129          * When capabilities are different for a common signer in the lineage, use the capabilites
130          * from the other instance.
131          */
132         int MERGE_OTHER_CAPABILITY = 1;
133 
134         /**
135          * When capabilities are different for a common signer in the lineage, use the most
136          * restrictive between the two signers.
137          */
138         int MERGE_RESTRICTED_CAPABILITY = 2;
139     }
140 
141     /** A representation of unknown signing details. Use instead of null. */
142     public static final SigningDetails UNKNOWN = new SigningDetails(/* signatures */ null,
143             SignatureSchemeVersion.UNKNOWN, /* keys */ null, /* pastSigningCertificates */ null);
144 
145     @VisibleForTesting
SigningDetails(@ullable Signature[] signatures, @SignatureSchemeVersion int signatureSchemeVersion, @Nullable ArraySet<PublicKey> keys, @Nullable Signature[] pastSigningCertificates)146     public SigningDetails(@Nullable Signature[] signatures,
147             @SignatureSchemeVersion int signatureSchemeVersion,
148             @Nullable ArraySet<PublicKey> keys, @Nullable Signature[] pastSigningCertificates) {
149         mSignatures = signatures;
150         mSignatureSchemeVersion = signatureSchemeVersion;
151         mPublicKeys = keys;
152         mPastSigningCertificates = pastSigningCertificates;
153     }
154 
SigningDetails(@ullable Signature[] signatures, @SignatureSchemeVersion int signatureSchemeVersion, @Nullable Signature[] pastSigningCertificates)155     public SigningDetails(@Nullable Signature[] signatures,
156             @SignatureSchemeVersion int signatureSchemeVersion,
157             @Nullable Signature[] pastSigningCertificates)
158             throws CertificateException {
159         this(signatures, signatureSchemeVersion, toSigningKeys(signatures),
160                 pastSigningCertificates);
161     }
162 
SigningDetails(@ullable Signature[] signatures, @SignatureSchemeVersion int signatureSchemeVersion)163     public SigningDetails(@Nullable Signature[] signatures,
164             @SignatureSchemeVersion int signatureSchemeVersion)
165             throws CertificateException {
166         this(signatures, signatureSchemeVersion, /* pastSigningCertificates */ null);
167     }
168 
SigningDetails(@ullable SigningDetails orig)169     public SigningDetails(@Nullable SigningDetails orig) {
170         if (orig != null) {
171             if (orig.mSignatures != null) {
172                 mSignatures = orig.mSignatures.clone();
173             } else {
174                 mSignatures = null;
175             }
176             mSignatureSchemeVersion = orig.mSignatureSchemeVersion;
177             mPublicKeys = new ArraySet<>(orig.mPublicKeys);
178             if (orig.mPastSigningCertificates != null) {
179                 mPastSigningCertificates = orig.mPastSigningCertificates.clone();
180             } else {
181                 mPastSigningCertificates = null;
182             }
183         } else {
184             mSignatures = null;
185             mSignatureSchemeVersion = SignatureSchemeVersion.UNKNOWN;
186             mPublicKeys = null;
187             mPastSigningCertificates = null;
188         }
189     }
190 
191     /**
192      * Merges the signing lineage of this instance with the lineage in the provided {@code
193      * otherSigningDetails} using {@link CapabilityMergeRule#MERGE_OTHER_CAPABILITY} as the merge
194      * rule.
195      *
196      * @param otherSigningDetails the {@code SigningDetails} with which to merge
197      * @return Merged {@code SigningDetails} instance when one has the same or an ancestor signer
198      *         of the other. If neither instance has a lineage, or if neither has the same or an
199      *         ancestor signer then this instance is returned.
200      * @see #mergeLineageWith(SigningDetails, int)
201      */
mergeLineageWith(@onNull SigningDetails otherSigningDetails)202     public @NonNull SigningDetails mergeLineageWith(@NonNull SigningDetails otherSigningDetails) {
203         return mergeLineageWith(otherSigningDetails, CapabilityMergeRule.MERGE_OTHER_CAPABILITY);
204     }
205 
206     /**
207      * Merges the signing lineage of this instance with the lineage in the provided {@code
208      * otherSigningDetails} when one has the same or an ancestor signer of the other using the
209      * provided {@code mergeRule} to handle differences in capabilities for shared signers.
210      *
211      * <p>Merging two signing lineages will result in a new {@code SigningDetails} instance
212      * containing the longest common lineage with differences in capabilities for shared signers
213      * resolved using the provided {@code mergeRule}. If the two lineages contain the same signers
214      * with the same capabilities then the instance on which this was invoked is returned without
215      * any changes. Similarly if neither instance has a lineage, or if neither has the same or an
216      * ancestor signer then this instance is returned.
217      *
218      * Following are some example results of this method for lineages with signers A, B, C, D:
219      * <ul>
220      *     <li>lineage B merged with lineage A -> B returns lineage A -> B.
221      *     <li>lineage A -> B merged with lineage B -> C returns lineage A -> B -> C
222      *     <li>lineage A -> B with the {@code PERMISSION} capability revoked for A merged with
223      *     lineage A -> B with the {@code SHARED_USER_ID} capability revoked for A returns the
224      *     following based on the {@code mergeRule}:
225      *     <ul>
226      *         <li>{@code MERGE_SELF_CAPABILITY} - lineage A -> B with {@code PERMISSION} revoked
227      *         for A.
228      *         <li>{@code MERGE_OTHER_CAPABILITY} - lineage A -> B with {@code SHARED_USER_ID}
229      *         revoked for A.
230      *         <li>{@code MERGE_RESTRICTED_CAPABILITY} - lineage A -> B with {@code PERMISSION} and
231      *         {@code SHARED_USER_ID} revoked for A.
232      *     </ul>
233      *     <li>lineage A -> B -> C merged with lineage A -> B -> D would return the original lineage
234      *     A -> B -> C since the current signer of both instances is not the same or in the
235      *     lineage of the other.
236      * </ul>
237      *
238      * @param otherSigningDetails the {@code SigningDetails} with which to merge
239      * @param mergeRule the {@link CapabilityMergeRule} to use when resolving differences in
240      *                  capabilities for shared signers
241      * @return Merged {@code SigningDetails} instance when one has the same or an ancestor signer
242      *         of the other. If neither instance has a lineage, or if neither has the same or an
243      *         ancestor signer then this instance is returned.
244      */
mergeLineageWith(@onNull SigningDetails otherSigningDetails, @CapabilityMergeRule int mergeRule)245     public @NonNull SigningDetails mergeLineageWith(@NonNull SigningDetails otherSigningDetails,
246             @CapabilityMergeRule int mergeRule) {
247         if (!hasPastSigningCertificates()) {
248             return otherSigningDetails.hasPastSigningCertificates()
249                     && otherSigningDetails.hasAncestorOrSelf(this) ? otherSigningDetails : this;
250         }
251         if (!otherSigningDetails.hasPastSigningCertificates()) {
252             return this;
253         }
254         // Use the utility method to determine which SigningDetails instance is the descendant
255         // and to confirm that the signing lineage does not diverge.
256         SigningDetails descendantSigningDetails = getDescendantOrSelf(otherSigningDetails);
257         if (descendantSigningDetails == null) {
258             return this;
259         }
260         SigningDetails mergedDetails = this;
261         if (descendantSigningDetails == this) {
262             // If this instance is the descendant then the merge will also be invoked against this
263             // instance and the provided mergeRule can be used as is.
264             mergedDetails = mergeLineageWithAncestorOrSelf(otherSigningDetails, mergeRule);
265         } else {
266             // If the provided instance is the descendant then the merge will be invoked against the
267             // other instance and a self or other merge rule will need to be flipped.
268             switch (mergeRule) {
269                 case CapabilityMergeRule.MERGE_SELF_CAPABILITY:
270                     mergedDetails = otherSigningDetails.mergeLineageWithAncestorOrSelf(this,
271                             CapabilityMergeRule.MERGE_OTHER_CAPABILITY);
272                     break;
273                 case CapabilityMergeRule.MERGE_OTHER_CAPABILITY:
274                     mergedDetails = otherSigningDetails.mergeLineageWithAncestorOrSelf(this,
275                             CapabilityMergeRule.MERGE_SELF_CAPABILITY);
276                     break;
277                 case CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY:
278                     mergedDetails = otherSigningDetails.mergeLineageWithAncestorOrSelf(this,
279                             mergeRule);
280                     break;
281             }
282         }
283         return mergedDetails;
284     }
285 
286     /**
287      * Merges the signing lineage of this instance with the lineage of the ancestor (or same)
288      * signer in the provided {@code otherSigningDetails}.
289      *
290      * @param otherSigningDetails the {@code SigningDetails} with which to merge
291      * @param mergeRule the {@link CapabilityMergeRule} to use when resolving differences in
292      *                  capabilities for shared signers
293      * @return Merged {@code SigningDetails} instance.
294      */
mergeLineageWithAncestorOrSelf( @onNull SigningDetails otherSigningDetails, @CapabilityMergeRule int mergeRule)295     private @NonNull SigningDetails mergeLineageWithAncestorOrSelf(
296             @NonNull SigningDetails otherSigningDetails, @CapabilityMergeRule int mergeRule) {
297         // This method should only be called with instances that contain lineages.
298         int index = mPastSigningCertificates.length - 1;
299         int otherIndex = otherSigningDetails.mPastSigningCertificates.length - 1;
300         if (index < 0 || otherIndex < 0) {
301             return this;
302         }
303 
304         List<Signature> mergedSignatures = new ArrayList<>();
305         boolean capabilitiesModified = false;
306         // If this is a descendant lineage then add all of the descendant signer(s) to the
307         // merged lineage until the ancestor signer is reached.
308         while (index >= 0 && !mPastSigningCertificates[index].equals(
309                 otherSigningDetails.mPastSigningCertificates[otherIndex])) {
310             mergedSignatures.add(new Signature(mPastSigningCertificates[index--]));
311         }
312         // If the signing lineage was exhausted then the provided ancestor is not actually an
313         // ancestor of this lineage.
314         if (index < 0) {
315             return this;
316         }
317 
318         do {
319             // Add the common signer to the merged lineage and resolve any differences in
320             // capabilites with the merge rule.
321             Signature signature = mPastSigningCertificates[index--];
322             Signature ancestorSignature =
323                     otherSigningDetails.mPastSigningCertificates[otherIndex--];
324             Signature mergedSignature = new Signature(signature);
325             if (signature.getFlags() != ancestorSignature.getFlags()) {
326                 capabilitiesModified = true;
327                 switch (mergeRule) {
328                     case CapabilityMergeRule.MERGE_SELF_CAPABILITY:
329                         mergedSignature.setFlags(signature.getFlags());
330                         break;
331                     case CapabilityMergeRule.MERGE_OTHER_CAPABILITY:
332                         mergedSignature.setFlags(ancestorSignature.getFlags());
333                         break;
334                     case CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY:
335                         mergedSignature.setFlags(
336                                 signature.getFlags() & ancestorSignature.getFlags());
337                         break;
338                 }
339             }
340             mergedSignatures.add(mergedSignature);
341         } while (index >= 0 && otherIndex >= 0 && mPastSigningCertificates[index].equals(
342                 otherSigningDetails.mPastSigningCertificates[otherIndex]));
343 
344         // If both lineages still have elements then their lineages have diverged; since this is
345         // not supported return the invoking instance.
346         if (index >= 0 && otherIndex >= 0) {
347             return this;
348         }
349 
350         // Add any remaining elements from either lineage that is not yet exhausted to the
351         // the merged lineage.
352         while (otherIndex >= 0) {
353             mergedSignatures.add(new Signature(
354                     otherSigningDetails.mPastSigningCertificates[otherIndex--]));
355         }
356         while (index >= 0) {
357             mergedSignatures.add(new Signature(mPastSigningCertificates[index--]));
358         }
359 
360         // if this lineage already contains all the elements in the ancestor and none of the
361         // capabilities were changed then just return this instance.
362         if (mergedSignatures.size() == mPastSigningCertificates.length
363                 && !capabilitiesModified) {
364             return this;
365         }
366         // Since the signatures were added to the merged lineage from newest to oldest reverse
367         // the list to ensure the oldest signer is at index 0.
368         Collections.reverse(mergedSignatures);
369         try {
370             return new SigningDetails(new Signature[]{new Signature(mSignatures[0])},
371                     mSignatureSchemeVersion, mergedSignatures.toArray(new Signature[0]));
372         } catch (CertificateException e) {
373             Slog.e(TAG, "Caught an exception creating the merged lineage: ", e);
374             return this;
375         }
376     }
377 
378     /**
379      * Returns whether this and the provided {@code otherSigningDetails} share a common
380      * ancestor.
381      *
382      * <p>The two SigningDetails have a common ancestor if any of the following conditions are
383      * met:
384      * - If neither has a lineage and their current signer(s) are equal.
385      * - If only one has a lineage and the signer of the other is the same or in the lineage.
386      * - If both have a lineage and their current signers are the same or one is in the lineage
387      * of the other, and their lineages do not diverge to different signers.
388      */
hasCommonAncestor(@onNull SigningDetails otherSigningDetails)389     public boolean hasCommonAncestor(@NonNull SigningDetails otherSigningDetails) {
390         if (!hasPastSigningCertificates()) {
391             // If this instance does not have a lineage then it must either be in the ancestry
392             // of or the same signer of the otherSigningDetails.
393             return otherSigningDetails.hasAncestorOrSelf(this);
394         }
395         if (!otherSigningDetails.hasPastSigningCertificates()) {
396             return hasAncestorOrSelf(otherSigningDetails);
397         }
398         // If both have a lineage then use getDescendantOrSelf to obtain the descendant signing
399         // details; a null return from that method indicates there is no common lineage between
400         // the two or that they diverge at a point in the lineage.
401         return getDescendantOrSelf(otherSigningDetails) != null;
402     }
403 
404     /**
405      * Returns whether this instance is currently signed, or has ever been signed, with a
406      * signing certificate from the provided {@link Set} of {@code certDigests}.
407      *
408      * <p>The provided {@code certDigests} should contain the SHA-256 digest of the DER encoding
409      * of each trusted certificate with the digest characters in upper case. If this instance
410      * has multiple signers then all signers must be in the provided {@code Set}. If this
411      * instance has a signing lineage then this method will return true if any of the previous
412      * signers in the lineage match one of the entries in the {@code Set}.
413      */
hasAncestorOrSelfWithDigest(@ullable Set<String> certDigests)414     public boolean hasAncestorOrSelfWithDigest(@Nullable Set<String> certDigests) {
415         if (this == UNKNOWN || certDigests == null || certDigests.size() == 0) {
416             return false;
417         }
418         // If an app is signed by multiple signers then all of the signers must be in the Set.
419         if (mSignatures.length > 1) {
420             // If the Set has less elements than the number of signatures then immediately
421             // return false as there's no way to satisfy the requirement of all signatures being
422             // in the Set.
423             if (certDigests.size() < mSignatures.length) {
424                 return false;
425             }
426             for (Signature signature : mSignatures) {
427                 String signatureDigest = PackageUtils.computeSha256Digest(
428                         signature.toByteArray());
429                 if (!certDigests.contains(signatureDigest)) {
430                     return false;
431                 }
432             }
433             return true;
434         }
435 
436         String signatureDigest = PackageUtils.computeSha256Digest(mSignatures[0].toByteArray());
437         if (certDigests.contains(signatureDigest)) {
438             return true;
439         }
440         if (hasPastSigningCertificates()) {
441             // The last element in the pastSigningCertificates array is the current signer;
442             // since that was verified above just check all the signers in the lineage.
443             for (int i = 0; i < mPastSigningCertificates.length - 1; i++) {
444                 signatureDigest = PackageUtils.computeSha256Digest(
445                         mPastSigningCertificates[i].toByteArray());
446                 if (certDigests.contains(signatureDigest)) {
447                     return true;
448                 }
449             }
450         }
451         return false;
452     }
453 
454     /**
455      * Returns the SigningDetails with a descendant (or same) signer after verifying the
456      * descendant has the same, a superset, or a subset of the lineage of the ancestor.
457      *
458      * <p>If this instance and the provided {@code otherSigningDetails} do not share an
459      * ancestry, or if their lineages diverge then null is returned to indicate there is no
460      * valid descendant SigningDetails.
461      */
getDescendantOrSelf( @onNull SigningDetails otherSigningDetails)462     private @Nullable SigningDetails getDescendantOrSelf(
463             @NonNull SigningDetails otherSigningDetails) {
464         final SigningDetails descendantSigningDetails;
465         final SigningDetails ancestorSigningDetails;
466         if (hasAncestorOrSelf(otherSigningDetails)) {
467             // If the otherSigningDetails has the same signer or a signer in the lineage of this
468             // instance then treat this instance as the descendant.
469             descendantSigningDetails = this;
470             ancestorSigningDetails = otherSigningDetails;
471         } else if (otherSigningDetails.hasAncestor(this)) {
472             // The above check confirmed that the two instances do not have the same signer and
473             // the signer of otherSigningDetails is not in this instance's lineage; if this
474             // signer is in the otherSigningDetails lineage then treat this as the ancestor.
475             descendantSigningDetails = otherSigningDetails;
476             ancestorSigningDetails = this;
477         } else {
478             // The signers are not the same and neither has the current signer of the other in
479             // its lineage; return null to indicate there is no descendant signer.
480             return null;
481         }
482         // Once the descent (or same) signer is identified iterate through the ancestry until
483         // the current signer of the ancestor is found.
484         int descendantIndex = descendantSigningDetails.mPastSigningCertificates.length - 1;
485         int ancestorIndex = ancestorSigningDetails.mPastSigningCertificates.length - 1;
486         while (descendantIndex >= 0
487                 && !descendantSigningDetails.mPastSigningCertificates[descendantIndex].equals(
488                 ancestorSigningDetails.mPastSigningCertificates[ancestorIndex])) {
489             descendantIndex--;
490         }
491         // Since the ancestry was verified above the descendant lineage should never be
492         // exhausted, but if for some reason the ancestor signer is not found then return null.
493         if (descendantIndex < 0) {
494             return null;
495         }
496         // Once the common ancestor (or same) signer is found iterate over the lineage of both
497         // to ensure that they are either the same or one is a subset of the other.
498         do {
499             descendantIndex--;
500             ancestorIndex--;
501         } while (descendantIndex >= 0 && ancestorIndex >= 0
502                 && descendantSigningDetails.mPastSigningCertificates[descendantIndex].equals(
503                 ancestorSigningDetails.mPastSigningCertificates[ancestorIndex]));
504 
505         // If both lineages still have elements then they diverge and cannot be considered a
506         // valid common lineage.
507         if (descendantIndex >= 0 && ancestorIndex >= 0) {
508             return null;
509         }
510         // Since one or both of the lineages was exhausted they are either the same or one is a
511         // subset of the other; return the valid descendant.
512         return descendantSigningDetails;
513     }
514 
515     /** Returns true if the signing details have one or more signatures. */
hasSignatures()516     public boolean hasSignatures() {
517         return mSignatures != null && mSignatures.length > 0;
518     }
519 
520     /** Returns true if the signing details have past signing certificates. */
hasPastSigningCertificates()521     public boolean hasPastSigningCertificates() {
522         return mPastSigningCertificates != null && mPastSigningCertificates.length > 0;
523     }
524 
525     /**
526      * Determines if the provided {@code oldDetails} is an ancestor of or the same as this one.
527      * If the {@code oldDetails} signing certificate appears in our pastSigningCertificates,
528      * then that means it has authorized a signing certificate rotation, which eventually leads
529      * to our certificate, and thus can be trusted. If this method evaluates to true, this
530      * SigningDetails object should be trusted if the previous one is.
531      */
hasAncestorOrSelf(@onNull SigningDetails oldDetails)532     public boolean hasAncestorOrSelf(@NonNull SigningDetails oldDetails) {
533         if (this == UNKNOWN || oldDetails == UNKNOWN) {
534             return false;
535         }
536         if (oldDetails.mSignatures.length > 1) {
537             // multiple-signer packages cannot rotate signing certs, so we just compare current
538             // signers for an exact match
539             return signaturesMatchExactly(oldDetails);
540         } else {
541             // we may have signing certificate rotation history, check to see if the oldDetails
542             // was one of our old signing certificates
543             return hasCertificate(oldDetails.mSignatures[0]);
544         }
545     }
546 
547     /**
548      * Similar to {@code hasAncestorOrSelf}. Returns true only if this {@code SigningDetails}
549      * is a descendant of {@code oldDetails}, not if they're the same. This is used to
550      * determine if this object is newer than the provided one.
551      */
hasAncestor(@onNull SigningDetails oldDetails)552     public boolean hasAncestor(@NonNull SigningDetails oldDetails) {
553         if (this == UNKNOWN || oldDetails == UNKNOWN) {
554             return false;
555         }
556         if (hasPastSigningCertificates() && oldDetails.mSignatures.length == 1) {
557             // the last entry in pastSigningCertificates is the current signer, ignore it
558             for (int i = 0; i < mPastSigningCertificates.length - 1; i++) {
559                 if (mPastSigningCertificates[i].equals(oldDetails.mSignatures[0])) {
560                     return true;
561                 }
562             }
563         }
564         return false;
565     }
566 
567     /**
568      * Returns whether this {@code SigningDetails} has a signer in common with the provided
569      * {@code otherDetails} with the specified {@code flags} capabilities provided by this
570      * signer.
571      *
572      * <p>Note this method allows for the signing lineage to diverge, so this should only be
573      * used for instances where the only requirement is a common signer in the lineage with
574      * the specified capabilities. If the current signer of this instance is an ancestor of
575      * {@code otherDetails} then {@code true} is immediately returned since the current signer
576      * has all capabilities granted.
577      */
hasCommonSignerWithCapability(@onNull SigningDetails otherDetails, @CertCapabilities int flags)578     public boolean hasCommonSignerWithCapability(@NonNull SigningDetails otherDetails,
579             @CertCapabilities int flags) {
580         if (this == UNKNOWN || otherDetails == UNKNOWN) {
581             return false;
582         }
583         // If either is signed with more than one signer then both must be signed by the same
584         // signers to consider the capabilities granted.
585         if (mSignatures.length > 1 || otherDetails.mSignatures.length > 1) {
586             return signaturesMatchExactly(otherDetails);
587         }
588         // The Signature class does not use the granted capabilities in the hashCode
589         // computation, so a Set can be used to check for a common signer.
590         Set<Signature> otherSignatures = new ArraySet<>();
591         if (otherDetails.hasPastSigningCertificates()) {
592             otherSignatures.addAll(Arrays.asList(otherDetails.mPastSigningCertificates));
593         } else {
594             otherSignatures.addAll(Arrays.asList(otherDetails.mSignatures));
595         }
596         // If the current signer of this instance is an ancestor of the other than return true
597         // since all capabilities are granted to the current signer.
598         if (otherSignatures.contains(mSignatures[0])) {
599             return true;
600         }
601         if (hasPastSigningCertificates()) {
602             // Since the current signer was checked above and the last signature in the
603             // pastSigningCertificates is the current signer skip checking the last element.
604             for (int i = 0; i < mPastSigningCertificates.length - 1; i++) {
605                 if (otherSignatures.contains(mPastSigningCertificates[i])) {
606                     // If the caller specified multiple capabilities ensure all are set.
607                     if ((mPastSigningCertificates[i].getFlags() & flags) == flags) {
608                         return true;
609                     }
610                 }
611             }
612         }
613         return false;
614     }
615 
616     /**
617      * Determines if the provided {@code oldDetails} is an ancestor of this one, and whether or
618      * not this one grants it the provided capability, represented by the {@code flags}
619      * parameter.  In the event of signing certificate rotation, a package may still interact
620      * with entities signed by its old signing certificate and not want to break previously
621      * functioning behavior.  The {@code flags} value determines which capabilities the app
622      * signed by the newer signing certificate would like to continue to give to its previous
623      * signing certificate(s).
624      */
checkCapability(@onNull SigningDetails oldDetails, @CertCapabilities int flags)625     public boolean checkCapability(@NonNull SigningDetails oldDetails,
626             @CertCapabilities int flags) {
627         if (this == UNKNOWN || oldDetails == UNKNOWN) {
628             return false;
629         }
630         if (oldDetails.mSignatures.length > 1) {
631             // multiple-signer packages cannot rotate signing certs, so we must have an exact
632             // match, which also means all capabilities are granted
633             return signaturesMatchExactly(oldDetails);
634         } else {
635             // we may have signing certificate rotation history, check to see if the oldDetails
636             // was one of our old signing certificates, and if we grant it the capability it's
637             // requesting
638             return hasCertificate(oldDetails.mSignatures[0], flags);
639         }
640     }
641 
642     /**
643      * A special case of {@code checkCapability} which re-encodes both sets of signing
644      * certificates to counteract a previous re-encoding.
645      */
checkCapabilityRecover(@onNull SigningDetails oldDetails, @CertCapabilities int flags)646     public boolean checkCapabilityRecover(@NonNull SigningDetails oldDetails,
647             @CertCapabilities int flags) throws CertificateException {
648         if (oldDetails == UNKNOWN || this == UNKNOWN) {
649             return false;
650         }
651         if (hasPastSigningCertificates() && oldDetails.mSignatures.length == 1) {
652             // signing certificates may have rotated, check entire history for effective match
653             for (int i = 0; i < mPastSigningCertificates.length; i++) {
654                 if (Signature.areEffectiveMatch(
655                         oldDetails.mSignatures[0],
656                         mPastSigningCertificates[i])
657                         && mPastSigningCertificates[i].getFlags() == flags) {
658                     return true;
659                 }
660             }
661         } else {
662             return Signature.areEffectiveMatch(oldDetails, this);
663         }
664         return false;
665     }
666 
667     /**
668      * Determine if {@code signature} is in this SigningDetails' signing certificate history,
669      * including the current signer.  Automatically returns false if this object has multiple
670      * signing certificates, since rotation is only supported for single-signers; this is
671      * enforced by {@code hasCertificateInternal}.
672      */
hasCertificate(@onNull Signature signature)673     public boolean hasCertificate(@NonNull Signature signature) {
674         return hasCertificateInternal(signature, PAST_CERT_EXISTS);
675     }
676 
677     /**
678      * Determine if {@code signature} is in this SigningDetails' signing certificate history,
679      * including the current signer, and whether or not it has the given permission.
680      * Certificates which match our current signer automatically get all capabilities.
681      * Automatically returns false if this object has multiple signing certificates, since
682      * rotation is only supported for single-signers.
683      */
hasCertificate(@onNull Signature signature, @CertCapabilities int flags)684     public boolean hasCertificate(@NonNull Signature signature, @CertCapabilities int flags) {
685         return hasCertificateInternal(signature, flags);
686     }
687 
688     /** Convenient wrapper for calling {@code hasCertificate} with certificate's raw bytes. */
hasCertificate(byte[] certificate)689     public boolean hasCertificate(byte[] certificate) {
690         Signature signature = new Signature(certificate);
691         return hasCertificate(signature);
692     }
693 
hasCertificateInternal(@onNull Signature signature, int flags)694     private boolean hasCertificateInternal(@NonNull Signature signature, int flags) {
695         if (this == UNKNOWN) {
696             return false;
697         }
698 
699         // only single-signed apps can have pastSigningCertificates
700         if (hasPastSigningCertificates()) {
701             // check all past certs, except for the current one, which automatically gets all
702             // capabilities, since it is the same as the current signature
703             for (int i = 0; i < mPastSigningCertificates.length - 1; i++) {
704                 if (mPastSigningCertificates[i].equals(signature)) {
705                     if (flags == PAST_CERT_EXISTS
706                             || (flags & mPastSigningCertificates[i].getFlags()) == flags) {
707                         return true;
708                     }
709                 }
710             }
711         }
712 
713         // not in previous certs signing history, just check the current signer and make sure
714         // we are singly-signed
715         return mSignatures.length == 1 && mSignatures[0].equals(signature);
716     }
717 
718     /**
719      * Determines if the provided {@code sha256String} is an ancestor of this one, and whether
720      * or not this one grants it the provided capability, represented by the {@code flags}
721      * parameter.  In the event of signing certificate rotation, a package may still interact
722      * with entities signed by its old signing certificate and not want to break previously
723      * functioning behavior.  The {@code flags} value determines which capabilities the app
724      * signed by the newer signing certificate would like to continue to give to its previous
725      * signing certificate(s).
726      *
727      * @param sha256String A hex-encoded representation of a sha256 digest. In the case of an
728      *                     app with multiple signers, this represents the hex-encoded sha256
729      *                     digest of the combined hex-encoded sha256 digests of each individual
730      *                     signing certificate according to {@link
731      *                     PackageUtils#computeSignaturesSha256Digest(Signature[])}
732      */
checkCapability(@ullable String sha256String, @CertCapabilities int flags)733     public boolean checkCapability(@Nullable String sha256String, @CertCapabilities int flags) {
734         if (this == UNKNOWN || TextUtils.isEmpty(sha256String)) {
735             return false;
736         }
737 
738         // first see if the hash represents a single-signer in our signing history
739         final byte[] sha256Bytes = HexEncoding.decode(sha256String, false /* allowSingleChar */);
740         if (hasSha256Certificate(sha256Bytes, flags)) {
741             return true;
742         }
743 
744         // Not in signing history, either represents multiple signatures or not a match.
745         // Multiple signers can't rotate, so no need to check flags, just see if the SHAs match.
746         // We already check the single-signer case above as part of hasSha256Certificate, so no
747         // need to verify we have multiple signers, just run the old check
748         // just consider current signing certs
749         final String[] mSignaturesSha256Digests =
750                 PackageUtils.computeSignaturesSha256Digests(mSignatures);
751         final String mSignaturesSha256Digest =
752                 PackageUtils.computeSignaturesSha256Digest(mSignaturesSha256Digests);
753         return mSignaturesSha256Digest.equals(sha256String);
754     }
755 
756     /**
757      * Determine if the {@code sha256Certificate} is in this SigningDetails' signing certificate
758      * history, including the current signer.  Automatically returns false if this object has
759      * multiple signing certificates, since rotation is only supported for single-signers.
760      */
hasSha256Certificate(byte[] sha256Certificate)761     public boolean hasSha256Certificate(byte[] sha256Certificate) {
762         return hasSha256CertificateInternal(sha256Certificate, PAST_CERT_EXISTS);
763     }
764 
765     /**
766      * Determine if the {@code sha256Certificate} certificate hash corresponds to a signing
767      * certificate in this SigningDetails' signing certificate history, including the current
768      * signer, and whether or not it has the given permission.  Certificates which match our
769      * current signer automatically get all capabilities. Automatically returns false if this
770      * object has multiple signing certificates, since rotation is only supported for
771      * single-signers.
772      */
hasSha256Certificate(byte[] sha256Certificate, @CertCapabilities int flags)773     public boolean hasSha256Certificate(byte[] sha256Certificate, @CertCapabilities int flags) {
774         return hasSha256CertificateInternal(sha256Certificate, flags);
775     }
776 
hasSha256CertificateInternal(byte[] sha256Certificate, int flags)777     private boolean hasSha256CertificateInternal(byte[] sha256Certificate, int flags) {
778         if (this == UNKNOWN) {
779             return false;
780         }
781         if (hasPastSigningCertificates()) {
782             // check all past certs, except for the last one, which automatically gets all
783             // capabilities, since it is the same as the current signature, and is checked below
784             for (int i = 0; i < mPastSigningCertificates.length - 1; i++) {
785                 byte[] digest = PackageUtils.computeSha256DigestBytes(
786                         mPastSigningCertificates[i].toByteArray());
787                 if (Arrays.equals(sha256Certificate, digest)) {
788                     if (flags == PAST_CERT_EXISTS
789                             || (flags & mPastSigningCertificates[i].getFlags()) == flags) {
790                         return true;
791                     }
792                 }
793             }
794         }
795 
796         // not in previous certs signing history, just check the current signer
797         if (mSignatures.length == 1) {
798             byte[] digest = PackageUtils.computeSha256DigestBytes(mSignatures[0].toByteArray());
799             return Arrays.equals(sha256Certificate, digest);
800         }
801         return false;
802     }
803 
804     /** Returns true if the signatures in this and other match exactly. */
signaturesMatchExactly(@onNull SigningDetails other)805     public boolean signaturesMatchExactly(@NonNull SigningDetails other) {
806         return Signature.areExactMatch(this, other);
807     }
808 
809     @Override
describeContents()810     public int describeContents() {
811         return 0;
812     }
813 
814     @Override
writeToParcel(@onNull Parcel dest, int flags)815     public void writeToParcel(@NonNull Parcel dest, int flags) {
816         boolean isUnknown = UNKNOWN == this;
817         dest.writeBoolean(isUnknown);
818         if (isUnknown) {
819             return;
820         }
821         dest.writeTypedArray(mSignatures, flags);
822         dest.writeInt(mSignatureSchemeVersion);
823         dest.writeArraySet(mPublicKeys);
824         dest.writeTypedArray(mPastSigningCertificates, flags);
825     }
826 
SigningDetails(@onNull Parcel in)827     protected SigningDetails(@NonNull Parcel in) {
828         final ClassLoader boot = Object.class.getClassLoader();
829         mSignatures = in.createTypedArray(Signature.CREATOR);
830         mSignatureSchemeVersion = in.readInt();
831         mPublicKeys = (ArraySet<PublicKey>) in.readArraySet(boot);
832         mPastSigningCertificates = in.createTypedArray(Signature.CREATOR);
833     }
834 
835     public static final @NonNull Parcelable.Creator<SigningDetails> CREATOR =
836             new Creator<SigningDetails>() {
837                 @Override
838                 public SigningDetails createFromParcel(@NonNull Parcel source) {
839                     if (source.readBoolean()) {
840                         return UNKNOWN;
841                     }
842                     return new SigningDetails(source);
843                 }
844 
845                 @Override
846                 public SigningDetails[] newArray(int size) {
847                     return new SigningDetails[size];
848                 }
849             };
850 
851     @Override
equals(@ullable Object o)852     public boolean equals(@Nullable Object o) {
853         if (this == o) return true;
854         if (!(o instanceof SigningDetails)) return false;
855 
856         final SigningDetails that = (SigningDetails) o;
857 
858         if (mSignatureSchemeVersion != that.mSignatureSchemeVersion) return false;
859         if (!Signature.areExactMatch(this, that)) return false;
860         if (mPublicKeys != null) {
861             if (!mPublicKeys.equals((that.mPublicKeys))) {
862                 return false;
863             }
864         } else if (that.mPublicKeys != null) {
865             return false;
866         }
867 
868         // can't use Signature.areExactMatch() because order matters with the past signing certs
869         if (!Arrays.equals(mPastSigningCertificates, that.mPastSigningCertificates)) {
870             return false;
871         }
872         // The capabilities for the past signing certs must match as well.
873         if (mPastSigningCertificates != null) {
874             for (int i = 0; i < mPastSigningCertificates.length; i++) {
875                 if (mPastSigningCertificates[i].getFlags()
876                         != that.mPastSigningCertificates[i].getFlags()) {
877                     return false;
878                 }
879             }
880         }
881         return true;
882     }
883 
884     @Override
hashCode()885     public int hashCode() {
886         int result = +Arrays.hashCode(mSignatures);
887         result = 31 * result + mSignatureSchemeVersion;
888         result = 31 * result + (mPublicKeys != null ? mPublicKeys.hashCode() : 0);
889         result = 31 * result + Arrays.hashCode(mPastSigningCertificates);
890         return result;
891     }
892 
893     /**
894      * Builder of {@code SigningDetails} instances.
895      */
896     public static class Builder {
897         private @NonNull Signature[] mSignatures;
898         private @SignatureSchemeVersion int mSignatureSchemeVersion =
899                 SignatureSchemeVersion.UNKNOWN;
900         private @Nullable Signature[] mPastSigningCertificates;
901 
Builder()902         public Builder() {
903         }
904 
905         /** get signing certificates used to sign the current APK */
setSignatures(@onNull Signature[] signatures)906         public SigningDetails.Builder setSignatures(@NonNull Signature[] signatures) {
907             mSignatures = signatures;
908             return this;
909         }
910 
911         /** set the signature scheme version used to sign the APK */
setSignatureSchemeVersion( @ignatureSchemeVersion int signatureSchemeVersion)912         public SigningDetails.Builder setSignatureSchemeVersion(
913                 @SignatureSchemeVersion int signatureSchemeVersion) {
914             mSignatureSchemeVersion = signatureSchemeVersion;
915             return this;
916         }
917 
918         /** set the signing certificates by which the APK proved it can be authenticated */
setPastSigningCertificates( @ullable Signature[] pastSigningCertificates)919         public SigningDetails.Builder setPastSigningCertificates(
920                 @Nullable Signature[] pastSigningCertificates) {
921             mPastSigningCertificates = pastSigningCertificates;
922             return this;
923         }
924 
checkInvariants()925         private void checkInvariants() {
926             // must have signatures and scheme version set
927             if (mSignatures == null) {
928                 throw new IllegalStateException("SigningDetails requires the current signing"
929                         + " certificates.");
930             }
931         }
932         /** build a {@code SigningDetails} object */
build()933         public SigningDetails build()
934                 throws CertificateException {
935             checkInvariants();
936             return new SigningDetails(mSignatures, mSignatureSchemeVersion,
937                     mPastSigningCertificates);
938         }
939     }
940 
941     /** Parses the public keys from the set of signatures. */
toSigningKeys(@onNull Signature[] signatures)942     public static ArraySet<PublicKey> toSigningKeys(@NonNull Signature[] signatures)
943             throws CertificateException {
944         final ArraySet<PublicKey> keys = new ArraySet<>(signatures.length);
945         for (int i = 0; i < signatures.length; i++) {
946             keys.add(signatures[i].getPublicKey());
947         }
948         return keys;
949     }
950 
951 
952 
953     // Code below generated by codegen v1.0.23.
954     //
955     // DO NOT MODIFY!
956     // CHECKSTYLE:OFF Generated code
957     //
958     // To regenerate run:
959     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/SigningDetails.java
960     //
961     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
962     //   Settings > Editor > Code Style > Formatter Control
963     //@formatter:off
964 
965 
966     /**
967      * The signing certificates associated with this application package.
968      */
969     @DataClass.Generated.Member
getSignatures()970     public @Nullable Signature[] getSignatures() {
971         return mSignatures;
972     }
973 
974     /**
975      * The signature scheme version for this application package.
976      */
977     @DataClass.Generated.Member
getSignatureSchemeVersion()978     public @SignatureSchemeVersion int getSignatureSchemeVersion() {
979         return mSignatureSchemeVersion;
980     }
981 
982     /**
983      * The public keys set for the certificates.
984      */
985     @DataClass.Generated.Member
getPublicKeys()986     public @Nullable ArraySet<PublicKey> getPublicKeys() {
987         return mPublicKeys;
988     }
989 
990     /**
991      * APK Signature Scheme v3 includes support for adding a proof-of-rotation record that
992      * contains two pieces of information:
993      *   1) the past signing certificates
994      *   2) the flags that APK wants to assign to each of the past signing certificates.
995      *
996      * This collection of {@code Signature} objects, each of which is formed from a former
997      * signing certificate of this APK before it was changed by signing certificate rotation,
998      * represents the first piece of information.  It is the APK saying to the rest of the
999      * world: "hey if you trust the old cert, you can trust me!"  This is useful, if for
1000      * instance, the platform would like to determine whether or not to allow this APK to do
1001      * something it would've allowed it to do under the old cert (like upgrade).
1002      */
1003     @DataClass.Generated.Member
getPastSigningCertificates()1004     public @Nullable Signature[] getPastSigningCertificates() {
1005         return mPastSigningCertificates;
1006     }
1007 
1008     @DataClass.Generated(
1009             time = 1650058974710L,
1010             codegenVersion = "1.0.23",
1011             sourceFile = "frameworks/base/core/java/android/content/pm/SigningDetails.java",
1012             inputSignatures = "private static final  java.lang.String TAG\nprivate final @android.annotation.Nullable android.content.pm.Signature[] mSignatures\nprivate final @android.content.pm.SigningDetails.SignatureSchemeVersion int mSignatureSchemeVersion\nprivate final @android.annotation.Nullable android.util.ArraySet<java.security.PublicKey> mPublicKeys\nprivate final @android.annotation.Nullable android.content.pm.Signature[] mPastSigningCertificates\nprivate static final  int PAST_CERT_EXISTS\npublic static final  android.content.pm.SigningDetails UNKNOWN\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.SigningDetails> CREATOR\npublic @android.annotation.NonNull android.content.pm.SigningDetails mergeLineageWith(android.content.pm.SigningDetails)\npublic @android.annotation.NonNull android.content.pm.SigningDetails mergeLineageWith(android.content.pm.SigningDetails,int)\nprivate @android.annotation.NonNull android.content.pm.SigningDetails mergeLineageWithAncestorOrSelf(android.content.pm.SigningDetails,int)\npublic  boolean hasCommonAncestor(android.content.pm.SigningDetails)\npublic  boolean hasAncestorOrSelfWithDigest(java.util.Set<java.lang.String>)\nprivate @android.annotation.Nullable android.content.pm.SigningDetails getDescendantOrSelf(android.content.pm.SigningDetails)\npublic  boolean hasSignatures()\npublic  boolean hasPastSigningCertificates()\npublic  boolean hasAncestorOrSelf(android.content.pm.SigningDetails)\npublic  boolean hasAncestor(android.content.pm.SigningDetails)\npublic  boolean hasCommonSignerWithCapability(android.content.pm.SigningDetails,int)\npublic  boolean checkCapability(android.content.pm.SigningDetails,int)\npublic  boolean checkCapabilityRecover(android.content.pm.SigningDetails,int)\npublic  boolean hasCertificate(android.content.pm.Signature)\npublic  boolean hasCertificate(android.content.pm.Signature,int)\npublic  boolean hasCertificate(byte[])\nprivate  boolean hasCertificateInternal(android.content.pm.Signature,int)\npublic  boolean checkCapability(java.lang.String,int)\npublic  boolean hasSha256Certificate(byte[])\npublic  boolean hasSha256Certificate(byte[],int)\nprivate  boolean hasSha256CertificateInternal(byte[],int)\npublic  boolean signaturesMatchExactly(android.content.pm.SigningDetails)\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\npublic @java.lang.Override boolean equals(java.lang.Object)\npublic @java.lang.Override int hashCode()\npublic static  android.util.ArraySet<java.security.PublicKey> toSigningKeys(android.content.pm.Signature[])\nclass SigningDetails extends java.lang.Object implements [android.os.Parcelable]\nprivate @android.annotation.NonNull android.content.pm.Signature[] mSignatures\nprivate @android.content.pm.SigningDetails.SignatureSchemeVersion int mSignatureSchemeVersion\nprivate @android.annotation.Nullable android.content.pm.Signature[] mPastSigningCertificates\npublic  android.content.pm.SigningDetails.Builder setSignatures(android.content.pm.Signature[])\npublic  android.content.pm.SigningDetails.Builder setSignatureSchemeVersion(int)\npublic  android.content.pm.SigningDetails.Builder setPastSigningCertificates(android.content.pm.Signature[])\nprivate  void checkInvariants()\npublic  android.content.pm.SigningDetails build()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false, genParcelable=true, genAidl=false)")
1013     @Deprecated
__metadata()1014     private void __metadata() {}
1015 
1016 
1017     //@formatter:on
1018     // End of generated code
1019 
1020 }
1021