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

Commit 5cdda342 authored by Daniel Cashman's avatar Daniel Cashman Committed by Dan Cashman
Browse files

Add API to expose signing certificate proof-of-rotation.

With the addition of APK Signature Scheme v3, the platform now can
support key rotation by using the proof-of-rotation provided by the
new scheme.  Create a new API which allows checking of the entire
provided history of an APK's signing certificates, not just the
current signer.  This should allow for changes of APK signing
certificates without fear of losing access to resources that would
have been provided under the old signing certificate.

Change getPackageInfo(GET_SIGNATURES) to return the oldest signing
certificate in the chain so that apps which do programmatic checks,
but are not updated to use the new API, still get the same information
they would have gotten had there been no rotation.

Bug: 64686581
Test: Builds, boots.
Change-Id: I8982fd4cce60f5d85a6180d157a6e2a661b1a6d7
parent 77029c5b
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -10870,7 +10870,8 @@ package android.content.pm {
    field public android.content.pm.ServiceInfo[] services;
    field public java.lang.String sharedUserId;
    field public int sharedUserLabel;
    field public android.content.pm.Signature[] signatures;
    field public deprecated android.content.pm.Signature[] signatures;
    field public android.content.pm.Signature[][] signingCertificateHistory;
    field public java.lang.String[] splitNames;
    field public int[] splitRevisionCodes;
    field public deprecated int versionCode;
@@ -11073,6 +11074,8 @@ package android.content.pm {
    method public abstract android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle);
    method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
    method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
    method public boolean hasSigningCertificate(java.lang.String, byte[], int);
    method public boolean hasSigningCertificate(int, byte[], int);
    method public abstract boolean hasSystemFeature(java.lang.String);
    method public abstract boolean hasSystemFeature(java.lang.String, int);
    method public abstract boolean isInstantApp();
@@ -11098,6 +11101,8 @@ package android.content.pm {
    method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
    method public abstract void updateInstantAppCookie(byte[]);
    method public abstract void verifyPendingInstall(int, int);
    field public static final int CERT_INPUT_RAW_X509 = 0; // 0x0
    field public static final int CERT_INPUT_SHA256 = 1; // 0x1
    field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0
    field public static final int COMPONENT_ENABLED_STATE_DISABLED = 2; // 0x2
    field public static final int COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4; // 0x4
@@ -11216,7 +11221,8 @@ package android.content.pm {
    field public static final int GET_RESOLVED_FILTER = 64; // 0x40
    field public static final int GET_SERVICES = 4; // 0x4
    field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
    field public static final int GET_SIGNATURES = 64; // 0x40
    field public static final deprecated int GET_SIGNATURES = 64; // 0x40
    field public static final int GET_SIGNING_CERTIFICATES = 134217728; // 0x8000000
    field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
    field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
    field public static final int INSTALL_REASON_DEVICE_RESTORE = 2; // 0x2
+20 −0
Original line number Diff line number Diff line
@@ -689,6 +689,26 @@ public class ApplicationPackageManager extends PackageManager {
        }
    }

    @Override
    public boolean hasSigningCertificate(
            String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
        try {
            return mPM.hasSigningCertificate(packageName, certificate, type);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @Override
    public boolean hasSigningCertificate(
            int uid, byte[] certificate, @PackageManager.CertificateInputType int type) {
        try {
            return mPM.hasUidSigningCertificate(uid, certificate, type);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @Override
    public String[] getPackagesForUid(int uid) {
        try {
+4 −0
Original line number Diff line number Diff line
@@ -656,4 +656,8 @@ interface IPackageManager {
    void setHarmfulAppWarning(String packageName, CharSequence warning, int userId);

    CharSequence getHarmfulAppWarning(String packageName, int userId);

    boolean hasSigningCertificate(String packageName, in byte[] signingCertificate, int flags);

    boolean hasUidSigningCertificate(int uid, in byte[] signingCertificate, int flags);
}
+36 −1
Original line number Diff line number Diff line
@@ -246,9 +246,44 @@ public class PackageInfo implements Parcelable {
     * 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 to be the same across updates.
     *
     * <strong>Deprecated</strong> This has been replaced by the
     * {@link PackageInfo#signingCertificateHistory} 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
     * callers as though no rotation occurred.
     *
     * @deprecated use {@code signingCertificateHistory} instead
     */
    @Deprecated
    public Signature[] signatures;

    /**
     * Array of all signatures arrays 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
     * 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.
     */
    public Signature[][] signingCertificateHistory;

    /**
     * Application specified preferred configuration
     * {@link android.R.styleable#AndroidManifestUsesConfiguration
+69 −1
Original line number Diff line number Diff line
@@ -133,6 +133,7 @@ public abstract class PackageManager {
            GET_SERVICES,
            GET_SHARED_LIBRARY_FILES,
            GET_SIGNATURES,
            GET_SIGNING_CERTIFICATES,
            GET_URI_PERMISSION_PATTERNS,
            MATCH_UNINSTALLED_PACKAGES,
            MATCH_DISABLED_COMPONENTS,
@@ -272,7 +273,10 @@ public abstract class PackageManager {
    /**
     * {@link PackageInfo} flag: return information about the
     * signatures included in the package.
     *
     * @deprecated use {@code GET_SIGNING_CERTIFICATES} instead
     */
    @Deprecated
    public static final int GET_SIGNATURES          = 0x00000040;

    /**
@@ -487,6 +491,14 @@ public abstract class PackageManager {
     */
    public static final int MATCH_STATIC_SHARED_LIBRARIES = 0x04000000;

    /**
     * {@link PackageInfo} flag: return the signing certificates associated with
     * this package.  Each entry is a signing certificate that the package
     * has proven it is authorized to use, usually a past signing certificate from
     * which it has rotated.
     */
    public static final int GET_SIGNING_CERTIFICATES = 0x08000000;

    /**
     * Internal flag used to indicate that a system component has done their
     * homework and verified that they correctly handle packages and components
@@ -3766,7 +3778,7 @@ public abstract class PackageManager {
    public abstract int getInstantAppCookieMaxBytes();

    /**
     * @deprecated
     * deprecated
     * @hide
     */
    public abstract int getInstantAppCookieMaxSize();
@@ -5899,4 +5911,60 @@ public abstract class PackageManager {
    public CharSequence getHarmfulAppWarning(@NonNull String packageName) {
        throw new UnsupportedOperationException("getHarmfulAppWarning not implemented in subclass");
    }

    /** @hide */
    @IntDef(prefix = { "CERT_INPUT_" }, value = {
            CERT_INPUT_RAW_X509,
            CERT_INPUT_SHA256
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface CertificateInputType {}

    /**
     * Certificate input bytes: the input bytes represent an encoded X.509 Certificate which could
     * be generated using an {@code CertificateFactory}
     */
    public static final int CERT_INPUT_RAW_X509 = 0;

    /**
     * Certificate input bytes: the input bytes represent the SHA256 output of an encoded X.509
     * Certificate.
     */
    public static final int CERT_INPUT_SHA256 = 1;

    /**
     * Searches the set of signing certificates by which the given package has proven to have been
     * signed.  This should be used instead of {@code getPackageInfo} with {@code GET_SIGNATURES}
     * since it takes into account the possibility of signing certificate rotation, except in the
     * case of packages that are signed by multiple certificates, for which signing certificate
     * rotation is not supported.
     *
     * @param packageName package whose signing certificates to check
     * @param certificate signing certificate for which to search
     * @param type representation of the {@code certificate}
     * @return true if this package was or is signed by exactly the certificate {@code certificate}
     */
    public boolean hasSigningCertificate(
            String packageName, byte[] certificate, @CertificateInputType int type) {
        throw new UnsupportedOperationException(
                "hasSigningCertificate not implemented in subclass");
    }

    /**
     * Searches the set of signing certificates by which the given uid has proven to have been
     * signed.  This should be used instead of {@code getPackageInfo} with {@code GET_SIGNATURES}
     * since it takes into account the possibility of signing certificate rotation, except in the
     * case of packages that are signed by multiple certificates, for which signing certificate
     * rotation is not supported.
     *
     * @param uid package whose signing certificates to check
     * @param certificate signing certificate for which to search
     * @param type representation of the {@code certificate}
     * @return true if this package was or is signed by exactly the certificate {@code certificate}
     */
    public boolean hasSigningCertificate(
            int uid, byte[] certificate, @CertificateInputType int type) {
        throw new UnsupportedOperationException(
                "hasSigningCertificate not implemented in subclass");
    }
}
Loading