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