Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* |
michael@0 | 2 | * ==================================================================== |
michael@0 | 3 | * Licensed to the Apache Software Foundation (ASF) under one |
michael@0 | 4 | * or more contributor license agreements. See the NOTICE file |
michael@0 | 5 | * distributed with this work for additional information |
michael@0 | 6 | * regarding copyright ownership. The ASF licenses this file |
michael@0 | 7 | * to you under the Apache License, Version 2.0 (the |
michael@0 | 8 | * "License"); you may not use this file except in compliance |
michael@0 | 9 | * with the License. You may obtain a copy of the License at |
michael@0 | 10 | * |
michael@0 | 11 | * http://www.apache.org/licenses/LICENSE-2.0 |
michael@0 | 12 | * |
michael@0 | 13 | * Unless required by applicable law or agreed to in writing, |
michael@0 | 14 | * software distributed under the License is distributed on an |
michael@0 | 15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
michael@0 | 16 | * KIND, either express or implied. See the License for the |
michael@0 | 17 | * specific language governing permissions and limitations |
michael@0 | 18 | * under the License. |
michael@0 | 19 | * ==================================================================== |
michael@0 | 20 | * |
michael@0 | 21 | * This software consists of voluntary contributions made by many |
michael@0 | 22 | * individuals on behalf of the Apache Software Foundation. For more |
michael@0 | 23 | * information on the Apache Software Foundation, please see |
michael@0 | 24 | * <http://www.apache.org/>. |
michael@0 | 25 | * |
michael@0 | 26 | */ |
michael@0 | 27 | |
michael@0 | 28 | package ch.boye.httpclientandroidlib.conn.ssl; |
michael@0 | 29 | |
michael@0 | 30 | import ch.boye.httpclientandroidlib.annotation.ThreadSafe; |
michael@0 | 31 | |
michael@0 | 32 | import ch.boye.httpclientandroidlib.conn.ConnectTimeoutException; |
michael@0 | 33 | import ch.boye.httpclientandroidlib.conn.scheme.HostNameResolver; |
michael@0 | 34 | import ch.boye.httpclientandroidlib.conn.scheme.LayeredSchemeSocketFactory; |
michael@0 | 35 | import ch.boye.httpclientandroidlib.conn.scheme.LayeredSocketFactory; |
michael@0 | 36 | import ch.boye.httpclientandroidlib.params.HttpConnectionParams; |
michael@0 | 37 | import ch.boye.httpclientandroidlib.params.HttpParams; |
michael@0 | 38 | |
michael@0 | 39 | import javax.net.ssl.KeyManager; |
michael@0 | 40 | import javax.net.ssl.KeyManagerFactory; |
michael@0 | 41 | import javax.net.ssl.SSLContext; |
michael@0 | 42 | import javax.net.ssl.SSLSocket; |
michael@0 | 43 | import javax.net.ssl.TrustManager; |
michael@0 | 44 | import javax.net.ssl.TrustManagerFactory; |
michael@0 | 45 | import javax.net.ssl.X509TrustManager; |
michael@0 | 46 | |
michael@0 | 47 | import java.io.IOException; |
michael@0 | 48 | import java.net.InetAddress; |
michael@0 | 49 | import java.net.InetSocketAddress; |
michael@0 | 50 | import java.net.Socket; |
michael@0 | 51 | import java.net.SocketTimeoutException; |
michael@0 | 52 | import java.net.UnknownHostException; |
michael@0 | 53 | import java.security.KeyManagementException; |
michael@0 | 54 | import java.security.KeyStore; |
michael@0 | 55 | import java.security.KeyStoreException; |
michael@0 | 56 | import java.security.NoSuchAlgorithmException; |
michael@0 | 57 | import java.security.SecureRandom; |
michael@0 | 58 | import java.security.UnrecoverableKeyException; |
michael@0 | 59 | |
michael@0 | 60 | /** |
michael@0 | 61 | * Layered socket factory for TLS/SSL connections. |
michael@0 | 62 | * <p> |
michael@0 | 63 | * SSLSocketFactory can be used to validate the identity of the HTTPS server against a list of |
michael@0 | 64 | * trusted certificates and to authenticate to the HTTPS server using a private key. |
michael@0 | 65 | * <p> |
michael@0 | 66 | * SSLSocketFactory will enable server authentication when supplied with |
michael@0 | 67 | * a {@link KeyStore trust-store} file containing one or several trusted certificates. The client |
michael@0 | 68 | * secure socket will reject the connection during the SSL session handshake if the target HTTPS |
michael@0 | 69 | * server attempts to authenticate itself with a non-trusted certificate. |
michael@0 | 70 | * <p> |
michael@0 | 71 | * Use JDK keytool utility to import a trusted certificate and generate a trust-store file: |
michael@0 | 72 | * <pre> |
michael@0 | 73 | * keytool -import -alias "my server cert" -file server.crt -keystore my.truststore |
michael@0 | 74 | * </pre> |
michael@0 | 75 | * <p> |
michael@0 | 76 | * In special cases the standard trust verification process can be bypassed by using a custom |
michael@0 | 77 | * {@link TrustStrategy}. This interface is primarily intended for allowing self-signed |
michael@0 | 78 | * certificates to be accepted as trusted without having to add them to the trust-store file. |
michael@0 | 79 | * <p> |
michael@0 | 80 | * The following parameters can be used to customize the behavior of this |
michael@0 | 81 | * class: |
michael@0 | 82 | * <ul> |
michael@0 | 83 | * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#CONNECTION_TIMEOUT}</li> |
michael@0 | 84 | * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#SO_TIMEOUT}</li> |
michael@0 | 85 | * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#SO_REUSEADDR}</li> |
michael@0 | 86 | * </ul> |
michael@0 | 87 | * <p> |
michael@0 | 88 | * SSLSocketFactory will enable client authentication when supplied with |
michael@0 | 89 | * a {@link KeyStore key-store} file containing a private key/public certificate |
michael@0 | 90 | * pair. The client secure socket will use the private key to authenticate |
michael@0 | 91 | * itself to the target HTTPS server during the SSL session handshake if |
michael@0 | 92 | * requested to do so by the server. |
michael@0 | 93 | * The target HTTPS server will in its turn verify the certificate presented |
michael@0 | 94 | * by the client in order to establish client's authenticity |
michael@0 | 95 | * <p> |
michael@0 | 96 | * Use the following sequence of actions to generate a key-store file |
michael@0 | 97 | * </p> |
michael@0 | 98 | * <ul> |
michael@0 | 99 | * <li> |
michael@0 | 100 | * <p> |
michael@0 | 101 | * Use JDK keytool utility to generate a new key |
michael@0 | 102 | * <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre> |
michael@0 | 103 | * For simplicity use the same password for the key as that of the key-store |
michael@0 | 104 | * </p> |
michael@0 | 105 | * </li> |
michael@0 | 106 | * <li> |
michael@0 | 107 | * <p> |
michael@0 | 108 | * Issue a certificate signing request (CSR) |
michael@0 | 109 | * <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre> |
michael@0 | 110 | * </p> |
michael@0 | 111 | * </li> |
michael@0 | 112 | * <li> |
michael@0 | 113 | * <p> |
michael@0 | 114 | * Send the certificate request to the trusted Certificate Authority for signature. |
michael@0 | 115 | * One may choose to act as her own CA and sign the certificate request using a PKI |
michael@0 | 116 | * tool, such as OpenSSL. |
michael@0 | 117 | * </p> |
michael@0 | 118 | * </li> |
michael@0 | 119 | * <li> |
michael@0 | 120 | * <p> |
michael@0 | 121 | * Import the trusted CA root certificate |
michael@0 | 122 | * <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre> |
michael@0 | 123 | * </p> |
michael@0 | 124 | * </li> |
michael@0 | 125 | * <li> |
michael@0 | 126 | * <p> |
michael@0 | 127 | * Import the PKCS#7 file containg the complete certificate chain |
michael@0 | 128 | * <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre> |
michael@0 | 129 | * </p> |
michael@0 | 130 | * </li> |
michael@0 | 131 | * <li> |
michael@0 | 132 | * <p> |
michael@0 | 133 | * Verify the content the resultant keystore file |
michael@0 | 134 | * <pre>keytool -list -v -keystore my.keystore</pre> |
michael@0 | 135 | * </p> |
michael@0 | 136 | * </li> |
michael@0 | 137 | * </ul> |
michael@0 | 138 | * |
michael@0 | 139 | * @since 4.0 |
michael@0 | 140 | */ |
michael@0 | 141 | @SuppressWarnings("deprecation") |
michael@0 | 142 | @ThreadSafe |
michael@0 | 143 | public class SSLSocketFactory implements LayeredSchemeSocketFactory, LayeredSocketFactory { |
michael@0 | 144 | |
michael@0 | 145 | public static final String TLS = "TLS"; |
michael@0 | 146 | public static final String SSL = "SSL"; |
michael@0 | 147 | public static final String SSLV2 = "SSLv2"; |
michael@0 | 148 | |
michael@0 | 149 | public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER |
michael@0 | 150 | = new AllowAllHostnameVerifier(); |
michael@0 | 151 | |
michael@0 | 152 | public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER |
michael@0 | 153 | = new BrowserCompatHostnameVerifier(); |
michael@0 | 154 | |
michael@0 | 155 | public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER |
michael@0 | 156 | = new StrictHostnameVerifier(); |
michael@0 | 157 | |
michael@0 | 158 | /** |
michael@0 | 159 | * Gets the default factory, which uses the default JVM settings for secure |
michael@0 | 160 | * connections. |
michael@0 | 161 | * |
michael@0 | 162 | * @return the default factory |
michael@0 | 163 | */ |
michael@0 | 164 | public static SSLSocketFactory getSocketFactory() { |
michael@0 | 165 | return new SSLSocketFactory(); |
michael@0 | 166 | } |
michael@0 | 167 | |
michael@0 | 168 | private final javax.net.ssl.SSLSocketFactory socketfactory; |
michael@0 | 169 | private final HostNameResolver nameResolver; |
michael@0 | 170 | // TODO: make final |
michael@0 | 171 | private volatile X509HostnameVerifier hostnameVerifier; |
michael@0 | 172 | |
michael@0 | 173 | private static SSLContext createSSLContext( |
michael@0 | 174 | String algorithm, |
michael@0 | 175 | final KeyStore keystore, |
michael@0 | 176 | final String keystorePassword, |
michael@0 | 177 | final KeyStore truststore, |
michael@0 | 178 | final SecureRandom random, |
michael@0 | 179 | final TrustStrategy trustStrategy) |
michael@0 | 180 | throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, KeyManagementException { |
michael@0 | 181 | if (algorithm == null) { |
michael@0 | 182 | algorithm = TLS; |
michael@0 | 183 | } |
michael@0 | 184 | KeyManagerFactory kmfactory = KeyManagerFactory.getInstance( |
michael@0 | 185 | KeyManagerFactory.getDefaultAlgorithm()); |
michael@0 | 186 | kmfactory.init(keystore, keystorePassword != null ? keystorePassword.toCharArray(): null); |
michael@0 | 187 | KeyManager[] keymanagers = kmfactory.getKeyManagers(); |
michael@0 | 188 | TrustManagerFactory tmfactory = TrustManagerFactory.getInstance( |
michael@0 | 189 | TrustManagerFactory.getDefaultAlgorithm()); |
michael@0 | 190 | tmfactory.init(truststore); |
michael@0 | 191 | TrustManager[] trustmanagers = tmfactory.getTrustManagers(); |
michael@0 | 192 | if (trustmanagers != null && trustStrategy != null) { |
michael@0 | 193 | for (int i = 0; i < trustmanagers.length; i++) { |
michael@0 | 194 | TrustManager tm = trustmanagers[i]; |
michael@0 | 195 | if (tm instanceof X509TrustManager) { |
michael@0 | 196 | trustmanagers[i] = new TrustManagerDecorator( |
michael@0 | 197 | (X509TrustManager) tm, trustStrategy); |
michael@0 | 198 | } |
michael@0 | 199 | } |
michael@0 | 200 | } |
michael@0 | 201 | |
michael@0 | 202 | SSLContext sslcontext = SSLContext.getInstance(algorithm); |
michael@0 | 203 | sslcontext.init(keymanagers, trustmanagers, random); |
michael@0 | 204 | return sslcontext; |
michael@0 | 205 | } |
michael@0 | 206 | |
michael@0 | 207 | private static SSLContext createDefaultSSLContext() { |
michael@0 | 208 | try { |
michael@0 | 209 | return createSSLContext(TLS, null, null, null, null, null); |
michael@0 | 210 | } catch (Exception ex) { |
michael@0 | 211 | throw new IllegalStateException("Failure initializing default SSL context", ex); |
michael@0 | 212 | } |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | /** |
michael@0 | 216 | * @deprecated Use {@link #SSLSocketFactory(String, KeyStore, String, KeyStore, SecureRandom, X509HostnameVerifier)} |
michael@0 | 217 | */ |
michael@0 | 218 | @Deprecated |
michael@0 | 219 | public SSLSocketFactory( |
michael@0 | 220 | final String algorithm, |
michael@0 | 221 | final KeyStore keystore, |
michael@0 | 222 | final String keystorePassword, |
michael@0 | 223 | final KeyStore truststore, |
michael@0 | 224 | final SecureRandom random, |
michael@0 | 225 | final HostNameResolver nameResolver) |
michael@0 | 226 | throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { |
michael@0 | 227 | this(createSSLContext( |
michael@0 | 228 | algorithm, keystore, keystorePassword, truststore, random, null), |
michael@0 | 229 | nameResolver); |
michael@0 | 230 | } |
michael@0 | 231 | |
michael@0 | 232 | /** |
michael@0 | 233 | * @since 4.1 |
michael@0 | 234 | */ |
michael@0 | 235 | public SSLSocketFactory( |
michael@0 | 236 | String algorithm, |
michael@0 | 237 | final KeyStore keystore, |
michael@0 | 238 | final String keystorePassword, |
michael@0 | 239 | final KeyStore truststore, |
michael@0 | 240 | final SecureRandom random, |
michael@0 | 241 | final X509HostnameVerifier hostnameVerifier) |
michael@0 | 242 | throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { |
michael@0 | 243 | this(createSSLContext( |
michael@0 | 244 | algorithm, keystore, keystorePassword, truststore, random, null), |
michael@0 | 245 | hostnameVerifier); |
michael@0 | 246 | } |
michael@0 | 247 | |
michael@0 | 248 | /** |
michael@0 | 249 | * @since 4.1 |
michael@0 | 250 | */ |
michael@0 | 251 | public SSLSocketFactory( |
michael@0 | 252 | String algorithm, |
michael@0 | 253 | final KeyStore keystore, |
michael@0 | 254 | final String keystorePassword, |
michael@0 | 255 | final KeyStore truststore, |
michael@0 | 256 | final SecureRandom random, |
michael@0 | 257 | final TrustStrategy trustStrategy, |
michael@0 | 258 | final X509HostnameVerifier hostnameVerifier) |
michael@0 | 259 | throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { |
michael@0 | 260 | this(createSSLContext( |
michael@0 | 261 | algorithm, keystore, keystorePassword, truststore, random, trustStrategy), |
michael@0 | 262 | hostnameVerifier); |
michael@0 | 263 | } |
michael@0 | 264 | |
michael@0 | 265 | public SSLSocketFactory( |
michael@0 | 266 | final KeyStore keystore, |
michael@0 | 267 | final String keystorePassword, |
michael@0 | 268 | final KeyStore truststore) |
michael@0 | 269 | throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { |
michael@0 | 270 | this(TLS, keystore, keystorePassword, truststore, null, null, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); |
michael@0 | 271 | } |
michael@0 | 272 | |
michael@0 | 273 | public SSLSocketFactory( |
michael@0 | 274 | final KeyStore keystore, |
michael@0 | 275 | final String keystorePassword) |
michael@0 | 276 | throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException{ |
michael@0 | 277 | this(TLS, keystore, keystorePassword, null, null, null, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); |
michael@0 | 278 | } |
michael@0 | 279 | |
michael@0 | 280 | public SSLSocketFactory( |
michael@0 | 281 | final KeyStore truststore) |
michael@0 | 282 | throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { |
michael@0 | 283 | this(TLS, null, null, truststore, null, null, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | /** |
michael@0 | 287 | * @since 4.1 |
michael@0 | 288 | */ |
michael@0 | 289 | public SSLSocketFactory( |
michael@0 | 290 | final TrustStrategy trustStrategy, |
michael@0 | 291 | final X509HostnameVerifier hostnameVerifier) |
michael@0 | 292 | throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { |
michael@0 | 293 | this(TLS, null, null, null, null, trustStrategy, hostnameVerifier); |
michael@0 | 294 | } |
michael@0 | 295 | |
michael@0 | 296 | /** |
michael@0 | 297 | * @since 4.1 |
michael@0 | 298 | */ |
michael@0 | 299 | public SSLSocketFactory( |
michael@0 | 300 | final TrustStrategy trustStrategy) |
michael@0 | 301 | throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { |
michael@0 | 302 | this(TLS, null, null, null, null, trustStrategy, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); |
michael@0 | 303 | } |
michael@0 | 304 | |
michael@0 | 305 | public SSLSocketFactory(final SSLContext sslContext) { |
michael@0 | 306 | this(sslContext, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); |
michael@0 | 307 | } |
michael@0 | 308 | |
michael@0 | 309 | /** |
michael@0 | 310 | * @deprecated Use {@link #SSLSocketFactory(SSLContext)} |
michael@0 | 311 | */ |
michael@0 | 312 | @Deprecated |
michael@0 | 313 | public SSLSocketFactory( |
michael@0 | 314 | final SSLContext sslContext, final HostNameResolver nameResolver) { |
michael@0 | 315 | super(); |
michael@0 | 316 | this.socketfactory = sslContext.getSocketFactory(); |
michael@0 | 317 | this.hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER; |
michael@0 | 318 | this.nameResolver = nameResolver; |
michael@0 | 319 | } |
michael@0 | 320 | |
michael@0 | 321 | /** |
michael@0 | 322 | * @since 4.1 |
michael@0 | 323 | */ |
michael@0 | 324 | public SSLSocketFactory( |
michael@0 | 325 | final SSLContext sslContext, final X509HostnameVerifier hostnameVerifier) { |
michael@0 | 326 | super(); |
michael@0 | 327 | this.socketfactory = sslContext.getSocketFactory(); |
michael@0 | 328 | this.hostnameVerifier = hostnameVerifier; |
michael@0 | 329 | this.nameResolver = null; |
michael@0 | 330 | } |
michael@0 | 331 | |
michael@0 | 332 | private SSLSocketFactory() { |
michael@0 | 333 | this(createDefaultSSLContext()); |
michael@0 | 334 | } |
michael@0 | 335 | |
michael@0 | 336 | /** |
michael@0 | 337 | * @param params Optional parameters. Parameters passed to this method will have no effect. |
michael@0 | 338 | * This method will create a unconnected instance of {@link Socket} class. |
michael@0 | 339 | * @since 4.1 |
michael@0 | 340 | */ |
michael@0 | 341 | public Socket createSocket(final HttpParams params) throws IOException { |
michael@0 | 342 | return this.socketfactory.createSocket(); |
michael@0 | 343 | } |
michael@0 | 344 | |
michael@0 | 345 | @Deprecated |
michael@0 | 346 | public Socket createSocket() throws IOException { |
michael@0 | 347 | return this.socketfactory.createSocket(); |
michael@0 | 348 | } |
michael@0 | 349 | |
michael@0 | 350 | /** |
michael@0 | 351 | * @since 4.1 |
michael@0 | 352 | */ |
michael@0 | 353 | public Socket connectSocket( |
michael@0 | 354 | final Socket socket, |
michael@0 | 355 | final InetSocketAddress remoteAddress, |
michael@0 | 356 | final InetSocketAddress localAddress, |
michael@0 | 357 | final HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException { |
michael@0 | 358 | if (remoteAddress == null) { |
michael@0 | 359 | throw new IllegalArgumentException("Remote address may not be null"); |
michael@0 | 360 | } |
michael@0 | 361 | if (params == null) { |
michael@0 | 362 | throw new IllegalArgumentException("HTTP parameters may not be null"); |
michael@0 | 363 | } |
michael@0 | 364 | Socket sock = socket != null ? socket : new Socket(); |
michael@0 | 365 | if (localAddress != null) { |
michael@0 | 366 | sock.setReuseAddress(HttpConnectionParams.getSoReuseaddr(params)); |
michael@0 | 367 | sock.bind(localAddress); |
michael@0 | 368 | } |
michael@0 | 369 | |
michael@0 | 370 | int connTimeout = HttpConnectionParams.getConnectionTimeout(params); |
michael@0 | 371 | int soTimeout = HttpConnectionParams.getSoTimeout(params); |
michael@0 | 372 | |
michael@0 | 373 | try { |
michael@0 | 374 | sock.setSoTimeout(soTimeout); |
michael@0 | 375 | sock.connect(remoteAddress, connTimeout); |
michael@0 | 376 | } catch (SocketTimeoutException ex) { |
michael@0 | 377 | throw new ConnectTimeoutException("Connect to " + remoteAddress + " timed out"); |
michael@0 | 378 | } |
michael@0 | 379 | |
michael@0 | 380 | // HttpInetSocketAddress#toString() returns original hostname value of the remote address |
michael@0 | 381 | String hostname = remoteAddress.toString(); |
michael@0 | 382 | int port = remoteAddress.getPort(); |
michael@0 | 383 | String s = ":" + port; |
michael@0 | 384 | if (hostname.endsWith(s)) { |
michael@0 | 385 | hostname = hostname.substring(0, hostname.length() - s.length()); |
michael@0 | 386 | } |
michael@0 | 387 | |
michael@0 | 388 | SSLSocket sslsock; |
michael@0 | 389 | // Setup SSL layering if necessary |
michael@0 | 390 | if (sock instanceof SSLSocket) { |
michael@0 | 391 | sslsock = (SSLSocket) sock; |
michael@0 | 392 | } else { |
michael@0 | 393 | sslsock = (SSLSocket) this.socketfactory.createSocket(sock, hostname, port, true); |
michael@0 | 394 | } |
michael@0 | 395 | if (this.hostnameVerifier != null) { |
michael@0 | 396 | try { |
michael@0 | 397 | this.hostnameVerifier.verify(hostname, sslsock); |
michael@0 | 398 | // verifyHostName() didn't blowup - good! |
michael@0 | 399 | } catch (IOException iox) { |
michael@0 | 400 | // close the socket before re-throwing the exception |
michael@0 | 401 | try { sslsock.close(); } catch (Exception x) { /*ignore*/ } |
michael@0 | 402 | throw iox; |
michael@0 | 403 | } |
michael@0 | 404 | } |
michael@0 | 405 | return sslsock; |
michael@0 | 406 | } |
michael@0 | 407 | |
michael@0 | 408 | |
michael@0 | 409 | /** |
michael@0 | 410 | * Checks whether a socket connection is secure. |
michael@0 | 411 | * This factory creates TLS/SSL socket connections |
michael@0 | 412 | * which, by default, are considered secure. |
michael@0 | 413 | * <br/> |
michael@0 | 414 | * Derived classes may override this method to perform |
michael@0 | 415 | * runtime checks, for example based on the cypher suite. |
michael@0 | 416 | * |
michael@0 | 417 | * @param sock the connected socket |
michael@0 | 418 | * |
michael@0 | 419 | * @return <code>true</code> |
michael@0 | 420 | * |
michael@0 | 421 | * @throws IllegalArgumentException if the argument is invalid |
michael@0 | 422 | */ |
michael@0 | 423 | public boolean isSecure(final Socket sock) throws IllegalArgumentException { |
michael@0 | 424 | if (sock == null) { |
michael@0 | 425 | throw new IllegalArgumentException("Socket may not be null"); |
michael@0 | 426 | } |
michael@0 | 427 | // This instanceof check is in line with createSocket() above. |
michael@0 | 428 | if (!(sock instanceof SSLSocket)) { |
michael@0 | 429 | throw new IllegalArgumentException("Socket not created by this factory"); |
michael@0 | 430 | } |
michael@0 | 431 | // This check is performed last since it calls the argument object. |
michael@0 | 432 | if (sock.isClosed()) { |
michael@0 | 433 | throw new IllegalArgumentException("Socket is closed"); |
michael@0 | 434 | } |
michael@0 | 435 | return true; |
michael@0 | 436 | } |
michael@0 | 437 | |
michael@0 | 438 | /** |
michael@0 | 439 | * @since 4.1 |
michael@0 | 440 | */ |
michael@0 | 441 | public Socket createLayeredSocket( |
michael@0 | 442 | final Socket socket, |
michael@0 | 443 | final String host, |
michael@0 | 444 | final int port, |
michael@0 | 445 | final boolean autoClose) throws IOException, UnknownHostException { |
michael@0 | 446 | SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket( |
michael@0 | 447 | socket, |
michael@0 | 448 | host, |
michael@0 | 449 | port, |
michael@0 | 450 | autoClose |
michael@0 | 451 | ); |
michael@0 | 452 | if (this.hostnameVerifier != null) { |
michael@0 | 453 | this.hostnameVerifier.verify(host, sslSocket); |
michael@0 | 454 | } |
michael@0 | 455 | // verifyHostName() didn't blowup - good! |
michael@0 | 456 | return sslSocket; |
michael@0 | 457 | } |
michael@0 | 458 | |
michael@0 | 459 | @Deprecated |
michael@0 | 460 | public void setHostnameVerifier(X509HostnameVerifier hostnameVerifier) { |
michael@0 | 461 | if ( hostnameVerifier == null ) { |
michael@0 | 462 | throw new IllegalArgumentException("Hostname verifier may not be null"); |
michael@0 | 463 | } |
michael@0 | 464 | this.hostnameVerifier = hostnameVerifier; |
michael@0 | 465 | } |
michael@0 | 466 | |
michael@0 | 467 | public X509HostnameVerifier getHostnameVerifier() { |
michael@0 | 468 | return this.hostnameVerifier; |
michael@0 | 469 | } |
michael@0 | 470 | |
michael@0 | 471 | /** |
michael@0 | 472 | * @deprecated Use {@link #connectSocket(Socket, InetSocketAddress, InetSocketAddress, HttpParams)} |
michael@0 | 473 | */ |
michael@0 | 474 | @Deprecated |
michael@0 | 475 | public Socket connectSocket( |
michael@0 | 476 | final Socket socket, |
michael@0 | 477 | final String host, int port, |
michael@0 | 478 | final InetAddress localAddress, int localPort, |
michael@0 | 479 | final HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException { |
michael@0 | 480 | InetSocketAddress local = null; |
michael@0 | 481 | if (localAddress != null || localPort > 0) { |
michael@0 | 482 | // we need to bind explicitly |
michael@0 | 483 | if (localPort < 0) { |
michael@0 | 484 | localPort = 0; // indicates "any" |
michael@0 | 485 | } |
michael@0 | 486 | local = new InetSocketAddress(localAddress, localPort); |
michael@0 | 487 | } |
michael@0 | 488 | InetAddress remoteAddress; |
michael@0 | 489 | if (this.nameResolver != null) { |
michael@0 | 490 | remoteAddress = this.nameResolver.resolve(host); |
michael@0 | 491 | } else { |
michael@0 | 492 | remoteAddress = InetAddress.getByName(host); |
michael@0 | 493 | } |
michael@0 | 494 | InetSocketAddress remote = new InetSocketAddress(remoteAddress, port); |
michael@0 | 495 | return connectSocket(socket, remote, local, params); |
michael@0 | 496 | } |
michael@0 | 497 | |
michael@0 | 498 | /** |
michael@0 | 499 | * @deprecated Use {@link #createLayeredSocket(Socket, String, int, boolean)} |
michael@0 | 500 | */ |
michael@0 | 501 | @Deprecated |
michael@0 | 502 | public Socket createSocket( |
michael@0 | 503 | final Socket socket, |
michael@0 | 504 | final String host, int port, |
michael@0 | 505 | boolean autoClose) throws IOException, UnknownHostException { |
michael@0 | 506 | return createLayeredSocket(socket, host, port, autoClose); |
michael@0 | 507 | } |
michael@0 | 508 | |
michael@0 | 509 | } |