[1174] | 1 | /* |
---|
| 2 | * $HeadURL$ |
---|
| 3 | * $Revision$ |
---|
| 4 | * $Date$ |
---|
| 5 | * |
---|
| 6 | * ==================================================================== |
---|
| 7 | * |
---|
| 8 | * Licensed to the Apache Software Foundation (ASF) under one or more |
---|
| 9 | * contributor license agreements. See the NOTICE file distributed with |
---|
| 10 | * this work for additional information regarding copyright ownership. |
---|
| 11 | * The ASF licenses this file to You under the Apache License, Version 2.0 |
---|
| 12 | * (the "License"); you may not use this file except in compliance with |
---|
| 13 | * the License. You may obtain a copy of the License at |
---|
| 14 | * |
---|
| 15 | * http://www.apache.org/licenses/LICENSE-2.0 |
---|
| 16 | * |
---|
| 17 | * Unless required by applicable law or agreed to in writing, software |
---|
| 18 | * distributed under the License is distributed on an "AS IS" BASIS, |
---|
| 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
---|
| 20 | * See the License for the specific language governing permissions and |
---|
| 21 | * limitations under the License. |
---|
| 22 | * ==================================================================== |
---|
| 23 | * |
---|
| 24 | * This software consists of voluntary contributions made by many |
---|
| 25 | * individuals on behalf of the Apache Software Foundation. For more |
---|
| 26 | * information on the Apache Software Foundation, please see |
---|
| 27 | * <http://www.apache.org/>. |
---|
| 28 | * |
---|
| 29 | */ |
---|
| 30 | |
---|
| 31 | package br.gov.serpro.cert; |
---|
| 32 | |
---|
| 33 | import br.gov.serpro.setup.Setup; |
---|
| 34 | import java.io.IOException; |
---|
| 35 | import java.io.InputStream; |
---|
| 36 | import java.net.InetAddress; |
---|
| 37 | import java.net.InetSocketAddress; |
---|
| 38 | import java.net.Socket; |
---|
| 39 | import java.net.SocketAddress; |
---|
| 40 | import java.net.URL; |
---|
| 41 | import java.net.UnknownHostException; |
---|
| 42 | import java.security.GeneralSecurityException; |
---|
| 43 | import java.security.KeyStore; |
---|
| 44 | import java.security.KeyStoreException; |
---|
| 45 | import java.security.NoSuchAlgorithmException; |
---|
| 46 | import java.security.UnrecoverableKeyException; |
---|
| 47 | import java.security.cert.Certificate; |
---|
| 48 | import java.security.cert.CertificateException; |
---|
| 49 | import java.security.cert.X509Certificate; |
---|
| 50 | import java.util.Enumeration; |
---|
| 51 | |
---|
| 52 | import org.apache.commons.httpclient.ConnectTimeoutException; |
---|
| 53 | import org.apache.commons.httpclient.params.HttpConnectionParams; |
---|
| 54 | import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; |
---|
| 55 | import org.apache.commons.logging.Log; |
---|
| 56 | import org.apache.commons.logging.LogFactory; |
---|
| 57 | |
---|
| 58 | import javax.net.SocketFactory; |
---|
| 59 | import javax.net.ssl.KeyManager; |
---|
| 60 | import javax.net.ssl.KeyManagerFactory; |
---|
| 61 | import javax.net.ssl.SSLContext; |
---|
| 62 | import javax.net.ssl.TrustManager; |
---|
| 63 | import javax.net.ssl.TrustManagerFactory; |
---|
| 64 | import javax.net.ssl.X509TrustManager; |
---|
| 65 | |
---|
| 66 | /** |
---|
| 67 | * <p> |
---|
| 68 | * AuthSSLProtocolSocketFactory can be used to validate the identity of the HTTPS |
---|
| 69 | * server against a list of trusted certificates and to authenticate to the HTTPS |
---|
| 70 | * server using a private key. |
---|
| 71 | * </p> |
---|
| 72 | * |
---|
| 73 | * <p> |
---|
| 74 | * AuthSSLProtocolSocketFactory will enable server authentication when supplied with |
---|
| 75 | * a {@link KeyStore truststore} file containg one or several trusted certificates. |
---|
| 76 | * The client secure socket will reject the connection during the SSL session handshake |
---|
| 77 | * if the target HTTPS server attempts to authenticate itself with a non-trusted |
---|
| 78 | * certificate. |
---|
| 79 | * </p> |
---|
| 80 | * |
---|
| 81 | * <p> |
---|
| 82 | * Use JDK keytool utility to import a trusted certificate and generate a truststore file: |
---|
| 83 | * <pre> |
---|
| 84 | * keytool -import -alias "my server cert" -file server.crt -keystore my.truststore |
---|
| 85 | * </pre> |
---|
| 86 | * </p> |
---|
| 87 | * |
---|
| 88 | * <p> |
---|
| 89 | * AuthSSLProtocolSocketFactory will enable client authentication when supplied with |
---|
| 90 | * a {@link KeyStore keystore} file containg a private key/public certificate pair. |
---|
| 91 | * The client secure socket will use the private key to authenticate itself to the target |
---|
| 92 | * HTTPS server during the SSL session handshake if requested to do so by the server. |
---|
| 93 | * The target HTTPS server will in its turn verify the certificate presented by the client |
---|
| 94 | * in order to establish client's authenticity |
---|
| 95 | * </p> |
---|
| 96 | * |
---|
| 97 | * <p> |
---|
| 98 | * Use the following sequence of actions to generate a keystore file |
---|
| 99 | * </p> |
---|
| 100 | * <ul> |
---|
| 101 | * <li> |
---|
| 102 | * <p> |
---|
| 103 | * Use JDK keytool utility to generate a new key |
---|
| 104 | * <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre> |
---|
| 105 | * For simplicity use the same password for the key as that of the keystore |
---|
| 106 | * </p> |
---|
| 107 | * </li> |
---|
| 108 | * <li> |
---|
| 109 | * <p> |
---|
| 110 | * Issue a certificate signing request (CSR) |
---|
| 111 | * <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre> |
---|
| 112 | * </p> |
---|
| 113 | * </li> |
---|
| 114 | * <li> |
---|
| 115 | * <p> |
---|
| 116 | * Send the certificate request to the trusted Certificate Authority for signature. |
---|
| 117 | * One may choose to act as her own CA and sign the certificate request using a PKI |
---|
| 118 | * tool, such as OpenSSL. |
---|
| 119 | * </p> |
---|
| 120 | * </li> |
---|
| 121 | * <li> |
---|
| 122 | * <p> |
---|
| 123 | * Import the trusted CA root certificate |
---|
| 124 | * <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre> |
---|
| 125 | * </p> |
---|
| 126 | * </li> |
---|
| 127 | * <li> |
---|
| 128 | * <p> |
---|
| 129 | * Import the PKCS#7 file containg the complete certificate chain |
---|
| 130 | * <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre> |
---|
| 131 | * </p> |
---|
| 132 | * </li> |
---|
| 133 | * <li> |
---|
| 134 | * <p> |
---|
| 135 | * Verify the content the resultant keystore file |
---|
| 136 | * <pre>keytool -list -v -keystore my.keystore</pre> |
---|
| 137 | * </p> |
---|
| 138 | * </li> |
---|
| 139 | * </ul> |
---|
| 140 | * <p> |
---|
| 141 | * Example of using custom protocol socket factory for a specific host: |
---|
| 142 | * <pre> |
---|
| 143 | * Protocol authhttps = new Protocol("https", |
---|
| 144 | * new AuthSSLProtocolSocketFactory( |
---|
| 145 | * new URL("file:my.keystore"), "mypassword", |
---|
| 146 | * new URL("file:my.truststore"), "mypassword"), 443); |
---|
| 147 | * |
---|
| 148 | * HttpClient client = new HttpClient(); |
---|
| 149 | * client.getHostConfiguration().setHost("localhost", 443, authhttps); |
---|
| 150 | * // use relative url only |
---|
| 151 | * GetMethod httpget = new GetMethod("/"); |
---|
| 152 | * client.executeMethod(httpget); |
---|
| 153 | * </pre> |
---|
| 154 | * </p> |
---|
| 155 | * <p> |
---|
| 156 | * Example of using custom protocol socket factory per default instead of the standard one: |
---|
| 157 | * <pre> |
---|
| 158 | * Protocol authhttps = new Protocol("https", |
---|
| 159 | * new AuthSSLProtocolSocketFactory( |
---|
| 160 | * new URL("file:my.keystore"), "mypassword", |
---|
| 161 | * new URL("file:my.truststore"), "mypassword"), 443); |
---|
| 162 | * Protocol.registerProtocol("https", authhttps); |
---|
| 163 | * |
---|
| 164 | * HttpClient client = new HttpClient(); |
---|
| 165 | * GetMethod httpget = new GetMethod("https://localhost/"); |
---|
| 166 | * client.executeMethod(httpget); |
---|
| 167 | * </pre> |
---|
| 168 | * </p> |
---|
| 169 | * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a> |
---|
| 170 | * |
---|
| 171 | * <p> |
---|
| 172 | * DISCLAIMER: HttpClient developers DO NOT actively support this component. |
---|
| 173 | * The component is provided as a reference material, which may be inappropriate |
---|
| 174 | * for use without additional customization. |
---|
| 175 | * </p> |
---|
| 176 | */ |
---|
| 177 | |
---|
| 178 | public class AuthSSLProtocolSocketFactory implements |
---|
| 179 | SecureProtocolSocketFactory { |
---|
| 180 | |
---|
| 181 | /** Log object for this class. */ |
---|
| 182 | private static final Log LOG = LogFactory.getLog(AuthSSLProtocolSocketFactory.class); |
---|
| 183 | |
---|
| 184 | private URL[] truststoreUrls = null; |
---|
| 185 | private String[] truststorePasswords = null; |
---|
| 186 | private SSLContext sslcontext = null; |
---|
| 187 | private static Setup setup = null; |
---|
| 188 | |
---|
| 189 | /** |
---|
| 190 | * Constructor for AuthSSLProtocolSocketFactory. Either a keystore or truststore file |
---|
| 191 | * must be given. Otherwise SSL context initialization error will result. |
---|
| 192 | * |
---|
| 193 | * @param keystoreUrl URL of the keystore file. May be <tt>null</tt> if HTTPS client |
---|
| 194 | * authentication is not to be used. |
---|
| 195 | * @param keystorePassword Password to unlock the keystore. IMPORTANT: this implementation |
---|
| 196 | * assumes that the same password is used to protect the key and the keystore itself. |
---|
| 197 | * @param truststoreUrls URL of the truststore file. May be <tt>null</tt> if HTTPS server |
---|
| 198 | * authentication is not to be used. |
---|
| 199 | * @param truststorePasswords Password to unlock the truststore. |
---|
| 200 | */ |
---|
| 201 | public AuthSSLProtocolSocketFactory( |
---|
| 202 | final URL[] truststoreUrls, final String[] truststorePasswords, final Setup setup) |
---|
| 203 | { |
---|
| 204 | super(); |
---|
| 205 | this.truststoreUrls = truststoreUrls; |
---|
| 206 | this.truststorePasswords = truststorePasswords; |
---|
| 207 | AuthSSLProtocolSocketFactory.setup = setup; |
---|
| 208 | } |
---|
| 209 | |
---|
| 210 | // TODO: Usar um mapa de keystores e senhas ou algo como KeystoreCredentialsPair |
---|
| 211 | private static KeyStore createKeyStore(final URL[] urls, final String[] passwords) |
---|
| 212 | throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException |
---|
| 213 | { |
---|
| 214 | KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); |
---|
| 215 | keystore.load(null); |
---|
| 216 | |
---|
| 217 | if (urls == null) { |
---|
| 218 | throw new IllegalArgumentException("Keystore urls may not be null"); |
---|
| 219 | } |
---|
| 220 | |
---|
| 221 | if (passwords != null && passwords.length != urls.length){ |
---|
| 222 | throw new IllegalArgumentException("Urls and passwords arrays must have the same size"); |
---|
| 223 | } |
---|
| 224 | |
---|
| 225 | LOG.debug("Initializing key store"); |
---|
| 226 | |
---|
| 227 | for (int i = 0; i < urls.length; i++){ |
---|
| 228 | |
---|
| 229 | LOG.debug("Adding " + urls[i].toString() + " to internal keystore"); |
---|
| 230 | KeyStore ks = KeyStore.getInstance("jks"); |
---|
| 231 | InputStream is = null; |
---|
| 232 | try { |
---|
| 233 | is = urls[i].openStream(); |
---|
| 234 | |
---|
| 235 | if (passwords == null){ |
---|
| 236 | ks.load(is, null); |
---|
| 237 | } |
---|
| 238 | else { |
---|
| 239 | ks.load(is, passwords[i] != null ? passwords[i].toCharArray(): null); |
---|
| 240 | } |
---|
| 241 | |
---|
| 242 | for (Enumeration<String> e = ks.aliases(); e.hasMoreElements();){ |
---|
| 243 | X509Certificate cert = (X509Certificate) ks.getCertificate(e.nextElement()); |
---|
| 244 | keystore.setCertificateEntry(cert.getSubjectX500Principal().getName(), cert); |
---|
| 245 | } |
---|
| 246 | } catch (IOException e){ |
---|
| 247 | if (AuthSSLProtocolSocketFactory.setup.getParameter("debug").equalsIgnoreCase("true")){ |
---|
| 248 | System.out.println("Erro ao abrir URL: " + urls[i].toExternalForm()); |
---|
| 249 | } |
---|
| 250 | } finally { |
---|
| 251 | if (is != null) is.close(); |
---|
| 252 | } |
---|
| 253 | } |
---|
| 254 | return keystore; |
---|
| 255 | } |
---|
| 256 | |
---|
| 257 | private static KeyManager[] createKeyManagers(final KeyStore keystore, final String password) |
---|
| 258 | throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException |
---|
| 259 | { |
---|
| 260 | if (keystore == null) { |
---|
| 261 | throw new IllegalArgumentException("Keystore may not be null"); |
---|
| 262 | } |
---|
| 263 | LOG.debug("Initializing key manager"); |
---|
| 264 | KeyManagerFactory kmfactory = KeyManagerFactory.getInstance( |
---|
| 265 | KeyManagerFactory.getDefaultAlgorithm()); |
---|
| 266 | kmfactory.init(keystore, password != null ? password.toCharArray(): null); |
---|
| 267 | return kmfactory.getKeyManagers(); |
---|
| 268 | } |
---|
| 269 | |
---|
| 270 | private static TrustManager[] createTrustManagers(final KeyStore keystore) |
---|
| 271 | throws KeyStoreException, NoSuchAlgorithmException |
---|
| 272 | { |
---|
| 273 | if (keystore == null) { |
---|
| 274 | throw new IllegalArgumentException("Keystore may not be null"); |
---|
| 275 | } |
---|
| 276 | LOG.debug("Initializing trust manager"); |
---|
| 277 | TrustManagerFactory tmfactory = TrustManagerFactory.getInstance( |
---|
| 278 | TrustManagerFactory.getDefaultAlgorithm()); |
---|
| 279 | tmfactory.init(keystore); |
---|
| 280 | TrustManager[] trustmanagers = tmfactory.getTrustManagers(); |
---|
| 281 | for (int i = 0; i < trustmanagers.length; i++) { |
---|
| 282 | if (trustmanagers[i] instanceof X509TrustManager) { |
---|
| 283 | trustmanagers[i] = new AuthSSLX509TrustManager( |
---|
| 284 | (X509TrustManager)trustmanagers[i]); |
---|
| 285 | } |
---|
| 286 | } |
---|
| 287 | return trustmanagers; |
---|
| 288 | } |
---|
| 289 | |
---|
| 290 | private SSLContext createSSLContext() { |
---|
| 291 | try { |
---|
| 292 | // KeyManager[] keymanagers = null; |
---|
| 293 | TrustManager[] trustmanagers = null; |
---|
| 294 | /* |
---|
| 295 | if (this.keystoreUrl != null) { |
---|
| 296 | KeyStore keystore = createKeyStore(this.keystoreUrl, this.keystorePassword); |
---|
| 297 | if (LOG.isDebugEnabled()) { |
---|
| 298 | Enumeration aliases = keystore.aliases(); |
---|
| 299 | while (aliases.hasMoreElements()) { |
---|
| 300 | String alias = (String)aliases.nextElement(); |
---|
| 301 | Certificate[] certs = keystore.getCertificateChain(alias); |
---|
| 302 | if (certs != null) { |
---|
| 303 | LOG.debug("Certificate chain '" + alias + "':"); |
---|
| 304 | for (int c = 0; c < certs.length; c++) { |
---|
| 305 | if (certs[c] instanceof X509Certificate) { |
---|
| 306 | X509Certificate cert = (X509Certificate)certs[c]; |
---|
| 307 | LOG.debug(" Certificate " + (c + 1) + ":"); |
---|
| 308 | LOG.debug(" Subject DN: " + cert.getSubjectDN()); |
---|
| 309 | LOG.debug(" Signature Algorithm: " + cert.getSigAlgName()); |
---|
| 310 | LOG.debug(" Valid from: " + cert.getNotBefore() ); |
---|
| 311 | LOG.debug(" Valid until: " + cert.getNotAfter()); |
---|
| 312 | LOG.debug(" Issuer: " + cert.getIssuerDN()); |
---|
| 313 | } |
---|
| 314 | } |
---|
| 315 | } |
---|
| 316 | } |
---|
| 317 | } |
---|
| 318 | keymanagers = createKeyManagers(keystore, this.keystorePassword); |
---|
| 319 | } |
---|
| 320 | */ |
---|
| 321 | if (this.truststoreUrls != null) { |
---|
| 322 | KeyStore keystore = createKeyStore(this.truststoreUrls, this.truststorePasswords); |
---|
| 323 | if (LOG.isDebugEnabled()) { |
---|
| 324 | Enumeration aliases = keystore.aliases(); |
---|
| 325 | while (aliases.hasMoreElements()) { |
---|
| 326 | String alias = (String)aliases.nextElement(); |
---|
| 327 | LOG.debug("Trusted certificate '" + alias + "':"); |
---|
| 328 | Certificate trustedcert = keystore.getCertificate(alias); |
---|
| 329 | if (trustedcert != null && trustedcert instanceof X509Certificate) { |
---|
| 330 | X509Certificate cert = (X509Certificate)trustedcert; |
---|
| 331 | LOG.debug(" Subject DN: " + cert.getSubjectDN()); |
---|
| 332 | LOG.debug(" Signature Algorithm: " + cert.getSigAlgName()); |
---|
| 333 | LOG.debug(" Valid from: " + cert.getNotBefore() ); |
---|
| 334 | LOG.debug(" Valid until: " + cert.getNotAfter()); |
---|
| 335 | LOG.debug(" Issuer: " + cert.getIssuerDN()); |
---|
| 336 | } |
---|
| 337 | } |
---|
| 338 | } |
---|
| 339 | trustmanagers = createTrustManagers(keystore); |
---|
| 340 | } |
---|
| 341 | SSLContext sslcontext = SSLContext.getInstance("SSL"); |
---|
| 342 | sslcontext.init(null, trustmanagers, null); |
---|
| 343 | return sslcontext; |
---|
| 344 | } catch (NoSuchAlgorithmException e) { |
---|
| 345 | LOG.error(e.getMessage(), e); |
---|
| 346 | throw new AuthSSLInitializationError("Unsupported algorithm exception: " + e.getMessage()); |
---|
| 347 | } catch (KeyStoreException e) { |
---|
| 348 | LOG.error(e.getMessage(), e); |
---|
| 349 | throw new AuthSSLInitializationError("Keystore exception: " + e.getMessage()); |
---|
| 350 | } catch (GeneralSecurityException e) { |
---|
| 351 | LOG.error(e.getMessage(), e); |
---|
| 352 | throw new AuthSSLInitializationError("Key management exception: " + e.getMessage()); |
---|
| 353 | } catch (IOException e) { |
---|
| 354 | LOG.error(e.getMessage(), e); |
---|
| 355 | throw new AuthSSLInitializationError("I/O error reading keystore/truststore file: " + e.getMessage()); |
---|
| 356 | } |
---|
| 357 | } |
---|
| 358 | |
---|
| 359 | private SSLContext getSSLContext() { |
---|
| 360 | if (this.sslcontext == null) { |
---|
| 361 | this.sslcontext = createSSLContext(); |
---|
| 362 | } |
---|
| 363 | return this.sslcontext; |
---|
| 364 | } |
---|
| 365 | |
---|
| 366 | /** |
---|
| 367 | * Attempts to get a new socket connection to the given host within the given time limit. |
---|
| 368 | * <p> |
---|
| 369 | * To circumvent the limitations of older JREs that do not support connect timeout a |
---|
| 370 | * controller thread is executed. The controller thread attempts to create a new socket |
---|
| 371 | * within the given limit of time. If socket constructor does not return until the |
---|
| 372 | * timeout expires, the controller terminates and throws an {@link ConnectTimeoutException} |
---|
| 373 | * </p> |
---|
| 374 | * |
---|
| 375 | * @param host the host name/IP |
---|
| 376 | * @param port the port on the host |
---|
| 377 | * @param clientHost the local host name/IP to bind the socket to |
---|
| 378 | * @param clientPort the port on the local machine |
---|
| 379 | * @param params {@link HttpConnectionParams Http connection parameters} |
---|
| 380 | * |
---|
| 381 | * @return Socket a new socket |
---|
| 382 | * |
---|
| 383 | * @throws IOException if an I/O error occurs while creating the socket |
---|
| 384 | * @throws UnknownHostException if the IP address of the host cannot be |
---|
| 385 | * determined |
---|
| 386 | */ |
---|
| 387 | public Socket createSocket( |
---|
| 388 | final String host, |
---|
| 389 | final int port, |
---|
| 390 | final InetAddress localAddress, |
---|
| 391 | final int localPort, |
---|
| 392 | final HttpConnectionParams params |
---|
| 393 | ) throws IOException, UnknownHostException, ConnectTimeoutException { |
---|
| 394 | if (params == null) { |
---|
| 395 | throw new IllegalArgumentException("Parameters may not be null"); |
---|
| 396 | } |
---|
| 397 | int timeout = params.getConnectionTimeout(); |
---|
| 398 | SocketFactory socketfactory = getSSLContext().getSocketFactory(); |
---|
| 399 | if (timeout == 0) { |
---|
| 400 | return socketfactory.createSocket(host, port, localAddress, localPort); |
---|
| 401 | } else { |
---|
| 402 | Socket socket = socketfactory.createSocket(); |
---|
| 403 | SocketAddress localaddr = new InetSocketAddress(localAddress, localPort); |
---|
| 404 | SocketAddress remoteaddr = new InetSocketAddress(host, port); |
---|
| 405 | socket.bind(localaddr); |
---|
| 406 | socket.connect(remoteaddr, timeout); |
---|
| 407 | return socket; |
---|
| 408 | } |
---|
| 409 | } |
---|
| 410 | |
---|
| 411 | /** |
---|
| 412 | * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int) |
---|
| 413 | */ |
---|
| 414 | public Socket createSocket( |
---|
| 415 | String host, |
---|
| 416 | int port, |
---|
| 417 | InetAddress clientHost, |
---|
| 418 | int clientPort) |
---|
| 419 | throws IOException, UnknownHostException |
---|
| 420 | { |
---|
| 421 | return getSSLContext().getSocketFactory().createSocket( |
---|
| 422 | host, |
---|
| 423 | port, |
---|
| 424 | clientHost, |
---|
| 425 | clientPort |
---|
| 426 | ); |
---|
| 427 | } |
---|
| 428 | |
---|
| 429 | /** |
---|
| 430 | * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int) |
---|
| 431 | */ |
---|
| 432 | public Socket createSocket(String host, int port) |
---|
| 433 | throws IOException, UnknownHostException |
---|
| 434 | { |
---|
| 435 | return getSSLContext().getSocketFactory().createSocket( |
---|
| 436 | host, |
---|
| 437 | port |
---|
| 438 | ); |
---|
| 439 | } |
---|
| 440 | |
---|
| 441 | /** |
---|
| 442 | * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean) |
---|
| 443 | */ |
---|
| 444 | public Socket createSocket( |
---|
| 445 | Socket socket, |
---|
| 446 | String host, |
---|
| 447 | int port, |
---|
| 448 | boolean autoClose) |
---|
| 449 | throws IOException, UnknownHostException |
---|
| 450 | { |
---|
| 451 | return getSSLContext().getSocketFactory().createSocket( |
---|
| 452 | socket, |
---|
| 453 | host, |
---|
| 454 | port, |
---|
| 455 | autoClose |
---|
| 456 | ); |
---|
| 457 | } |
---|
| 458 | |
---|
| 459 | |
---|
| 460 | } |
---|