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