diff options
Diffstat (limited to 'luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java')
-rw-r--r-- | luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java | 376 |
1 files changed, 319 insertions, 57 deletions
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java index 900d950..dccadbd 100644 --- a/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java +++ b/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java @@ -16,17 +16,39 @@ package libcore.javax.net.ssl; +import java.security.InvalidAlgorithmParameterException; import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; import java.security.Provider; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import libcore.io.IoUtils; import libcore.java.security.StandardNames; import javax.net.ServerSocketFactory; import javax.net.SocketFactory; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.KeyManagerFactorySpi; +import javax.net.ssl.ManagerFactoryParameters; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.TrustManagerFactorySpi; +import javax.net.ssl.X509KeyManager; +import junit.framework.AssertionFailedError; import junit.framework.TestCase; public class SSLContextTest extends TestCase { @@ -59,6 +81,106 @@ public class SSLContextTest extends TestCase { SSLContext.setDefault(defaultContext); } + public void test_SSLContext_defaultConfiguration() throws Exception { + SSLDefaultConfigurationAsserts.assertSSLContext(SSLContext.getDefault()); + + for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) { + SSLContext sslContext = SSLContext.getInstance(protocol); + if (!protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) { + sslContext.init(null, null, null); + } + SSLDefaultConfigurationAsserts.assertSSLContext(sslContext); + } + } + + public void test_SSLContext_pskOnlyConfiguration_defaultProviderOnly() throws Exception { + // Test the scenario where only a PSKKeyManager is provided and no TrustManagers are + // provided. + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init( + new KeyManager[] { + PSKKeyManagerProxy.getConscryptPSKKeyManager(new PSKKeyManagerProxy()) + }, + new TrustManager[0], + null); + List<String> expectedCipherSuites = + new ArrayList<String>(StandardNames.CIPHER_SUITES_DEFAULT_PSK); + expectedCipherSuites.add(StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION); + assertEnabledCipherSuites(expectedCipherSuites, sslContext); + } + + public void test_SSLContext_x509AndPskConfiguration_defaultProviderOnly() throws Exception { + // Test the scenario where an X509TrustManager and PSKKeyManager are provided. + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init( + new KeyManager[] { + PSKKeyManagerProxy.getConscryptPSKKeyManager(new PSKKeyManagerProxy()) + }, + null, // Use default trust managers, one of which is an X.509 one. + null); + List<String> expectedCipherSuites = + new ArrayList<String>(StandardNames.CIPHER_SUITES_DEFAULT_PSK); + expectedCipherSuites.addAll(StandardNames.CIPHER_SUITES_DEFAULT); + assertEnabledCipherSuites(expectedCipherSuites, sslContext); + + // Test the scenario where an X509KeyManager and PSKKeyManager are provided. + sslContext = SSLContext.getInstance("TLS"); + // Just an arbitrary X509KeyManager -- it won't be invoked in this test. + X509KeyManager x509KeyManager = new RandomPrivateKeyX509ExtendedKeyManager(null); + sslContext.init( + new KeyManager[] { + x509KeyManager, + PSKKeyManagerProxy.getConscryptPSKKeyManager(new PSKKeyManagerProxy()) + }, + new TrustManager[0], + null); + assertEnabledCipherSuites(expectedCipherSuites, sslContext); + } + + public void test_SSLContext_emptyConfiguration_defaultProviderOnly() throws Exception { + // Test the scenario where neither X.509 nor PSK KeyManagers or TrustManagers are provided. + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init( + new KeyManager[0], + new TrustManager[0], + null); + assertEnabledCipherSuites( + Arrays.asList(StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION), + sslContext); + } + + private static void assertEnabledCipherSuites( + List<String> expectedCipherSuites, SSLContext sslContext) throws Exception { + assertContentsInOrder( + expectedCipherSuites, sslContext.createSSLEngine().getEnabledCipherSuites()); + assertContentsInOrder( + expectedCipherSuites, + sslContext.createSSLEngine().getSSLParameters().getCipherSuites()); + assertContentsInOrder( + expectedCipherSuites, sslContext.getSocketFactory().getDefaultCipherSuites()); + assertContentsInOrder( + expectedCipherSuites, sslContext.getServerSocketFactory().getDefaultCipherSuites()); + + SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(); + try { + assertContentsInOrder( + expectedCipherSuites, sslSocket.getEnabledCipherSuites()); + assertContentsInOrder( + expectedCipherSuites, sslSocket.getSSLParameters().getCipherSuites()); + } finally { + IoUtils.closeQuietly(sslSocket); + } + + SSLServerSocket sslServerSocket = + (SSLServerSocket) sslContext.getServerSocketFactory().createServerSocket(); + try { + assertContentsInOrder( + expectedCipherSuites, sslServerSocket.getEnabledCipherSuites()); + } finally { + IoUtils.closeQuietly(sslSocket); + } + } + public void test_SSLContext_getInstance() throws Exception { try { SSLContext.getInstance(null); @@ -109,16 +231,183 @@ public class SSLContextTest extends TestCase { assertEquals(StandardNames.JSSE_PROVIDER_NAME, provider.getName()); } - public void test_SSLContext_init() throws Exception { + public void test_SSLContext_init_Default() throws Exception { + // Assert that initializing a default SSLContext fails because it's supposed to be + // initialized already. + SSLContext sslContext = SSLContext.getInstance(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT); + try { + sslContext.init(null, null, null); + fail(); + } catch (KeyManagementException expected) {} + try { + sslContext.init(new KeyManager[0], new TrustManager[0], null); + fail(); + } catch (KeyManagementException expected) {} + try { + sslContext.init( + new KeyManager[] {new KeyManager() {}}, + new TrustManager[] {new TrustManager() {}}, + null); + fail(); + } catch (KeyManagementException expected) {} + } + + public void test_SSLContext_init_withNullManagerArrays() throws Exception { + // Assert that SSLContext.init works fine even when provided with null arrays of + // KeyManagers and TrustManagers. + // The contract of SSLContext.init is that it will for default X.509 KeyManager and + // TrustManager from the highest priority KeyManagerFactory and TrustManagerFactory. for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) { - SSLContext sslContext = SSLContext.getInstance(protocol); if (protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) { - try { - sslContext.init(null, null, null); - } catch (KeyManagementException expected) { + // Default SSLContext is provided in an already initialized state + continue; + } + SSLContext sslContext = SSLContext.getInstance(protocol); + sslContext.init(null, null, null); + } + } + + public void test_SSLContext_init_withEmptyManagerArrays() throws Exception { + // Assert that SSLContext.init works fine even when provided with empty arrays of + // KeyManagers and TrustManagers. + // The contract of SSLContext.init is that it will not look for default X.509 KeyManager and + // TrustManager. + // This test thus installs a Provider of KeyManagerFactory and TrustManagerFactory whose + // factories throw exceptions which will make this test fail if the factories are used. + Provider provider = new ThrowExceptionKeyAndTrustManagerFactoryProvider(); + invokeWithHighestPrioritySecurityProvider(provider, new Callable<Void>() { + @Override + public Void call() throws Exception { + assertEquals( + ThrowExceptionKeyAndTrustManagerFactoryProvider.class, + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) + .getProvider().getClass()); + assertEquals( + ThrowExceptionKeyAndTrustManagerFactoryProvider.class, + KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()) + .getProvider().getClass()); + + KeyManager[] keyManagers = new KeyManager[0]; + TrustManager[] trustManagers = new TrustManager[0]; + for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) { + if (protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) { + // Default SSLContext is provided in an already initialized state + continue; + } + SSLContext sslContext = SSLContext.getInstance(protocol); + sslContext.init(keyManagers, trustManagers, null); } - } else { - sslContext.init(null, null, null); + + return null; + } + }); + } + + public void test_SSLContext_init_withoutX509() throws Exception { + // Assert that SSLContext.init works fine even when provided with KeyManagers and + // TrustManagers which don't include the X.509 ones. + // The contract of SSLContext.init is that it will not look for default X.509 KeyManager and + // TrustManager. + // This test thus installs a Provider of KeyManagerFactory and TrustManagerFactory whose + // factories throw exceptions which will make this test fail if the factories are used. + Provider provider = new ThrowExceptionKeyAndTrustManagerFactoryProvider(); + invokeWithHighestPrioritySecurityProvider(provider, new Callable<Void>() { + @Override + public Void call() throws Exception { + assertEquals( + ThrowExceptionKeyAndTrustManagerFactoryProvider.class, + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) + .getProvider().getClass()); + assertEquals( + ThrowExceptionKeyAndTrustManagerFactoryProvider.class, + KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()) + .getProvider().getClass()); + + KeyManager[] keyManagers = new KeyManager[] {new KeyManager() {}}; + TrustManager[] trustManagers = new TrustManager[] {new TrustManager() {}}; + for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) { + if (protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) { + // Default SSLContext is provided in an already initialized state + continue; + } + SSLContext sslContext = SSLContext.getInstance(protocol); + sslContext.init(keyManagers, trustManagers, null); + } + + return null; + } + }); + } + + public static class ThrowExceptionKeyAndTrustManagerFactoryProvider extends Provider { + public ThrowExceptionKeyAndTrustManagerFactoryProvider() { + super("ThrowExceptionKeyAndTrustManagerProvider", + 1.0, + "SSLContextTest fake KeyManagerFactory and TrustManagerFactory provider"); + + put("TrustManagerFactory." + TrustManagerFactory.getDefaultAlgorithm(), + ThrowExceptionTrustManagagerFactorySpi.class.getName()); + put("TrustManagerFactory.PKIX", ThrowExceptionTrustManagagerFactorySpi.class.getName()); + + put("KeyManagerFactory." + KeyManagerFactory.getDefaultAlgorithm(), + ThrowExceptionKeyManagagerFactorySpi.class.getName()); + put("KeyManagerFactory.PKIX", ThrowExceptionKeyManagagerFactorySpi.class.getName()); + } + } + + public static class ThrowExceptionTrustManagagerFactorySpi extends TrustManagerFactorySpi { + @Override + protected void engineInit(KeyStore ks) throws KeyStoreException { + fail(); + } + + @Override + protected void engineInit(ManagerFactoryParameters spec) + throws InvalidAlgorithmParameterException { + fail(); + } + + @Override + protected TrustManager[] engineGetTrustManagers() { + throw new AssertionFailedError(); + } + } + + public static class ThrowExceptionKeyManagagerFactorySpi extends KeyManagerFactorySpi { + @Override + protected void engineInit(KeyStore ks, char[] password) throws KeyStoreException, + NoSuchAlgorithmException, UnrecoverableKeyException { + fail(); + } + + @Override + protected void engineInit(ManagerFactoryParameters spec) + throws InvalidAlgorithmParameterException { + fail(); + } + + @Override + protected KeyManager[] engineGetKeyManagers() { + throw new AssertionFailedError(); + } + } + + /** + * Installs the specified security provider as the highest provider, invokes the provided + * {@link Callable}, and removes the provider. + * + * @return result returned by the {@code callable}. + */ + private static <T> T invokeWithHighestPrioritySecurityProvider( + Provider provider, Callable<T> callable) throws Exception { + int providerPosition = -1; + try { + providerPosition = Security.insertProviderAt(provider, 1); + assertEquals(1, providerPosition); + return callable.call(); + } finally { + if (providerPosition != -1) { + Security.removeProvider(provider.getName()); } } } @@ -244,53 +533,6 @@ public class SSLContextTest extends TestCase { } } - public void test_SSLContext_getDefaultSSLParameters() throws Exception { - for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) { - SSLContext sslContext = SSLContext.getInstance(protocol); - if (!protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) { - sslContext.init(null, null, null); - } - - SSLParameters p = sslContext.getDefaultSSLParameters(); - assertNotNull(p); - - String[] cipherSuites = p.getCipherSuites(); - assertNotNull(cipherSuites); - StandardNames.assertValidCipherSuites(StandardNames.CIPHER_SUITES, cipherSuites); - - String[] protocols = p.getProtocols(); - assertNotNull(protocols); - StandardNames.assertValidCipherSuites(StandardNames.SSL_SOCKET_PROTOCOLS, protocols); - - assertFalse(p.getWantClientAuth()); - assertFalse(p.getNeedClientAuth()); - } - } - - public void test_SSLContext_getSupportedSSLParameters() throws Exception { - for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) { - SSLContext sslContext = SSLContext.getInstance(protocol); - if (!protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) { - sslContext.init(null, null, null); - } - - SSLParameters p = sslContext.getSupportedSSLParameters(); - assertNotNull(p); - - String[] cipherSuites = p.getCipherSuites(); - assertNotNull(cipherSuites); - StandardNames.assertSupportedCipherSuites(StandardNames.CIPHER_SUITES, cipherSuites); - - String[] protocols = p.getProtocols(); - assertNotNull(protocols); - StandardNames.assertSupportedProtocols(StandardNames.SSL_SOCKET_PROTOCOLS, - protocols); - - assertFalse(p.getWantClientAuth()); - assertFalse(p.getNeedClientAuth()); - } - } - public void test_SSLContextTest_TestSSLContext_create() { TestSSLContext testContext = TestSSLContext.create(); assertNotNull(testContext); @@ -298,8 +540,16 @@ public class SSLContextTest extends TestCase { assertNull(testContext.clientStorePassword); assertNotNull(testContext.serverKeyStore); assertEquals(StandardNames.IS_RI, testContext.serverStorePassword != null); - assertNotNull(testContext.clientKeyManager); - assertNotNull(testContext.serverKeyManager); + assertNotNull(testContext.clientKeyManagers); + assertNotNull(testContext.serverKeyManagers); + if (testContext.clientKeyManagers.length == 0) { + fail("No client KeyManagers"); + } + if (testContext.serverKeyManagers.length == 0) { + fail("No server KeyManagers"); + } + assertNotNull(testContext.clientKeyManagers[0]); + assertNotNull(testContext.serverKeyManagers[0]); assertNotNull(testContext.clientTrustManager); assertNotNull(testContext.serverTrustManager); assertNotNull(testContext.clientContext); @@ -309,4 +559,16 @@ public class SSLContextTest extends TestCase { assertTrue(testContext.port != 0); testContext.close(); } + + private static void assertContentsInOrder(List<String> expected, String... actual) { + if (expected.size() != actual.length) { + fail("Unexpected length. Expected len <" + expected.size() + + ">, actual len <" + actual.length + ">, expected <" + expected + + ">, actual <" + Arrays.asList(actual) + ">"); + } + if (!expected.equals(Arrays.asList(actual))) { + fail("Unexpected element(s). Expected <" + expected + + ">, actual <" + Arrays.asList(actual) + ">" ); + } + } } |