1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.content.pm;
18 
19 import android.annotation.NonNull;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 
23 /**
24  * Information pertaining to the signing certificates used to sign a package.
25  */
26 public final class SigningInfo implements Parcelable {
27 
28     @NonNull
29     private final SigningDetails mSigningDetails;
30 
SigningInfo()31     public SigningInfo() {
32         mSigningDetails = SigningDetails.UNKNOWN;
33     }
34 
35     /**
36      * @hide only packagemanager should be populating this
37      */
SigningInfo(SigningDetails signingDetails)38     public SigningInfo(SigningDetails signingDetails) {
39         mSigningDetails = new SigningDetails(signingDetails);
40     }
41 
SigningInfo(SigningInfo orig)42     public SigningInfo(SigningInfo orig) {
43         mSigningDetails = new SigningDetails(orig.mSigningDetails);
44     }
45 
SigningInfo(Parcel source)46     private SigningInfo(Parcel source) {
47         mSigningDetails = SigningDetails.CREATOR.createFromParcel(source);
48     }
49 
50     /**
51      * Although relatively uncommon, packages may be signed by more than one signer, in which case
52      * their identity is viewed as being the set of all signers, not just any one.
53      */
hasMultipleSigners()54     public boolean hasMultipleSigners() {
55         return mSigningDetails.getSignatures() != null
56                 && mSigningDetails.getSignatures().length > 1;
57     }
58 
59     /**
60      * APK Signature Scheme v3 enables packages to provide a proof-of-rotation record that the
61      * platform verifies, and uses, to allow the use of new signing certificates.  This is only
62      * available to packages that are not signed by multiple signers.  In the event of a change to a
63      * new signing certificate, the package's past signing certificates are presented as well.  Any
64      * check of a package's signing certificate should also include a search through its entire
65      * signing history, since it could change to a new signing certificate at any time.
66      */
hasPastSigningCertificates()67     public boolean hasPastSigningCertificates() {
68         return mSigningDetails.getPastSigningCertificates() != null
69                 && mSigningDetails.getPastSigningCertificates().length > 0;
70     }
71 
72     /**
73      * Returns the signing certificates this package has proven it is authorized to use. This
74      * includes both the signing certificate associated with the signer of the package and the past
75      * signing certificates it included as its proof of signing certificate rotation.  Signing
76      * certificates are returned in the order of rotation with the original signing certificate at
77      * index 0, and the current signing certificate at the last index. This method is the preferred
78      * replacement for the {@code GET_SIGNATURES} flag used with {@link
79      * PackageManager#getPackageInfo(String, int)}. When determining if a package is signed by a
80      * desired certificate, the returned array should be checked to determine if it is one of the
81      * entries.
82      *
83      * <note>
84      *     This method returns null if the package is signed by multiple signing certificates, as
85      *     opposed to being signed by one current signer and also providing the history of past
86      *     signing certificates.  {@link #hasMultipleSigners()} may be used to determine if this
87      *     package is signed by multiple signers.  Packages which are signed by multiple signers
88      *     cannot change their signing certificates and their {@code Signature} array should be
89      *     checked to make sure that every entry matches the looked-for signing certificates.
90      * </note>
91      */
getSigningCertificateHistory()92     public Signature[] getSigningCertificateHistory() {
93         if (hasMultipleSigners()) {
94             return null;
95         } else if (!hasPastSigningCertificates()) {
96 
97             // this package is only signed by one signer with no history, return it
98             return mSigningDetails.getSignatures();
99         } else {
100 
101             // this package has provided proof of past signing certificates, include them
102             return mSigningDetails.getPastSigningCertificates();
103         }
104     }
105 
106     /**
107      * Returns the signing certificates used to sign the APK contents of this application.  Not
108      * including any past signing certificates the package proved it is authorized to use.
109      * <note>
110      *     This method should not be used unless {@link #hasMultipleSigners()} returns true,
111      *     indicating that {@link #getSigningCertificateHistory()} cannot be used, otherwise {@link
112      *     #getSigningCertificateHistory()} should be preferred.
113      * </note>
114      */
getApkContentsSigners()115     public Signature[] getApkContentsSigners() {
116         return mSigningDetails.getSignatures();
117     }
118 
119     @Override
describeContents()120     public int describeContents() {
121         return 0;
122     }
123 
124     @Override
writeToParcel(Parcel dest, int parcelableFlags)125     public void writeToParcel(Parcel dest, int parcelableFlags) {
126         mSigningDetails.writeToParcel(dest, parcelableFlags);
127     }
128 
129     public static final @android.annotation.NonNull Parcelable.Creator<SigningInfo> CREATOR =
130             new Parcelable.Creator<SigningInfo>() {
131         @Override
132         public SigningInfo createFromParcel(Parcel source) {
133             return new SigningInfo(source);
134         }
135 
136         @Override
137         public SigningInfo[] newArray(int size) {
138             return new SigningInfo[size];
139         }
140     };
141 }
142