summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
author Chad Brubaker <cbrubaker@google.com> 2015-11-05 19:05:47 +0000
committer android-build-merger <android-build-merger@google.com> 2015-11-05 19:05:47 +0000
commitf386e9da362600a44e9c32860a57451b2e2a404f (patch)
tree6bd6866719edcfd105358b9c64d36292fc294530 /tests
parentce8bf86d6d6d3342d6b94c90fcfe382070127eb2 (diff)
parentb4b53b0741b6ff75842d6630d5d1010c4efa766c (diff)
Merge "Add initial network security config implementation" am: 8c35820720 am: 0bafbbfcb4
am: b4b53b0741 * commit 'b4b53b0741b6ff75842d6630d5d1010c4efa766c': Add initial network security config implementation
Diffstat (limited to 'tests')
-rw-r--r--tests/NetworkSecurityConfigTest/Android.mk15
-rw-r--r--tests/NetworkSecurityConfigTest/AndroidManifest.xml29
-rw-r--r--tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java241
-rw-r--r--tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java33
-rw-r--r--tests/NetworkSecurityConfigTest/src/android/security/net/config/TestConfigSource.java39
5 files changed, 357 insertions, 0 deletions
diff --git a/tests/NetworkSecurityConfigTest/Android.mk b/tests/NetworkSecurityConfigTest/Android.mk
new file mode 100644
index 000000000000..a63162d9ba09
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+LOCAL_CERTIFICATE := platform
+
+LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := NetworkSecurityConfigTests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/NetworkSecurityConfigTest/AndroidManifest.xml b/tests/NetworkSecurityConfigTest/AndroidManifest.xml
new file mode 100644
index 000000000000..811a3f4f4f80
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.tests"
+ android:sharedUserId="android.uid.system">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="android.security.tests"
+ android:label="ANSC Tests">
+ </instrumentation>
+</manifest>
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
new file mode 100644
index 000000000000..9a1fe151a2dc
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
@@ -0,0 +1,241 @@
+/*
+ * 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.app.Activity;
+import android.test.ActivityUnitTestCase;
+import android.util.ArraySet;
+import android.util.Pair;
+import java.io.IOException;
+import java.net.Socket;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.TrustManager;
+
+public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> {
+
+ public NetworkSecurityConfigTests() {
+ super(Activity.class);
+ }
+
+ // SHA-256 of the G2 intermediate CA for android.com (as of 10/2015).
+ private static final byte[] G2_SPKI_SHA256
+ = hexToBytes("ec722969cb64200ab6638f68ac538e40abab5b19a6485661042a1061c4612776");
+
+ private static byte[] hexToBytes(String s) {
+ int len = s.length();
+ byte[] data = new byte[len / 2];
+ for (int i = 0; i < len; i += 2) {
+ data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(
+ s.charAt(i + 1), 16));
+ }
+ return data;
+ }
+
+ private void assertConnectionFails(SSLContext context, String host, int port)
+ throws Exception {
+ try {
+ Socket s = context.getSocketFactory().createSocket(host, port);
+ s.getInputStream();
+ fail("Expected connection to " + host + ":" + port + " to fail.");
+ } catch (SSLHandshakeException expected) {
+ }
+ }
+
+ private void assertConnectionSucceeds(SSLContext context, String host, int port)
+ throws Exception {
+ Socket s = context.getSocketFactory().createSocket(host, port);
+ s.getInputStream();
+ }
+
+ private void assertUrlConnectionFails(SSLContext context, String host, int port)
+ throws Exception {
+ URL url = new URL("https://" + host + ":" + port);
+ HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
+ connection.setSSLSocketFactory(context.getSocketFactory());
+ try {
+ connection.getInputStream();
+ fail("Connection to " + host + ":" + port + " expected to fail");
+ } catch (SSLHandshakeException expected) {
+ // ignored.
+ }
+ }
+
+ private void assertUrlConnectionSucceeds(SSLContext context, String host, int port)
+ throws Exception {
+ URL url = new URL("https://" + host + ":" + port);
+ HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
+ connection.setSSLSocketFactory(context.getSocketFactory());
+ connection.getInputStream();
+ }
+
+ private SSLContext getSSLContext(ConfigSource source) throws Exception {
+ ApplicationConfig config = new ApplicationConfig(source);
+ SSLContext context = SSLContext.getInstance("TLS");
+ context.init(null, new TrustManager[] {config.getTrustManager()}, null);
+ return context;
+ }
+
+
+ /**
+ * Return a NetworkSecurityConfig that has an empty TrustAnchor set. This should always cause a
+ * SSLHandshakeException when used for a connection.
+ */
+ private NetworkSecurityConfig getEmptyConfig() {
+ return new NetworkSecurityConfig(true, false,
+ new PinSet(new ArraySet<Pin>(), -1),
+ new ArrayList<CertificatesEntryRef>());
+ }
+
+ private NetworkSecurityConfig getSystemStoreConfig() {
+ ArrayList<CertificatesEntryRef> defaultSource = new ArrayList<CertificatesEntryRef>();
+ defaultSource.add(new CertificatesEntryRef(new SystemCertificateSource(), false));
+ return new NetworkSecurityConfig(true, false, new PinSet(new ArraySet<Pin>(),
+ -1), defaultSource);
+ }
+
+ public void testEmptyConfig() throws Exception {
+ ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap
+ = new ArraySet<Pair<Domain, NetworkSecurityConfig>>();
+ ConfigSource testSource =
+ new TestConfigSource(domainMap, getEmptyConfig());
+ SSLContext context = getSSLContext(testSource);
+ assertConnectionFails(context, "android.com", 443);
+ }
+
+ public void testEmptyPerNetworkSecurityConfig() throws Exception {
+ ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap
+ = new ArraySet<Pair<Domain, NetworkSecurityConfig>>();
+ domainMap.add(new Pair<Domain, NetworkSecurityConfig>(
+ new Domain("android.com", true), getEmptyConfig()));
+ ArrayList<CertificatesEntryRef> defaultSource = new ArrayList<CertificatesEntryRef>();
+ defaultSource.add(new CertificatesEntryRef(new SystemCertificateSource(), false));
+ NetworkSecurityConfig defaultConfig = new NetworkSecurityConfig(true, false,
+ new PinSet(new ArraySet<Pin>(), -1),
+ defaultSource);
+ SSLContext context = getSSLContext(new TestConfigSource(domainMap, defaultConfig));
+ assertConnectionFails(context, "android.com", 443);
+ assertConnectionSucceeds(context, "google.com", 443);
+ }
+
+ public void testBadPin() throws Exception {
+ ArrayList<CertificatesEntryRef> systemSource = new ArrayList<CertificatesEntryRef>();
+ systemSource.add(new CertificatesEntryRef(new SystemCertificateSource(), false));
+ ArraySet<Pin> pins = new ArraySet<Pin>();
+ pins.add(new Pin("SHA-256", new byte[0]));
+ NetworkSecurityConfig domain = new NetworkSecurityConfig(true, false,
+ new PinSet(pins, Long.MAX_VALUE),
+ systemSource);
+ ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap
+ = new ArraySet<Pair<Domain, NetworkSecurityConfig>>();
+ domainMap.add(new Pair<Domain, NetworkSecurityConfig>(
+ new Domain("android.com", true), domain));
+ SSLContext context
+ = getSSLContext(new TestConfigSource(domainMap, getSystemStoreConfig()));
+ assertConnectionFails(context, "android.com", 443);
+ assertConnectionSucceeds(context, "google.com", 443);
+ }
+
+ public void testGoodPin() throws Exception {
+ ArrayList<CertificatesEntryRef> systemSource = new ArrayList<CertificatesEntryRef>();
+ systemSource.add(new CertificatesEntryRef(new SystemCertificateSource(), false));
+ ArraySet<Pin> pins = new ArraySet<Pin>();
+ pins.add(new Pin("SHA-256", G2_SPKI_SHA256));
+ NetworkSecurityConfig domain = new NetworkSecurityConfig(true, false,
+ new PinSet(pins, Long.MAX_VALUE),
+ systemSource);
+ ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap
+ = new ArraySet<Pair<Domain, NetworkSecurityConfig>>();
+ domainMap.add(new Pair<Domain, NetworkSecurityConfig>(
+ new Domain("android.com", true), domain));
+ SSLContext context
+ = getSSLContext(new TestConfigSource(domainMap, getEmptyConfig()));
+ assertConnectionSucceeds(context, "android.com", 443);
+ assertConnectionSucceeds(context, "developer.android.com", 443);
+ }
+
+ public void testOverridePins() throws Exception {
+ // Use a bad pin + granting the system CA store the ability to override pins.
+ ArrayList<CertificatesEntryRef> systemSource = new ArrayList<CertificatesEntryRef>();
+ systemSource.add(new CertificatesEntryRef(new SystemCertificateSource(), true));
+ ArraySet<Pin> pins = new ArraySet<Pin>();
+ pins.add(new Pin("SHA-256", new byte[0]));
+ NetworkSecurityConfig domain = new NetworkSecurityConfig(true, false,
+ new PinSet(pins, Long.MAX_VALUE),
+ systemSource);
+ ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap
+ = new ArraySet<Pair<Domain, NetworkSecurityConfig>>();
+ domainMap.add(new Pair<Domain, NetworkSecurityConfig>(
+ new Domain("android.com", true), domain));
+ SSLContext context
+ = getSSLContext(new TestConfigSource(domainMap, getEmptyConfig()));
+ assertConnectionSucceeds(context, "android.com", 443);
+ }
+
+ public void testMostSpecificNetworkSecurityConfig() throws Exception {
+ ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap
+ = new ArraySet<Pair<Domain, NetworkSecurityConfig>>();
+ domainMap.add(new Pair<Domain, NetworkSecurityConfig>(
+ new Domain("android.com", true), getEmptyConfig()));
+ domainMap.add(new Pair<Domain, NetworkSecurityConfig>(
+ new Domain("developer.android.com", false), getSystemStoreConfig()));
+ SSLContext context
+ = getSSLContext(new TestConfigSource(domainMap, getEmptyConfig()));
+ assertConnectionFails(context, "android.com", 443);
+ assertConnectionSucceeds(context, "developer.android.com", 443);
+ }
+
+ public void testSubdomainIncluded() throws Exception {
+ // First try connecting to a subdomain of a domain entry that includes subdomains.
+ ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap
+ = new ArraySet<Pair<Domain, NetworkSecurityConfig>>();
+ domainMap.add(new Pair<Domain, NetworkSecurityConfig>(
+ new Domain("android.com", true), getSystemStoreConfig()));
+ SSLContext context
+ = getSSLContext(new TestConfigSource(domainMap, getEmptyConfig()));
+ assertConnectionSucceeds(context, "developer.android.com", 443);
+ // Now try without including subdomains.
+ domainMap = new ArraySet<Pair<Domain, NetworkSecurityConfig>>();
+ domainMap.add(new Pair<Domain, NetworkSecurityConfig>(
+ new Domain("android.com", false), getSystemStoreConfig()));
+ context = getSSLContext(new TestConfigSource(domainMap, getEmptyConfig()));
+ assertConnectionFails(context, "developer.android.com", 443);
+ }
+
+ public void testWithUrlConnection() throws Exception {
+ ArrayList<CertificatesEntryRef> systemSource = new ArrayList<CertificatesEntryRef>();
+ systemSource.add(new CertificatesEntryRef(new SystemCertificateSource(), false));
+ ArraySet<Pin> pins = new ArraySet<Pin>();
+ pins.add(new Pin("SHA-256", G2_SPKI_SHA256));
+ NetworkSecurityConfig domain = new NetworkSecurityConfig(true, false,
+ new PinSet(pins, Long.MAX_VALUE),
+ systemSource);
+ ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap
+ = new ArraySet<Pair<Domain, NetworkSecurityConfig>>();
+ domainMap.add(new Pair<Domain, NetworkSecurityConfig>(
+ new Domain("android.com", true), domain));
+ SSLContext context
+ = getSSLContext(new TestConfigSource(domainMap, getEmptyConfig()));
+ assertUrlConnectionSucceeds(context, "android.com", 443);
+ assertUrlConnectionSucceeds(context, "developer.android.com", 443);
+ assertUrlConnectionFails(context, "google.com", 443);
+ }
+}
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java
new file mode 100644
index 000000000000..92eadc06cd49
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.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.util.Set;
+import java.security.cert.X509Certificate;
+
+/** @hide */
+public class TestCertificateSource implements CertificateSource {
+
+ private final Set<X509Certificate> mCertificates;
+ public TestCertificateSource(Set<X509Certificate> certificates) {
+ mCertificates = certificates;
+ }
+
+ public Set<X509Certificate> getCertificates() {
+ return mCertificates;
+ }
+}
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestConfigSource.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestConfigSource.java
new file mode 100644
index 000000000000..609f481a312c
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestConfigSource.java
@@ -0,0 +1,39 @@
+/*
+ * 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.util.Set;
+
+/** @hide */
+public class TestConfigSource implements ConfigSource {
+ private final Set<Pair<Domain, NetworkSecurityConfig>> mConfigs;
+ private final NetworkSecurityConfig mDefaultConfig;
+ public TestConfigSource(Set<Pair<Domain, NetworkSecurityConfig>> configs,
+ NetworkSecurityConfig defaultConfig) {
+ mConfigs = configs;
+ mDefaultConfig = defaultConfig;
+ }
+
+ public Set<Pair<Domain, NetworkSecurityConfig>> getPerDomainConfigs() {
+ return mConfigs;
+ }
+
+ public NetworkSecurityConfig getDefaultConfig() {
+ return mDefaultConfig;
+ }
+}