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