Merge "Add NetworkSecurityConfigProvider"
This commit is contained in:
@@ -30,6 +30,9 @@ import javax.net.ssl.X509TrustManager;
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public final class ApplicationConfig {
|
public final class ApplicationConfig {
|
||||||
|
private static ApplicationConfig sInstance;
|
||||||
|
private static Object sLock = new Object();
|
||||||
|
|
||||||
private Set<Pair<Domain, NetworkSecurityConfig>> mConfigs;
|
private Set<Pair<Domain, NetworkSecurityConfig>> mConfigs;
|
||||||
private NetworkSecurityConfig mDefaultConfig;
|
private NetworkSecurityConfig mDefaultConfig;
|
||||||
private X509TrustManager mTrustManager;
|
private X509TrustManager mTrustManager;
|
||||||
@@ -129,4 +132,16 @@ public final class ApplicationConfig {
|
|||||||
mInitialized = true;
|
mInitialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setDefaultInstance(ApplicationConfig config) {
|
||||||
|
synchronized (sLock) {
|
||||||
|
sInstance = config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApplicationConfig getDefaultInstance() {
|
||||||
|
synchronized (sLock) {
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ import javax.net.ssl.HttpsURLConnection;
|
|||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLHandshakeException;
|
import javax.net.ssl.SSLHandshakeException;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
@@ -69,8 +70,11 @@ public final class TestUtils extends Assert {
|
|||||||
|
|
||||||
public static SSLContext getSSLContext(ConfigSource source) throws Exception {
|
public static SSLContext getSSLContext(ConfigSource source) throws Exception {
|
||||||
ApplicationConfig config = new ApplicationConfig(source);
|
ApplicationConfig config = new ApplicationConfig(source);
|
||||||
|
TrustManagerFactory tmf =
|
||||||
|
TrustManagerFactory.getInstance("PKIX", new NetworkSecurityConfigProvider());
|
||||||
|
tmf.init(new RootTrustManagerFactorySpi.ApplicationConfigParameters(config));
|
||||||
SSLContext context = SSLContext.getInstance("TLS");
|
SSLContext context = SSLContext.getInstance("TLS");
|
||||||
context.init(null, new TrustManager[] {config.getTrustManager()}, null);
|
context.init(null, tmf.getTrustManagers(), null);
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ import android.util.Pair;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.URL;
|
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.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -31,6 +35,7 @@ import javax.net.ssl.HttpsURLConnection;
|
|||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLHandshakeException;
|
import javax.net.ssl.SSLHandshakeException;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
|
||||||
public class XmlConfigTests extends AndroidTestCase {
|
public class XmlConfigTests extends AndroidTestCase {
|
||||||
|
|
||||||
@@ -375,4 +380,26 @@ public class XmlConfigTests extends AndroidTestCase {
|
|||||||
public void testBadConfig5() throws Exception {
|
public void testBadConfig5() throws Exception {
|
||||||
testBadConfig(R.xml.bad_config4);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user