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 
20 import android.annotation.NonNull;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 
24 /**
25  * Information pertaining to the signing certificates used to sign a package.
26  */
27 public final class SigningInfo implements Parcelable {
28 
29     @NonNull
30     private final PackageParser.SigningDetails mSigningDetails;
31 
SigningInfo()32     public SigningInfo() {
33         mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
34     }
35 
36     /**
37      * @hide only packagemanager should be populating this
38      */
SigningInfo(PackageParser.SigningDetails signingDetails)39     public SigningInfo(PackageParser.SigningDetails signingDetails) {
40         mSigningDetails = new PackageParser.SigningDetails(signingDetails);
41     }
42 
SigningInfo(SigningInfo orig)43     public SigningInfo(SigningInfo orig) {
44         mSigningDetails = new PackageParser.SigningDetails(orig.mSigningDetails);
45     }
46 
SigningInfo(Parcel source)47     private SigningInfo(Parcel source) {
48         mSigningDetails = PackageParser.SigningDetails.CREATOR.createFromParcel(source);
49     }
50 
51     /**
52      * Although relatively uncommon, packages may be signed by more than one signer, in which case
53      * their identity is viewed as being the set of all signers, not just any one.
54      */
hasMultipleSigners()55     public boolean hasMultipleSigners() {
56         return mSigningDetails.signatures != null && mSigningDetails.signatures.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.signatures != null
69                 && mSigningDetails.pastSigningCertificates != null;
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.  This method
76      * is the preferred replacement for the {@code GET_SIGNATURES} flag used with {@link
77      * PackageManager#getPackageInfo(String, int)}.  When determining if a package is signed by a
78      * desired certificate, the returned array should be checked to determine if it is one of the
79      * entries.
80      *
81      * <note>
82      *     This method returns null if the package is signed by multiple signing certificates, as
83      *     opposed to being signed by one current signer and also providing the history of past
84      *     signing certificates.  {@link #hasMultipleSigners()} may be used to determine if this
85      *     package is signed by multiple signers.  Packages which are signed by multiple signers
86      *     cannot change their signing certificates and their {@code Signature} array should be
87      *     checked to make sure that every entry matches the looked-for signing certificates.
88      * </note>
89      */
getSigningCertificateHistory()90     public Signature[] getSigningCertificateHistory() {
91         if (hasMultipleSigners()) {
92             return null;
93         } else if (!hasPastSigningCertificates()) {
94 
95             // this package is only signed by one signer with no history, return it
96             return mSigningDetails.signatures;
97         } else {
98 
99             // this package has provided proof of past signing certificates, include them
100             return mSigningDetails.pastSigningCertificates;
101         }
102     }
103 
104     /**
105      * Returns the signing certificates used to sign the APK contents of this application.  Not
106      * including any past signing certificates the package proved it is authorized to use.
107      * <note>
108      *     This method should not be used unless {@link #hasMultipleSigners()} returns true,
109      *     indicating that {@link #getSigningCertificateHistory()} cannot be used, otherwise {@link
110      *     #getSigningCertificateHistory()} should be preferred.
111      * </note>
112      */
getApkContentsSigners()113     public Signature[] getApkContentsSigners() {
114         return mSigningDetails.signatures;
115     }
116 
117     @Override
describeContents()118     public int describeContents() {
119         return 0;
120     }
121 
122     @Override
writeToParcel(Parcel dest, int parcelableFlags)123     public void writeToParcel(Parcel dest, int parcelableFlags) {
124         mSigningDetails.writeToParcel(dest, parcelableFlags);
125     }
126 
127     public static final @android.annotation.NonNull Parcelable.Creator<SigningInfo> CREATOR =
128             new Parcelable.Creator<SigningInfo>() {
129         @Override
130         public SigningInfo createFromParcel(Parcel source) {
131             return new SigningInfo(source);
132         }
133 
134         @Override
135         public SigningInfo[] newArray(int size) {
136             return new SigningInfo[size];
137         }
138     };
139 }
140