Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 960a0c6c authored by Daniel Cashman's avatar Daniel Cashman Committed by Android (Google) Code Review
Browse files

Merge "Add SigningInfo class to expose package signing details." into pi-dev

parents 10fb6582 5c9f527e
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -11020,7 +11020,7 @@ package android.content.pm {
    field public java.lang.String sharedUserId;
    field public int sharedUserLabel;
    field public deprecated android.content.pm.Signature[] signatures;
    field public android.content.pm.Signature[][] signingCertificateHistory;
    field public android.content.pm.SigningInfo signingInfo;
    field public java.lang.String[] splitNames;
    field public int[] splitRevisionCodes;
    field public deprecated int versionCode;
@@ -11648,6 +11648,18 @@ package android.content.pm {
    field public static final android.os.Parcelable.Creator<android.content.pm.Signature> CREATOR;
  }
  public final class SigningInfo implements android.os.Parcelable {
    ctor public SigningInfo();
    ctor public SigningInfo(android.content.pm.SigningInfo);
    method public int describeContents();
    method public android.content.pm.Signature[] getApkContentsSigners();
    method public android.content.pm.Signature[] getSigningCertificateHistory();
    method public boolean hasMultipleSigners();
    method public boolean hasPastSigningCertificates();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.content.pm.SigningInfo> CREATOR;
  }
  public final class VersionedPackage implements android.os.Parcelable {
    ctor public VersionedPackage(java.lang.String, int);
    ctor public VersionedPackage(java.lang.String, long);
+14 −41
Original line number Diff line number Diff line
@@ -244,7 +244,7 @@ public class PackageInfo implements Parcelable {
     * the first position to be the same across updates.
     *
     * <strong>Deprecated</strong> This has been replaced by the
     * {@link PackageInfo#signingCertificateHistory} field, which takes into
     * {@link PackageInfo#signingInfo} field, which takes into
     * account signing certificate rotation.  For backwards compatibility in
     * the event of signing certificate rotation, this will return the oldest
     * reported signing certificate, so that an application will appear to
@@ -256,29 +256,15 @@ public class PackageInfo implements Parcelable {
    public Signature[] signatures;

    /**
     * Array of all signatures arrays read from the package file, potentially
     * Signing information read from the package file, potentially
     * including past signing certificates no longer used after signing
     * certificate rotation.  Though signing certificate rotation is only
     * available for apps with a single signing certificate, this provides an
     * array of arrays so that packages signed with multiple signing
     * certificates can still return all signers.  This is only filled in if
     * certificate rotation.  This is only filled in if
     * the flag {@link PackageManager#GET_SIGNING_CERTIFICATES} was set.
     *
     * A package must be singed with at least one certificate, which is at
     * position zero in the array.  An application may be signed by multiple
     * certificates, which would be in the array at position zero in an
     * indeterminate order.  A package may also have a history of certificates
     * due to signing certificate rotation.  In this case, the array will be
     * populated by a series of single-entry arrays corresponding to a signing
     * certificate of the package.
     *
     * <strong>Note:</strong> Signature ordering is not guaranteed to be
     * stable which means that a package signed with certificates A and B is
     * equivalent to being signed with certificates B and A. This means that
     * in case multiple signatures are reported you cannot assume the one at
     * the first position will be the same across updates.
     * Use this field instead of the deprecated {@code signatures} field.
     * See {@link SigningInfo} for more information on its contents.
     */
    public Signature[][] signingCertificateHistory;
    public SigningInfo signingInfo;

    /**
     * Application specified preferred configuration
@@ -476,17 +462,11 @@ public class PackageInfo implements Parcelable {
        dest.writeBoolean(mOverlayIsStatic);
        dest.writeInt(compileSdkVersion);
        dest.writeString(compileSdkVersionCodename);
        writeSigningCertificateHistoryToParcel(dest, parcelableFlags);
    }

    private void writeSigningCertificateHistoryToParcel(Parcel dest, int parcelableFlags) {
        if (signingCertificateHistory != null) {
            dest.writeInt(signingCertificateHistory.length);
            for (int i = 0; i < signingCertificateHistory.length; i++) {
                dest.writeTypedArray(signingCertificateHistory[i], parcelableFlags);
            }
        if (signingInfo != null) {
            dest.writeInt(1);
            signingInfo.writeToParcel(dest, parcelableFlags);
        } else {
            dest.writeInt(-1);
            dest.writeInt(0);
        }
    }

@@ -544,7 +524,10 @@ public class PackageInfo implements Parcelable {
        mOverlayIsStatic = source.readBoolean();
        compileSdkVersion = source.readInt();
        compileSdkVersionCodename = source.readString();
        readSigningCertificateHistoryFromParcel(source);
        int hasSigningInfo = source.readInt();
        if (hasSigningInfo != 0) {
            signingInfo = SigningInfo.CREATOR.createFromParcel(source);
        }

        // The component lists were flattened with the redundant ApplicationInfo
        // instances omitted.  Distribute the canonical one here as appropriate.
@@ -556,16 +539,6 @@ public class PackageInfo implements Parcelable {
        }
    }

    private void readSigningCertificateHistoryFromParcel(Parcel source) {
        int len = source.readInt();
        if (len != -1) {
            signingCertificateHistory = new Signature[len][];
            for (int i = 0; i < len; i++) {
                signingCertificateHistory[i] = source.createTypedArray(Signature.CREATOR);
            }
        }
    }

    private void propagateApplicationInfo(ApplicationInfo appInfo, ComponentInfo[] components) {
        if (components != null) {
            for (ComponentInfo ci : components) {
+5 −15
Original line number Diff line number Diff line
@@ -810,21 +810,11 @@ public class PackageParser {

        // replacement for GET_SIGNATURES
        if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
            if (p.mSigningDetails.hasPastSigningCertificates()) {
                // Package has included signing certificate rotation information.  Convert each
                // entry to an array
                int numberOfSigs = p.mSigningDetails.pastSigningCertificates.length;
                pi.signingCertificateHistory = new Signature[numberOfSigs][];
                for (int i = 0; i < numberOfSigs; i++) {
                    pi.signingCertificateHistory[i] =
                            new Signature[] { p.mSigningDetails.pastSigningCertificates[i] };
                }
            } else if (p.mSigningDetails.hasSignatures()) {
                // otherwise keep old behavior
                int numberOfSigs = p.mSigningDetails.signatures.length;
                pi.signingCertificateHistory = new Signature[1][numberOfSigs];
                System.arraycopy(p.mSigningDetails.signatures, 0,
                        pi.signingCertificateHistory[0], 0, numberOfSigs);
            if (p.mSigningDetails != SigningDetails.UNKNOWN) {
                // only return a valid SigningInfo if there is signing information to report
                pi.signingInfo = new SigningInfo(p.mSigningDetails);
            } else {
                pi.signingInfo = null;
            }
        }
        return pi;
+139 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.content.pm;


import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;

/**
 * Information pertaining to the signing certificates used to sign a package.
 */
public final class SigningInfo implements Parcelable {

    @NonNull
    private final PackageParser.SigningDetails mSigningDetails;

    public SigningInfo() {
        mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
    }

    /**
     * @hide only packagemanager should be populating this
     */
    public SigningInfo(PackageParser.SigningDetails signingDetails) {
        mSigningDetails = new PackageParser.SigningDetails(signingDetails);
    }

    public SigningInfo(SigningInfo orig) {
        mSigningDetails = new PackageParser.SigningDetails(orig.mSigningDetails);
    }

    private SigningInfo(Parcel source) {
        mSigningDetails = PackageParser.SigningDetails.CREATOR.createFromParcel(source);
    }

    /**
     * Although relatively uncommon, packages may be signed by more than one signer, in which case
     * their identity is viewed as being the set of all signers, not just any one.
     */
    public boolean hasMultipleSigners() {
        return mSigningDetails.signatures != null && mSigningDetails.signatures.length > 1;
    }

    /**
     * APK Signature Scheme v3 enables packages to provide a proof-of-rotation record that the
     * platform verifies, and uses, to allow the use of new signing certificates.  This is only
     * available to packages that are not signed by multiple signers.  In the event of a change to a
     * new signing certificate, the package's past signing certificates are presented as well.  Any
     * check of a package's signing certificate should also include a search through its entire
     * signing history, since it could change to a new signing certificate at any time.
     */
    public boolean hasPastSigningCertificates() {
        return mSigningDetails.signatures != null
                && mSigningDetails.pastSigningCertificates != null;
    }

    /**
     * Returns the signing certificates this package has proven it is authorized to use. This
     * includes both the signing certificate associated with the signer of the package and the past
     * signing certificates it included as its proof of signing certificate rotation.  This method
     * is the preferred replacement for the {@code GET_SIGNATURES} flag used with {@link
     * PackageManager#getPackageInfo(String, int)}.  When determining if a package is signed by a
     * desired certificate, the returned array should be checked to determine if it is one of the
     * entries.
     *
     * <note>
     *     This method returns null if the package is signed by multiple signing certificates, as
     *     opposed to being signed by one current signer and also providing the history of past
     *     signing certificates.  {@link #hasMultipleSigners()} may be used to determine if this
     *     package is signed by multiple signers.  Packages which are signed by multiple signers
     *     cannot change their signing certificates and their {@code Signature} array should be
     *     checked to make sure that every entry matches the looked-for signing certificates.
     * </note>
     */
    public Signature[] getSigningCertificateHistory() {
        if (hasMultipleSigners()) {
            return null;
        } else if (!hasPastSigningCertificates()) {

            // this package is only signed by one signer with no history, return it
            return mSigningDetails.signatures;
        } else {

            // this package has provided proof of past signing certificates, include them
            return mSigningDetails.pastSigningCertificates;
        }
    }

    /**
     * Returns the signing certificates used to sign the APK contents of this application.  Not
     * including any past signing certificates the package proved it is authorized to use.
     * <note>
     *     This method should not be used unless {@link #hasMultipleSigners()} returns true,
     *     indicating that {@link #getSigningCertificateHistory()} cannot be used, otherwise {@link
     *     #getSigningCertificateHistory()} should be preferred.
     * </note>
     */
    public Signature[] getApkContentsSigners() {
        return mSigningDetails.signatures;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int parcelableFlags) {
        mSigningDetails.writeToParcel(dest, parcelableFlags);
    }

    public static final Parcelable.Creator<SigningInfo> CREATOR =
            new Parcelable.Creator<SigningInfo>() {
        @Override
        public SigningInfo createFromParcel(Parcel source) {
            return new SigningInfo(source);
        }

        @Override
        public SigningInfo[] newArray(int size) {
            return new SigningInfo[size];
        }
    };
}
+9 −7
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.content.pm.SigningInfo;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.util.Slog;
@@ -240,12 +241,13 @@ public class PackageManagerBackupAgent extends BackupAgent {
                        PackageManager.GET_SIGNING_CERTIFICATES);
                homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName());
                homeVersion = homeInfo.getLongVersionCode();
                Signature[][] signingHistory = homeInfo.signingCertificateHistory;
                if (signingHistory == null || signingHistory.length == 0) {
                    Slog.e(TAG, "Home app has no signing history");
                SigningInfo signingInfo = homeInfo.signingInfo;
                if (signingInfo == null) {
                    Slog.e(TAG, "Home app has no signing information");
                } else {
                    // retrieve the newest sigs to back up
                    Signature[] homeInfoSignatures = signingHistory[signingHistory.length - 1];
                    // TODO (b/73988180) use entire signing history in case of rollbacks
                    Signature[] homeInfoSignatures = signingInfo.getApkContentsSigners();
                    homeSigHashes = BackupUtils.hashSignatureArray(homeInfoSignatures);
                }
            } catch (NameNotFoundException e) {
@@ -334,8 +336,8 @@ public class PackageManagerBackupAgent extends BackupAgent {
                        }
                    }

                    Signature[][] signingHistory = info.signingCertificateHistory;
                    if (signingHistory == null || signingHistory.length == 0) {
                    SigningInfo signingInfo = info.signingInfo;
                    if (signingInfo == null) {
                        Slog.w(TAG, "Not backing up package " + packName
                                + " since it appears to have no signatures.");
                        continue;
@@ -358,7 +360,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
                        outputBufferStream.writeInt(info.versionCode);
                    }
                    // retrieve the newest sigs to back up
                    Signature[] infoSignatures = signingHistory[signingHistory.length - 1];
                    Signature[] infoSignatures = signingInfo.getApkContentsSigners();
                    writeSignatureHashArray(outputBufferStream,
                            BackupUtils.hashSignatureArray(infoSignatures));

Loading