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