Loading core/java/android/security/net/config/ApplicationConfig.java +33 −23 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ public final class ApplicationConfig { private Set<Pair<Domain, NetworkSecurityConfig>> mConfigs; private NetworkSecurityConfig mDefaultConfig; private NetworkSecurityConfig mLocalhostConfig; private X509TrustManager mTrustManager; private ConfigSource mConfigSource; Loading @@ -62,8 +63,10 @@ public final class ApplicationConfig { /** * Get the {@link NetworkSecurityConfig} corresponding to the provided hostname. * When matching the most specific matching domain rule will be used, if no match exists * then the default configuration will be returned. * The most specific matching domain rule will be used. If no match exists * and the hostname is considered to be localhost (according to {@link * Domain#isLocalhost()}), the localhost configuration will be returned. * Otherwise, the default configuration will be returned. * * {@code NetworkSecurityConfig} objects returned by this method can be safely cached for * {@code hostname}. Subsequent calls with the same hostname will always return the same Loading @@ -74,7 +77,8 @@ public final class ApplicationConfig { */ public NetworkSecurityConfig getConfigForHostname(String hostname) { ensureInitialized(); if (hostname == null || hostname.isEmpty() || mConfigs == null) { if (hostname == null || hostname.isEmpty() || (mConfigs == null && mLocalhostConfig == null)) { return mDefaultConfig; } if (hostname.charAt(0) == '.') { Loading @@ -89,7 +93,7 @@ public final class ApplicationConfig { } // Find the Domain -> NetworkSecurityConfig entry with the most specific matching // Domain entry for hostname. // TODO: Use a smarter data structure for the lookup. if (mConfigs != null) { Pair<Domain, NetworkSecurityConfig> bestMatch = null; for (Pair<Domain, NetworkSecurityConfig> entry : mConfigs) { Domain domain = entry.first; Loading @@ -102,7 +106,8 @@ public final class ApplicationConfig { // sub-domain of the Domain. if (domain.subdomainsIncluded && hostname.endsWith(domain.hostname) && hostname.charAt(hostname.length() - domain.hostname.length() - 1) == '.') { && hostname.charAt( hostname.length() - domain.hostname.length() - 1) == '.') { if (bestMatch == null) { bestMatch = entry; } else if (domain.hostname.length() > bestMatch.first.hostname.length()) { Loading @@ -113,6 +118,10 @@ public final class ApplicationConfig { if (bestMatch != null) { return bestMatch.second; } } if (mLocalhostConfig != null && Domain.isLocalhost(hostname)) { return mLocalhostConfig; } // If no match was found use the default configuration. return mDefaultConfig; } Loading Loading @@ -195,6 +204,7 @@ public final class ApplicationConfig { } mConfigs = mConfigSource.getPerDomainConfigs(); mDefaultConfig = mConfigSource.getDefaultConfig(); mLocalhostConfig = mConfigSource.getLocalhostConfig(); mConfigSource = null; mTrustManager = new RootTrustManager(this); mInitialized = true; Loading core/java/android/security/net/config/ConfigSource.java +13 −0 Original line number Diff line number Diff line Loading @@ -16,11 +16,24 @@ package android.security.net.config; import android.annotation.Nullable; import android.util.Pair; import java.util.Set; /** @hide */ public interface ConfigSource { /** Returns the set of configurations that are associated with a Domain. */ @Nullable Set<Pair<Domain, NetworkSecurityConfig>> getPerDomainConfigs(); /** Returns the default NetworkSecurityConfig */ NetworkSecurityConfig getDefaultConfig(); /** Returns the NetworkSecurityConfig associated with localhost. * See {@link Domain#isLocalhost()} for the exact definition. */ @Nullable NetworkSecurityConfig getLocalhostConfig(); } core/java/android/security/net/config/Domain.java +33 −0 Original line number Diff line number Diff line Loading @@ -17,11 +17,17 @@ package android.security.net.config; import android.annotation.Nullable; import android.net.InetAddresses; import java.net.InetAddress; import java.util.Locale; import java.util.Set; /** @hide */ public final class Domain { private static final Set<String> LOCALHOSTS = Set.of("localhost", "ip6-localhost"); /** * Lower case hostname for this domain rule. */ Loading Loading @@ -57,4 +63,31 @@ public final class Domain { return otherDomain.subdomainsIncluded == this.subdomainsIncluded && otherDomain.hostname.equals(this.hostname); } public boolean isLocalhost() { return isLocalhost(this.hostname); } /** * Whether the hostname is considered to be localhost or not. */ public static boolean isLocalhost(String hostname) { if (LOCALHOSTS.contains(hostname)) { return true; } // RFC 2732: To use a literal IPv6 address in a URL, the literal // address should be enclosed in "[" and "]" characters. if (hostname.charAt(0) == '[' && hostname.charAt(hostname.length() - 1) == ']') { hostname = hostname.substring(1, hostname.length() - 1); } // parseNumericAddress raises an exception if the address is not valid. // We could use isNumericAddress beforehand to avoid the exception, but // this would imply parsing the address twice. Simply ignore // IllegalArgumentException. try { InetAddress addr = InetAddresses.parseNumericAddress(hostname); return addr.isLoopbackAddress(); } catch (IllegalArgumentException e) { } return false; } } core/java/android/security/net/config/KeyStoreConfigSource.java +5 −0 Original line number Diff line number Diff line Loading @@ -45,5 +45,10 @@ class KeyStoreConfigSource implements ConfigSource { public NetworkSecurityConfig getDefaultConfig() { return mConfig; } @Override public NetworkSecurityConfig getLocalhostConfig() { return null; } } core/java/android/security/net/config/ManifestConfigSource.java +18 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.security.net.config; import static com.android.org.conscrypt.net.flags.Flags.networkSecurityConfigLocalhost; import android.content.Context; import android.content.pm.ApplicationInfo; import android.util.Log; Loading Loading @@ -50,6 +52,11 @@ public class ManifestConfigSource implements ConfigSource { return getConfigSource().getDefaultConfig(); } @Override public NetworkSecurityConfig getLocalhostConfig() { return getConfigSource().getLocalhostConfig(); } private ConfigSource getConfigSource() { synchronized (mLock) { if (mConfigSource != null) { Loading Loading @@ -86,11 +93,17 @@ public class ManifestConfigSource implements ConfigSource { private static final class DefaultConfigSource implements ConfigSource { private final NetworkSecurityConfig mDefaultConfig; private final NetworkSecurityConfig mLocalhostConfig; DefaultConfigSource(boolean usesCleartextTraffic, ApplicationInfo info) { mDefaultConfig = NetworkSecurityConfig.getDefaultBuilder(info) .setCleartextTrafficPermitted(usesCleartextTraffic) .build(); if (networkSecurityConfigLocalhost()) { mLocalhostConfig = NetworkSecurityConfig.getLocalhostBuilder().build(); } else { mLocalhostConfig = null; } } @Override Loading @@ -98,6 +111,11 @@ public class ManifestConfigSource implements ConfigSource { return mDefaultConfig; } @Override public NetworkSecurityConfig getLocalhostConfig() { return mLocalhostConfig; } @Override public Set<Pair<Domain, NetworkSecurityConfig>> getPerDomainConfigs() { return null; Loading Loading
core/java/android/security/net/config/ApplicationConfig.java +33 −23 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ public final class ApplicationConfig { private Set<Pair<Domain, NetworkSecurityConfig>> mConfigs; private NetworkSecurityConfig mDefaultConfig; private NetworkSecurityConfig mLocalhostConfig; private X509TrustManager mTrustManager; private ConfigSource mConfigSource; Loading @@ -62,8 +63,10 @@ public final class ApplicationConfig { /** * Get the {@link NetworkSecurityConfig} corresponding to the provided hostname. * When matching the most specific matching domain rule will be used, if no match exists * then the default configuration will be returned. * The most specific matching domain rule will be used. If no match exists * and the hostname is considered to be localhost (according to {@link * Domain#isLocalhost()}), the localhost configuration will be returned. * Otherwise, the default configuration will be returned. * * {@code NetworkSecurityConfig} objects returned by this method can be safely cached for * {@code hostname}. Subsequent calls with the same hostname will always return the same Loading @@ -74,7 +77,8 @@ public final class ApplicationConfig { */ public NetworkSecurityConfig getConfigForHostname(String hostname) { ensureInitialized(); if (hostname == null || hostname.isEmpty() || mConfigs == null) { if (hostname == null || hostname.isEmpty() || (mConfigs == null && mLocalhostConfig == null)) { return mDefaultConfig; } if (hostname.charAt(0) == '.') { Loading @@ -89,7 +93,7 @@ public final class ApplicationConfig { } // Find the Domain -> NetworkSecurityConfig entry with the most specific matching // Domain entry for hostname. // TODO: Use a smarter data structure for the lookup. if (mConfigs != null) { Pair<Domain, NetworkSecurityConfig> bestMatch = null; for (Pair<Domain, NetworkSecurityConfig> entry : mConfigs) { Domain domain = entry.first; Loading @@ -102,7 +106,8 @@ public final class ApplicationConfig { // sub-domain of the Domain. if (domain.subdomainsIncluded && hostname.endsWith(domain.hostname) && hostname.charAt(hostname.length() - domain.hostname.length() - 1) == '.') { && hostname.charAt( hostname.length() - domain.hostname.length() - 1) == '.') { if (bestMatch == null) { bestMatch = entry; } else if (domain.hostname.length() > bestMatch.first.hostname.length()) { Loading @@ -113,6 +118,10 @@ public final class ApplicationConfig { if (bestMatch != null) { return bestMatch.second; } } if (mLocalhostConfig != null && Domain.isLocalhost(hostname)) { return mLocalhostConfig; } // If no match was found use the default configuration. return mDefaultConfig; } Loading Loading @@ -195,6 +204,7 @@ public final class ApplicationConfig { } mConfigs = mConfigSource.getPerDomainConfigs(); mDefaultConfig = mConfigSource.getDefaultConfig(); mLocalhostConfig = mConfigSource.getLocalhostConfig(); mConfigSource = null; mTrustManager = new RootTrustManager(this); mInitialized = true; Loading
core/java/android/security/net/config/ConfigSource.java +13 −0 Original line number Diff line number Diff line Loading @@ -16,11 +16,24 @@ package android.security.net.config; import android.annotation.Nullable; import android.util.Pair; import java.util.Set; /** @hide */ public interface ConfigSource { /** Returns the set of configurations that are associated with a Domain. */ @Nullable Set<Pair<Domain, NetworkSecurityConfig>> getPerDomainConfigs(); /** Returns the default NetworkSecurityConfig */ NetworkSecurityConfig getDefaultConfig(); /** Returns the NetworkSecurityConfig associated with localhost. * See {@link Domain#isLocalhost()} for the exact definition. */ @Nullable NetworkSecurityConfig getLocalhostConfig(); }
core/java/android/security/net/config/Domain.java +33 −0 Original line number Diff line number Diff line Loading @@ -17,11 +17,17 @@ package android.security.net.config; import android.annotation.Nullable; import android.net.InetAddresses; import java.net.InetAddress; import java.util.Locale; import java.util.Set; /** @hide */ public final class Domain { private static final Set<String> LOCALHOSTS = Set.of("localhost", "ip6-localhost"); /** * Lower case hostname for this domain rule. */ Loading Loading @@ -57,4 +63,31 @@ public final class Domain { return otherDomain.subdomainsIncluded == this.subdomainsIncluded && otherDomain.hostname.equals(this.hostname); } public boolean isLocalhost() { return isLocalhost(this.hostname); } /** * Whether the hostname is considered to be localhost or not. */ public static boolean isLocalhost(String hostname) { if (LOCALHOSTS.contains(hostname)) { return true; } // RFC 2732: To use a literal IPv6 address in a URL, the literal // address should be enclosed in "[" and "]" characters. if (hostname.charAt(0) == '[' && hostname.charAt(hostname.length() - 1) == ']') { hostname = hostname.substring(1, hostname.length() - 1); } // parseNumericAddress raises an exception if the address is not valid. // We could use isNumericAddress beforehand to avoid the exception, but // this would imply parsing the address twice. Simply ignore // IllegalArgumentException. try { InetAddress addr = InetAddresses.parseNumericAddress(hostname); return addr.isLoopbackAddress(); } catch (IllegalArgumentException e) { } return false; } }
core/java/android/security/net/config/KeyStoreConfigSource.java +5 −0 Original line number Diff line number Diff line Loading @@ -45,5 +45,10 @@ class KeyStoreConfigSource implements ConfigSource { public NetworkSecurityConfig getDefaultConfig() { return mConfig; } @Override public NetworkSecurityConfig getLocalhostConfig() { return null; } }
core/java/android/security/net/config/ManifestConfigSource.java +18 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.security.net.config; import static com.android.org.conscrypt.net.flags.Flags.networkSecurityConfigLocalhost; import android.content.Context; import android.content.pm.ApplicationInfo; import android.util.Log; Loading Loading @@ -50,6 +52,11 @@ public class ManifestConfigSource implements ConfigSource { return getConfigSource().getDefaultConfig(); } @Override public NetworkSecurityConfig getLocalhostConfig() { return getConfigSource().getLocalhostConfig(); } private ConfigSource getConfigSource() { synchronized (mLock) { if (mConfigSource != null) { Loading Loading @@ -86,11 +93,17 @@ public class ManifestConfigSource implements ConfigSource { private static final class DefaultConfigSource implements ConfigSource { private final NetworkSecurityConfig mDefaultConfig; private final NetworkSecurityConfig mLocalhostConfig; DefaultConfigSource(boolean usesCleartextTraffic, ApplicationInfo info) { mDefaultConfig = NetworkSecurityConfig.getDefaultBuilder(info) .setCleartextTrafficPermitted(usesCleartextTraffic) .build(); if (networkSecurityConfigLocalhost()) { mLocalhostConfig = NetworkSecurityConfig.getLocalhostBuilder().build(); } else { mLocalhostConfig = null; } } @Override Loading @@ -98,6 +111,11 @@ public class ManifestConfigSource implements ConfigSource { return mDefaultConfig; } @Override public NetworkSecurityConfig getLocalhostConfig() { return mLocalhostConfig; } @Override public Set<Pair<Domain, NetworkSecurityConfig>> getPerDomainConfigs() { return null; Loading