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

Commit 5ac2ea1b authored by Chad Brubaker's avatar Chad Brubaker
Browse files

Make priv apps not trust user added CAs by default

Privileged applications provide core system functionality and as such a
MiTM in one can put the entire system at risk. These applications should
not be trusting user added CAs by default.

Bug: 65406503
Test: runtest --path framework/base/tests/NetworkSecurityConfigTest
Change-Id: I033258fe1c66ad245d172899df52e9cd02e9ca75
parent 02cca1e0
Loading
Loading
Loading
Loading
+16 −24
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.util.Log;
import android.util.Pair;

import java.util.Set;

/** @hide */
@@ -29,21 +30,14 @@ public class ManifestConfigSource implements ConfigSource {

    private final Object mLock = new Object();
    private final Context mContext;
    private final int mApplicationInfoFlags;
    private final int mTargetSdkVersion;
    private final int mConfigResourceId;
    private final int mTargetSandboxVesrsion;
    private final ApplicationInfo mApplicationInfo;

    private ConfigSource mConfigSource;

    public ManifestConfigSource(Context context) {
        mContext = context;
        // Cache values because ApplicationInfo is mutable and apps do modify it :(
        ApplicationInfo info = context.getApplicationInfo();
        mApplicationInfoFlags = info.flags;
        mTargetSdkVersion = info.targetSdkVersion;
        mConfigResourceId = info.networkSecurityConfigRes;
        mTargetSandboxVesrsion = info.targetSandboxVersion;
        // Cache the info because ApplicationInfo is mutable and apps do modify it :(
        mApplicationInfo = new ApplicationInfo(context.getApplicationInfo());
    }

    @Override
@@ -61,17 +55,18 @@ public class ManifestConfigSource implements ConfigSource {
            if (mConfigSource != null) {
                return mConfigSource;
            }

            int configResource = mApplicationInfo.networkSecurityConfigRes;
            ConfigSource source;
            if (mConfigResourceId != 0) {
                boolean debugBuild = (mApplicationInfoFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
            if (configResource != 0) {
                boolean debugBuild =
                        (mApplicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
                if (DBG) {
                    Log.d(LOG_TAG, "Using Network Security Config from resource "
                            + mContext.getResources().getResourceEntryName(mConfigResourceId)
                            + mContext.getResources()
                                .getResourceEntryName(configResource)
                            + " debugBuild: " + debugBuild);
                }
                source = new XmlConfigSource(mContext, mConfigResourceId, debugBuild,
                        mTargetSdkVersion, mTargetSandboxVesrsion);
                source = new XmlConfigSource(mContext, configResource, mApplicationInfo);
            } else {
                if (DBG) {
                    Log.d(LOG_TAG, "No Network Security Config specified, using platform default");
@@ -79,10 +74,9 @@ public class ManifestConfigSource implements ConfigSource {
                // the legacy FLAG_USES_CLEARTEXT_TRAFFIC is not supported for Ephemeral apps, they
                // should use the network security config.
                boolean usesCleartextTraffic =
                        (mApplicationInfoFlags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0
                        && mTargetSandboxVesrsion < 2;
                source = new DefaultConfigSource(usesCleartextTraffic, mTargetSdkVersion,
                        mTargetSandboxVesrsion);
                        (mApplicationInfo.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0
                        && mApplicationInfo.targetSandboxVersion < 2;
                source = new DefaultConfigSource(usesCleartextTraffic, mApplicationInfo);
            }
            mConfigSource = source;
            return mConfigSource;
@@ -93,10 +87,8 @@ public class ManifestConfigSource implements ConfigSource {

        private final NetworkSecurityConfig mDefaultConfig;

        public DefaultConfigSource(boolean usesCleartextTraffic, int targetSdkVersion,
                int targetSandboxVesrsion) {
            mDefaultConfig = NetworkSecurityConfig.getDefaultBuilder(targetSdkVersion,
                    targetSandboxVesrsion)
        DefaultConfigSource(boolean usesCleartextTraffic, ApplicationInfo info) {
            mDefaultConfig = NetworkSecurityConfig.getDefaultBuilder(info)
                    .setCleartextTrafficPermitted(usesCleartextTraffic)
                    .build();
        }
+8 −6
Original line number Diff line number Diff line
@@ -16,9 +16,11 @@

package android.security.net.config;

import android.content.pm.ApplicationInfo;
import android.os.Build;
import android.util.ArrayMap;
import android.util.ArraySet;

import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
@@ -28,8 +30,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.net.ssl.X509TrustManager;

/**
 * @hide
 */
@@ -170,22 +170,24 @@ public final class NetworkSecurityConfig {
     * <li>No certificate pinning is used.</li>
     * <li>The system certificate store is trusted for connections.</li>
     * <li>If the application targets API level 23 (Android M) or lower then the user certificate
     * store is trusted by default as well.</li>
     * store is trusted by default as well for non-privileged applications.</li>
     * <li>Privileged applications do not trust the user certificate store on Android P and higher.
     * </li>
     * </ol>
     *
     * @hide
     */
    public static final Builder getDefaultBuilder(int targetSdkVersion, int targetSandboxVesrsion) {
    public static Builder getDefaultBuilder(ApplicationInfo info) {
        Builder builder = new Builder()
                .setHstsEnforced(DEFAULT_HSTS_ENFORCED)
                // System certificate store, does not bypass static pins.
                .addCertificatesEntryRef(
                        new CertificatesEntryRef(SystemCertificateSource.getInstance(), false));
        final boolean cleartextTrafficPermitted = targetSandboxVesrsion < 2;
        final boolean cleartextTrafficPermitted = info.targetSandboxVersion < 2;
        builder.setCleartextTrafficPermitted(cleartextTrafficPermitted);
        // Applications targeting N and above must opt in into trusting the user added certificate
        // store.
        if (targetSdkVersion <= Build.VERSION_CODES.M) {
        if (info.targetSdkVersion <= Build.VERSION_CODES.M && !info.isPrivilegedApp()) {
            // User certificate store, does not bypass static pins.
            builder.addCertificatesEntryRef(
                    new CertificatesEntryRef(UserCertificateSource.getInstance(), false));
+9 −27
Original line number Diff line number Diff line
package android.security.net.config;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Build;
import android.util.ArraySet;
import android.util.Base64;
import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;

import com.android.internal.util.XmlUtils;

import org.xmlpull.v1.XmlPullParser;
@@ -36,37 +36,19 @@ public class XmlConfigSource implements ConfigSource {
    private final Object mLock = new Object();
    private final int mResourceId;
    private final boolean mDebugBuild;
    private final int mTargetSdkVersion;
    private final int mTargetSandboxVesrsion;
    private final ApplicationInfo mApplicationInfo;

    private boolean mInitialized;
    private NetworkSecurityConfig mDefaultConfig;
    private Set<Pair<Domain, NetworkSecurityConfig>> mDomainMap;
    private Context mContext;

    @VisibleForTesting
    public XmlConfigSource(Context context, int resourceId) {
        this(context, resourceId, false);
    }

    @VisibleForTesting
    public XmlConfigSource(Context context, int resourceId, boolean debugBuild) {
        this(context, resourceId, debugBuild, Build.VERSION_CODES.CUR_DEVELOPMENT);
    }

    @VisibleForTesting
    public XmlConfigSource(Context context, int resourceId, boolean debugBuild,
            int targetSdkVersion) {
        this(context, resourceId, debugBuild, targetSdkVersion, 1 /*targetSandboxVersion*/);
    }

    public XmlConfigSource(Context context, int resourceId, boolean debugBuild,
            int targetSdkVersion, int targetSandboxVesrsion) {
        mResourceId = resourceId;
    public XmlConfigSource(Context context, int resourceId, ApplicationInfo info) {
        mContext = context;
        mDebugBuild = debugBuild;
        mTargetSdkVersion = targetSdkVersion;
        mTargetSandboxVesrsion = targetSandboxVesrsion;
        mResourceId = resourceId;
        mApplicationInfo = new ApplicationInfo(info);

        mDebugBuild = (mApplicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
    }

    public Set<Pair<Domain, NetworkSecurityConfig>> getPerDomainConfigs() {
@@ -365,7 +347,7 @@ public class XmlConfigSource implements ConfigSource {
        // Use the platform default as the parent of the base config for any values not provided
        // there. If there is no base config use the platform default.
        NetworkSecurityConfig.Builder platformDefaultBuilder =
                NetworkSecurityConfig.getDefaultBuilder(mTargetSdkVersion, mTargetSandboxVesrsion);
                NetworkSecurityConfig.getDefaultBuilder(mApplicationInfo);
        addDebugAnchorsIfNeeded(debugConfigBuilder, platformDefaultBuilder);
        if (baseConfigBuilder != null) {
            baseConfigBuilder.setParent(platformDefaultBuilder);
+21 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.security.net.config;

import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.os.Build;
import android.test.ActivityUnitTestCase;
import android.util.ArraySet;
@@ -227,7 +228,8 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
    public void testConfigBuilderUsesParents() throws Exception {
        // Check that a builder with a parent uses the parent's values when non is set.
        NetworkSecurityConfig config = new NetworkSecurityConfig.Builder()
                .setParent(NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.N, 1))
                .setParent(NetworkSecurityConfig
                        .getDefaultBuilder(TestUtils.makeApplicationInfo()))
                .build();
        assert(!config.getTrustAnchors().isEmpty());
    }
@@ -268,11 +270,22 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
            // Install the test CA.
            store.installCertificate(TEST_CA_CERT);
            NetworkSecurityConfig preNConfig =
                    NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.M, 1).build();
                    NetworkSecurityConfig
                    .getDefaultBuilder(TestUtils.makeApplicationInfo(Build.VERSION_CODES.M))
                    .build();
            NetworkSecurityConfig nConfig =
                    NetworkSecurityConfig.getDefaultBuilder(Build.VERSION_CODES.N, 1).build();
                    NetworkSecurityConfig
                    .getDefaultBuilder(TestUtils.makeApplicationInfo(Build.VERSION_CODES.N))
                    .build();
            ApplicationInfo privInfo = TestUtils.makeApplicationInfo(Build.VERSION_CODES.M);
            privInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
            NetworkSecurityConfig privConfig =
                    NetworkSecurityConfig
                    .getDefaultBuilder(privInfo)
                    .build();
            Set<TrustAnchor> preNAnchors = preNConfig.getTrustAnchors();
            Set<TrustAnchor> nAnchors = nConfig.getTrustAnchors();
            Set<TrustAnchor> privAnchors = privConfig.getTrustAnchors();
            Set<X509Certificate> preNCerts = new HashSet<X509Certificate>();
            for (TrustAnchor anchor : preNAnchors) {
                preNCerts.add(anchor.certificate);
@@ -281,8 +294,13 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
            for (TrustAnchor anchor : nAnchors) {
                nCerts.add(anchor.certificate);
            }
            Set<X509Certificate> privCerts = new HashSet<X509Certificate>();
            for (TrustAnchor anchor : privAnchors) {
                privCerts.add(anchor.certificate);
            }
            assertTrue(preNCerts.contains(TEST_CA_CERT));
            assertFalse(nCerts.contains(TEST_CA_CERT));
            assertFalse(privCerts.contains(TEST_CA_CERT));
        } finally {
            // Delete the user added CA. We don't know the alias so just delete them all.
            for (String alias : store.aliases()) {
+15 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.security.net.config;

import android.content.pm.ApplicationInfo;
import android.os.Build;
import java.net.Socket;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
@@ -77,4 +79,17 @@ public final class TestUtils extends Assert {
        context.init(null, tmf.getTrustManagers(), null);
        return context;
    }

    public static ApplicationInfo makeApplicationInfo() {
        ApplicationInfo info = new ApplicationInfo();
        info.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
        info.targetSandboxVersion = 1;
        return info;
    }

    public static ApplicationInfo makeApplicationInfo(int targetSdkVersion) {
        ApplicationInfo info = makeApplicationInfo();
        info.targetSdkVersion = targetSdkVersion;
        return info;
    }
}
Loading