Merge "Add NetworkSecurityConfigProvider" am: d1c469e876
am: 8c89f4d28c
* commit '8c89f4d28c927ffe81c6e46159d0e5d3a0dd2986':
Add NetworkSecurityConfigProvider
diff --git a/core/java/android/security/net/config/ApplicationConfig.java b/core/java/android/security/net/config/ApplicationConfig.java
index 9bf344a..b627641 100644
--- a/core/java/android/security/net/config/ApplicationConfig.java
+++ b/core/java/android/security/net/config/ApplicationConfig.java
@@ -30,6 +30,9 @@
* @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 @@
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 0000000..1973ef1
--- /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 0000000..8d4f098
--- /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 0000000..ca8cdae
--- /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 0000000..0a1fe88
--- /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 43c0e57..f7590fd 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.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 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 43fa830..c6f3680 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 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.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 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);
+ }
}