blob: d3cd174016c6ce335d2a89ffc3b56fbeb068ac35 [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 org.conscrypt.javax.net.ssl;
import static org.conscrypt.Conscrypt.isConscrypt;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class SSLSessionContextTest {
@Test
public void test_SSLSessionContext_getIds() {
TestSSLContext c = TestSSLContext.create();
assertSSLSessionContextSize(0, c);
c.close();
TestSSLSocketPair s = TestSSLSocketPair.create().connect();
assertSSLSessionContextSize(1, s.c);
Enumeration<byte[]> clientIds = s.c.clientContext.getClientSessionContext().getIds();
Enumeration<byte[]> serverIds = s.c.serverContext.getServerSessionContext().getIds();
byte[] clientId = clientIds.nextElement();
assertEquals(32, clientId.length);
if (TestSSLContext.sslServerSocketSupportsSessionTickets()) {
assertFalse(serverIds.hasMoreElements());
} else {
byte[] serverId = serverIds.nextElement();
assertEquals(32, serverId.length);
assertTrue(Arrays.equals(clientId, serverId));
}
s.close();
}
@Test
public void test_SSLSessionContext_getSession() {
TestSSLContext c = TestSSLContext.create();
try {
c.clientContext.getClientSessionContext().getSession(null);
fail();
} catch (NullPointerException expected) {
// Ignored.
}
assertNull(c.clientContext.getClientSessionContext().getSession(new byte[0]));
assertNull(c.clientContext.getClientSessionContext().getSession(new byte[1]));
try {
c.serverContext.getServerSessionContext().getSession(null);
fail();
} catch (NullPointerException expected) {
// Ignored.
}
assertNull(c.serverContext.getServerSessionContext().getSession(new byte[0]));
assertNull(c.serverContext.getServerSessionContext().getSession(new byte[1]));
c.close();
TestSSLSocketPair s = TestSSLSocketPair.create().connect();
SSLSessionContext client = s.c.clientContext.getClientSessionContext();
SSLSessionContext server = s.c.serverContext.getServerSessionContext();
byte[] clientId = client.getIds().nextElement();
assertNotNull(client.getSession(clientId));
assertTrue(Arrays.equals(clientId, client.getSession(clientId).getId()));
if (TestSSLContext.sslServerSocketSupportsSessionTickets()) {
assertFalse(server.getIds().hasMoreElements());
} else {
byte[] serverId = server.getIds().nextElement();
assertNotNull(server.getSession(serverId));
assertTrue(Arrays.equals(serverId, server.getSession(serverId).getId()));
}
s.close();
}
@Test
public void test_SSLSessionContext_getSessionCacheSize() {
TestSSLContext c = TestSSLContext.create();
int expectedClientSessionCacheSize = expectedClientSslSessionCacheSize(c);
int expectedServerSessionCacheSize = expectedServerSslSessionCacheSize(c);
assertEquals(expectedClientSessionCacheSize,
c.clientContext.getClientSessionContext().getSessionCacheSize());
assertEquals(expectedServerSessionCacheSize,
c.serverContext.getServerSessionContext().getSessionCacheSize());
c.close();
TestSSLSocketPair s = TestSSLSocketPair.create().connect();
assertEquals(expectedClientSessionCacheSize,
s.c.clientContext.getClientSessionContext().getSessionCacheSize());
assertEquals(expectedServerSessionCacheSize,
s.c.serverContext.getServerSessionContext().getSessionCacheSize());
s.close();
}
@Test
public void test_SSLSessionContext_setSessionCacheSize_noConnect() {
TestSSLContext c = TestSSLContext.create();
int expectedClientSessionCacheSize = expectedClientSslSessionCacheSize(c);
int expectedServerSessionCacheSize = expectedServerSslSessionCacheSize(c);
assertNoConnectSetSessionCacheSizeBehavior(
expectedClientSessionCacheSize, c.clientContext.getClientSessionContext());
assertNoConnectSetSessionCacheSizeBehavior(
expectedServerSessionCacheSize, c.serverContext.getServerSessionContext());
c.close();
}
private static void assertNoConnectSetSessionCacheSizeBehavior(
int expectedDefault, SSLSessionContext s) {
try {
s.setSessionCacheSize(-1);
fail();
} catch (IllegalArgumentException expected) {
// Ignored.
}
assertEquals(expectedDefault, s.getSessionCacheSize());
s.setSessionCacheSize(1);
assertEquals(1, s.getSessionCacheSize());
}
@Test
public void test_SSLSessionContext_setSessionCacheSize_oneConnect() {
TestSSLSocketPair s = TestSSLSocketPair.create().connect();
int expectedClientSessionCacheSize = expectedClientSslSessionCacheSize(s.c);
int expectedServerSessionCacheSize = expectedServerSslSessionCacheSize(s.c);
SSLSessionContext client = s.c.clientContext.getClientSessionContext();
SSLSessionContext server = s.c.serverContext.getServerSessionContext();
assertEquals(expectedClientSessionCacheSize, client.getSessionCacheSize());
assertEquals(expectedServerSessionCacheSize, server.getSessionCacheSize());
assertSSLSessionContextSize(1, s.c);
s.close();
}
@Test
public void test_SSLSessionContext_setSessionCacheSize_dynamic() throws Exception {
TestSSLContext c = TestSSLContext.create();
SSLSessionContext client = c.clientContext.getClientSessionContext();
SSLSessionContext server = c.serverContext.getServerSessionContext();
String[] supportedCipherSuites = c.serverSocket.getSupportedCipherSuites();
c.serverSocket.setEnabledCipherSuites(supportedCipherSuites);
Deque<String> uniqueCipherSuites =
new ArrayDeque<String>(Arrays.asList(supportedCipherSuites));
// only use RSA cipher suites which will work with our TrustProvider
Iterator<String> i = uniqueCipherSuites.iterator();
while (i.hasNext()) {
String cipherSuite = i.next();
// Certificate key length too long for export ciphers
if (cipherSuite.startsWith("SSL_RSA_EXPORT_")) {
i.remove();
continue;
}
if (cipherSuite.startsWith("SSL_RSA_")) {
continue;
}
if (cipherSuite.startsWith("TLS_RSA_")) {
continue;
}
if (cipherSuite.startsWith("TLS_DHE_RSA_")) {
continue;
}
if (cipherSuite.startsWith("SSL_DHE_RSA_")) {
continue;
}
i.remove();
}
/*
* having more than 3 uniqueCipherSuites is a test
* requirement, not a requirement of the interface or
* implementation. It simply allows us to make sure that we
* will not get a cached session ID since we'll have to
* renegotiate a new session due to the new cipher suite
* requirement. even this test only really needs three if it
* reused the unique cipher suites every time it resets the
* session cache.
*/
assertTrue(uniqueCipherSuites.size() >= 3);
String cipherSuite1 = uniqueCipherSuites.pop();
String cipherSuite2 = uniqueCipherSuites.pop();
String cipherSuite3 = uniqueCipherSuites.pop();
List<SSLSocket[]> toClose = new ArrayList<SSLSocket[]>();
toClose.add(
TestSSLSocketPair.create(c).connect(new String[] {cipherSuite1}, null).sockets());
assertSSLSessionContextSize(1, c);
toClose.add(
TestSSLSocketPair.create(c).connect(new String[] {cipherSuite2}, null).sockets());
assertSSLSessionContextSize(2, c);
toClose.add(
TestSSLSocketPair.create(c).connect(new String[] {cipherSuite3}, null).sockets());
assertSSLSessionContextSize(3, c);
client.setSessionCacheSize(1);
server.setSessionCacheSize(1);
assertEquals(1, client.getSessionCacheSize());
assertEquals(1, server.getSessionCacheSize());
assertSSLSessionContextSize(1, c);
toClose.add(
TestSSLSocketPair.create(c).connect(new String[] {cipherSuite1}, null).sockets());
assertSSLSessionContextSize(1, c);
client.setSessionCacheSize(2);
server.setSessionCacheSize(2);
toClose.add(
TestSSLSocketPair.create(c).connect(new String[] {cipherSuite2}, null).sockets());
assertSSLSessionContextSize(2, c);
toClose.add(
TestSSLSocketPair.create(c).connect(new String[] {cipherSuite3}, null).sockets());
assertSSLSessionContextSize(2, c);
for (SSLSocket[] pair : toClose) {
for (SSLSocket s : pair) {
s.close();
}
}
c.close();
}
@Test
public void test_SSLSessionContext_getSessionTimeout() {
TestSSLContext c = TestSSLContext.create();
int expectedCacheTimeout = expectedSslSessionCacheTimeout(c);
assertEquals(expectedCacheTimeout,
c.clientContext.getClientSessionContext().getSessionTimeout());
assertEquals(expectedCacheTimeout,
c.serverContext.getServerSessionContext().getSessionTimeout());
c.close();
TestSSLSocketPair s = TestSSLSocketPair.create().connect();
assertEquals(expectedCacheTimeout,
s.c.clientContext.getClientSessionContext().getSessionTimeout());
assertEquals(expectedCacheTimeout,
s.c.serverContext.getServerSessionContext().getSessionTimeout());
s.close();
}
@Test
public void test_SSLSessionContext_setSessionTimeout() throws Exception {
TestSSLContext c = TestSSLContext.create();
int expectedCacheTimeout = expectedSslSessionCacheTimeout(c);
assertEquals(expectedCacheTimeout,
c.clientContext.getClientSessionContext().getSessionTimeout());
assertEquals(expectedCacheTimeout,
c.serverContext.getServerSessionContext().getSessionTimeout());
c.clientContext.getClientSessionContext().setSessionTimeout(0);
c.serverContext.getServerSessionContext().setSessionTimeout(0);
assertEquals(0, c.clientContext.getClientSessionContext().getSessionTimeout());
assertEquals(0, c.serverContext.getServerSessionContext().getSessionTimeout());
try {
c.clientContext.getClientSessionContext().setSessionTimeout(-1);
fail();
} catch (IllegalArgumentException expected) {
// Ignored.
}
try {
c.serverContext.getServerSessionContext().setSessionTimeout(-1);
fail();
} catch (IllegalArgumentException expected) {
// Ignored.
}
c.close();
TestSSLSocketPair s = TestSSLSocketPair.create().connect();
assertSSLSessionContextSize(1, s.c);
Thread.sleep(1000);
s.c.clientContext.getClientSessionContext().setSessionTimeout(1);
s.c.serverContext.getServerSessionContext().setSessionTimeout(1);
assertSSLSessionContextSize(0, s.c);
s.close();
}
private static void assertSSLSessionContextSize(int expected, TestSSLContext c) {
assertSSLSessionContextSize(expected, c.clientContext.getClientSessionContext(),
c.serverContext.getServerSessionContext());
assertSSLSessionContextSize(0, c.serverContext.getClientSessionContext(),
c.clientContext.getServerSessionContext());
}
private static void assertSSLSessionContextSize(
int expected, SSLSessionContext client, SSLSessionContext server) {
assertSSLSessionContextSize(expected, client, false);
assertSSLSessionContextSize(expected, server, true);
}
private static void assertSSLSessionContextSize(
int expected, SSLSessionContext s, boolean server) {
if (server && TestSSLContext.sslServerSocketSupportsSessionTickets()) {
assertEquals(0, numSessions(s));
} else {
assertEquals(expected, numSessions(s));
}
}
private int expectedClientSslSessionCacheSize(TestSSLContext c) {
return isConscrypt(c.clientContext.getProvider()) ? 10 : 0;
}
private int expectedServerSslSessionCacheSize(TestSSLContext c) {
return isConscrypt(c.serverContext.getProvider()) ? 100 : 0;
}
private int expectedSslSessionCacheTimeout(TestSSLContext c) {
return (isConscrypt(c.serverContext.getProvider())) ? 8 * 3600 : 24 * 3600;
}
private static int numSessions(SSLSessionContext s) {
return Collections.list(s.getIds()).size();
}
}