1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package libcore.javax.net.ssl;
18
19import java.util.ArrayList;
20import java.util.Arrays;
21import java.util.Collections;
22import java.util.Enumeration;
23import java.util.Iterator;
24import java.util.LinkedList;
25import java.util.List;
26import javax.net.ssl.SSLSessionContext;
27import javax.net.ssl.SSLSocket;
28import junit.framework.TestCase;
29
30public class SSLSessionContextTest extends TestCase {
31
32    public static final void assertSSLSessionContextSize(int expected, TestSSLContext c) {
33        assertSSLSessionContextSize(expected,
34                                    c.clientContext.getClientSessionContext(),
35                                    c.serverContext.getServerSessionContext());
36        assertSSLSessionContextSize(0,
37                                    c.serverContext.getClientSessionContext(),
38                                    c.clientContext.getServerSessionContext());
39    }
40
41    public static final void assertSSLSessionContextSize(int expected,
42                                                         SSLSessionContext client,
43                                                         SSLSessionContext server) {
44        assertSSLSessionContextSize(expected, client, false);
45        assertSSLSessionContextSize(expected, server, true);
46    }
47
48    public static final void assertSSLSessionContextSize(int expected,
49                                                         SSLSessionContext s,
50                                                         boolean server) {
51        int size = Collections.list(s.getIds()).size();
52        if (server && TestSSLContext.sslServerSocketSupportsSessionTickets()) {
53            assertEquals(0, size);
54        } else {
55            assertEquals(expected, size);
56        }
57    }
58
59    public void test_SSLSessionContext_getIds() {
60        TestSSLContext c = TestSSLContext.create();
61        assertSSLSessionContextSize(0, c);
62        c.close();
63
64        TestSSLSocketPair s = TestSSLSocketPair.create();
65        assertSSLSessionContextSize(1, s.c);
66        Enumeration clientIds = s.c.clientContext.getClientSessionContext().getIds();
67        Enumeration serverIds = s.c.serverContext.getServerSessionContext().getIds();
68        byte[] clientId = (byte[]) clientIds.nextElement();
69        assertEquals(32, clientId.length);
70        if (TestSSLContext.sslServerSocketSupportsSessionTickets()) {
71            assertFalse(serverIds.hasMoreElements());
72        } else {
73            byte[] serverId = (byte[]) serverIds.nextElement();
74            assertEquals(32, serverId.length);
75            assertTrue(Arrays.equals(clientId, serverId));
76        }
77        s.close();
78    }
79
80    public void test_SSLSessionContext_getSession() {
81        TestSSLContext c = TestSSLContext.create();
82        try {
83            c.clientContext.getClientSessionContext().getSession(null);
84            fail();
85        } catch (NullPointerException expected) {
86        }
87        assertNull(c.clientContext.getClientSessionContext().getSession(new byte[0]));
88        assertNull(c.clientContext.getClientSessionContext().getSession(new byte[1]));
89        try {
90            c.serverContext.getServerSessionContext().getSession(null);
91            fail();
92        } catch (NullPointerException expected) {
93        }
94        assertNull(c.serverContext.getServerSessionContext().getSession(new byte[0]));
95        assertNull(c.serverContext.getServerSessionContext().getSession(new byte[1]));
96        c.close();
97
98        TestSSLSocketPair s = TestSSLSocketPair.create();
99        SSLSessionContext client = s.c.clientContext.getClientSessionContext();
100        SSLSessionContext server = s.c.serverContext.getServerSessionContext();
101        byte[] clientId = (byte[]) client.getIds().nextElement();
102        assertNotNull(client.getSession(clientId));
103        assertTrue(Arrays.equals(clientId, client.getSession(clientId).getId()));
104        if (TestSSLContext.sslServerSocketSupportsSessionTickets()) {
105            assertFalse(server.getIds().hasMoreElements());
106        } else {
107            byte[] serverId = (byte[]) server.getIds().nextElement();
108            assertNotNull(server.getSession(serverId));
109            assertTrue(Arrays.equals(serverId, server.getSession(serverId).getId()));
110        }
111        s.close();
112    }
113
114    public void test_SSLSessionContext_getSessionCacheSize() {
115        TestSSLContext c = TestSSLContext.create();
116        assertEquals(TestSSLContext.EXPECTED_DEFAULT_CLIENT_SSL_SESSION_CACHE_SIZE,
117                     c.clientContext.getClientSessionContext().getSessionCacheSize());
118        assertEquals(TestSSLContext.EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE,
119                     c.serverContext.getServerSessionContext().getSessionCacheSize());
120        c.close();
121
122        TestSSLSocketPair s = TestSSLSocketPair.create();
123        assertEquals(TestSSLContext.EXPECTED_DEFAULT_CLIENT_SSL_SESSION_CACHE_SIZE,
124                     s.c.clientContext.getClientSessionContext().getSessionCacheSize());
125        assertEquals(TestSSLContext.EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE,
126                     s.c.serverContext.getServerSessionContext().getSessionCacheSize());
127        s.close();
128    }
129
130    public void test_SSLSessionContext_setSessionCacheSize_noConnect() {
131        TestSSLContext c = TestSSLContext.create();
132        assertNoConnectSetSessionCacheSizeBehavior(
133                TestSSLContext.EXPECTED_DEFAULT_CLIENT_SSL_SESSION_CACHE_SIZE,
134                c.clientContext.getClientSessionContext());
135        assertNoConnectSetSessionCacheSizeBehavior(
136                TestSSLContext.EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE,
137                c.serverContext.getServerSessionContext());
138        c.close();
139    }
140
141    private static void assertNoConnectSetSessionCacheSizeBehavior(int expectedDefault,
142                                                                   SSLSessionContext s) {
143        try {
144            s.setSessionCacheSize(-1);
145            fail();
146        } catch (IllegalArgumentException expected) {
147        }
148        assertEquals(expectedDefault, s.getSessionCacheSize());
149        s.setSessionCacheSize(1);
150        assertEquals(1, s.getSessionCacheSize());
151    }
152
153    public void test_SSLSessionContext_setSessionCacheSize_oneConnect() {
154        TestSSLSocketPair s = TestSSLSocketPair.create();
155        SSLSessionContext client = s.c.clientContext.getClientSessionContext();
156        SSLSessionContext server = s.c.serverContext.getServerSessionContext();
157        assertEquals(TestSSLContext.EXPECTED_DEFAULT_CLIENT_SSL_SESSION_CACHE_SIZE,
158                     client.getSessionCacheSize());
159        assertEquals(TestSSLContext.EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE,
160                     server.getSessionCacheSize());
161        assertSSLSessionContextSize(1, s.c);
162        s.close();
163    }
164
165    public void test_SSLSessionContext_setSessionCacheSize_dynamic() throws Exception {
166        TestSSLContext c = TestSSLContext.create();
167        SSLSessionContext client = c.clientContext.getClientSessionContext();
168        SSLSessionContext server = c.serverContext.getServerSessionContext();
169
170        String[] supportedCipherSuites = c.serverSocket.getSupportedCipherSuites();
171        c.serverSocket.setEnabledCipherSuites(supportedCipherSuites);
172        LinkedList<String> uniqueCipherSuites
173            = new LinkedList(Arrays.asList(supportedCipherSuites));
174        // only use RSA cipher suites which will work with our TrustProvider
175        Iterator<String> i = uniqueCipherSuites.iterator();
176        while (i.hasNext()) {
177            String cipherSuite = i.next();
178
179            // Certificate key length too long for export ciphers
180            if (cipherSuite.startsWith("SSL_RSA_EXPORT_")) {
181                i.remove();
182                continue;
183            }
184
185            if (cipherSuite.startsWith("SSL_RSA_")) {
186                continue;
187            }
188            if (cipherSuite.startsWith("TLS_RSA_")) {
189                continue;
190            }
191            if (cipherSuite.startsWith("TLS_DHE_RSA_")) {
192                continue;
193            }
194            if (cipherSuite.startsWith("SSL_DHE_RSA_")) {
195                continue;
196            }
197            i.remove();
198        }
199
200        /*
201         * having more than 3 uniqueCipherSuites is a test
202         * requirement, not a requirement of the interface or
203         * implementation. It simply allows us to make sure that we
204         * will not get a cached session ID since we'll have to
205         * renegotiate a new session due to the new cipher suite
206         * requirement. even this test only really needs three if it
207         * reused the unique cipher suites every time it resets the
208         * session cache.
209         */
210        assertTrue(uniqueCipherSuites.size() >= 3);
211        String cipherSuite1 = uniqueCipherSuites.get(0);
212        String cipherSuite2 = uniqueCipherSuites.get(1);
213        String cipherSuite3 = uniqueCipherSuites.get(2);
214
215        List<SSLSocket[]> toClose = new ArrayList<SSLSocket[]>();
216        toClose.add(TestSSLSocketPair.connect(c, new String[] { cipherSuite1 }, null));
217        assertSSLSessionContextSize(1, c);
218        toClose.add(TestSSLSocketPair.connect(c, new String[] { cipherSuite2 }, null));
219        assertSSLSessionContextSize(2, c);
220        toClose.add(TestSSLSocketPair.connect(c, new String[] { cipherSuite3 }, null));
221        assertSSLSessionContextSize(3, c);
222
223        client.setSessionCacheSize(1);
224        server.setSessionCacheSize(1);
225        assertEquals(1, client.getSessionCacheSize());
226        assertEquals(1, server.getSessionCacheSize());
227        assertSSLSessionContextSize(1, c);
228        toClose.add(TestSSLSocketPair.connect(c, new String[] { cipherSuite1 }, null));
229        assertSSLSessionContextSize(1, c);
230
231        client.setSessionCacheSize(2);
232        server.setSessionCacheSize(2);
233        toClose.add(TestSSLSocketPair.connect(c, new String[] { cipherSuite2 }, null));
234        assertSSLSessionContextSize(2, c);
235        toClose.add(TestSSLSocketPair.connect(c, new String[] { cipherSuite3 }, null));
236        assertSSLSessionContextSize(2, c);
237
238        for (SSLSocket[] pair : toClose) {
239            for (SSLSocket s : pair) {
240                s.close();
241            }
242        }
243        c.close();
244    }
245
246    public void test_SSLSessionContext_getSessionTimeout() {
247        TestSSLContext c = TestSSLContext.create();
248        assertEquals(TestSSLContext.EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT,
249                     c.clientContext.getClientSessionContext().getSessionTimeout());
250        assertEquals(TestSSLContext.EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT,
251                     c.serverContext.getServerSessionContext().getSessionTimeout());
252        c.close();
253
254        TestSSLSocketPair s = TestSSLSocketPair.create();
255        assertEquals(TestSSLContext.EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT,
256                     s.c.clientContext.getClientSessionContext().getSessionTimeout());
257        assertEquals(TestSSLContext.EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT,
258                     s.c.serverContext.getServerSessionContext().getSessionTimeout());
259        s.close();
260    }
261
262    public void test_SSLSessionContext_setSessionTimeout() throws Exception {
263        TestSSLContext c = TestSSLContext.create();
264        assertEquals(TestSSLContext.EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT,
265                     c.clientContext.getClientSessionContext().getSessionTimeout());
266        assertEquals(TestSSLContext.EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT,
267                     c.serverContext.getServerSessionContext().getSessionTimeout());
268        c.clientContext.getClientSessionContext().setSessionTimeout(0);
269        c.serverContext.getServerSessionContext().setSessionTimeout(0);
270        assertEquals(0, c.clientContext.getClientSessionContext().getSessionTimeout());
271        assertEquals(0, c.serverContext.getServerSessionContext().getSessionTimeout());
272
273        try {
274            c.clientContext.getClientSessionContext().setSessionTimeout(-1);
275            fail();
276        } catch (IllegalArgumentException expected) {
277        }
278        try {
279            c.serverContext.getServerSessionContext().setSessionTimeout(-1);
280            fail();
281        } catch (IllegalArgumentException expected) {
282        }
283        c.close();
284
285        TestSSLSocketPair s = TestSSLSocketPair.create();
286        assertSSLSessionContextSize(1, s.c);
287        Thread.sleep(1 * 1000);
288        s.c.clientContext.getClientSessionContext().setSessionTimeout(1);
289        s.c.serverContext.getServerSessionContext().setSessionTimeout(1);
290        assertSSLSessionContextSize(0, s.c);
291        s.close();
292    }
293}
294