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

Commit 41456aa9 authored by Khaled Abdelmohsen's avatar Khaled Abdelmohsen
Browse files

Create rule atom for source stamp

Bug: 149200249
Test: atest FrameworksCoreTests:IntegrityFormulaTest
Change-Id: I8a5ca33e8b2b125a8b7bc178557b7689c0eab50d
parent 117da246
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -1958,6 +1958,11 @@ package android.content.integrity {
    method @NonNull public static android.content.integrity.IntegrityFormula packageNameEquals(@NonNull String);
  }
  public static final class IntegrityFormula.SourceStamp {
    method @NonNull public static android.content.integrity.IntegrityFormula notTrusted();
    method @NonNull public static android.content.integrity.IntegrityFormula stampCertificateHashEquals(@NonNull String);
  }
  public final class Rule implements android.os.Parcelable {
    ctor public Rule(@NonNull android.content.integrity.IntegrityFormula, int);
    method public int describeContents();
+5 −0
Original line number Diff line number Diff line
@@ -846,6 +846,11 @@ package android.content.integrity {
    method @NonNull public static android.content.integrity.IntegrityFormula packageNameEquals(@NonNull String);
  }

  public static final class IntegrityFormula.SourceStamp {
    method @NonNull public static android.content.integrity.IntegrityFormula notTrusted();
    method @NonNull public static android.content.integrity.IntegrityFormula stampCertificateHashEquals(@NonNull String);
  }

  public final class Rule implements android.os.Parcelable {
    ctor public Rule(@NonNull android.content.integrity.IntegrityFormula, int);
    method public int describeContents();
+48 −5
Original line number Diff line number Diff line
@@ -42,6 +42,9 @@ public final class AppInstallMetadata {
    private final List<String> mInstallerCertificates;
    private final long mVersionCode;
    private final boolean mIsPreInstalled;
    private final boolean mIsStampTrusted;
    // Raw string encoding for the SHA-256 hash of the certificate of the stamp.
    private final String mStampCertificateHash;
    private final Map<String, String> mAllowedInstallersAndCertificates;

    private AppInstallMetadata(Builder builder) {
@@ -51,6 +54,8 @@ public final class AppInstallMetadata {
        this.mInstallerCertificates = builder.mInstallerCertificates;
        this.mVersionCode = builder.mVersionCode;
        this.mIsPreInstalled = builder.mIsPreInstalled;
        this.mIsStampTrusted = builder.mIsStampTrusted;
        this.mStampCertificateHash = builder.mStampCertificateHash;
        this.mAllowedInstallersAndCertificates = builder.mAllowedInstallersAndCertificates;
    }

@@ -84,9 +89,17 @@ public final class AppInstallMetadata {
        return mIsPreInstalled;
    }

    /**
     * Get the allowed installers and their corresponding cert.
     */
    /** @see AppInstallMetadata.Builder#setIsStampTrusted(boolean) */
    public boolean isStampTrusted() {
        return mIsStampTrusted;
    }

    /** @see AppInstallMetadata.Builder#setStampCertificateHash(String) */
    public String getStampCertificateHash() {
        return mStampCertificateHash;
    }

    /** Get the allowed installers and their corresponding cert. */
    public Map<String, String> getAllowedInstallersAndCertificates() {
        return mAllowedInstallersAndCertificates;
    }
@@ -95,13 +108,16 @@ public final class AppInstallMetadata {
    public String toString() {
        return String.format(
                "AppInstallMetadata { PackageName = %s, AppCerts = %s, InstallerName = %s,"
                    + " InstallerCerts = %s, VersionCode = %d, PreInstalled = %b }",
                        + " InstallerCerts = %s, VersionCode = %d, PreInstalled = %b, "
                        + "StampTrusted = %b, StampCert = %s }",
                mPackageName,
                mAppCertificates,
                mInstallerName == null ? "null" : mInstallerName,
                mInstallerCertificates == null ? "null" : mInstallerCertificates,
                mVersionCode,
                mIsPreInstalled);
                mIsPreInstalled,
                mIsStampTrusted,
                mStampCertificateHash == null ? "null" : mStampCertificateHash);
    }

    /** Builder class for constructing {@link AppInstallMetadata} objects. */
@@ -112,6 +128,8 @@ public final class AppInstallMetadata {
        private List<String> mInstallerCertificates;
        private long mVersionCode;
        private boolean mIsPreInstalled;
        private boolean mIsStampTrusted;
        private String mStampCertificateHash;
        private Map<String, String> mAllowedInstallersAndCertificates;

        public Builder() {
@@ -202,6 +220,31 @@ public final class AppInstallMetadata {
            return this;
        }

        /**
         * Set certificate hash of the stamp embedded in the APK.
         *
         * <p>It is represented as the raw string encoding for the SHA-256 hash of the certificate
         * of the stamp.
         *
         * @see AppInstallMetadata#getStampCertificateHash()
         */
        @NonNull
        public Builder setStampCertificateHash(@NonNull String stampCertificateHash) {
            this.mStampCertificateHash = Objects.requireNonNull(stampCertificateHash);
            return this;
        }

        /**
         * Set whether the stamp embedded in the APK is trusted or not.
         *
         * @see AppInstallMetadata#isStampTrusted()
         */
        @NonNull
        public Builder setIsStampTrusted(boolean isStampTrusted) {
            this.mIsStampTrusted = isStampTrusted;
            return this;
        }

        /**
         * Build {@link AppInstallMetadata}.
         *
+50 −23
Original line number Diff line number Diff line
@@ -53,6 +53,8 @@ public abstract class AtomicFormula extends IntegrityFormula {
                INSTALLER_CERTIFICATE,
                VERSION_CODE,
                PRE_INSTALLED,
                STAMP_TRUSTED,
                STAMP_CERTIFICATE_HASH,
            })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Key {}
@@ -105,6 +107,20 @@ public abstract class AtomicFormula extends IntegrityFormula {
     */
    public static final int PRE_INSTALLED = 5;

    /**
     * If the APK has an embedded trusted stamp.
     *
     * <p>Can only be used in {@link BooleanAtomicFormula}.
     */
    public static final int STAMP_TRUSTED = 6;

    /**
     * SHA-256 of the certificate used to sign the stamp embedded in the APK.
     *
     * <p>Can only be used in {@link StringAtomicFormula}.
     */
    public static final int STAMP_CERTIFICATE_HASH = 7;

    public static final int EQ = 0;
    public static final int GT = 1;
    public static final int GTE = 2;
@@ -266,9 +282,7 @@ public abstract class AtomicFormula extends IntegrityFormula {
        }

        private static boolean isValidOperator(int operator) {
            return operator == EQ
                    || operator == GT
                    || operator == GTE;
            return operator == EQ || operator == GT || operator == GTE;
        }

        private static long getLongMetadataValue(AppInstallMetadata appInstallMetadata, int key) {
@@ -300,7 +314,8 @@ public abstract class AtomicFormula extends IntegrityFormula {
                    key == PACKAGE_NAME
                            || key == APP_CERTIFICATE
                            || key == INSTALLER_CERTIFICATE
                            || key == INSTALLER_NAME,
                            || key == INSTALLER_NAME
                            || key == STAMP_CERTIFICATE_HASH,
                    String.format(
                            "Key %s cannot be used with StringAtomicFormula", keyToString(key)));
            mValue = null;
@@ -321,7 +336,8 @@ public abstract class AtomicFormula extends IntegrityFormula {
                    key == PACKAGE_NAME
                            || key == APP_CERTIFICATE
                            || key == INSTALLER_CERTIFICATE
                            || key == INSTALLER_NAME,
                            || key == INSTALLER_NAME
                            || key == STAMP_CERTIFICATE_HASH,
                    String.format(
                            "Key %s cannot be used with StringAtomicFormula", keyToString(key)));
            mValue = value;
@@ -329,15 +345,14 @@ public abstract class AtomicFormula extends IntegrityFormula {
        }

        /**
         * Constructs a new {@link StringAtomicFormula} together with handling the necessary
         * hashing for the given key.
         * Constructs a new {@link StringAtomicFormula} together with handling the necessary hashing
         * for the given key.
         *
         * <p> The value will be automatically hashed with SHA256 and the hex digest will be
         * computed when the key is PACKAGE_NAME or INSTALLER_NAME and the value is more than 32
         * characters.
         * <p>The value will be automatically hashed with SHA256 and the hex digest will be computed
         * when the key is PACKAGE_NAME or INSTALLER_NAME and the value is more than 32 characters.
         *
         * <p> The APP_CERTIFICATES and INSTALLER_CERTIFICATES are always delivered in hashed
         * form. So the isHashedValue is set to true by default.
         * <p>The APP_CERTIFICATES, INSTALLER_CERTIFICATES, and STAMP_CERTIFICATE_HASH are always
         * delivered in hashed form. So the isHashedValue is set to true by default.
         *
         * @throws IllegalArgumentException if {@code key} cannot be used with string value.
         */
@@ -347,13 +362,15 @@ public abstract class AtomicFormula extends IntegrityFormula {
                    key == PACKAGE_NAME
                            || key == APP_CERTIFICATE
                            || key == INSTALLER_CERTIFICATE
                            || key == INSTALLER_NAME,
                            || key == INSTALLER_NAME
                            || key == STAMP_CERTIFICATE_HASH,
                    String.format(
                            "Key %s cannot be used with StringAtomicFormula", keyToString(key)));
            mValue = hashValue(key, value);
            mIsHashedValue =
                    key == APP_CERTIFICATE
                                    || key == INSTALLER_CERTIFICATE
                                    || key == STAMP_CERTIFICATE_HASH
                            ? true
                            : !mValue.equals(value);
        }
@@ -460,6 +477,8 @@ public abstract class AtomicFormula extends IntegrityFormula {
                    return appInstallMetadata.getInstallerCertificates();
                case AtomicFormula.INSTALLER_NAME:
                    return Collections.singletonList(appInstallMetadata.getInstallerName());
                case AtomicFormula.STAMP_CERTIFICATE_HASH:
                    return Collections.singletonList(appInstallMetadata.getStampCertificateHash());
                default:
                    throw new IllegalStateException(
                            "Unexpected key in StringAtomicFormula: " + key);
@@ -502,7 +521,7 @@ public abstract class AtomicFormula extends IntegrityFormula {
        public BooleanAtomicFormula(@Key int key) {
            super(key);
            checkArgument(
                    key == PRE_INSTALLED,
                    key == PRE_INSTALLED || key == STAMP_TRUSTED,
                    String.format(
                            "Key %s cannot be used with BooleanAtomicFormula", keyToString(key)));
            mValue = null;
@@ -519,7 +538,7 @@ public abstract class AtomicFormula extends IntegrityFormula {
        public BooleanAtomicFormula(@Key int key, boolean value) {
            super(key);
            checkArgument(
                    key == PRE_INSTALLED,
                    key == PRE_INSTALLED || key == STAMP_TRUSTED,
                    String.format(
                            "Key %s cannot be used with BooleanAtomicFormula", keyToString(key)));
            mValue = value;
@@ -615,6 +634,8 @@ public abstract class AtomicFormula extends IntegrityFormula {
            switch (key) {
                case AtomicFormula.PRE_INSTALLED:
                    return appInstallMetadata.isPreInstalled();
                case AtomicFormula.STAMP_TRUSTED:
                    return appInstallMetadata.isStampTrusted();
                default:
                    throw new IllegalStateException(
                            "Unexpected key in BooleanAtomicFormula: " + key);
@@ -640,6 +661,10 @@ public abstract class AtomicFormula extends IntegrityFormula {
                return "INSTALLER_CERTIFICATE";
            case PRE_INSTALLED:
                return "PRE_INSTALLED";
            case STAMP_TRUSTED:
                return "STAMP_TRUSTED";
            case STAMP_CERTIFICATE_HASH:
                return "STAMP_CERTIFICATE_HASH";
            default:
                throw new IllegalArgumentException("Unknown key " + key);
        }
@@ -664,6 +689,8 @@ public abstract class AtomicFormula extends IntegrityFormula {
                || key == VERSION_CODE
                || key == INSTALLER_NAME
                || key == INSTALLER_CERTIFICATE
                || key == PRE_INSTALLED;
                || key == PRE_INSTALLED
                || key == STAMP_TRUSTED
                || key == STAMP_CERTIFICATE_HASH;
    }
}
+34 −19
Original line number Diff line number Diff line
@@ -90,8 +90,7 @@ public abstract class IntegrityFormula {
            return new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
        }

        private Application() {
        }
        private Application() {}
    }

    /** Factory class for creating integrity formulas based on installer. */
@@ -117,12 +116,32 @@ public abstract class IntegrityFormula {
         */
        @NonNull
        public static IntegrityFormula certificatesContain(@NonNull String installerCertificate) {
            return new StringAtomicFormula(AtomicFormula.INSTALLER_CERTIFICATE,
                    installerCertificate);
            return new StringAtomicFormula(
                    AtomicFormula.INSTALLER_CERTIFICATE, installerCertificate);
        }

        private Installer() {}
    }

        private Installer() {
    /** Factory class for creating integrity formulas based on source stamp. */
    public static final class SourceStamp {
        /** Returns an integrity formula that checks the equality to a stamp certificate hash. */
        @NonNull
        public static IntegrityFormula stampCertificateHashEquals(
                @NonNull String stampCertificateHash) {
            return new StringAtomicFormula(
                    AtomicFormula.STAMP_CERTIFICATE_HASH, stampCertificateHash);
        }

        /**
         * Returns an integrity formula that is valid when stamp embedded in the APK is NOT trusted.
         */
        @NonNull
        public static IntegrityFormula notTrusted() {
            return new BooleanAtomicFormula(AtomicFormula.STAMP_TRUSTED, /* value= */ false);
        }

        private SourceStamp() {}
    }

    /** @hide */
@@ -135,8 +154,7 @@ public abstract class IntegrityFormula {
                INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG
            })
    @Retention(RetentionPolicy.SOURCE)
    @interface Tag {
    }
    @interface Tag {}

    /** @hide */
    public static final int COMPOUND_FORMULA_TAG = 0;
@@ -171,8 +189,8 @@ public abstract class IntegrityFormula {
    public abstract boolean isAppCertificateFormula();

    /**
     * Returns true when the formula (or one of its atomic formulas) has installer package name
     * or installer certificate as key.
     * Returns true when the formula (or one of its atomic formulas) has installer package name or
     * installer certificate as key.
     *
     * @hide
     */
@@ -243,15 +261,12 @@ public abstract class IntegrityFormula {
        return new CompoundFormula(CompoundFormula.AND, Arrays.asList(formulae));
    }

    /**
     * Returns a formula that evaluates to true when {@code formula} evaluates to false.
     */
    /** Returns a formula that evaluates to true when {@code formula} evaluates to false. */
    @NonNull
    public static IntegrityFormula not(@NonNull IntegrityFormula formula) {
        return new CompoundFormula(CompoundFormula.NOT, Arrays.asList(formula));
    }

    // Constructor is package private so it cannot be inherited outside of this package.
    IntegrityFormula() {
    }
    IntegrityFormula() {}
}
Loading