• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 android.net;
18 
19 import android.annotation.UnsupportedAppUsage;
20 import android.os.Build;
21 import android.os.SystemProperties;
22 import android.util.Log;
23 
24 import com.android.internal.annotations.VisibleForTesting;
25 import com.android.internal.os.RoSystemProperties;
26 import com.android.org.conscrypt.ClientSessionContext;
27 import com.android.org.conscrypt.OpenSSLSocketImpl;
28 import com.android.org.conscrypt.SSLClientSessionCache;
29 
30 import java.io.IOException;
31 import java.net.InetAddress;
32 import java.net.Socket;
33 import java.net.SocketException;
34 import java.security.KeyManagementException;
35 import java.security.NoSuchAlgorithmException;
36 import java.security.NoSuchProviderException;
37 import java.security.PrivateKey;
38 import java.security.cert.X509Certificate;
39 
40 import javax.net.SocketFactory;
41 import javax.net.ssl.HostnameVerifier;
42 import javax.net.ssl.HttpsURLConnection;
43 import javax.net.ssl.KeyManager;
44 import javax.net.ssl.SSLContext;
45 import javax.net.ssl.SSLException;
46 import javax.net.ssl.SSLPeerUnverifiedException;
47 import javax.net.ssl.SSLSession;
48 import javax.net.ssl.SSLSocket;
49 import javax.net.ssl.SSLSocketFactory;
50 import javax.net.ssl.TrustManager;
51 import javax.net.ssl.X509TrustManager;
52 
53 /**
54  * SSLSocketFactory implementation with several extra features:
55  *
56  * <ul>
57  * <li>Timeout specification for SSL handshake operations
58  * <li>Hostname verification in most cases (see WARNINGs below)
59  * <li>Optional SSL session caching with {@link SSLSessionCache}
60  * <li>Optionally bypass all SSL certificate checks
61  * </ul>
62  *
63  * The handshake timeout does not apply to actual TCP socket connection.
64  * If you want a connection timeout as well, use {@link #createSocket()}
65  * and {@link Socket#connect(java.net.SocketAddress, int)}, after which you
66  * must verify the identity of the server you are connected to.
67  *
68  * <p class="caution"><b>Most {@link SSLSocketFactory} implementations do not
69  * verify the server's identity, allowing man-in-the-middle attacks.</b>
70  * This implementation does check the server's certificate hostname, but only
71  * for createSocket variants that specify a hostname.  When using methods that
72  * use {@link InetAddress} or which return an unconnected socket, you MUST
73  * verify the server's identity yourself to ensure a secure connection.
74  *
75  * Refer to
76  * <a href="https://developer.android.com/training/articles/security-gms-provider.html">
77  * Updating Your Security Provider to Protect Against SSL Exploits</a>
78  * for further information.</p>
79  *
80  * <p>The recommended way to verify the server's identity is to use
81  * {@link HttpsURLConnection#getDefaultHostnameVerifier()} to get a
82  * {@link HostnameVerifier} to verify the certificate hostname.
83  *
84  * <p><b>Warning</b>: Some methods on this class return connected sockets and some return
85  * unconnected sockets.  For the methods that return connected sockets, setting
86  * connection- or handshake-related properties on those sockets will have no effect.
87  *
88  * <p>On development devices, "setprop socket.relaxsslcheck yes" bypasses all
89  * SSL certificate and hostname checks for testing purposes.  This setting
90  * requires root access.
91  *
92  * @deprecated This class has less error-prone replacements using standard APIs.  To create an
93  * {@code SSLSocket}, obtain an {@link SSLSocketFactory} from {@link SSLSocketFactory#getDefault()}
94  * or {@link javax.net.ssl.SSLContext#getSocketFactory()}.  To verify hostnames, pass
95  * {@code "HTTPS"} to
96  * {@link javax.net.ssl.SSLParameters#setEndpointIdentificationAlgorithm(String)}.  To enable ALPN,
97  * use {@link javax.net.ssl.SSLParameters#setApplicationProtocols(String[])}.  To enable SNI,
98  * use {@link javax.net.ssl.SSLParameters#setServerNames(java.util.List)}.
99  */
100 @Deprecated
101 public class SSLCertificateSocketFactory extends SSLSocketFactory {
102     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
103     private static final String TAG = "SSLCertificateSocketFactory";
104 
105     @UnsupportedAppUsage
106     private static final TrustManager[] INSECURE_TRUST_MANAGER = new TrustManager[] {
107         new X509TrustManager() {
108             public X509Certificate[] getAcceptedIssuers() { return null; }
109             public void checkClientTrusted(X509Certificate[] certs, String authType) { }
110             public void checkServerTrusted(X509Certificate[] certs, String authType) { }
111         }
112     };
113 
114     @UnsupportedAppUsage
115     private SSLSocketFactory mInsecureFactory = null;
116     @UnsupportedAppUsage
117     private SSLSocketFactory mSecureFactory = null;
118     @UnsupportedAppUsage
119     private TrustManager[] mTrustManagers = null;
120     @UnsupportedAppUsage
121     private KeyManager[] mKeyManagers = null;
122     @UnsupportedAppUsage
123     private byte[] mNpnProtocols = null;
124     @UnsupportedAppUsage
125     private byte[] mAlpnProtocols = null;
126     @UnsupportedAppUsage
127     private PrivateKey mChannelIdPrivateKey = null;
128 
129     @UnsupportedAppUsage
130     private final int mHandshakeTimeoutMillis;
131     @UnsupportedAppUsage
132     private final SSLClientSessionCache mSessionCache;
133     @UnsupportedAppUsage
134     private final boolean mSecure;
135 
136     /** @deprecated Use {@link #getDefault(int)} instead. */
137     @Deprecated
SSLCertificateSocketFactory(int handshakeTimeoutMillis)138     public SSLCertificateSocketFactory(int handshakeTimeoutMillis) {
139         this(handshakeTimeoutMillis, null, true);
140     }
141 
142     @UnsupportedAppUsage
SSLCertificateSocketFactory( int handshakeTimeoutMillis, SSLSessionCache cache, boolean secure)143     private SSLCertificateSocketFactory(
144             int handshakeTimeoutMillis, SSLSessionCache cache, boolean secure) {
145         mHandshakeTimeoutMillis = handshakeTimeoutMillis;
146         mSessionCache = cache == null ? null : cache.mSessionCache;
147         mSecure = secure;
148     }
149 
150     /**
151      * Returns a new socket factory instance with an optional handshake timeout.
152      *
153      * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
154      *         for none.  The socket timeout is reset to 0 after the handshake.
155      * @return a new SSLSocketFactory with the specified parameters
156      */
getDefault(int handshakeTimeoutMillis)157     public static SocketFactory getDefault(int handshakeTimeoutMillis) {
158         return new SSLCertificateSocketFactory(handshakeTimeoutMillis, null, true);
159     }
160 
161     /**
162      * Returns a new socket factory instance with an optional handshake timeout
163      * and SSL session cache.
164      *
165      * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
166      *         for none.  The socket timeout is reset to 0 after the handshake.
167      * @param cache The {@link SSLSessionCache} to use, or null for no cache.
168      * @return a new SSLSocketFactory with the specified parameters
169      */
getDefault(int handshakeTimeoutMillis, SSLSessionCache cache)170     public static SSLSocketFactory getDefault(int handshakeTimeoutMillis, SSLSessionCache cache) {
171         return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true);
172     }
173 
174     /**
175      * Returns a new instance of a socket factory with all SSL security checks
176      * disabled, using an optional handshake timeout and SSL session cache.
177      *
178      * <p class="caution"><b>Warning:</b> Sockets created using this factory
179      * are vulnerable to man-in-the-middle attacks!</p>
180      *
181      * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
182      *         for none.  The socket timeout is reset to 0 after the handshake.
183      * @param cache The {@link SSLSessionCache} to use, or null for no cache.
184      * @return an insecure SSLSocketFactory with the specified parameters
185      */
getInsecure(int handshakeTimeoutMillis, SSLSessionCache cache)186     public static SSLSocketFactory getInsecure(int handshakeTimeoutMillis, SSLSessionCache cache) {
187         return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, false);
188     }
189 
190     /**
191      * Returns a socket factory (also named SSLSocketFactory, but in a different
192      * namespace) for use with the Apache HTTP stack.
193      *
194      * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
195      *         for none.  The socket timeout is reset to 0 after the handshake.
196      * @param cache The {@link SSLSessionCache} to use, or null for no cache.
197      * @return a new SocketFactory with the specified parameters
198      *
199      * @deprecated Use {@link #getDefault()} along with a {@link javax.net.ssl.HttpsURLConnection}
200      *     instead. The Apache HTTP client is no longer maintained and may be removed in a future
201      *     release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
202      *     for further details.
203      *
204      * @removed
205      */
206     @Deprecated
getHttpSocketFactory( int handshakeTimeoutMillis, SSLSessionCache cache)207     public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(
208             int handshakeTimeoutMillis, SSLSessionCache cache) {
209         return new org.apache.http.conn.ssl.SSLSocketFactory(
210                 new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true));
211     }
212 
213     /**
214      * Verify the hostname of the certificate used by the other end of a connected socket using the
215      * {@link HostnameVerifier} obtained from {@code
216      * HttpsURLConnection.getDefaultHostnameVerifier()}. You MUST call this if you did not supply a
217      * hostname to {@link #createSocket()}.  It is harmless to call this method redundantly if the
218      * hostname has already been verified.
219      *
220      * <p>Wildcard certificates are allowed to verify any matching hostname, so
221      * "foo.bar.example.com" is verified if the peer has a certificate for "*.example.com".
222      *
223      * @param socket An SSL socket which has been connected to a server
224      * @param hostname The expected hostname of the remote server
225      * @throws IOException if something goes wrong handshaking with the server
226      * @throws SSLPeerUnverifiedException if the server cannot prove its identity
227      *
228      * @hide
229      */
230     @UnsupportedAppUsage
verifyHostname(Socket socket, String hostname)231     public static void verifyHostname(Socket socket, String hostname) throws IOException {
232         if (!(socket instanceof SSLSocket)) {
233             throw new IllegalArgumentException("Attempt to verify non-SSL socket");
234         }
235 
236         if (!isSslCheckRelaxed()) {
237             // The code at the start of OpenSSLSocketImpl.startHandshake()
238             // ensures that the call is idempotent, so we can safely call it.
239             SSLSocket ssl = (SSLSocket) socket;
240             ssl.startHandshake();
241 
242             SSLSession session = ssl.getSession();
243             if (session == null) {
244                 throw new SSLException("Cannot verify SSL socket without session");
245             }
246             if (!HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session)) {
247                 throw new SSLPeerUnverifiedException("Cannot verify hostname: " + hostname);
248             }
249         }
250     }
251 
252     @UnsupportedAppUsage
makeSocketFactory( KeyManager[] keyManagers, TrustManager[] trustManagers)253     private SSLSocketFactory makeSocketFactory(
254             KeyManager[] keyManagers, TrustManager[] trustManagers) {
255         try {
256             SSLContext sslContext = SSLContext.getInstance("TLS", "AndroidOpenSSL");
257             sslContext.init(keyManagers, trustManagers, null);
258             ((ClientSessionContext) sslContext.getClientSessionContext())
259                 .setPersistentCache(mSessionCache);
260             return sslContext.getSocketFactory();
261         } catch (KeyManagementException | NoSuchAlgorithmException | NoSuchProviderException e) {
262             Log.wtf(TAG, e);
263             return (SSLSocketFactory) SSLSocketFactory.getDefault();  // Fallback
264         }
265     }
266 
267     @UnsupportedAppUsage
isSslCheckRelaxed()268     private static boolean isSslCheckRelaxed() {
269         return RoSystemProperties.DEBUGGABLE &&
270             SystemProperties.getBoolean("socket.relaxsslcheck", false);
271     }
272 
273     @UnsupportedAppUsage
getDelegate()274     private synchronized SSLSocketFactory getDelegate() {
275         // Relax the SSL check if instructed (for this factory, or systemwide)
276         if (!mSecure || isSslCheckRelaxed()) {
277             if (mInsecureFactory == null) {
278                 if (mSecure) {
279                     Log.w(TAG, "*** BYPASSING SSL SECURITY CHECKS (socket.relaxsslcheck=yes) ***");
280                 } else {
281                     Log.w(TAG, "Bypassing SSL security checks at caller's request");
282                 }
283                 mInsecureFactory = makeSocketFactory(mKeyManagers, INSECURE_TRUST_MANAGER);
284             }
285             return mInsecureFactory;
286         } else {
287             if (mSecureFactory == null) {
288                 mSecureFactory = makeSocketFactory(mKeyManagers, mTrustManagers);
289             }
290             return mSecureFactory;
291         }
292     }
293 
294     /**
295      * Sets the {@link TrustManager}s to be used for connections made by this factory.
296      */
setTrustManagers(TrustManager[] trustManager)297     public void setTrustManagers(TrustManager[] trustManager) {
298         mTrustManagers = trustManager;
299 
300         // Clear out all cached secure factories since configurations have changed.
301         mSecureFactory = null;
302         // Note - insecure factories only ever use the INSECURE_TRUST_MANAGER so they need not
303         // be cleared out here.
304     }
305 
306     /**
307      * Sets the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next
308      * Protocol Negotiation (NPN)</a> protocols that this peer is interested in.
309      *
310      * <p>For servers this is the sequence of protocols to advertise as
311      * supported, in order of preference. This list is sent unencrypted to
312      * all clients that support NPN.
313      *
314      * <p>For clients this is a list of supported protocols to match against the
315      * server's list. If there is no protocol supported by both client and
316      * server then the first protocol in the client's list will be selected.
317      * The order of the client's protocols is otherwise insignificant.
318      *
319      * @param npnProtocols a non-empty list of protocol byte arrays. All arrays
320      *     must be non-empty and of length less than 256.
321      */
setNpnProtocols(byte[][] npnProtocols)322     public void setNpnProtocols(byte[][] npnProtocols) {
323         this.mNpnProtocols = toLengthPrefixedList(npnProtocols);
324     }
325 
326     /**
327      * Sets the
328      * <a href="http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-01">
329      * Application Layer Protocol Negotiation (ALPN)</a> protocols that this peer
330      * is interested in.
331      *
332      * <p>For servers this is the sequence of protocols to advertise as
333      * supported, in order of preference. This list is sent unencrypted to
334      * all clients that support ALPN.
335      *
336      * <p>For clients this is a list of supported protocols to match against the
337      * server's list. If there is no protocol supported by both client and
338      * server then the first protocol in the client's list will be selected.
339      * The order of the client's protocols is otherwise insignificant.
340      *
341      * @param protocols a non-empty list of protocol byte arrays. All arrays
342      *     must be non-empty and of length less than 256.
343      * @hide
344      */
345     @UnsupportedAppUsage
setAlpnProtocols(byte[][] protocols)346     public void setAlpnProtocols(byte[][] protocols) {
347         this.mAlpnProtocols = toLengthPrefixedList(protocols);
348     }
349 
350     /**
351      * Returns an array containing the concatenation of length-prefixed byte
352      * strings.
353      * @hide
354      */
355     @VisibleForTesting
toLengthPrefixedList(byte[]... items)356     public static byte[] toLengthPrefixedList(byte[]... items) {
357         if (items.length == 0) {
358             throw new IllegalArgumentException("items.length == 0");
359         }
360         int totalLength = 0;
361         for (byte[] s : items) {
362             if (s.length == 0 || s.length > 255) {
363                 throw new IllegalArgumentException("s.length == 0 || s.length > 255: " + s.length);
364             }
365             totalLength += 1 + s.length;
366         }
367         byte[] result = new byte[totalLength];
368         int pos = 0;
369         for (byte[] s : items) {
370             result[pos++] = (byte) s.length;
371             for (byte b : s) {
372                 result[pos++] = b;
373             }
374         }
375         return result;
376     }
377 
378     /**
379      * Returns the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next
380      * Protocol Negotiation (NPN)</a> protocol selected by client and server, or
381      * null if no protocol was negotiated.
382      *
383      * @param socket a socket created by this factory.
384      * @throws IllegalArgumentException if the socket was not created by this factory.
385      */
getNpnSelectedProtocol(Socket socket)386     public byte[] getNpnSelectedProtocol(Socket socket) {
387         return castToOpenSSLSocket(socket).getNpnSelectedProtocol();
388     }
389 
390     /**
391      * Returns the
392      * <a href="http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-01">Application
393      * Layer Protocol Negotiation (ALPN)</a> protocol selected by client and server, or null
394      * if no protocol was negotiated.
395      *
396      * @param socket a socket created by this factory.
397      * @throws IllegalArgumentException if the socket was not created by this factory.
398      * @hide
399      */
400     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
getAlpnSelectedProtocol(Socket socket)401     public byte[] getAlpnSelectedProtocol(Socket socket) {
402         return castToOpenSSLSocket(socket).getAlpnSelectedProtocol();
403     }
404 
405     /**
406      * Sets the {@link KeyManager}s to be used for connections made by this factory.
407      */
setKeyManagers(KeyManager[] keyManagers)408     public void setKeyManagers(KeyManager[] keyManagers) {
409         mKeyManagers = keyManagers;
410 
411         // Clear out any existing cached factories since configurations have changed.
412         mSecureFactory = null;
413         mInsecureFactory = null;
414     }
415 
416     /**
417      * Sets the private key to be used for TLS Channel ID by connections made by this
418      * factory.
419      *
420      * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
421      *        TLS Channel ID). The private key has to be an Elliptic Curve (EC) key based on the
422      *        NIST P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
423      *
424      * @hide
425      */
426     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
setChannelIdPrivateKey(PrivateKey privateKey)427     public void setChannelIdPrivateKey(PrivateKey privateKey) {
428         mChannelIdPrivateKey = privateKey;
429     }
430 
431     /**
432      * Enables <a href="http://tools.ietf.org/html/rfc5077#section-3.2">session ticket</a>
433      * support on the given socket.
434      *
435      * @param socket a socket created by this factory
436      * @param useSessionTickets {@code true} to enable session ticket support on this socket.
437      * @throws IllegalArgumentException if the socket was not created by this factory.
438      */
setUseSessionTickets(Socket socket, boolean useSessionTickets)439     public void setUseSessionTickets(Socket socket, boolean useSessionTickets) {
440         castToOpenSSLSocket(socket).setUseSessionTickets(useSessionTickets);
441     }
442 
443     /**
444      * Turns on <a href="http://tools.ietf.org/html/rfc6066#section-3">Server
445      * Name Indication (SNI)</a> on a given socket.
446      *
447      * @param socket a socket created by this factory.
448      * @param hostName the desired SNI hostname, null to disable.
449      * @throws IllegalArgumentException if the socket was not created by this factory.
450      */
setHostname(Socket socket, String hostName)451     public void setHostname(Socket socket, String hostName) {
452         castToOpenSSLSocket(socket).setHostname(hostName);
453     }
454 
455     /**
456      * Sets this socket's SO_SNDTIMEO write timeout in milliseconds.
457      * Use 0 for no timeout.
458      * To take effect, this option must be set before the blocking method was called.
459      *
460      * @param socket a socket created by this factory.
461      * @param timeout the desired write timeout in milliseconds.
462      * @throws IllegalArgumentException if the socket was not created by this factory.
463      *
464      * @hide
465      */
466     @UnsupportedAppUsage
setSoWriteTimeout(Socket socket, int writeTimeoutMilliseconds)467     public void setSoWriteTimeout(Socket socket, int writeTimeoutMilliseconds)
468             throws SocketException {
469         castToOpenSSLSocket(socket).setSoWriteTimeout(writeTimeoutMilliseconds);
470     }
471 
472     @UnsupportedAppUsage
castToOpenSSLSocket(Socket socket)473     private static OpenSSLSocketImpl castToOpenSSLSocket(Socket socket) {
474         if (!(socket instanceof OpenSSLSocketImpl)) {
475             throw new IllegalArgumentException("Socket not created by this factory: "
476                     + socket);
477         }
478 
479         return (OpenSSLSocketImpl) socket;
480     }
481 
482     /**
483      * {@inheritDoc}
484      *
485      * <p>By default, this method returns a <i>connected</i> socket and verifies the peer's
486      * certificate hostname after connecting using the {@link HostnameVerifier} obtained from
487      * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with
488      * {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i>
489      * instead.
490      */
491     @Override
createSocket(Socket k, String host, int port, boolean close)492     public Socket createSocket(Socket k, String host, int port, boolean close) throws IOException {
493         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close);
494         s.setNpnProtocols(mNpnProtocols);
495         s.setAlpnProtocols(mAlpnProtocols);
496         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
497         s.setChannelIdPrivateKey(mChannelIdPrivateKey);
498         if (mSecure) {
499             verifyHostname(s, host);
500         }
501         return s;
502     }
503 
504     /**
505      * Creates a new socket which is <i>not connected</i> to any remote host.
506      * You must use {@link Socket#connect} to connect the socket.
507      *
508      * <p class="caution"><b>Warning:</b> Hostname verification is not performed
509      * with this method.  You MUST verify the server's identity after connecting
510      * the socket to avoid man-in-the-middle attacks.</p>
511      */
512     @Override
createSocket()513     public Socket createSocket() throws IOException {
514         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket();
515         s.setNpnProtocols(mNpnProtocols);
516         s.setAlpnProtocols(mAlpnProtocols);
517         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
518         s.setChannelIdPrivateKey(mChannelIdPrivateKey);
519         return s;
520     }
521 
522     /**
523      * {@inheritDoc}
524      *
525      * <p>This method returns a socket that is <i>not connected</i>.
526      *
527      * <p class="caution"><b>Warning:</b> Hostname verification is not performed
528      * with this method.  You MUST verify the server's identity after connecting
529      * the socket to avoid man-in-the-middle attacks.</p>
530      */
531     @Override
createSocket(InetAddress addr, int port, InetAddress localAddr, int localPort)532     public Socket createSocket(InetAddress addr, int port, InetAddress localAddr, int localPort)
533             throws IOException {
534         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
535                 addr, port, localAddr, localPort);
536         s.setNpnProtocols(mNpnProtocols);
537         s.setAlpnProtocols(mAlpnProtocols);
538         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
539         s.setChannelIdPrivateKey(mChannelIdPrivateKey);
540         return s;
541     }
542 
543     /**
544      * {@inheritDoc}
545      *
546      * <p>This method returns a socket that is <i>not connected</i>.
547      *
548      * <p class="caution"><b>Warning:</b> Hostname verification is not performed
549      * with this method.  You MUST verify the server's identity after connecting
550      * the socket to avoid man-in-the-middle attacks.</p>
551      */
552     @Override
createSocket(InetAddress addr, int port)553     public Socket createSocket(InetAddress addr, int port) throws IOException {
554         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port);
555         s.setNpnProtocols(mNpnProtocols);
556         s.setAlpnProtocols(mAlpnProtocols);
557         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
558         s.setChannelIdPrivateKey(mChannelIdPrivateKey);
559         return s;
560     }
561 
562     /**
563      * {@inheritDoc}
564      *
565      * <p>By default, this method returns a <i>connected</i> socket and verifies the peer's
566      * certificate hostname after connecting using the {@link HostnameVerifier} obtained from
567      * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with
568      * {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i>
569      * instead.
570      */
571     @Override
createSocket(String host, int port, InetAddress localAddr, int localPort)572     public Socket createSocket(String host, int port, InetAddress localAddr, int localPort)
573             throws IOException {
574         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
575                 host, port, localAddr, localPort);
576         s.setNpnProtocols(mNpnProtocols);
577         s.setAlpnProtocols(mAlpnProtocols);
578         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
579         s.setChannelIdPrivateKey(mChannelIdPrivateKey);
580         if (mSecure) {
581             verifyHostname(s, host);
582         }
583         return s;
584     }
585 
586     /**
587      * {@inheritDoc}
588      *
589      * <p>By default, this method returns a <i>connected</i> socket and verifies the peer's
590      * certificate hostname after connecting using the {@link HostnameVerifier} obtained from
591      * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with
592      * {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i>
593      * instead.
594      */
595     @Override
createSocket(String host, int port)596     public Socket createSocket(String host, int port) throws IOException {
597         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
598         s.setNpnProtocols(mNpnProtocols);
599         s.setAlpnProtocols(mAlpnProtocols);
600         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
601         s.setChannelIdPrivateKey(mChannelIdPrivateKey);
602         if (mSecure) {
603             verifyHostname(s, host);
604         }
605         return s;
606     }
607 
608     @Override
getDefaultCipherSuites()609     public String[] getDefaultCipherSuites() {
610         return getDelegate().getDefaultCipherSuites();
611     }
612 
613     @Override
getSupportedCipherSuites()614     public String[] getSupportedCipherSuites() {
615         return getDelegate().getSupportedCipherSuites();
616     }
617 }
618