diff options
author | 2015-11-11 20:25:04 +0000 | |
---|---|---|
committer | 2015-11-11 20:25:04 +0000 | |
commit | d1c469e8769822c48584034076861331fd792a7c (patch) | |
tree | c0e215286a8ed04661964d37232645cb76df73b5 | |
parent | 10b0bae06ffdeb79494ddd1aff19387b56770960 (diff) | |
parent | 5a1078f40dd511901c33ccf78be6e2d5081d6637 (diff) |
Merge "Add NetworkSecurityConfigProvider"
7 files changed, 269 insertions, 1 deletions
diff --git a/core/java/android/security/net/config/ApplicationConfig.java b/core/java/android/security/net/config/ApplicationConfig.java index 9bf344a0e2bc..b6276418c49d 100644 --- a/core/java/android/security/net/config/ApplicationConfig.java +++ b/core/java/android/security/net/config/ApplicationConfig.java @@ -30,6 +30,9 @@ import javax.net.ssl.X509TrustManager; * @hide */ public final class ApplicationConfig { + private static ApplicationConfig sInstance; + private static Object sLock = new Object(); + private Set<Pair<Domain, NetworkSecurityConfig>> mConfigs; private NetworkSecurityConfig mDefaultConfig; private X509TrustManager mTrustManager; @@ -129,4 +132,16 @@ public final class ApplicationConfig { mInitialized = true; } } + + public static void setDefaultInstance(ApplicationConfig config) { + synchronized (sLock) { + sInstance = config; + } + } + + public static ApplicationConfig getDefaultInstance() { + synchronized (sLock) { + return sInstance; + } + } } diff --git a/core/java/android/security/net/config/KeyStoreCertificateSource.java b/core/java/android/security/net/config/KeyStoreCertificateSource.java new file mode 100644 index 000000000000..1973ef1825e9 --- /dev/null +++ b/core/java/android/security/net/config/KeyStoreCertificateSource.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.net.config; + +import android.util.ArraySet; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import java.util.Set; + +/** + * {@link CertificateSource} which provides certificates from trusted certificate entries of a + * {@link KeyStore}. + */ +class KeyStoreCertificateSource implements CertificateSource { + private final Object mLock = new Object(); + private final KeyStore mKeyStore; + private Set<X509Certificate> mCertificates; + + public KeyStoreCertificateSource(KeyStore ks) { + mKeyStore = ks; + } + + @Override + public Set<X509Certificate> getCertificates() { + synchronized (mLock) { + if (mCertificates != null) { + return mCertificates; + } + try { + Set<X509Certificate> certificates = new ArraySet<>(mKeyStore.size()); + for (Enumeration<String> en = mKeyStore.aliases(); en.hasMoreElements();) { + String alias = en.nextElement(); + if (!mKeyStore.isCertificateEntry(alias)) { + continue; + } + X509Certificate cert = (X509Certificate) mKeyStore.getCertificate(alias); + if (cert != null) { + certificates.add(cert); + } + } + mCertificates = certificates; + return mCertificates; + } catch (KeyStoreException e) { + throw new RuntimeException("Failed to load certificates from KeyStore", e); + } + } + } +} diff --git a/core/java/android/security/net/config/KeyStoreConfigSource.java b/core/java/android/security/net/config/KeyStoreConfigSource.java new file mode 100644 index 000000000000..8d4f098bcb37 --- /dev/null +++ b/core/java/android/security/net/config/KeyStoreConfigSource.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.net.config; + +import android.util.Pair; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.util.Set; + +/** + * {@link ConfigSource} with a single default config based on a {@link KeyStore} and no per domain + * configs. + */ +class KeyStoreConfigSource implements ConfigSource { + private final NetworkSecurityConfig mConfig; + + public KeyStoreConfigSource(KeyStore ks) { + mConfig = new NetworkSecurityConfig.Builder() + .addCertificatesEntryRef( + // Use the KeyStore and do not override pins (of which there are none). + new CertificatesEntryRef(new KeyStoreCertificateSource(ks), false)) + .build(); + } + + @Override + public Set<Pair<Domain, NetworkSecurityConfig>> getPerDomainConfigs() { + return null; + } + + @Override + public NetworkSecurityConfig getDefaultConfig() { + return mConfig; + } +} + diff --git a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java new file mode 100644 index 000000000000..ca8cdae47162 --- /dev/null +++ b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.net.config; + +import java.security.Provider; + +/** @hide */ +public final class NetworkSecurityConfigProvider extends Provider { + + private static String PREFIX = + NetworkSecurityConfigProvider.class.getPackage().getName() + "."; + + public NetworkSecurityConfigProvider() { + // TODO: More clever name than this + super("AndroidNSSP", 1.0, "Android Network Security Policy Provider"); + put("TrustManagerFactory.PKIX", PREFIX + "RootTrustManagerFactorySpi"); + put("Alg.Alias.TrustManagerFactory.X509", "PKIX"); + } +} diff --git a/core/java/android/security/net/config/RootTrustManagerFactorySpi.java b/core/java/android/security/net/config/RootTrustManagerFactorySpi.java new file mode 100644 index 000000000000..0a1fe881cb17 --- /dev/null +++ b/core/java/android/security/net/config/RootTrustManagerFactorySpi.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.net.config; + +import android.util.Pair; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.util.Set; +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.TrustManagerFactorySpi; + +import com.android.internal.annotations.VisibleForTesting; + +/** @hide */ +public class RootTrustManagerFactorySpi extends TrustManagerFactorySpi { + private ApplicationConfig mApplicationConfig; + private NetworkSecurityConfig mConfig; + + @Override + public void engineInit(ManagerFactoryParameters spec) + throws InvalidAlgorithmParameterException { + if (!(spec instanceof ApplicationConfigParameters)) { + throw new InvalidAlgorithmParameterException("Unsupported spec: " + spec + ". Only " + + ApplicationConfigParameters.class.getName() + " supported"); + + } + mApplicationConfig = ((ApplicationConfigParameters) spec).config; + } + + @Override + public void engineInit(KeyStore ks) throws KeyStoreException { + if (ks != null) { + mApplicationConfig = new ApplicationConfig(new KeyStoreConfigSource(ks)); + } else { + mApplicationConfig = ApplicationConfig.getDefaultInstance(); + } + } + + @Override + public TrustManager[] engineGetTrustManagers() { + if (mApplicationConfig == null) { + throw new IllegalStateException("TrustManagerFactory not initialized"); + } + return new TrustManager[] { mApplicationConfig.getTrustManager() }; + } + + @VisibleForTesting + public static final class ApplicationConfigParameters implements ManagerFactoryParameters { + public final ApplicationConfig config; + public ApplicationConfigParameters(ApplicationConfig config) { + this.config = config; + } + } +} diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java index 43c0e5708233..f7590fd6ff12 100644 --- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java +++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java @@ -22,6 +22,7 @@ import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; import junit.framework.Assert; @@ -69,8 +70,11 @@ public final class TestUtils extends Assert { public static SSLContext getSSLContext(ConfigSource source) throws Exception { ApplicationConfig config = new ApplicationConfig(source); + TrustManagerFactory tmf = + TrustManagerFactory.getInstance("PKIX", new NetworkSecurityConfigProvider()); + tmf.init(new RootTrustManagerFactorySpi.ApplicationConfigParameters(config)); SSLContext context = SSLContext.getInstance("TLS"); - context.init(null, new TrustManager[] {config.getTrustManager()}, null); + context.init(null, tmf.getTrustManagers(), null); return context; } } diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java index 43fa830f733e..c6f3680f455c 100644 --- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java +++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java @@ -24,6 +24,10 @@ import android.util.Pair; import java.io.IOException; import java.net.Socket; import java.net.URL; +import java.security.KeyStore; +import java.security.Provider; +import java.security.Security; +import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.Set; @@ -31,6 +35,7 @@ import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; public class XmlConfigTests extends AndroidTestCase { @@ -375,4 +380,26 @@ public class XmlConfigTests extends AndroidTestCase { public void testBadConfig5() throws Exception { testBadConfig(R.xml.bad_config4); } + + public void testTrustManagerKeystore() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.bad_pin, true); + ApplicationConfig appConfig = new ApplicationConfig(source); + Provider provider = new NetworkSecurityConfigProvider(); + TrustManagerFactory tmf = + TrustManagerFactory.getInstance("PKIX", provider); + KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); + keystore.load(null); + int i = 0; + for (X509Certificate cert : SystemCertificateSource.getInstance().getCertificates()) { + keystore.setEntry(String.valueOf(i), + new KeyStore.TrustedCertificateEntry(cert), + null); + i++; + } + tmf.init(keystore); + TrustManager[] tms = tmf.getTrustManagers(); + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, tms, null); + TestUtils.assertConnectionSucceeds(context, "android.com" , 443); + } } |