diff options
author | Chad Brubaker <cbrubaker@google.com> | 2015-11-04 23:55:29 -0800 |
---|---|---|
committer | Chad Brubaker <cbrubaker@google.com> | 2015-11-06 22:24:01 -0800 |
commit | 5f96702f582050c1598136ed2a748f76b981c94e (patch) | |
tree | 95bff660c4abcc6b7057372e254acfbb2ea52d89 /tests/NetworkSecurityConfigTest | |
parent | 1347cb81f402c628f3346ea350a5862749901d59 (diff) |
Add xml source for network security configuration
XmlConfigSource parses an ApplicationConfig from an xml resource.
Currently this supports app-wide default configuration via the
base-config element, per domain via the domain-config element and
inheritance of unset properties at parse time.
Inheritance of unset properties is currently only:
domain-config -> base-config -> platform default configuration
Where the most specific value is used.
For example: If the base-config specifies trust anchors, all connections
will use those anchors except for connections to a domain which has a
domain-config that specifies trust anchors, in which case the
domain-config's trust anchors will be used. If the domain-config or
base-config don't set trust anchors, or don't exist, then the platform
default trust anchors will be used.
Nested domain-config entries, debug-overrides, and thorough
documentation of the xml format will follow in later commits.
Change-Id: I1232ff1e8079a81b340bc12e142f0889f6947aa0
Diffstat (limited to 'tests/NetworkSecurityConfigTest')
25 files changed, 621 insertions, 69 deletions
diff --git a/tests/NetworkSecurityConfigTest/AndroidManifest.xml b/tests/NetworkSecurityConfigTest/AndroidManifest.xml index 811a3f4f4f80..4c1fbd375e1e 100644 --- a/tests/NetworkSecurityConfigTest/AndroidManifest.xml +++ b/tests/NetworkSecurityConfigTest/AndroidManifest.xml @@ -15,7 +15,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="android.security.tests" + package="android.security.net.config" android:sharedUserId="android.uid.system"> <application> @@ -23,7 +23,7 @@ </application> <instrumentation android:name="android.test.InstrumentationTestRunner" - android:targetPackage="android.security.tests" + android:targetPackage="android.security.net.config" android:label="ANSC Tests"> </instrumentation> </manifest> diff --git a/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der Binary files differnew file mode 100644 index 000000000000..235bd4797b78 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der diff --git a/tests/NetworkSecurityConfigTest/res/raw/ca_certs_pem.pem b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_pem.pem new file mode 100644 index 000000000000..413e3c07d2ab --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_pem.pem @@ -0,0 +1,35 @@ +-----BEGIN CERTIFICATE----- +MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT +MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0 +aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw +WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE +AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m +OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu +T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c +JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR +Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz +PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm +aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM +TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g +LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO +BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv +dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB +AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL +NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W +b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz +cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 +MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV +BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN +ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE +BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is +I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G +CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i +2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ +2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ +-----END CERTIFICATE----- diff --git a/tests/NetworkSecurityConfigTest/res/xml/attributes.xml b/tests/NetworkSecurityConfigTest/res/xml/attributes.xml new file mode 100644 index 000000000000..eff13c80c343 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/attributes.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <base-config cleartextTrafficPermitted="false" hstsEnforced="true"> + </base-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/bad_config0.xml b/tests/NetworkSecurityConfigTest/res/xml/bad_config0.xml new file mode 100644 index 000000000000..6af855d12d5f --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/bad_config0.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <domain-config> + <domain>android.com</domain> + <pin-set> + <!-- Bad pin digest --> + <pin digest="I am probably not an algorithm">1HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin> + </pin-set> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/bad_config1.xml b/tests/NetworkSecurityConfigTest/res/xml/bad_config1.xml new file mode 100644 index 000000000000..d683b74ae197 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/bad_config1.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <domain-config> + <domain>android.com</domain> + <pin-set> + <!-- Unknown pin digest --> + <pin>1HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin> + </pin-set> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/bad_config2.xml b/tests/NetworkSecurityConfigTest/res/xml/bad_config2.xml new file mode 100644 index 000000000000..6f3f8b43d653 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/bad_config2.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <domain-config> + <domain>android.com</domain> + <pin-set> + <!-- empty digest --> + <pin digest="SHA-256"></pin> + </pin-set> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/bad_config3.xml b/tests/NetworkSecurityConfigTest/res/xml/bad_config3.xml new file mode 100644 index 000000000000..fb2126c0f778 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/bad_config3.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <domain-config> + <domain>android.com</domain> + </domain-config> + <domain-config> + <!-- Same domain name used in two configs --> + <domain>android.com</domain> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/bad_config4.xml b/tests/NetworkSecurityConfigTest/res/xml/bad_config4.xml new file mode 100644 index 000000000000..95972cedfc90 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/bad_config4.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <base-config> + <!-- domains are not allowed in base-config --> + <domain>android.com</domain> + </base-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/bad_config5.xml b/tests/NetworkSecurityConfigTest/res/xml/bad_config5.xml new file mode 100644 index 000000000000..8b6b72151269 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/bad_config5.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <base-config> + <!-- pins are not allowed in base-config --> + <pin-set> + </pin-set> + </base-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/bad_pin.xml b/tests/NetworkSecurityConfigTest/res/xml/bad_pin.xml new file mode 100644 index 000000000000..62a7b8819d87 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/bad_pin.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <domain-config> + <domain>android.com</domain> + <pin-set> + <pin digest="SHA-256">1HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin> + </pin-set> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/domain1.xml b/tests/NetworkSecurityConfigTest/res/xml/domain1.xml new file mode 100644 index 000000000000..6d8565c35717 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/domain1.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <base-config> + <trust-anchors> + </trust-anchors> + </base-config> + <domain-config> + <domain>android.com</domain> + <trust-anchors> + <certificates src="system" /> + <certificates src="user" /> + </trust-anchors> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/empty_config.xml b/tests/NetworkSecurityConfigTest/res/xml/empty_config.xml new file mode 100644 index 000000000000..1bd94b648d22 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/empty_config.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/empty_trust.xml b/tests/NetworkSecurityConfigTest/res/xml/empty_trust.xml new file mode 100644 index 000000000000..8093b9d05153 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/empty_trust.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <base-config> + <trust-anchors> + </trust-anchors> + </base-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/expired_pin.xml b/tests/NetworkSecurityConfigTest/res/xml/expired_pin.xml new file mode 100644 index 000000000000..f9f846526a92 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/expired_pin.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <domain-config> + <domain>android.com</domain> + <!-- Invalid pin that has expired --> + <pin-set expiration="2015-01-01"> + <pin digest="SHA-256">aaaaaaaaaaa2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin> + </pin-set> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/multiple_configs.xml b/tests/NetworkSecurityConfigTest/res/xml/multiple_configs.xml new file mode 100644 index 000000000000..df08467af744 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/multiple_configs.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <base-config> + <trust-anchors> + </trust-anchors> + </base-config> + <domain-config> + <domain>android.com</domain> + <trust-anchors> + <certificates src="system" /> + <certificates src="user" /> + </trust-anchors> + </domain-config> + <domain-config> + <domain>google.com</domain> + <trust-anchors> + <certificates src="system" /> + <certificates src="user" /> + </trust-anchors> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/multiple_domains.xml b/tests/NetworkSecurityConfigTest/res/xml/multiple_domains.xml new file mode 100644 index 000000000000..9743c5f0c4a0 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/multiple_domains.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <base-config> + <trust-anchors> + </trust-anchors> + </base-config> + <domain-config> + <domain>android.com</domain> + <domain>google.com</domain> + <trust-anchors> + <certificates src="system" /> + <certificates src="user" /> + </trust-anchors> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/override_pins.xml b/tests/NetworkSecurityConfigTest/res/xml/override_pins.xml new file mode 100644 index 000000000000..785714a8f19e --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/override_pins.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <domain-config> + <domain>android.com</domain> + <pin-set> + <pin digest="SHA-256">aaaaaaaaIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin> + </pin-set> + <trust-anchors> + <certificates src="system" overridePins="true" /> + </trust-anchors> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/pins1.xml b/tests/NetworkSecurityConfigTest/res/xml/pins1.xml new file mode 100644 index 000000000000..1773d28094a3 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/pins1.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <domain-config> + <domain>android.com</domain> + <pin-set> + <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin> + </pin-set> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/resource_anchors_der.xml b/tests/NetworkSecurityConfigTest/res/xml/resource_anchors_der.xml new file mode 100644 index 000000000000..dfd6fd9cc373 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/resource_anchors_der.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <base-config> + <trust-anchors> + </trust-anchors> + </base-config> + <domain-config> + <domain>android.com</domain> + <trust-anchors> + <certificates src="@raw/ca_certs_der" /> + </trust-anchors> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/resource_anchors_pem.xml b/tests/NetworkSecurityConfigTest/res/xml/resource_anchors_pem.xml new file mode 100644 index 000000000000..894f29b4027c --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/resource_anchors_pem.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <base-config> + <trust-anchors> + </trust-anchors> + </base-config> + <domain-config> + <domain>android.com</domain> + <trust-anchors> + <certificates src="@raw/ca_certs_pem" /> + </trust-anchors> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/res/xml/subdomains.xml b/tests/NetworkSecurityConfigTest/res/xml/subdomains.xml new file mode 100644 index 000000000000..482b26c18716 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/subdomains.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <base-config> + <trust-anchors> + </trust-anchors> + </base-config> + <domain-config> + <domain includeSubdomains="true">android.com</domain> + <trust-anchors> + <certificates src="system" /> + <certificates src="user" /> + </trust-anchors> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java index 11d8136b9f5d..9f48d56cb56b 100644 --- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java +++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java @@ -50,49 +50,6 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { 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; - } /** @@ -115,8 +72,8 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { = new ArraySet<Pair<Domain, NetworkSecurityConfig>>(); ConfigSource testSource = new TestConfigSource(domainMap, getEmptyConfig()); - SSLContext context = getSSLContext(testSource); - assertConnectionFails(context, "android.com", 443); + SSLContext context = TestUtils.getSSLContext(testSource); + TestUtils.assertConnectionFails(context, "android.com", 443); } public void testEmptyPerNetworkSecurityConfig() throws Exception { @@ -125,9 +82,9 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { domainMap.add(new Pair<Domain, NetworkSecurityConfig>( new Domain("android.com", true), getEmptyConfig())); NetworkSecurityConfig defaultConfig = getSystemStoreConfig(); - SSLContext context = getSSLContext(new TestConfigSource(domainMap, defaultConfig)); - assertConnectionFails(context, "android.com", 443); - assertConnectionSucceeds(context, "google.com", 443); + SSLContext context = TestUtils.getSSLContext(new TestConfigSource(domainMap, defaultConfig)); + TestUtils.assertConnectionFails(context, "android.com", 443); + TestUtils.assertConnectionSucceeds(context, "google.com", 443); } public void testBadPin() throws Exception { @@ -143,9 +100,9 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { 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); + = TestUtils.getSSLContext(new TestConfigSource(domainMap, getSystemStoreConfig())); + TestUtils.assertConnectionFails(context, "android.com", 443); + TestUtils.assertConnectionSucceeds(context, "google.com", 443); } public void testGoodPin() throws Exception { @@ -161,9 +118,9 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { 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); + = TestUtils.getSSLContext(new TestConfigSource(domainMap, getEmptyConfig())); + TestUtils.assertConnectionSucceeds(context, "android.com", 443); + TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443); } public void testOverridePins() throws Exception { @@ -180,8 +137,8 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { domainMap.add(new Pair<Domain, NetworkSecurityConfig>( new Domain("android.com", true), domain)); SSLContext context - = getSSLContext(new TestConfigSource(domainMap, getEmptyConfig())); - assertConnectionSucceeds(context, "android.com", 443); + = TestUtils.getSSLContext(new TestConfigSource(domainMap, getEmptyConfig())); + TestUtils.assertConnectionSucceeds(context, "android.com", 443); } public void testMostSpecificNetworkSecurityConfig() throws Exception { @@ -192,9 +149,9 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { 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); + = TestUtils.getSSLContext(new TestConfigSource(domainMap, getEmptyConfig())); + TestUtils.assertConnectionFails(context, "android.com", 443); + TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443); } public void testSubdomainIncluded() throws Exception { @@ -204,14 +161,14 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { 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); + = TestUtils.getSSLContext(new TestConfigSource(domainMap, getEmptyConfig())); + TestUtils.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); + context = TestUtils.getSSLContext(new TestConfigSource(domainMap, getEmptyConfig())); + TestUtils.assertConnectionFails(context, "developer.android.com", 443); } public void testConfigBuilderUsesParents() throws Exception { @@ -246,9 +203,9 @@ public class NetworkSecurityConfigTests extends ActivityUnitTestCase<Activity> { 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); + = TestUtils.getSSLContext(new TestConfigSource(domainMap, getEmptyConfig())); + TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443); + TestUtils.assertUrlConnectionSucceeds(context, "developer.android.com", 443); + TestUtils.assertUrlConnectionFails(context, "google.com", 443); } } diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java new file mode 100644 index 000000000000..43c0e5708233 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java @@ -0,0 +1,76 @@ +/* + * 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.net.Socket; +import java.net.URL; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.TrustManager; + +import junit.framework.Assert; + +public final class TestUtils extends Assert { + + private TestUtils() { + } + + public static 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) { + } + } + + public static void assertConnectionSucceeds(SSLContext context, String host, int port) + throws Exception { + Socket s = context.getSocketFactory().createSocket(host, port); + s.getInputStream(); + } + + public static 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. + } + } + + public static 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(); + } + + public static 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; + } +} diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java new file mode 100644 index 000000000000..4914d06e2311 --- /dev/null +++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java @@ -0,0 +1,284 @@ +/* + * 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.content.Context; +import android.test.AndroidTestCase; +import android.test.MoreAsserts; +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 XmlConfigTests extends AndroidTestCase { + + public void testEmptyConfigFile() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.empty_config); + ApplicationConfig appConfig = new ApplicationConfig(source); + assertFalse(appConfig.hasPerDomainConfigs()); + NetworkSecurityConfig config = appConfig.getConfigForHostname(""); + assertNotNull(config); + // Check defaults. + assertTrue(config.isCleartextTrafficPermitted()); + assertFalse(config.isHstsEnforced()); + assertFalse(config.getTrustAnchors().isEmpty()); + PinSet pinSet = config.getPins(); + assertTrue(pinSet.pins.isEmpty()); + // Try some connections. + SSLContext context = TestUtils.getSSLContext(source); + TestUtils.assertConnectionSucceeds(context, "android.com", 443); + TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443); + TestUtils.assertUrlConnectionSucceeds(context, "google.com", 443); + } + + public void testEmptyAnchors() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.empty_trust); + ApplicationConfig appConfig = new ApplicationConfig(source); + assertFalse(appConfig.hasPerDomainConfigs()); + NetworkSecurityConfig config = appConfig.getConfigForHostname(""); + assertNotNull(config); + // Check defaults. + assertTrue(config.isCleartextTrafficPermitted()); + assertFalse(config.isHstsEnforced()); + assertTrue(config.getTrustAnchors().isEmpty()); + PinSet pinSet = config.getPins(); + assertTrue(pinSet.pins.isEmpty()); + SSLContext context = TestUtils.getSSLContext(source); + TestUtils.assertConnectionFails(context, "android.com", 443); + TestUtils.assertConnectionFails(context, "developer.android.com", 443); + TestUtils.assertUrlConnectionFails(context, "google.com", 443); + } + + public void testBasicDomainConfig() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.domain1); + ApplicationConfig appConfig = new ApplicationConfig(source); + assertTrue(appConfig.hasPerDomainConfigs()); + NetworkSecurityConfig config = appConfig.getConfigForHostname(""); + assertNotNull(config); + // Check defaults. + assertTrue(config.isCleartextTrafficPermitted()); + assertFalse(config.isHstsEnforced()); + assertTrue(config.getTrustAnchors().isEmpty()); + PinSet pinSet = config.getPins(); + assertTrue(pinSet.pins.isEmpty()); + // Check android.com. + config = appConfig.getConfigForHostname("android.com"); + assertTrue(config.isCleartextTrafficPermitted()); + assertFalse(config.isHstsEnforced()); + assertFalse(config.getTrustAnchors().isEmpty()); + pinSet = config.getPins(); + assertTrue(pinSet.pins.isEmpty()); + // Try connections. + SSLContext context = TestUtils.getSSLContext(source); + TestUtils.assertConnectionSucceeds(context, "android.com", 443); + TestUtils.assertConnectionFails(context, "developer.android.com", 443); + TestUtils.assertUrlConnectionFails(context, "google.com", 443); + TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443); + } + + public void testBasicPinning() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.pins1); + ApplicationConfig appConfig = new ApplicationConfig(source); + assertTrue(appConfig.hasPerDomainConfigs()); + // Check android.com. + NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com"); + PinSet pinSet = config.getPins(); + assertFalse(pinSet.pins.isEmpty()); + // Try connections. + SSLContext context = TestUtils.getSSLContext(source); + TestUtils.assertConnectionSucceeds(context, "android.com", 443); + TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443); + TestUtils.assertConnectionSucceeds(context, "google.com", 443); + } + + public void testExpiredPin() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.expired_pin); + ApplicationConfig appConfig = new ApplicationConfig(source); + assertTrue(appConfig.hasPerDomainConfigs()); + // Check android.com. + NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com"); + PinSet pinSet = config.getPins(); + assertFalse(pinSet.pins.isEmpty()); + // Try connections. + SSLContext context = TestUtils.getSSLContext(source); + TestUtils.assertConnectionSucceeds(context, "android.com", 443); + TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443); + } + + public void testOverridesPins() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.override_pins); + ApplicationConfig appConfig = new ApplicationConfig(source); + assertTrue(appConfig.hasPerDomainConfigs()); + // Check android.com. + NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com"); + PinSet pinSet = config.getPins(); + assertFalse(pinSet.pins.isEmpty()); + // Try connections. + SSLContext context = TestUtils.getSSLContext(source); + TestUtils.assertConnectionSucceeds(context, "android.com", 443); + TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443); + } + + public void testBadPin() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.bad_pin); + ApplicationConfig appConfig = new ApplicationConfig(source); + assertTrue(appConfig.hasPerDomainConfigs()); + // Check android.com. + NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com"); + PinSet pinSet = config.getPins(); + assertFalse(pinSet.pins.isEmpty()); + // Try connections. + SSLContext context = TestUtils.getSSLContext(source); + TestUtils.assertConnectionFails(context, "android.com", 443); + TestUtils.assertUrlConnectionFails(context, "android.com", 443); + TestUtils.assertConnectionSucceeds(context, "google.com", 443); + } + + public void testMultipleDomains() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.multiple_domains); + ApplicationConfig appConfig = new ApplicationConfig(source); + assertTrue(appConfig.hasPerDomainConfigs()); + NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com"); + assertTrue(config.isCleartextTrafficPermitted()); + assertFalse(config.isHstsEnforced()); + assertFalse(config.getTrustAnchors().isEmpty()); + PinSet pinSet = config.getPins(); + assertTrue(pinSet.pins.isEmpty()); + // Both android.com and google.com should use the same config + NetworkSecurityConfig other = appConfig.getConfigForHostname("google.com"); + assertEquals(config, other); + // Try connections. + SSLContext context = TestUtils.getSSLContext(source); + TestUtils.assertConnectionSucceeds(context, "android.com", 443); + TestUtils.assertConnectionSucceeds(context, "google.com", 443); + TestUtils.assertConnectionFails(context, "developer.android.com", 443); + TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443); + } + + public void testMultipleDomainConfigs() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.multiple_configs); + ApplicationConfig appConfig = new ApplicationConfig(source); + assertTrue(appConfig.hasPerDomainConfigs()); + // Should be two different config objects + NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com"); + NetworkSecurityConfig other = appConfig.getConfigForHostname("google.com"); + MoreAsserts.assertNotEqual(config, other); + // Try connections. + SSLContext context = TestUtils.getSSLContext(source); + TestUtils.assertConnectionSucceeds(context, "android.com", 443); + TestUtils.assertConnectionSucceeds(context, "google.com", 443); + TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443); + } + + public void testIncludeSubdomains() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.subdomains); + ApplicationConfig appConfig = new ApplicationConfig(source); + assertTrue(appConfig.hasPerDomainConfigs()); + // Try connections. + SSLContext context = TestUtils.getSSLContext(source); + TestUtils.assertConnectionSucceeds(context, "android.com", 443); + TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443); + TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443); + TestUtils.assertUrlConnectionSucceeds(context, "developer.android.com", 443); + TestUtils.assertConnectionFails(context, "google.com", 443); + } + + public void testAttributes() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.attributes); + ApplicationConfig appConfig = new ApplicationConfig(source); + assertFalse(appConfig.hasPerDomainConfigs()); + NetworkSecurityConfig config = appConfig.getConfigForHostname(""); + assertTrue(config.isHstsEnforced()); + assertFalse(config.isCleartextTrafficPermitted()); + } + + public void testResourcePemCertificateSource() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.resource_anchors_pem); + ApplicationConfig appConfig = new ApplicationConfig(source); + // Check android.com. + NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com"); + assertTrue(config.isCleartextTrafficPermitted()); + assertFalse(config.isHstsEnforced()); + assertEquals(2, config.getTrustAnchors().size()); + // Try connections. + SSLContext context = TestUtils.getSSLContext(source); + TestUtils.assertConnectionSucceeds(context, "android.com", 443); + TestUtils.assertConnectionFails(context, "developer.android.com", 443); + TestUtils.assertUrlConnectionFails(context, "google.com", 443); + TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443); + } + + public void testResourceDerCertificateSource() throws Exception { + XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.resource_anchors_der); + ApplicationConfig appConfig = new ApplicationConfig(source); + // Check android.com. + NetworkSecurityConfig config = appConfig.getConfigForHostname("android.com"); + assertTrue(config.isCleartextTrafficPermitted()); + assertFalse(config.isHstsEnforced()); + assertEquals(2, config.getTrustAnchors().size()); + // Try connections. + SSLContext context = TestUtils.getSSLContext(source); + TestUtils.assertConnectionSucceeds(context, "android.com", 443); + TestUtils.assertConnectionFails(context, "developer.android.com", 443); + TestUtils.assertUrlConnectionFails(context, "google.com", 443); + TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443); + } + + private void testBadConfig(int configId) throws Exception { + try { + XmlConfigSource source = new XmlConfigSource(getContext(), configId); + ApplicationConfig appConfig = new ApplicationConfig(source); + appConfig.getConfigForHostname("android.com"); + fail("Bad config " + getContext().getResources().getResourceName(configId) + + " did not fail to parse"); + } catch (RuntimeException e) { + MoreAsserts.assertAssignableFrom(XmlConfigSource.ParserException.class, + e.getCause()); + } + } + + public void testBadConfig0() throws Exception { + testBadConfig(R.xml.bad_config0); + } + + public void testBadConfig1() throws Exception { + testBadConfig(R.xml.bad_config1); + } + + public void testBadConfig2() throws Exception { + testBadConfig(R.xml.bad_config2); + } + + public void testBadConfig3() throws Exception { + testBadConfig(R.xml.bad_config3); + } + + public void testBadConfig4() throws Exception { + testBadConfig(R.xml.bad_config4); + } + + public void testBadConfig5() throws Exception { + testBadConfig(R.xml.bad_config4); + } +} |