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