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

Commit b994372e authored by Omer Nebil Yaveroglu's avatar Omer Nebil Yaveroglu Committed by Ömer Nebil Yaveroğlu
Browse files

Change the way we handle app and installer certificates to be prepared

for the case that there might be multiple certificates signing the app.

Bug: 148373316
Test: atest frameworks/base/core/tests/coretests/src/android/content/integrity
Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/integrity
Change-Id: Ic1e86aeff6c087266739682fe4fe206200a87420
parent b4ab54ad
Loading
Loading
Loading
Loading
+22 −21
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.content.integrity;

import android.annotation.NonNull;

import java.util.List;
import java.util.Objects;

/**
@@ -33,18 +34,18 @@ import java.util.Objects;
public final class AppInstallMetadata {
    private final String mPackageName;
    // Raw string encoding for the SHA-256 hash of the certificate of the app.
    private final String mAppCertificate;
    private final List<String> mAppCertificates;
    private final String mInstallerName;
    // Raw string encoding for the SHA-256 hash of the certificate of the installer.
    private final String mInstallerCertificate;
    private final List<String> mInstallerCertificates;
    private final long mVersionCode;
    private final boolean mIsPreInstalled;

    private AppInstallMetadata(Builder builder) {
        this.mPackageName = builder.mPackageName;
        this.mAppCertificate = builder.mAppCertificate;
        this.mAppCertificates = builder.mAppCertificates;
        this.mInstallerName = builder.mInstallerName;
        this.mInstallerCertificate = builder.mInstallerCertificate;
        this.mInstallerCertificates = builder.mInstallerCertificates;
        this.mVersionCode = builder.mVersionCode;
        this.mIsPreInstalled = builder.mIsPreInstalled;
    }
@@ -55,8 +56,8 @@ public final class AppInstallMetadata {
    }

    @NonNull
    public String getAppCertificate() {
        return mAppCertificate;
    public List<String> getAppCertificates() {
        return mAppCertificates;
    }

    @NonNull
@@ -65,8 +66,8 @@ public final class AppInstallMetadata {
    }

    @NonNull
    public String getInstallerCertificate() {
        return mInstallerCertificate;
    public List<String> getInstallerCertificates() {
        return mInstallerCertificates;
    }

    /** @see AppInstallMetadata.Builder#setVersionCode(long) */
@@ -82,12 +83,12 @@ public final class AppInstallMetadata {
    @Override
    public String toString() {
        return String.format(
                "AppInstallMetadata { PackageName = %s, AppCert = %s, InstallerName = %s,"
                    + " InstallerCert = %s, VersionCode = %d, PreInstalled = %b }",
                "AppInstallMetadata { PackageName = %s, AppCerts = %s, InstallerName = %s,"
                    + " InstallerCerts = %s, VersionCode = %d, PreInstalled = %b }",
                mPackageName,
                mAppCertificate,
                mAppCertificates,
                mInstallerName == null ? "null" : mInstallerName,
                mInstallerCertificate == null ? "null" : mInstallerCertificate,
                mInstallerCertificates == null ? "null" : mInstallerCertificates,
                mVersionCode,
                mIsPreInstalled);
    }
@@ -95,9 +96,9 @@ public final class AppInstallMetadata {
    /** Builder class for constructing {@link AppInstallMetadata} objects. */
    public static final class Builder {
        private String mPackageName;
        private String mAppCertificate;
        private List<String> mAppCertificates;
        private String mInstallerName;
        private String mInstallerCertificate;
        private List<String> mInstallerCertificates;
        private long mVersionCode;
        private boolean mIsPreInstalled;

@@ -118,11 +119,11 @@ public final class AppInstallMetadata {
         * <p>It is represented as the raw string encoding for the SHA-256 hash of the certificate
         * of the app.
         *
         * @see AppInstallMetadata#getAppCertificate()
         * @see AppInstallMetadata#getAppCertificates()
         */
        @NonNull
        public Builder setAppCertificate(@NonNull String appCertificate) {
            this.mAppCertificate = Objects.requireNonNull(appCertificate);
        public Builder setAppCertificates(@NonNull List<String> appCertificates) {
            this.mAppCertificates = Objects.requireNonNull(appCertificates);
            return this;
        }

@@ -143,11 +144,11 @@ public final class AppInstallMetadata {
         * <p>It is represented as the raw string encoding for the SHA-256 hash of the certificate
         * of the installer.
         *
         * @see AppInstallMetadata#getInstallerCertificate()
         * @see AppInstallMetadata#getInstallerCertificates()
         */
        @NonNull
        public Builder setInstallerCertificate(@NonNull String installerCertificate) {
            this.mInstallerCertificate = Objects.requireNonNull(installerCertificate);
        public Builder setInstallerCertificates(@NonNull List<String> installerCertificates) {
            this.mInstallerCertificates = Objects.requireNonNull(installerCertificates);
            return this;
        }

@@ -181,7 +182,7 @@ public final class AppInstallMetadata {
        @NonNull
        public AppInstallMetadata build() {
            Objects.requireNonNull(mPackageName);
            Objects.requireNonNull(mAppCertificate);
            Objects.requireNonNull(mAppCertificates);
            return new AppInstallMetadata(this);
        }
    }
+8 −6
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
@@ -387,7 +389,7 @@ public abstract class AtomicFormula extends IntegrityFormula {
            if (mValue == null || mIsHashedValue == null) {
                return false;
            }
            return getStringMetadataValue(appInstallMetadata, getKey()).equals(mValue);
            return getMetadataValue(appInstallMetadata, getKey()).contains(mValue);
        }

        @Override
@@ -448,17 +450,17 @@ public abstract class AtomicFormula extends IntegrityFormula {
            return mIsHashedValue;
        }

        private static String getStringMetadataValue(
        private static List<String> getMetadataValue(
                AppInstallMetadata appInstallMetadata, int key) {
            switch (key) {
                case AtomicFormula.PACKAGE_NAME:
                    return appInstallMetadata.getPackageName();
                    return Collections.singletonList(appInstallMetadata.getPackageName());
                case AtomicFormula.APP_CERTIFICATE:
                    return appInstallMetadata.getAppCertificate();
                    return appInstallMetadata.getAppCertificates();
                case AtomicFormula.INSTALLER_CERTIFICATE:
                    return appInstallMetadata.getInstallerCertificate();
                    return appInstallMetadata.getInstallerCertificates();
                case AtomicFormula.INSTALLER_NAME:
                    return appInstallMetadata.getInstallerName();
                    return Collections.singletonList(appInstallMetadata.getInstallerName());
                default:
                    throw new IllegalStateException(
                            "Unexpected key in StringAtomicFormula: " + key);
+64 −4
Original line number Diff line number Diff line
@@ -29,6 +29,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.Arrays;
import java.util.Collections;

@RunWith(JUnit4.class)
public class AtomicFormulaTest {

@@ -230,7 +233,7 @@ public class AtomicFormulaTest {
    }

    @Test
    public void testFormulaMatches_string_true() {
    public void testFormulaMatches_string_packageNameFormula_true() {
        StringAtomicFormula stringAtomicFormula =
                new StringAtomicFormula(
                        AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */
@@ -242,7 +245,7 @@ public class AtomicFormulaTest {
    }

    @Test
    public void testFormulaMatches_string_false() {
    public void testFormulaMatches_string_packageNameFormula_false() {
        StringAtomicFormula stringAtomicFormula =
                new StringAtomicFormula(
                        AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */
@@ -253,6 +256,63 @@ public class AtomicFormulaTest {
        assertThat(stringAtomicFormula.matches(appInstallMetadata)).isFalse();
    }

    @Test
    public void testFormulaMatches_string_multipleAppCertificates_true() {
        StringAtomicFormula stringAtomicFormula =
                new StringAtomicFormula(
                        AtomicFormula.APP_CERTIFICATE, "cert", /* isHashedValue= */ true);
        AppInstallMetadata appInstallMetadata =
                getAppInstallMetadataBuilder()
                        .setPackageName("com.test.app")
                        .setAppCertificates(Arrays.asList("test-cert", "cert"))
                        .build();

        assertThat(stringAtomicFormula.matches(appInstallMetadata)).isTrue();
    }

    @Test
    public void testFormulaMatches_string_multipleAppCertificates_false() {
        StringAtomicFormula stringAtomicFormula =
                new StringAtomicFormula(
                        AtomicFormula.APP_CERTIFICATE, "cert", /* isHashedValue= */ true);
        AppInstallMetadata appInstallMetadata =
                getAppInstallMetadataBuilder()
                        .setPackageName("com.test.app")
                        .setAppCertificates(Arrays.asList("test-cert", "another-cert"))
                        .build();

        assertThat(stringAtomicFormula.matches(appInstallMetadata)).isFalse();
    }

    @Test
    public void testFormulaMatches_string_multipleInstallerCertificates_true() {
        StringAtomicFormula stringAtomicFormula =
                new StringAtomicFormula(
                        AtomicFormula.INSTALLER_CERTIFICATE, "cert", /* isHashedValue= */ true);
        AppInstallMetadata appInstallMetadata =
                getAppInstallMetadataBuilder()
                        .setPackageName("com.test.app")
                        .setAppCertificates(Collections.singletonList("abc"))
                        .setInstallerCertificates(Arrays.asList("test-cert", "cert"))
                        .build();

        assertThat(stringAtomicFormula.matches(appInstallMetadata)).isTrue();
    }

    @Test
    public void testFormulaMatches_string_multipleInstallerCertificates_false() {
        StringAtomicFormula stringAtomicFormula =
                new StringAtomicFormula(
                        AtomicFormula.INSTALLER_CERTIFICATE, "cert", /* isHashedValue= */ true);
        AppInstallMetadata appInstallMetadata =
                getAppInstallMetadataBuilder()
                        .setPackageName("com.test.app")
                        .setAppCertificates(Collections.singletonList("abc"))
                        .setInstallerCertificates(Arrays.asList("test-cert", "another-cert"))
                        .build();

        assertThat(stringAtomicFormula.matches(appInstallMetadata)).isFalse();
    }

    @Test
    public void testIsAppCertificateFormula_string_true() {
@@ -430,8 +490,8 @@ public class AtomicFormulaTest {
    private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
        return new AppInstallMetadata.Builder()
                .setPackageName("abc")
                .setAppCertificate("abc")
                .setInstallerCertificate("abc")
                .setAppCertificates(Collections.singletonList("abc"))
                .setInstallerCertificates(Collections.singletonList("abc"))
                .setInstallerName("abc")
                .setVersionCode(-1)
                .setIsPreInstalled(true);
+2 −2
Original line number Diff line number Diff line
@@ -286,8 +286,8 @@ public class CompoundFormulaTest {
    private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
        return new AppInstallMetadata.Builder()
                .setPackageName("abc")
                .setAppCertificate("abc")
                .setInstallerCertificate("abc")
                .setAppCertificates(Collections.singletonList("abc"))
                .setInstallerCertificates(Collections.singletonList("abc"))
                .setInstallerName("abc")
                .setVersionCode(-1)
                .setIsPreInstalled(true);
+3 −9
Original line number Diff line number Diff line
@@ -272,21 +272,15 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
            List<String> installerCertificates =
                    getInstallerCertificateFingerprint(installerPackageName);

            // TODO (b/148373316): Figure out what field contains which fields are populated for
            // rotated and the multiple signers. Until then, return the first certificate.
            String appCert = appCertificates.isEmpty() ? "" : appCertificates.get(0);
            String installerCert =
                    installerCertificates.isEmpty() ? "" : installerCertificates.get(0);

            Slog.w(TAG, appCertificates.toString());

            AppInstallMetadata.Builder builder = new AppInstallMetadata.Builder();

            builder.setPackageName(getPackageNameNormalized(packageName));
            builder.setAppCertificate(appCert);
            builder.setAppCertificates(appCertificates);
            builder.setVersionCode(intent.getLongExtra(EXTRA_LONG_VERSION_CODE, -1));
            builder.setInstallerName(getPackageNameNormalized(installerPackageName));
            builder.setInstallerCertificate(installerCert);
            builder.setInstallerCertificates(installerCertificates);
            builder.setIsPreInstalled(isSystemApp(packageName));

            AppInstallMetadata appInstallMetadata = builder.build();
@@ -307,7 +301,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
            FrameworkStatsLog.write(
                    FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED,
                    packageName,
                    appCert,
                    appCertificates.toString(),
                    appInstallMetadata.getVersionCode(),
                    installerPackageName,
                    result.getLoggingResponse(),
Loading