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

Commit 63b44753 authored by Daniel Cashman's avatar Daniel Cashman Committed by android-build-merger
Browse files

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

am: 960a0c6c

Change-Id: I512db4ad4f81da5cdd61bb2de5f3ed0e719379c1
parents ea440a76 960a0c6c
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