blob: d9a7b4fadc895af09bb46b8a69c668a3fd8267e2 [file] [log] [blame]
/*
* Copyright (C) 2010 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 libcore.javax.net.ssl;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509ExtendedKeyManager;
import junit.framework.TestCase;
import libcore.java.security.StandardNames;
import libcore.java.security.TestKeyStore;
public class SSLEngineTest extends TestCase {
public void assertConnected(TestSSLEnginePair e) {
assertConnected(e.client, e.server);
}
public void assertNotConnected(TestSSLEnginePair e) {
assertNotConnected(e.client, e.server);
}
public void assertConnected(SSLEngine a, SSLEngine b) {
assertTrue(connected(a, b));
}
public void assertNotConnected(SSLEngine a, SSLEngine b) {
assertFalse(connected(a, b));
}
public boolean connected(SSLEngine a, SSLEngine b) {
return (a.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING
&& b.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING
&& a.getSession() != null
&& b.getSession() != null
&& !a.isInboundDone()
&& !b.isInboundDone()
&& !a.isOutboundDone()
&& !b.isOutboundDone());
}
public void test_SSLEngine_defaultConfiguration() throws Exception {
SSLConfigurationAsserts.assertSSLEngineDefaultConfiguration(
TestSSLContext.create().clientContext.createSSLEngine());
}
public void test_SSLEngine_getSupportedCipherSuites_returnsCopies() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
assertNotSame(e.getSupportedCipherSuites(), e.getSupportedCipherSuites());
c.close();
}
public void test_SSLEngine_getSupportedCipherSuites_connect() throws Exception {
// note the rare usage of non-RSA keys
TestKeyStore testKeyStore = new TestKeyStore.Builder()
.keyAlgorithms("RSA", "DSA", "EC", "EC_RSA")
.aliasPrefix("rsa-dsa-ec")
.ca(true)
.build();
test_SSLEngine_getSupportedCipherSuites_connect(testKeyStore, false);
test_SSLEngine_getSupportedCipherSuites_connect(testKeyStore, true);
}
// http://b/18554122
public void test_SSLEngine_underflowsOnEmptyBuffersDuringHandshake() throws Exception {
final SSLEngine sslEngine = SSLContext.getDefault().createSSLEngine();
sslEngine.setUseClientMode(false);
ByteBuffer input = ByteBuffer.allocate(1024);
input.flip();
ByteBuffer output = ByteBuffer.allocate(1024);
sslEngine.beginHandshake();
assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP, sslEngine.getHandshakeStatus());
SSLEngineResult result = sslEngine.unwrap(input, output);
assertEquals(SSLEngineResult.Status.BUFFER_UNDERFLOW, result.getStatus());
assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP, result.getHandshakeStatus());
}
// http://b/18554122
public void test_SSLEngine_underflowsOnEmptyBuffersAfterHandshake() throws Exception {
// Note that create performs the handshake.
final TestSSLEnginePair engines = TestSSLEnginePair.create(null /* hooks */);
ByteBuffer input = ByteBuffer.allocate(1024);
input.flip();
ByteBuffer output = ByteBuffer.allocate(1024);
assertEquals(SSLEngineResult.Status.BUFFER_UNDERFLOW,
engines.client.unwrap(input, output).getStatus());
}
private void test_SSLEngine_getSupportedCipherSuites_connect(TestKeyStore testKeyStore,
boolean secureRenegotiation)
throws Exception {
KeyManager pskKeyManager = PSKKeyManagerProxy.getConscryptPSKKeyManager(
new PSKKeyManagerProxy() {
@Override
protected SecretKey getKey(String identityHint, String identity, SSLEngine engine) {
return new SecretKeySpec("Just an arbitrary key".getBytes(UTF_8), "RAW");
}
});
TestSSLContext c = TestSSLContext.createWithAdditionalKeyManagers(
testKeyStore, testKeyStore,
new KeyManager[] {pskKeyManager}, new KeyManager[] {pskKeyManager});
// Create a TestSSLContext where the KeyManager returns wrong (randomly generated) private
// keys, matching the algorithm and parameters of the correct keys.
// I couldn't find a more elegant way to achieve this other than temporarily replacing the
// first X509ExtendedKeyManager element of TestKeyStore.keyManagers while invoking
// TestSSLContext.create.
TestSSLContext cWithWrongPrivateKeys;
{
// Create a RandomPrivateKeyX509ExtendedKeyManager based on the first
// X509ExtendedKeyManager in c.serverKeyManagers.
KeyManager randomPrivateKeyX509ExtendedKeyManager = null;
for (KeyManager keyManager : c.serverKeyManagers) {
if (keyManager instanceof X509ExtendedKeyManager) {
randomPrivateKeyX509ExtendedKeyManager =
new RandomPrivateKeyX509ExtendedKeyManager((X509ExtendedKeyManager) keyManager);
break;
}
}
if (randomPrivateKeyX509ExtendedKeyManager == null) {
fail("No X509ExtendedKeyManager in c.serverKeyManagers");
}
// Find the first X509ExtendedKeyManager in testKeyStore.keyManagers
int replaceIndex = -1;
for (int i = 0; i < testKeyStore.keyManagers.length; i++) {
KeyManager keyManager = testKeyStore.keyManagers[i];
if (keyManager instanceof X509ExtendedKeyManager) {
replaceIndex = i;
break;
}
}
if (replaceIndex == -1) {
fail("No X509ExtendedKeyManager in testKeyStore.keyManagers");
}
// Temporarily substitute the RandomPrivateKeyX509ExtendedKeyManager in place of the
// original X509ExtendedKeyManager.
KeyManager originalKeyManager = testKeyStore.keyManagers[replaceIndex];
testKeyStore.keyManagers[replaceIndex] = randomPrivateKeyX509ExtendedKeyManager;
cWithWrongPrivateKeys = TestSSLContext.create(testKeyStore, testKeyStore);
testKeyStore.keyManagers[replaceIndex] = originalKeyManager;
}
// To catch all the errors.
StringBuilder error = new StringBuilder();
String[] cipherSuites = c.clientContext.createSSLEngine().getSupportedCipherSuites();
for (String cipherSuite : cipherSuites) {
try {
// Skip cipher suites that are obsoleted.
if (StandardNames.IS_RI && "TLSv1.2".equals(c.clientContext.getProtocol())
&& StandardNames.CIPHER_SUITES_OBSOLETE_TLS12.contains(cipherSuite)) {
continue;
}
/*
* Signaling Cipher Suite Values (SCSV) cannot be used on their own, but instead in
* conjunction with other cipher suites.
*/
if (cipherSuite.equals(StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION)
|| cipherSuite.equals(StandardNames.CIPHER_SUITE_FALLBACK)) {
continue;
}
/*
* Kerberos cipher suites require external setup. See "Kerberos Requirements" in
* https://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html
* #KRBRequire
*/
if (cipherSuite.startsWith("TLS_KRB5_")) {
continue;
}
final String[] cipherSuiteArray
= (secureRenegotiation
? new String[] { cipherSuite,
StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION }
: new String[] { cipherSuite });
// Check that handshake succeeds.
TestSSLEnginePair pair = null;
try {
pair = TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
client.setEnabledCipherSuites(cipherSuiteArray);
server.setEnabledCipherSuites(cipherSuiteArray);
}
});
assertConnected(pair);
boolean needsRecordSplit =
"TLS".equalsIgnoreCase(c.clientContext.getProtocol())
&& cipherSuite.contains("_CBC_");
assertSendsCorrectly("This is the client. Hello!".getBytes(UTF_8),
pair.client, pair.server, needsRecordSplit);
assertSendsCorrectly("This is the server. Hi!".getBytes(UTF_8),
pair.server, pair.client, needsRecordSplit);
} finally {
if (pair != null) {
pair.close();
}
}
// Check that handshake fails when the server does not possess the private key
// corresponding to the server's certificate. This is achieved by using SSLContext
// cWithWrongPrivateKeys whose KeyManager returns wrong private keys that match
// the algorithm (and parameters) of the correct keys.
boolean serverAuthenticatedUsingPublicKey = true;
if (cipherSuite.contains("_anon_")) {
serverAuthenticatedUsingPublicKey = false;
} else if ((cipherSuite.startsWith("TLS_PSK_"))
|| (cipherSuite.startsWith("TLS_ECDHE_PSK_"))) {
serverAuthenticatedUsingPublicKey = false;
}
if (serverAuthenticatedUsingPublicKey) {
TestSSLEnginePair p = null;
try {
p = TestSSLEnginePair.create(
cWithWrongPrivateKeys, new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
client.setEnabledCipherSuites(cipherSuiteArray);
server.setEnabledCipherSuites(cipherSuiteArray);
}
});
assertNotConnected(p);
} catch (IOException expected) {
} finally {
if (p != null) {
p.close();
}
}
}
} catch (Exception e) {
String message = ("Problem trying to connect cipher suite " + cipherSuite);
System.out.println(message);
e.printStackTrace();
error.append(message);
error.append('\n');
}
}
c.close();
if (error.length() > 0) {
throw new Exception("One or more problems in "
+ "test_SSLEngine_getSupportedCipherSuites_connect:\n" + error);
}
}
private static void assertSendsCorrectly(final byte[] sourceBytes, SSLEngine source,
SSLEngine dest, boolean needsRecordSplit) throws SSLException {
ByteBuffer sourceOut = ByteBuffer.wrap(sourceBytes);
SSLSession sourceSession = source.getSession();
ByteBuffer sourceToDest = ByteBuffer.allocate(sourceSession.getPacketBufferSize());
SSLEngineResult sourceOutRes = source.wrap(sourceOut, sourceToDest);
sourceToDest.flip();
String sourceCipherSuite = source.getSession().getCipherSuite();
assertEquals(sourceCipherSuite, sourceBytes.length, sourceOutRes.bytesConsumed());
assertEquals(sourceCipherSuite, HandshakeStatus.NOT_HANDSHAKING,
sourceOutRes.getHandshakeStatus());
SSLSession destSession = dest.getSession();
ByteBuffer destIn = ByteBuffer.allocate(destSession.getApplicationBufferSize());
int numUnwrapCalls = 0;
while (destIn.position() != sourceOut.limit()) {
SSLEngineResult destRes = dest.unwrap(sourceToDest, destIn);
assertEquals(sourceCipherSuite, HandshakeStatus.NOT_HANDSHAKING,
destRes.getHandshakeStatus());
if (needsRecordSplit && numUnwrapCalls == 0) {
assertEquals(sourceCipherSuite, 1, destRes.bytesProduced());
}
numUnwrapCalls++;
}
destIn.flip();
byte[] actual = new byte[destIn.remaining()];
destIn.get(actual);
assertEquals(sourceCipherSuite, Arrays.toString(sourceBytes), Arrays.toString(actual));
if (needsRecordSplit) {
assertEquals(sourceCipherSuite, 2, numUnwrapCalls);
} else {
assertEquals(sourceCipherSuite, 1, numUnwrapCalls);
}
}
public void test_SSLEngine_getEnabledCipherSuites_returnsCopies() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
assertNotSame(e.getEnabledCipherSuites(), e.getEnabledCipherSuites());
c.close();
}
public void test_SSLEngine_setEnabledCipherSuites_storesCopy() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
String[] array = new String[] {e.getEnabledCipherSuites()[0]};
String originalFirstElement = array[0];
e.setEnabledCipherSuites(array);
array[0] = "Modified after having been set";
assertEquals(originalFirstElement, e.getEnabledCipherSuites()[0]);
}
public void test_SSLEngine_setEnabledCipherSuites() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
try {
e.setEnabledCipherSuites(null);
fail();
} catch (IllegalArgumentException expected) {
}
try {
e.setEnabledCipherSuites(new String[1]);
fail();
} catch (IllegalArgumentException expected) {
}
try {
e.setEnabledCipherSuites(new String[] { "Bogus" } );
fail();
} catch (IllegalArgumentException expected) {
}
e.setEnabledCipherSuites(new String[0]);
e.setEnabledCipherSuites(e.getEnabledCipherSuites());
e.setEnabledCipherSuites(e.getSupportedCipherSuites());
// Check that setEnabledCipherSuites affects getEnabledCipherSuites
String[] cipherSuites = new String[] { e.getSupportedCipherSuites()[0] };
e.setEnabledCipherSuites(cipherSuites);
assertEquals(Arrays.asList(cipherSuites), Arrays.asList(e.getEnabledCipherSuites()));
c.close();
}
public void test_SSLEngine_getSupportedProtocols_returnsCopies() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
assertNotSame(e.getSupportedProtocols(), e.getSupportedProtocols());
c.close();
}
public void test_SSLEngine_getEnabledProtocols_returnsCopies() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
assertNotSame(e.getEnabledProtocols(), e.getEnabledProtocols());
c.close();
}
public void test_SSLEngine_setEnabledProtocols_storesCopy() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
String[] array = new String[] {e.getEnabledProtocols()[0]};
String originalFirstElement = array[0];
e.setEnabledProtocols(array);
array[0] = "Modified after having been set";
assertEquals(originalFirstElement, e.getEnabledProtocols()[0]);
}
public void test_SSLEngine_setEnabledProtocols() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
try {
e.setEnabledProtocols(null);
fail();
} catch (IllegalArgumentException expected) {
}
try {
e.setEnabledProtocols(new String[1]);
fail();
} catch (IllegalArgumentException expected) {
}
try {
e.setEnabledProtocols(new String[] { "Bogus" } );
fail();
} catch (IllegalArgumentException expected) {
}
e.setEnabledProtocols(new String[0]);
e.setEnabledProtocols(e.getEnabledProtocols());
e.setEnabledProtocols(e.getSupportedProtocols());
// Check that setEnabledProtocols affects getEnabledProtocols
for (String protocol : e.getSupportedProtocols()) {
if ("SSLv2Hello".equals(protocol)) {
try {
e.setEnabledProtocols(new String[] { protocol });
fail("Should fail when SSLv2Hello is set by itself");
} catch (IllegalArgumentException expected) {}
} else {
String[] protocols = new String[] { protocol };
e.setEnabledProtocols(protocols);
assertEquals(Arrays.deepToString(protocols),
Arrays.deepToString(e.getEnabledProtocols()));
}
}
c.close();
}
public void test_SSLEngine_getSession() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
SSLSession session = e.getSession();
assertNotNull(session);
assertFalse(session.isValid());
c.close();
}
public void test_SSLEngine_beginHandshake() throws Exception {
TestSSLContext c = TestSSLContext.create();
try {
c.clientContext.createSSLEngine().beginHandshake();
fail();
} catch (IllegalStateException expected) {
}
c.close();
TestSSLEnginePair p = TestSSLEnginePair.create(null);
assertConnected(p);
p.close();
}
public void test_SSLEngine_beginHandshake_noKeyStore() throws Exception {
TestSSLContext c = TestSSLContext.create(null, null, null, null, null, null, null, null,
SSLContext.getDefault(), SSLContext.getDefault());
SSLEngine[] p = null;
try {
// TODO Fix KnownFailure AlertException "NO SERVER CERTIFICATE FOUND"
// ServerHandshakeImpl.selectSuite should not select a suite without a required cert
p = TestSSLEnginePair.connect(c, null);
fail();
} catch (SSLHandshakeException expected) {
} finally {
if (p != null) {
TestSSLEnginePair.close(p);
}
}
c.close();
}
public void test_SSLEngine_beginHandshake_noClientCertificate() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine[] engines = TestSSLEnginePair.connect(c, null);
assertConnected(engines[0], engines[1]);
c.close();
TestSSLEnginePair.close(engines);
}
public void test_SSLEngine_getUseClientMode() throws Exception {
TestSSLContext c = TestSSLContext.create();
assertFalse(c.clientContext.createSSLEngine().getUseClientMode());
assertFalse(c.clientContext.createSSLEngine(null, -1).getUseClientMode());
c.close();
}
public void test_SSLEngine_setUseClientMode() throws Exception {
boolean[] finished;
TestSSLEnginePair p = null;
// client is client, server is server
finished = new boolean[2];
p = test_SSLEngine_setUseClientMode(true, false, finished);
assertConnected(p);
assertTrue(finished[0]);
assertTrue(finished[1]);
p.close();
// client is server, server is client
finished = new boolean[2];
p = test_SSLEngine_setUseClientMode(false, true, finished);
assertConnected(p);
assertTrue(finished[0]);
assertTrue(finished[1]);
p.close();
// both are client
/*
* Our implementation throws an SSLHandshakeException, but RI just
* stalls forever
*/
p = null;
try {
p = test_SSLEngine_setUseClientMode(true, true, null);
assertNotConnected(p);
assertTrue(StandardNames.IS_RI);
} catch (SSLHandshakeException maybeExpected) {
assertFalse(StandardNames.IS_RI);
} finally {
if (p != null) {
p.close();
}
}
p = test_SSLEngine_setUseClientMode(false, false, null);
// both are server
assertNotConnected(p);
p.close();
}
public void test_SSLEngine_setUseClientMode_afterHandshake() throws Exception {
// can't set after handshake
TestSSLEnginePair pair = TestSSLEnginePair.create(null);
try {
pair.server.setUseClientMode(false);
fail();
} catch (IllegalArgumentException expected) {
}
try {
pair.client.setUseClientMode(false);
fail();
} catch (IllegalArgumentException expected) {
}
pair.close();
}
private TestSSLEnginePair test_SSLEngine_setUseClientMode(final boolean clientClientMode,
final boolean serverClientMode,
final boolean[] finished)
throws Exception {
TestSSLContext c;
if (!clientClientMode && serverClientMode) {
c = TestSSLContext.create(TestKeyStore.getServer(), TestKeyStore.getClient());
} else {
c = TestSSLContext.create();
}
return TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
client.setUseClientMode(clientClientMode);
server.setUseClientMode(serverClientMode);
}
}, finished);
}
public void test_SSLEngine_clientAuth() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
assertFalse(e.getWantClientAuth());
assertFalse(e.getNeedClientAuth());
// confirm turning one on by itself
e.setWantClientAuth(true);
assertTrue(e.getWantClientAuth());
assertFalse(e.getNeedClientAuth());
// confirm turning setting on toggles the other
e.setNeedClientAuth(true);
assertFalse(e.getWantClientAuth());
assertTrue(e.getNeedClientAuth());
// confirm toggling back
e.setWantClientAuth(true);
assertTrue(e.getWantClientAuth());
assertFalse(e.getNeedClientAuth());
// TODO Fix KnownFailure "init - invalid private key"
TestSSLContext clientAuthContext
= TestSSLContext.create(TestKeyStore.getClientCertificate(),
TestKeyStore.getServer());
TestSSLEnginePair p = TestSSLEnginePair.create(clientAuthContext,
new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
server.setWantClientAuth(true);
}
});
assertConnected(p);
assertNotNull(p.client.getSession().getLocalCertificates());
TestKeyStore.assertChainLength(p.client.getSession().getLocalCertificates());
TestSSLContext.assertClientCertificateChain(clientAuthContext.clientTrustManager,
p.client.getSession().getLocalCertificates());
clientAuthContext.close();
c.close();
p.close();
}
/**
* http://code.google.com/p/android/issues/detail?id=31903
* This test case directly tests the fix for the issue.
*/
public void test_SSLEngine_clientAuthWantedNoClientCert() throws Exception {
TestSSLContext clientAuthContext
= TestSSLContext.create(TestKeyStore.getClient(),
TestKeyStore.getServer());
TestSSLEnginePair p = TestSSLEnginePair.create(clientAuthContext,
new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
server.setWantClientAuth(true);
}
});
assertConnected(p);
clientAuthContext.close();
p.close();
}
/**
* http://code.google.com/p/android/issues/detail?id=31903
* This test case verifies that if the server requires a client cert
* (setNeedClientAuth) but the client does not provide one SSL connection
* establishment will fail
*/
public void test_SSLEngine_clientAuthNeededNoClientCert() throws Exception {
boolean handshakeExceptionCaught = false;
TestSSLContext clientAuthContext
= TestSSLContext.create(TestKeyStore.getClient(),
TestKeyStore.getServer());
TestSSLEnginePair p = null;
try {
p = TestSSLEnginePair.create(clientAuthContext,
new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
server.setNeedClientAuth(true);
}
});
fail();
} catch (SSLHandshakeException expected) {
} finally {
clientAuthContext.close();
if (p != null) {
p.close();
}
}
}
public void test_SSLEngine_endpointVerification_Success() throws Exception {
TestSSLContext c = TestSSLContext.create();
TestSSLEnginePair p = TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
SSLParameters p = client.getSSLParameters();
p.setEndpointIdentificationAlgorithm("HTTPS");
client.setSSLParameters(p);
}
});
assertConnected(p);
c.close();
}
public void test_SSLEngine_getEnableSessionCreation() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
assertTrue(e.getEnableSessionCreation());
c.close();
TestSSLEnginePair.close(new SSLEngine[] { e });
}
public void test_SSLEngine_setEnableSessionCreation_server() throws Exception {
TestSSLEnginePair p = null;
try {
p = TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
server.setEnableSessionCreation(false);
}
});
// For some reason, the RI doesn't throw an SSLException.
assertTrue(StandardNames.IS_RI);
assertNotConnected(p);
} catch (SSLException maybeExpected) {
assertFalse(StandardNames.IS_RI);
} finally {
if (p != null) {
p.close();
}
}
}
public void test_SSLEngine_setEnableSessionCreation_client() throws Exception {
TestSSLEnginePair p = null;
try {
p = TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
client.setEnableSessionCreation(false);
}
});
fail();
} catch (SSLException expected) {
} finally {
if (p != null) {
p.close();
}
}
}
public void test_SSLEngine_getSSLParameters() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
SSLParameters p = e.getSSLParameters();
assertNotNull(p);
String[] cipherSuites = p.getCipherSuites();
assertNotSame(cipherSuites, e.getEnabledCipherSuites());
assertEquals(Arrays.asList(cipherSuites), Arrays.asList(e.getEnabledCipherSuites()));
String[] protocols = p.getProtocols();
assertNotSame(protocols, e.getEnabledProtocols());
assertEquals(Arrays.asList(protocols), Arrays.asList(e.getEnabledProtocols()));
assertEquals(p.getWantClientAuth(), e.getWantClientAuth());
assertEquals(p.getNeedClientAuth(), e.getNeedClientAuth());
c.close();
}
public void test_SSLEngine_setSSLParameters() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
String[] defaultCipherSuites = e.getEnabledCipherSuites();
String[] defaultProtocols = e.getEnabledProtocols();
String[] supportedCipherSuites = e.getSupportedCipherSuites();
String[] supportedProtocols = e.getSupportedProtocols();
{
SSLParameters p = new SSLParameters();
e.setSSLParameters(p);
assertEquals(Arrays.asList(defaultCipherSuites),
Arrays.asList(e.getEnabledCipherSuites()));
assertEquals(Arrays.asList(defaultProtocols),
Arrays.asList(e.getEnabledProtocols()));
}
{
SSLParameters p = new SSLParameters(supportedCipherSuites,
supportedProtocols);
e.setSSLParameters(p);
assertEquals(Arrays.asList(supportedCipherSuites),
Arrays.asList(e.getEnabledCipherSuites()));
assertEquals(Arrays.asList(supportedProtocols),
Arrays.asList(e.getEnabledProtocols()));
}
{
SSLParameters p = new SSLParameters();
p.setNeedClientAuth(true);
assertFalse(e.getNeedClientAuth());
assertFalse(e.getWantClientAuth());
e.setSSLParameters(p);
assertTrue(e.getNeedClientAuth());
assertFalse(e.getWantClientAuth());
p.setWantClientAuth(true);
assertTrue(e.getNeedClientAuth());
assertFalse(e.getWantClientAuth());
e.setSSLParameters(p);
assertFalse(e.getNeedClientAuth());
assertTrue(e.getWantClientAuth());
p.setWantClientAuth(false);
assertFalse(e.getNeedClientAuth());
assertTrue(e.getWantClientAuth());
e.setSSLParameters(p);
assertFalse(e.getNeedClientAuth());
assertFalse(e.getWantClientAuth());
}
c.close();
}
public void test_TestSSLEnginePair_create() throws Exception {
TestSSLEnginePair test = TestSSLEnginePair.create(null);
assertNotNull(test.c);
assertNotNull(test.server);
assertNotNull(test.client);
assertConnected(test);
test.close();
}
private final int NUM_STRESS_ITERATIONS = 1000;
public void test_SSLEngine_Multiple_Thread_Success() throws Exception {
try (final TestSSLEnginePair pair = TestSSLEnginePair.create()) {
assertConnected(pair);
final CountDownLatch startUpSync = new CountDownLatch(2);
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<Void> client = executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
startUpSync.countDown();
for (int i = 0; i < NUM_STRESS_ITERATIONS; i++) {
assertSendsCorrectly("This is the client. Hello!".getBytes(UTF_8),
pair.client, pair.server, false);
}
return null;
}
});
Future<Void> server = executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
startUpSync.countDown();
for (int i = 0; i < NUM_STRESS_ITERATIONS; i++) {
assertSendsCorrectly("This is the server. Hi!".getBytes(UTF_8),
pair.server, pair.client, false);
}
return null;
}
});
executor.shutdown();
client.get();
server.get();
}
}
}