TestSSLContext.java revision 6882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5
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 javax.net.ssl;
18
19import java.net.InetAddress;
20import java.net.InetSocketAddress;
21import java.security.KeyStore;
22import java.security.Principal;
23import java.security.SecureRandom;
24import java.security.StandardNames;
25import java.security.TestKeyStore;
26import java.security.cert.Certificate;
27import java.security.cert.CertificateException;
28import java.security.cert.X509Certificate;
29import java.util.Collections;
30import junit.framework.Assert;
31
32/**
33 * TestSSLContext is a convenience class for other tests that
34 * want a canned SSLContext and related state for testing so they
35 * don't have to duplicate the logic.
36 */
37public final class TestSSLContext extends Assert {
38
39    /*
40     * The RI and Android have very different default SSLSession cache behaviors.
41     * The RI keeps an unlimited number of SSLSesions around for 1 day.
42     * Android keeps 10 SSLSessions forever.
43     */
44    private static final boolean IS_RI = StandardNames.IS_RI;
45    public static final int EXPECTED_DEFAULT_CLIENT_SSL_SESSION_CACHE_SIZE = (IS_RI) ? 0 : 10;
46    public static final int EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE = (IS_RI) ? 0 : 100;
47    public static final int EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT = (IS_RI) ? 86400 : 0;
48
49    /**
50     * The Android SSLSocket and SSLServerSocket implementations are
51     * based on a version of OpenSSL which includes support for RFC
52     * 4507 session tickets. When using session tickets, the server
53     * does not need to keep a cache mapping session IDs to SSL
54     * sessions for reuse. Instead, the client presents the server
55     * with a session ticket it received from the server earlier,
56     * which is an SSL session encrypted by the server's secret
57     * key. Since in this case the server does not need to keep a
58     * cache, some tests may find different results depending on
59     * whether or not the session tickets are in use. These tests can
60     * use this function to determine if loopback SSL connections are
61     * expected to use session tickets and conditionalize their
62     * results appropriately.
63     */
64    public static boolean sslServerSocketSupportsSessionTickets () {
65        // Disabled session tickets for better compatability b/2682876
66        // return !IS_RI;
67        return false;
68    }
69
70    public final KeyStore clientKeyStore;
71    public final char[] clientStorePassword;
72    public final KeyStore serverKeyStore;
73    public final char[] serverStorePassword;
74    public final X509ExtendedKeyManager clientKeyManager;
75    public final X509ExtendedKeyManager serverKeyManager;
76    public final X509TrustManager clientTrustManager;
77    public final X509TrustManager serverTrustManager;
78    public final SSLContext clientContext;
79    public final SSLContext serverContext;
80    public final SSLServerSocket serverSocket;
81    public final InetAddress host;
82    public final int port;
83
84    private TestSSLContext(KeyStore clientKeyStore,
85                           char[] clientStorePassword,
86                           KeyStore serverKeyStore,
87                           char[] serverStorePassword,
88                           X509ExtendedKeyManager clientKeyManager,
89                           X509ExtendedKeyManager serverKeyManager,
90                           X509TrustManager clientTrustManager,
91                           X509TrustManager serverTrustManager,
92                           SSLContext clientContext,
93                           SSLContext serverContext,
94                           SSLServerSocket serverSocket,
95                           InetAddress host,
96                           int port) {
97        this.clientKeyStore = clientKeyStore;
98        this.clientStorePassword = clientStorePassword;
99        this.serverKeyStore = serverKeyStore;
100        this.serverStorePassword = serverStorePassword;
101        this.clientKeyManager = clientKeyManager;
102        this.serverKeyManager = serverKeyManager;
103        this.clientTrustManager = clientTrustManager;
104        this.serverTrustManager = serverTrustManager;
105        this.clientContext = clientContext;
106        this.serverContext = serverContext;
107        this.serverSocket = serverSocket;
108        this.host = host;
109        this.port = port;
110    }
111
112    /**
113     * Usual TestSSLContext creation method, creates underlying
114     * SSLContext with certificate and key as well as SSLServerSocket
115     * listening provided host and port.
116     */
117    public static TestSSLContext create() {
118        return create(TestKeyStore.getClient(),
119                      TestKeyStore.getServer());
120    }
121
122    /**
123     * TestSSLContext creation method that allows separate creation of server key store
124     */
125    public static TestSSLContext create(TestKeyStore client, TestKeyStore server) {
126        String provider = StandardNames.JSSE_PROVIDER_NAME;
127        return create(client, server, provider, provider);
128    }
129    public static TestSSLContext create(TestKeyStore client, TestKeyStore server,
130                                        String clientProvider, String serverProvider) {
131        String protocol = "TLS";
132        SSLContext clientContext = createSSLContext(protocol, clientProvider,
133                                                    client.keyManagers, client.trustManagers);
134        SSLContext serverContext = createSSLContext(protocol, serverProvider,
135                                                    server.keyManagers, server.trustManagers);
136        return create(client.keyStore, client.storePassword,
137                      server.keyStore, server.storePassword,
138                      client.keyManagers[0],
139                      server.keyManagers[0],
140                      client.trustManagers[0],
141                      server.trustManagers[0],
142                      clientContext,
143                      serverContext);
144    }
145
146    /**
147     * TestSSLContext creation method that allows separate creation of client and server key store
148     */
149    public static TestSSLContext create(KeyStore clientKeyStore, char[] clientStorePassword,
150                                        KeyStore serverKeyStore, char[] serverStorePassword,
151                                        KeyManager clientKeyManagers,
152                                        KeyManager serverKeyManagers,
153                                        TrustManager clientTrustManagers,
154                                        TrustManager serverTrustManagers,
155                                        SSLContext clientContext,
156                                        SSLContext serverContext) {
157        try {
158            SSLServerSocket serverSocket = (SSLServerSocket)
159                serverContext.getServerSocketFactory().createServerSocket(0);
160            InetSocketAddress sa = (InetSocketAddress) serverSocket.getLocalSocketAddress();
161            InetAddress host = sa.getAddress();
162            int port = sa.getPort();
163
164            return new TestSSLContext(clientKeyStore, clientStorePassword,
165                                      serverKeyStore, serverStorePassword,
166                                      (X509ExtendedKeyManager) clientKeyManagers,
167                                      (X509ExtendedKeyManager) serverKeyManagers,
168                                      (X509TrustManager) clientTrustManagers,
169                                      (X509TrustManager) serverTrustManagers,
170                                      clientContext, serverContext,
171                                      serverSocket, host, port);
172        } catch (RuntimeException e) {
173            throw e;
174        } catch (Exception e) {
175            throw new RuntimeException(e);
176        }
177    }
178
179    /**
180     * Create a SSLContext with a KeyManager using the private key and
181     * certificate chain from the given KeyStore and a TrustManager
182     * using the certificates authorities from the same KeyStore.
183     */
184    public static final SSLContext createSSLContext(final String protocol,
185                                                    final String provider,
186                                                    final KeyManager[] keyManagers,
187                                                    final TrustManager[] trustManagers)
188    {
189        try {
190            SSLContext context = SSLContext.getInstance(protocol, provider);
191            context.init(keyManagers, trustManagers, new SecureRandom());
192            return context;
193        } catch (Exception e) {
194            throw new RuntimeException(e);
195        }
196    }
197
198    public static void assertCertificateInKeyStore(Principal principal,
199                                                   KeyStore keyStore) throws Exception {
200        String subjectName = principal.getName();
201        boolean found = false;
202        for (String alias: Collections.list(keyStore.aliases())) {
203            if (!keyStore.isCertificateEntry(alias)) {
204                continue;
205            }
206            X509Certificate keyStoreCertificate = (X509Certificate) keyStore.getCertificate(alias);
207            if (subjectName.equals(keyStoreCertificate.getSubjectDN().getName())) {
208                found = true;
209                break;
210            }
211        }
212        assertTrue(found);
213    }
214
215    public static void assertCertificateInKeyStore(Certificate certificate,
216                                                   KeyStore keyStore) throws Exception {
217        boolean found = false;
218        for (String alias: Collections.list(keyStore.aliases())) {
219            if (!keyStore.isCertificateEntry(alias)) {
220                continue;
221            }
222            Certificate keyStoreCertificate = keyStore.getCertificate(alias);
223            if (certificate.equals(keyStoreCertificate)) {
224                found = true;
225                break;
226            }
227        }
228        assertTrue(found);
229    }
230
231    public static void assertServerCertificateChain(X509TrustManager trustManager,
232                                                    Certificate[] serverChain)
233            throws CertificateException {
234        X509Certificate[] chain = (X509Certificate[]) serverChain;
235        trustManager.checkServerTrusted(chain, chain[0].getPublicKey().getAlgorithm());
236    }
237
238    public static void assertClientCertificateChain(X509TrustManager trustManager,
239                                                    Certificate[] clientChain)
240            throws CertificateException {
241        X509Certificate[] chain = (X509Certificate[]) clientChain;
242        trustManager.checkClientTrusted(chain, chain[0].getPublicKey().getAlgorithm());
243    }
244}
245