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