View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.http.conn.ssl;
29  
30  import java.io.IOException;
31  import java.net.InetAddress;
32  import java.net.InetSocketAddress;
33  import java.net.Socket;
34  import java.net.SocketTimeoutException;
35  import java.net.UnknownHostException;
36  import java.security.KeyManagementException;
37  import java.security.KeyStore;
38  import java.security.KeyStoreException;
39  import java.security.NoSuchAlgorithmException;
40  import java.security.SecureRandom;
41  import java.security.UnrecoverableKeyException;
42  
43  import javax.net.ssl.KeyManager;
44  import javax.net.ssl.KeyManagerFactory;
45  import javax.net.ssl.SSLContext;
46  import javax.net.ssl.SSLSocket;
47  import javax.net.ssl.TrustManager;
48  import javax.net.ssl.TrustManagerFactory;
49  import javax.net.ssl.X509TrustManager;
50  
51  import org.apache.http.HttpHost;
52  import org.apache.http.annotation.ThreadSafe;
53  import org.apache.http.conn.ConnectTimeoutException;
54  import org.apache.http.conn.HttpInetSocketAddress;
55  import org.apache.http.conn.scheme.HostNameResolver;
56  import org.apache.http.conn.scheme.LayeredSchemeSocketFactory;
57  import org.apache.http.conn.scheme.LayeredSocketFactory;
58  import org.apache.http.conn.scheme.SchemeLayeredSocketFactory;
59  import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
60  import org.apache.http.params.HttpConnectionParams;
61  import org.apache.http.params.HttpParams;
62  import org.apache.http.protocol.HttpContext;
63  import org.apache.http.util.Args;
64  import org.apache.http.util.Asserts;
65  
66  /**
67   * Layered socket factory for TLS/SSL connections.
68   * <p>
69   * SSLSocketFactory can be used to validate the identity of the HTTPS server against a list of
70   * trusted certificates and to authenticate to the HTTPS server using a private key.
71   * <p>
72   * SSLSocketFactory will enable server authentication when supplied with
73   * a {@link KeyStore trust-store} file containing one or several trusted certificates. The client
74   * secure socket will reject the connection during the SSL session handshake if the target HTTPS
75   * server attempts to authenticate itself with a non-trusted certificate.
76   * <p>
77   * Use JDK keytool utility to import a trusted certificate and generate a trust-store file:
78   *    <pre>
79   *     keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
80   *    </pre>
81   * <p>
82   * In special cases the standard trust verification process can be bypassed by using a custom
83   * {@link TrustStrategy}. This interface is primarily intended for allowing self-signed
84   * certificates to be accepted as trusted without having to add them to the trust-store file.
85   * <p>
86   * SSLSocketFactory will enable client authentication when supplied with
87   * a {@link KeyStore key-store} file containing a private key/public certificate
88   * pair. The client secure socket will use the private key to authenticate
89   * itself to the target HTTPS server during the SSL session handshake if
90   * requested to do so by the server.
91   * The target HTTPS server will in its turn verify the certificate presented
92   * by the client in order to establish client's authenticity
93   * <p>
94   * Use the following sequence of actions to generate a key-store file
95   * </p>
96   *   <ul>
97   *     <li>
98   *      <p>
99   *      Use JDK keytool utility to generate a new key
100  *      <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre>
101  *      For simplicity use the same password for the key as that of the key-store
102  *      </p>
103  *     </li>
104  *     <li>
105  *      <p>
106  *      Issue a certificate signing request (CSR)
107  *      <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre>
108  *     </p>
109  *     </li>
110  *     <li>
111  *      <p>
112  *      Send the certificate request to the trusted Certificate Authority for signature.
113  *      One may choose to act as her own CA and sign the certificate request using a PKI
114  *      tool, such as OpenSSL.
115  *      </p>
116  *     </li>
117  *     <li>
118  *      <p>
119  *       Import the trusted CA root certificate
120  *       <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
121  *      </p>
122  *     </li>
123  *     <li>
124  *      <p>
125  *       Import the PKCS#7 file containg the complete certificate chain
126  *       <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>
127  *      </p>
128  *     </li>
129  *     <li>
130  *      <p>
131  *       Verify the content the resultant keystore file
132  *       <pre>keytool -list -v -keystore my.keystore</pre>
133  *      </p>
134  *     </li>
135  *   </ul>
136  *
137  * @since 4.0
138  */
139 @SuppressWarnings("deprecation")
140 @ThreadSafe
141 public class SSLSocketFactory implements LayeredConnectionSocketFactory, SchemeLayeredSocketFactory,
142                                          LayeredSchemeSocketFactory, LayeredSocketFactory {
143 
144     public static final String TLS   = "TLS";
145     public static final String SSL   = "SSL";
146     public static final String SSLV2 = "SSLv2";
147 
148     public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER
149         = new AllowAllHostnameVerifier();
150 
151     public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
152         = new BrowserCompatHostnameVerifier();
153 
154     public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER
155         = new StrictHostnameVerifier();
156 
157     /**
158      * Obtains default SSL socket factory with an SSL context based on the standard JSSE
159      * trust material (<code>cacerts</code> file in the security properties directory).
160      * System properties are not taken into consideration.
161      *
162      * @return default SSL socket factory
163      */
164     public static SSLSocketFactory getSocketFactory() throws SSLInitializationException {
165         return new SSLSocketFactory(
166             SSLContexts.createDefault(),
167             BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
168     }
169 
170     /**
171      * Obtains default SSL socket factory with an SSL context based on system properties
172      * as described in
173      * <a href="http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html">
174      * "JavaTM Secure Socket Extension (JSSE) Reference Guide for the JavaTM 2 Platform
175      * Standard Edition 5</a>
176      *
177      * @return default system SSL socket factory
178      */
179     public static SSLSocketFactory getSystemSocketFactory() throws SSLInitializationException {
180         return new SSLSocketFactory(
181             (javax.net.ssl.SSLSocketFactory) javax.net.ssl.SSLSocketFactory.getDefault(),
182             BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
183     }
184 
185     private final javax.net.ssl.SSLSocketFactory socketfactory;
186     private final HostNameResolver nameResolver;
187     // TODO: make final
188     private volatile X509HostnameVerifier hostnameVerifier;
189 
190     private static SSLContext createSSLContext(
191             String algorithm,
192             final KeyStore keystore,
193             final char[] keystorePassword,
194             final KeyStore truststore,
195             final SecureRandom random,
196             final TrustStrategy trustStrategy)
197                 throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, KeyManagementException {
198         if (algorithm == null) {
199             algorithm = TLS;
200         }
201         final KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
202                 KeyManagerFactory.getDefaultAlgorithm());
203         kmfactory.init(keystore, keystorePassword);
204         final KeyManager[] keymanagers =  kmfactory.getKeyManagers();
205         final TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
206                 TrustManagerFactory.getDefaultAlgorithm());
207         tmfactory.init(truststore);
208         final TrustManager[] trustmanagers = tmfactory.getTrustManagers();
209         if (trustmanagers != null && trustStrategy != null) {
210             for (int i = 0; i < trustmanagers.length; i++) {
211                 final TrustManager tm = trustmanagers[i];
212                 if (tm instanceof X509TrustManager) {
213                     trustmanagers[i] = new TrustManagerDecorator(
214                             (X509TrustManager) tm, trustStrategy);
215                 }
216             }
217         }
218 
219         final SSLContext sslcontext = SSLContext.getInstance(algorithm);
220         sslcontext.init(keymanagers, trustmanagers, random);
221         return sslcontext;
222     }
223 
224     /**
225      * @since 4.3
226      */
227     public SSLSocketFactory(
228             final String algorithm,
229             final KeyStore keystore,
230             final char[] keystorePassword,
231             final KeyStore truststore,
232             final SecureRandom random,
233             final TrustStrategy trustStrategy,
234             final X509HostnameVerifier hostnameVerifier)
235                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
236         this(createSSLContext(algorithm, keystore, keystorePassword, truststore, random, trustStrategy),
237                 hostnameVerifier);
238     }
239 
240     /**
241      * @deprecated (4.1) Use {@link #SSLSocketFactory(String, KeyStore, char[], KeyStore,
242      *   SecureRandom, X509HostnameVerifier)}
243      */
244     @Deprecated
245     public SSLSocketFactory(
246             final String algorithm,
247             final KeyStore keystore,
248             final String keystorePassword,
249             final KeyStore truststore,
250             final SecureRandom random,
251             final HostNameResolver nameResolver)
252                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
253         this(createSSLContext(
254                 algorithm, keystore, keystorePassword != null ? keystorePassword.toCharArray() : null,
255                         truststore, random, null), nameResolver);
256     }
257 
258     /**
259      * @since 4.1
260      *
261      * @deprecated (4.3) Use {@link SSLSocketFactory#SSLSocketFactory(String, KeyStore, char[],
262      *   KeyStore, SecureRandom, TrustStrategy, X509HostnameVerifier)}
263      */
264     @Deprecated
265     public SSLSocketFactory(
266             final String algorithm,
267             final KeyStore keystore,
268             final String keystorePassword,
269             final KeyStore truststore,
270             final SecureRandom random,
271             final TrustStrategy trustStrategy,
272             final X509HostnameVerifier hostnameVerifier)
273                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
274         this(createSSLContext(
275                 algorithm, keystore, keystorePassword != null ? keystorePassword.toCharArray() : null,
276                         truststore, random, trustStrategy), hostnameVerifier);
277     }
278 
279     /**
280      * @since 4.1
281      *
282      * @deprecated (4.3) Use {@link SSLSocketFactory#SSLSocketFactory(String, KeyStore, char[],
283      *   KeyStore, SecureRandom, X509HostnameVerifier)}
284      */
285     @Deprecated
286     public SSLSocketFactory(
287             final String algorithm,
288             final KeyStore keystore,
289             final String keystorePassword,
290             final KeyStore truststore,
291             final SecureRandom random,
292             final X509HostnameVerifier hostnameVerifier)
293                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
294         this(createSSLContext(
295                 algorithm, keystore, keystorePassword != null ? keystorePassword.toCharArray() : null,
296                         truststore, random, null), hostnameVerifier);
297     }
298 
299     /**
300      * @since 4.3
301      */
302     public SSLSocketFactory(
303             final String algorithm,
304             final KeyStore keystore,
305             final char[] keystorePassword,
306             final KeyStore truststore,
307             final SecureRandom random,
308             final X509HostnameVerifier hostnameVerifier)
309                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
310         this(createSSLContext(algorithm, keystore, keystorePassword, truststore, random, null),
311                 hostnameVerifier);
312     }
313 
314     /**
315      * @deprecated (4.3) Use {@link SSLSocketFactory#SSLSocketFactory(KeyStore, char[], KeyStore)}
316      */
317     @Deprecated
318     public SSLSocketFactory(
319             final KeyStore keystore,
320             final String keystorePassword,
321             final KeyStore truststore)
322                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
323         this(TLS, keystore, keystorePassword, truststore, null, null, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
324     }
325 
326     /**
327      * @since 4.3
328      */
329     public SSLSocketFactory(
330             final KeyStore keystore,
331             final char[] keystorePassword,
332             final KeyStore truststore)
333                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException{
334         this(createSSLContext(TLS, keystore, keystorePassword, truststore, null, null),
335                 BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
336     }
337 
338     /**
339      * @deprecated (4.3) Use {@link SSLSocketFactory#SSLSocketFactory(KeyStore, char[])}
340      */
341     @Deprecated
342     public SSLSocketFactory(
343             final KeyStore keystore,
344             final String keystorePassword)
345                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException{
346         this(createSSLContext(TLS, keystore, keystorePassword != null ? keystorePassword.toCharArray() : null,
347                 null, null, null),
348                 BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
349     }
350 
351     /**
352      * @since 4.3
353      */
354     public SSLSocketFactory(
355             final KeyStore keystore,
356             final char[] keystorePassword)
357                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException{
358         this(createSSLContext(TLS, keystore, keystorePassword, null, null, null),
359                 BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
360     }
361 
362     public SSLSocketFactory(
363             final KeyStore truststore)
364                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
365         this(createSSLContext(TLS, null, null, truststore, null, null),
366                 BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
367     }
368 
369     /**
370      * @since 4.1
371      */
372     public SSLSocketFactory(
373             final TrustStrategy trustStrategy,
374             final X509HostnameVerifier hostnameVerifier)
375                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
376         this(createSSLContext(TLS, null, null, null, null, trustStrategy), hostnameVerifier);
377     }
378 
379     /**
380      * @since 4.1
381      */
382     public SSLSocketFactory(
383             final TrustStrategy trustStrategy)
384                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
385         this(createSSLContext(TLS, null, null, null, null, trustStrategy), BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
386     }
387 
388     public SSLSocketFactory(final SSLContext sslContext) {
389         this(sslContext, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
390     }
391 
392     /**
393      * @deprecated (4.1) Use {@link #SSLSocketFactory(SSLContext)}
394      */
395     @Deprecated
396     public SSLSocketFactory(
397             final SSLContext sslContext, final HostNameResolver nameResolver) {
398         super();
399         this.socketfactory = sslContext.getSocketFactory();
400         this.hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
401         this.nameResolver = nameResolver;
402     }
403 
404     /**
405      * @since 4.1
406      */
407     public SSLSocketFactory(
408             final SSLContext sslContext, final X509HostnameVerifier hostnameVerifier) {
409         super();
410         Args.notNull(sslContext, "SSL context");
411         this.socketfactory = sslContext.getSocketFactory();
412         this.hostnameVerifier = hostnameVerifier;
413         this.nameResolver = null;
414     }
415 
416     /**
417      * @since 4.2
418      */
419     public SSLSocketFactory(
420             final javax.net.ssl.SSLSocketFactory socketfactory,
421             final X509HostnameVerifier hostnameVerifier) {
422         Args.notNull(socketfactory, "SSL socket factory");
423         this.socketfactory = socketfactory;
424         this.hostnameVerifier = hostnameVerifier;
425         this.nameResolver = null;
426     }
427 
428     /**
429      * @param params Optional parameters. Parameters passed to this method will have no effect.
430      *               This method will create a unconnected instance of {@link Socket} class.
431      * @since 4.1
432      *
433      * @deprecated (4.3) use {@link #createSocket(HttpContext)}
434      */
435     @Deprecated
436     public Socket createSocket(final HttpParams params) throws IOException {
437         return createSocket((HttpContext) null);
438     }
439 
440     /**
441      * @deprecated (4.1) use {@link #createSocket(HttpParams)}
442      */
443     @Deprecated
444     public Socket createSocket() throws IOException {
445         return createSocket((HttpContext) null);
446     }
447 
448     /**
449      * @since 4.1
450      *
451      * @deprecated (4.3) use {@link #connectSocket(int, Socket, HttpHost, InetSocketAddress,
452      *  InetSocketAddress, HttpContext)}
453      */
454     @Deprecated
455     public Socket connectSocket(
456             final Socket socket,
457             final InetSocketAddress remoteAddress,
458             final InetSocketAddress localAddress,
459             final HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException {
460         Args.notNull(remoteAddress, "Remote address");
461         Args.notNull(params, "HTTP parameters");
462         HttpHost host;
463         if (remoteAddress instanceof HttpInetSocketAddress) {
464             host = ((HttpInetSocketAddress) remoteAddress).getHttpHost();
465         } else {
466             host = new HttpHost(remoteAddress.getHostName(), remoteAddress.getPort(), "https");
467         }
468         final int connectTimeout = HttpConnectionParams.getConnectionTimeout(params);
469         return connectSocket(connectTimeout, socket, host, remoteAddress, localAddress, null);
470     }
471 
472     /**
473      * Checks whether a socket connection is secure.
474      * This factory creates TLS/SSL socket connections
475      * which, by default, are considered secure.
476      * <br/>
477      * Derived classes may override this method to perform
478      * runtime checks, for example based on the cypher suite.
479      *
480      * @param sock      the connected socket
481      *
482      * @return  <code>true</code>
483      *
484      * @throws IllegalArgumentException if the argument is invalid
485      *
486      * @deprecated (4.3) no longer used.
487      */
488     @Deprecated
489     public boolean isSecure(final Socket sock) throws IllegalArgumentException {
490         Args.notNull(sock, "Socket");
491         Asserts.check(sock instanceof SSLSocket, "Socket not created by this factory");
492         Asserts.check(!sock.isClosed(), "Socket is closed");
493         return true;
494     }
495 
496     /**
497      * @since 4.2
498      *
499      * @deprecated (4.3) use {@link #createLayeredSocket(Socket, String, int, HttpContext)}
500      */
501     @Deprecated
502     public Socket createLayeredSocket(
503         final Socket socket,
504         final String host,
505         final int port,
506         final HttpParams params) throws IOException, UnknownHostException {
507         return createLayeredSocket(socket, host, port, (HttpContext) null);
508     }
509 
510     /**
511      * @deprecated (4.1) use {@link #createLayeredSocket(Socket, String, int, HttpParams)}
512      */
513     @Deprecated
514     public Socket createLayeredSocket(
515         final Socket socket,
516         final String host,
517         final int port,
518         final boolean autoClose) throws IOException, UnknownHostException {
519         return createLayeredSocket(socket, host, port, (HttpContext) null);
520     }
521 
522     /**
523      * @deprecated (4.1) use constructor.
524      */
525     @Deprecated
526     public void setHostnameVerifier(final X509HostnameVerifier hostnameVerifier) {
527         Args.notNull(hostnameVerifier, "Hostname verifier");
528         this.hostnameVerifier = hostnameVerifier;
529     }
530 
531     public X509HostnameVerifier getHostnameVerifier() {
532         return this.hostnameVerifier;
533     }
534 
535     /**
536      * @deprecated (4.1) Use {@link #connectSocket(Socket, InetSocketAddress, InetSocketAddress,
537      *   HttpParams)}
538      */
539     @Deprecated
540     public Socket connectSocket(
541             final Socket socket,
542             final String host, final int port,
543             final InetAddress local, int localPort,
544             final HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException {
545         InetAddress remote;
546         if (this.nameResolver != null) {
547             remote = this.nameResolver.resolve(host);
548         } else {
549             remote = InetAddress.getByName(host);
550         }
551         InetSocketAddress localAddress = null;
552         if (local != null || localPort > 0) {
553             // we need to bind explicitly
554             if (localPort < 0) {
555                 localPort = 0; // indicates "any"
556             }
557             localAddress = new InetSocketAddress(local, localPort);
558         }
559         final InetSocketAddress remoteAddress = new HttpInetSocketAddress(
560                 new HttpHost(host, port), remote, port);
561         return connectSocket(socket, remoteAddress, localAddress, params);
562     }
563 
564     /**
565      * @deprecated (4.1) Use {@link #createLayeredSocket(Socket, String, int, boolean)}
566      */
567     @Deprecated
568     public Socket createSocket(
569             final Socket socket,
570             final String host, final int port,
571             final boolean autoClose) throws IOException, UnknownHostException {
572         return createLayeredSocket(socket, host, port, autoClose);
573     }
574 
575     /**
576      * Performs any custom initialization for a newly created SSLSocket
577      * (before the SSL handshake happens).
578      *
579      * The default implementation is a no-op, but could be overriden to, e.g.,
580      * call {@link SSLSocket#setEnabledCipherSuites(java.lang.String[])}.
581      *
582      * @since 4.2
583      */
584     protected void prepareSocket(final SSLSocket socket) throws IOException {
585     }
586 
587     /**
588      * {@inheritDoc}
589      *
590      * @since 4.3
591      */
592     public Socket createSocket(final HttpContext context) throws IOException {
593         final SSLSocket sock = (SSLSocket) this.socketfactory.createSocket();
594         prepareSocket(sock);
595         return sock;
596     }
597 
598     /**
599      * {@inheritDoc}
600      *
601      * @since 4.3
602      */
603     public Socket connectSocket(
604             final int connectTimeout,
605             final Socket socket,
606             final HttpHost host,
607             final InetSocketAddress remoteAddress,
608             final InetSocketAddress localAddress,
609             final HttpContext context) throws IOException, ConnectTimeoutException {
610         Args.notNull(host, "HTTP host");
611         Args.notNull(remoteAddress, "Remote address");
612         Socket sock = socket != null ? socket : createSocket(context);
613         if (localAddress != null) {
614             sock.bind(localAddress);
615         }
616         try {
617             sock.connect(remoteAddress, connectTimeout);
618         } catch (final SocketTimeoutException ex) {
619             throw new ConnectTimeoutException(host, remoteAddress);
620         }
621         // Setup SSL layering if necessary
622         if (sock instanceof SSLSocket) {
623             verifyHostname((SSLSocket) sock, host.getHostName());
624         } else {
625             sock = createLayeredSocket(sock, host.getHostName(), remoteAddress.getPort(), context);
626         }
627         return sock;
628     }
629 
630     public Socket createLayeredSocket(
631             final Socket socket,
632             final String target,
633             final int port,
634             final HttpContext context) throws IOException, UnknownHostException {
635         final SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(
636                 socket,
637                 target,
638                 port,
639                 true);
640           prepareSocket(sslSocket);
641           verifyHostname(sslSocket, target);
642           return sslSocket;
643     }
644 
645     private void verifyHostname(final SSLSocket sslsock, final String hostname) throws IOException {
646         if (this.hostnameVerifier != null) {
647             try {
648                 this.hostnameVerifier.verify(hostname, sslsock);
649                 // verifyHostName() didn't blowup - good!
650             } catch (final IOException iox) {
651                 // close the socket before re-throwing the exception
652                 try { sslsock.close(); } catch (final Exception x) { /*ignore*/ }
653                 throw iox;
654             }
655         }
656     }
657 
658 }