Loading core/java/android/security/net/config/CertificatesEntryRef.java +9 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.security.net.config; import android.util.ArraySet; import java.security.cert.X509Certificate; import java.util.Set; Loading @@ -24,16 +25,23 @@ import java.util.Set; public final class CertificatesEntryRef { private final CertificateSource mSource; private final boolean mOverridesPins; private final boolean mDisableCT; public CertificatesEntryRef(CertificateSource source, boolean overridesPins) { public CertificatesEntryRef(CertificateSource source, boolean overridesPins, boolean disableCT) { mSource = source; mOverridesPins = overridesPins; mDisableCT = disableCT; } boolean overridesPins() { return mOverridesPins; } boolean disableCT() { return mDisableCT; } public Set<TrustAnchor> getTrustAnchors() { // TODO: cache this [but handle mutable sources] Set<TrustAnchor> anchors = new ArraySet<TrustAnchor>(); Loading core/java/android/security/net/config/KeyStoreConfigSource.java +2 −2 Original line number Diff line number Diff line Loading @@ -17,8 +17,8 @@ package android.security.net.config; import android.util.Pair; import java.security.KeyStore; import java.security.KeyStoreException; import java.util.Set; /** Loading @@ -32,7 +32,7 @@ class KeyStoreConfigSource implements ConfigSource { mConfig = new NetworkSecurityConfig.Builder() .addCertificatesEntryRef( // Use the KeyStore and do not override pins (of which there are none). new CertificatesEntryRef(new KeyStoreCertificateSource(ks), false)) new CertificatesEntryRef(new KeyStoreCertificateSource(ks), false, false)) .build(); } Loading core/java/android/security/net/config/NetworkSecurityConfig.java +16 −6 Original line number Diff line number Diff line Loading @@ -112,7 +112,6 @@ public final class NetworkSecurityConfig { return mHstsEnforced; } // TODO(b/28746284): add exceptions for user-added certificates and enterprise overrides. public boolean isCertificateTransparencyVerificationRequired() { return mCertificateTransparencyVerificationRequired; } Loading Loading @@ -192,20 +191,21 @@ public final class NetworkSecurityConfig { * @hide */ public static Builder getDefaultBuilder(ApplicationInfo info) { // System certificate store, does not bypass static pins, does not disable CT. CertificatesEntryRef systemRef = new CertificatesEntryRef( SystemCertificateSource.getInstance(), false, false); Builder builder = new Builder() .setHstsEnforced(DEFAULT_HSTS_ENFORCED) // System certificate store, does not bypass static pins. .addCertificatesEntryRef( new CertificatesEntryRef(SystemCertificateSource.getInstance(), false)); .addCertificatesEntryRef(systemRef); final boolean cleartextTrafficPermitted = info.targetSdkVersion < Build.VERSION_CODES.P && !info.isInstantApp(); builder.setCleartextTrafficPermitted(cleartextTrafficPermitted); // Applications targeting N and above must opt in into trusting the user added certificate // store. if (info.targetSdkVersion <= Build.VERSION_CODES.M && !info.isPrivilegedApp()) { // User certificate store, does not bypass static pins. // User certificate store, does not bypass static pins. CT is disabled. builder.addCertificatesEntryRef( new CertificatesEntryRef(UserCertificateSource.getInstance(), false)); new CertificatesEntryRef(UserCertificateSource.getInstance(), false, true)); } return builder; } Loading Loading @@ -339,6 +339,16 @@ public final class NetworkSecurityConfig { if (mCertificateTransparencyVerificationRequiredSet) { return mCertificateTransparencyVerificationRequired; } // CT verification has not been set explicitly. Before deferring to // the parent, check if any of the CertificatesEntryRef requires it // to be disabled (i.e., user store or inline certificate). if (hasCertificatesEntryRefs()) { for (CertificatesEntryRef ref : getCertificatesEntryRefs()) { if (ref.disableCT()) { return false; } } } if (mParentBuilder != null) { return mParentBuilder.getCertificateTransparencyVerificationRequired(); } Loading core/java/android/security/net/config/XmlConfigSource.java +4 −1 Original line number Diff line number Diff line Loading @@ -182,6 +182,7 @@ public class XmlConfigSource implements ConfigSource { boolean overridePins = parser.getAttributeBooleanValue(null, "overridePins", defaultOverridePins); int sourceId = parser.getAttributeResourceValue(null, "src", -1); boolean disableCT = false; String sourceString = parser.getAttributeValue(null, "src"); CertificateSource source = null; if (sourceString == null) { Loading @@ -190,10 +191,12 @@ public class XmlConfigSource implements ConfigSource { if (sourceId != -1) { // TODO: Cache ResourceCertificateSources by sourceId source = new ResourceCertificateSource(sourceId, mContext); disableCT = true; } else if ("system".equals(sourceString)) { source = SystemCertificateSource.getInstance(); } else if ("user".equals(sourceString)) { source = UserCertificateSource.getInstance(); disableCT = true; } else if ("wfa".equals(sourceString)) { source = WfaCertificateSource.getInstance(); } else { Loading @@ -201,7 +204,7 @@ public class XmlConfigSource implements ConfigSource { + "Should be one of system|user|@resourceVal"); } XmlUtils.skipCurrentTag(parser); return new CertificatesEntryRef(source, overridePins); return new CertificatesEntryRef(source, overridePins, disableCT); } private Collection<CertificatesEntryRef> parseTrustAnchors(XmlResourceParser parser, Loading tests/NetworkSecurityConfigTest/res/xml/ct_domains.xml 0 → 100644 +38 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config> <certificateTransparency enabled="true" /> </base-config> <domain-config> <domain>android.com</domain> <trust-anchors> <certificates src="system" /> </trust-anchors> </domain-config> <domain-config> <domain>subdomain_user.android.com</domain> <trust-anchors> <certificates src="user" /> </trust-anchors> </domain-config> <domain-config> <certificateTransparency enabled="true" /> <domain>subdomain_user_ct.android.com</domain> <trust-anchors> <certificates src="user" /> </trust-anchors> </domain-config> <domain-config> <domain>subdomain_inline.android.com</domain> <trust-anchors> <certificates src="@raw/ca_certs_pem" /> </trust-anchors> </domain-config> <domain-config> <certificateTransparency enabled="true" /> <domain>subdomain_inline_ct.android.com</domain> <trust-anchors> <certificates src="@raw/ca_certs_pem" /> </trust-anchors> </domain-config> </network-security-config> Loading
core/java/android/security/net/config/CertificatesEntryRef.java +9 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.security.net.config; import android.util.ArraySet; import java.security.cert.X509Certificate; import java.util.Set; Loading @@ -24,16 +25,23 @@ import java.util.Set; public final class CertificatesEntryRef { private final CertificateSource mSource; private final boolean mOverridesPins; private final boolean mDisableCT; public CertificatesEntryRef(CertificateSource source, boolean overridesPins) { public CertificatesEntryRef(CertificateSource source, boolean overridesPins, boolean disableCT) { mSource = source; mOverridesPins = overridesPins; mDisableCT = disableCT; } boolean overridesPins() { return mOverridesPins; } boolean disableCT() { return mDisableCT; } public Set<TrustAnchor> getTrustAnchors() { // TODO: cache this [but handle mutable sources] Set<TrustAnchor> anchors = new ArraySet<TrustAnchor>(); Loading
core/java/android/security/net/config/KeyStoreConfigSource.java +2 −2 Original line number Diff line number Diff line Loading @@ -17,8 +17,8 @@ package android.security.net.config; import android.util.Pair; import java.security.KeyStore; import java.security.KeyStoreException; import java.util.Set; /** Loading @@ -32,7 +32,7 @@ class KeyStoreConfigSource implements ConfigSource { mConfig = new NetworkSecurityConfig.Builder() .addCertificatesEntryRef( // Use the KeyStore and do not override pins (of which there are none). new CertificatesEntryRef(new KeyStoreCertificateSource(ks), false)) new CertificatesEntryRef(new KeyStoreCertificateSource(ks), false, false)) .build(); } Loading
core/java/android/security/net/config/NetworkSecurityConfig.java +16 −6 Original line number Diff line number Diff line Loading @@ -112,7 +112,6 @@ public final class NetworkSecurityConfig { return mHstsEnforced; } // TODO(b/28746284): add exceptions for user-added certificates and enterprise overrides. public boolean isCertificateTransparencyVerificationRequired() { return mCertificateTransparencyVerificationRequired; } Loading Loading @@ -192,20 +191,21 @@ public final class NetworkSecurityConfig { * @hide */ public static Builder getDefaultBuilder(ApplicationInfo info) { // System certificate store, does not bypass static pins, does not disable CT. CertificatesEntryRef systemRef = new CertificatesEntryRef( SystemCertificateSource.getInstance(), false, false); Builder builder = new Builder() .setHstsEnforced(DEFAULT_HSTS_ENFORCED) // System certificate store, does not bypass static pins. .addCertificatesEntryRef( new CertificatesEntryRef(SystemCertificateSource.getInstance(), false)); .addCertificatesEntryRef(systemRef); final boolean cleartextTrafficPermitted = info.targetSdkVersion < Build.VERSION_CODES.P && !info.isInstantApp(); builder.setCleartextTrafficPermitted(cleartextTrafficPermitted); // Applications targeting N and above must opt in into trusting the user added certificate // store. if (info.targetSdkVersion <= Build.VERSION_CODES.M && !info.isPrivilegedApp()) { // User certificate store, does not bypass static pins. // User certificate store, does not bypass static pins. CT is disabled. builder.addCertificatesEntryRef( new CertificatesEntryRef(UserCertificateSource.getInstance(), false)); new CertificatesEntryRef(UserCertificateSource.getInstance(), false, true)); } return builder; } Loading Loading @@ -339,6 +339,16 @@ public final class NetworkSecurityConfig { if (mCertificateTransparencyVerificationRequiredSet) { return mCertificateTransparencyVerificationRequired; } // CT verification has not been set explicitly. Before deferring to // the parent, check if any of the CertificatesEntryRef requires it // to be disabled (i.e., user store or inline certificate). if (hasCertificatesEntryRefs()) { for (CertificatesEntryRef ref : getCertificatesEntryRefs()) { if (ref.disableCT()) { return false; } } } if (mParentBuilder != null) { return mParentBuilder.getCertificateTransparencyVerificationRequired(); } Loading
core/java/android/security/net/config/XmlConfigSource.java +4 −1 Original line number Diff line number Diff line Loading @@ -182,6 +182,7 @@ public class XmlConfigSource implements ConfigSource { boolean overridePins = parser.getAttributeBooleanValue(null, "overridePins", defaultOverridePins); int sourceId = parser.getAttributeResourceValue(null, "src", -1); boolean disableCT = false; String sourceString = parser.getAttributeValue(null, "src"); CertificateSource source = null; if (sourceString == null) { Loading @@ -190,10 +191,12 @@ public class XmlConfigSource implements ConfigSource { if (sourceId != -1) { // TODO: Cache ResourceCertificateSources by sourceId source = new ResourceCertificateSource(sourceId, mContext); disableCT = true; } else if ("system".equals(sourceString)) { source = SystemCertificateSource.getInstance(); } else if ("user".equals(sourceString)) { source = UserCertificateSource.getInstance(); disableCT = true; } else if ("wfa".equals(sourceString)) { source = WfaCertificateSource.getInstance(); } else { Loading @@ -201,7 +204,7 @@ public class XmlConfigSource implements ConfigSource { + "Should be one of system|user|@resourceVal"); } XmlUtils.skipCurrentTag(parser); return new CertificatesEntryRef(source, overridePins); return new CertificatesEntryRef(source, overridePins, disableCT); } private Collection<CertificatesEntryRef> parseTrustAnchors(XmlResourceParser parser, Loading
tests/NetworkSecurityConfigTest/res/xml/ct_domains.xml 0 → 100644 +38 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config> <certificateTransparency enabled="true" /> </base-config> <domain-config> <domain>android.com</domain> <trust-anchors> <certificates src="system" /> </trust-anchors> </domain-config> <domain-config> <domain>subdomain_user.android.com</domain> <trust-anchors> <certificates src="user" /> </trust-anchors> </domain-config> <domain-config> <certificateTransparency enabled="true" /> <domain>subdomain_user_ct.android.com</domain> <trust-anchors> <certificates src="user" /> </trust-anchors> </domain-config> <domain-config> <domain>subdomain_inline.android.com</domain> <trust-anchors> <certificates src="@raw/ca_certs_pem" /> </trust-anchors> </domain-config> <domain-config> <certificateTransparency enabled="true" /> <domain>subdomain_inline_ct.android.com</domain> <trust-anchors> <certificates src="@raw/ca_certs_pem" /> </trust-anchors> </domain-config> </network-security-config>