From 5f96702f582050c1598136ed2a748f76b981c94e Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Wed, 4 Nov 2015 23:55:29 -0800 Subject: 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 --- .../NetworkSecurityConfigTest/AndroidManifest.xml | 4 +- .../res/raw/ca_certs_der.der | Bin 0 -> 1473 bytes .../res/raw/ca_certs_pem.pem | 35 +++ .../res/xml/attributes.xml | 5 + .../res/xml/bad_config0.xml | 10 + .../res/xml/bad_config1.xml | 10 + .../res/xml/bad_config2.xml | 10 + .../res/xml/bad_config3.xml | 10 + .../res/xml/bad_config4.xml | 7 + .../res/xml/bad_config5.xml | 8 + .../NetworkSecurityConfigTest/res/xml/bad_pin.xml | 9 + .../NetworkSecurityConfigTest/res/xml/domain1.xml | 14 + .../res/xml/empty_config.xml | 3 + .../res/xml/empty_trust.xml | 7 + .../res/xml/expired_pin.xml | 10 + .../res/xml/multiple_configs.xml | 21 ++ .../res/xml/multiple_domains.xml | 15 ++ .../res/xml/override_pins.xml | 12 + tests/NetworkSecurityConfigTest/res/xml/pins1.xml | 9 + .../res/xml/resource_anchors_der.xml | 13 + .../res/xml/resource_anchors_pem.xml | 13 + .../res/xml/subdomains.xml | 14 + .../net/config/NetworkSecurityConfigTests.java | 91 ++----- .../src/android/security/net/config/TestUtils.java | 76 ++++++ .../security/net/config/XmlConfigTests.java | 284 +++++++++++++++++++++ 25 files changed, 621 insertions(+), 69 deletions(-) create mode 100644 tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der create mode 100644 tests/NetworkSecurityConfigTest/res/raw/ca_certs_pem.pem create mode 100644 tests/NetworkSecurityConfigTest/res/xml/attributes.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/bad_config0.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/bad_config1.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/bad_config2.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/bad_config3.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/bad_config4.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/bad_config5.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/bad_pin.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/domain1.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/empty_config.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/empty_trust.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/expired_pin.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/multiple_configs.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/multiple_domains.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/override_pins.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/pins1.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/resource_anchors_der.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/resource_anchors_pem.xml create mode 100644 tests/NetworkSecurityConfigTest/res/xml/subdomains.xml create mode 100644 tests/NetworkSecurityConfigTest/src/android/security/net/config/TestUtils.java create mode 100644 tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java (limited to 'tests/NetworkSecurityConfigTest') 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 @@ --> @@ -23,7 +23,7 @@ diff --git a/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der new file mode 100644 index 000000000000..235bd4797b78 Binary files /dev/null and b/tests/NetworkSecurityConfigTest/res/raw/ca_certs_der.der differ 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 @@ + + + + + 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 @@ + + + + android.com + + + 1HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y= + + + 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 @@ + + + + android.com + + + 1HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y= + + + 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 @@ + + + + android.com + + + + + + 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 @@ + + + + android.com + + + + android.com + + 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 @@ + + + + + android.com + + 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 @@ + + + + + + + + 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 @@ + + + + android.com + + 1HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y= + + + 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 @@ + + + + + + + + android.com + + + + + + 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 @@ + + + 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 @@ + + + + + + + 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 @@ + + + + android.com + + + aaaaaaaaaaa2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y= + + + 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 @@ + + + + + + + + android.com + + + + + + + google.com + + + + + + 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 @@ + + + + + + + + android.com + google.com + + + + + + 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 @@ + + + + android.com + + aaaaaaaaIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y= + + + + + + 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 @@ + + + + android.com + + 7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y= + + + 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 @@ + + + + + + + + android.com + + + + + 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 @@ + + + + + + + + android.com + + + + + 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 @@ + + + + + + + + android.com + + + + + + 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 { 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 { = new ArraySet>(); 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 { domainMap.add(new Pair( 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 { domainMap.add(new Pair( 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 { domainMap.add(new Pair( 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 { domainMap.add(new Pair( 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 { domainMap.add(new Pair( 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 { domainMap.add(new Pair( 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>(); domainMap.add(new Pair( 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 { domainMap.add(new Pair( 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); + } +} -- cgit v1.2.3-59-g8ed1b