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.compat.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
308      * <a class="external" href="https://tools.ietf.org/id/draft-agl-tls-nextprotoneg-03.html">Next
309      * Protocol Negotiation (NPN)</a> protocols that this peer is interested in.
310      *
311      * <p>For servers this is the sequence of protocols to advertise as
312      * supported, in order of preference. This list is sent unencrypted to
313      * all clients that support NPN.
314      *
315      * <p>For clients this is a list of supported protocols to match against the
316      * server's list. If there is no protocol supported by both client and
317      * server then the first protocol in the client's list will be selected.
318      * The order of the client's protocols is otherwise insignificant.
319      *
320      * @param npnProtocols a non-empty list of protocol byte arrays. All arrays
321      *     must be non-empty and of length less than 256.
322      */
setNpnProtocols(byte[][] npnProtocols)323     public void setNpnProtocols(byte[][] npnProtocols) {
324         this.mNpnProtocols = toLengthPrefixedList(npnProtocols);
325     }
326 
327     /**
328      * Sets the
329      * <a href="http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-01">
330      * Application Layer Protocol Negotiation (ALPN)</a> protocols that this peer
331      * is interested in.
332      *
333      * <p>For servers this is the sequence of protocols to advertise as
334      * supported, in order of preference. This list is sent unencrypted to
335      * all clients that support ALPN.
336      *
337      * <p>For clients this is a list of supported protocols to match against the
338      * server's list. If there is no protocol supported by both client and
339      * server then the first protocol in the client's list will be selected.
340      * The order of the client's protocols is otherwise insignificant.
341      *
342      * @param protocols a non-empty list of protocol byte arrays. All arrays
343      *     must be non-empty and of length less than 256.
344      * @hide
345      */
346     @UnsupportedAppUsage
setAlpnProtocols(byte[][] protocols)347     public void setAlpnProtocols(byte[][] protocols) {
348         this.mAlpnProtocols = toLengthPrefixedList(protocols);
349     }
350 
351     /**
352      * Returns an array containing the concatenation of length-prefixed byte
353      * strings.
354      * @hide
355      */
356     @VisibleForTesting
toLengthPrefixedList(byte[]... items)357     public static byte[] toLengthPrefixedList(byte[]... items) {
358         if (items.length == 0) {
359             throw new IllegalArgumentException("items.length == 0");
360         }
361         int totalLength = 0;
362         for (byte[] s : items) {
363             if (s.length == 0 || s.length > 255) {
364                 throw new IllegalArgumentException("s.length == 0 || s.length > 255: " + s.length);
365             }
366             totalLength += 1 + s.length;
367         }
368         byte[] result = new byte[totalLength];
369         int pos = 0;
370         for (byte[] s : items) {
371             result[pos++] = (byte) s.length;
372             for (byte b : s) {
373                 result[pos++] = b;
374             }
375         }
376         return result;
377     }
378 
379     /**
380      * Returns the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next
381      * Protocol Negotiation (NPN)</a> protocol selected by client and server, or
382      * null if no protocol was negotiated.
383      *
384      * @param socket a socket created by this factory.
385      * @throws IllegalArgumentException if the socket was not created by this factory.
386      */
getNpnSelectedProtocol(Socket socket)387     public byte[] getNpnSelectedProtocol(Socket socket) {
388         return castToOpenSSLSocket(socket).getNpnSelectedProtocol();
389     }
390 
391     /**
392      * Returns the
393      * <a href="http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-01">Application
394      * Layer Protocol Negotiation (ALPN)</a> protocol selected by client and server, or null
395      * if no protocol was negotiated.
396      *
397      * @param socket a socket created by this factory.
398      * @throws IllegalArgumentException if the socket was not created by this factory.
399      * @hide
400      */
401     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
getAlpnSelectedProtocol(Socket socket)402     public byte[] getAlpnSelectedProtocol(Socket socket) {
403         return castToOpenSSLSocket(socket).getAlpnSelectedProtocol();
404     }
405 
406     /**
407      * Sets the {@link KeyManager}s to be used for connections made by this factory.
408      */
setKeyManagers(KeyManager[] keyManagers)409     public void setKeyManagers(KeyManager[] keyManagers) {
410         mKeyManagers = keyManagers;
411 
412         // Clear out any existing cached factories since configurations have changed.
413         mSecureFactory = null;
414         mInsecureFactory = null;
415     }
416 
417     /**
418      * Sets the private key to be used for TLS Channel ID by connections made by this
419      * factory.
420      *
421      * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
422      *        TLS Channel ID). The private key has to be an Elliptic Curve (EC) key based on the
423      *        NIST P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
424      *
425      * @hide
426      */
427     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
setChannelIdPrivateKey(PrivateKey privateKey)428     public void setChannelIdPrivateKey(PrivateKey privateKey) {
429         mChannelIdPrivateKey = privateKey;
430     }
431 
432     /**
433      * Enables <a href="http://tools.ietf.org/html/rfc5077#section-3.2">session ticket</a>
434      * support on the given socket.
435      *
436      * @param socket a socket created by this factory
437      * @param useSessionTickets {@code true} to enable session ticket support on this socket.
438      * @throws IllegalArgumentException if the socket was not created by this factory.
439      */
setUseSessionTickets(Socket socket, boolean useSessionTickets)440     public void setUseSessionTickets(Socket socket, boolean useSessionTickets) {
441         castToOpenSSLSocket(socket).setUseSessionTickets(useSessionTickets);
442     }
443 
444     /**
445      * Turns on <a href="http://tools.ietf.org/html/rfc6066#section-3">Server
446      * Name Indication (SNI)</a> on a given socket.
447      *
448      * @param socket a socket created by this factory.
449      * @param hostName the desired SNI hostname, null to disable.
450      * @throws IllegalArgumentException if the socket was not created by this factory.
451      */
setHostname(Socket socket, String hostName)452     public void setHostname(Socket socket, String hostName) {
453         castToOpenSSLSocket(socket).setHostname(hostName);
454     }
455 
456     /**
457      * Sets this socket's SO_SNDTIMEO write timeout in milliseconds.
458      * Use 0 for no timeout.
459      * To take effect, this option must be set before the blocking method was called.
460      *
461      * @param socket a socket created by this factory.
462      * @param timeout the desired write timeout in milliseconds.
463      * @throws IllegalArgumentException if the socket was not created by this factory.
464      *
465      * @hide
466      */
467     @UnsupportedAppUsage
setSoWriteTimeout(Socket socket, int writeTimeoutMilliseconds)468     public void setSoWriteTimeout(Socket socket, int writeTimeoutMilliseconds)
469             throws SocketException {
470         castToOpenSSLSocket(socket).setSoWriteTimeout(writeTimeoutMilliseconds);
471     }
472 
473     @UnsupportedAppUsage
castToOpenSSLSocket(Socket socket)474     private static OpenSSLSocketImpl castToOpenSSLSocket(Socket socket) {
475         if (!(socket instanceof OpenSSLSocketImpl)) {
476             throw new IllegalArgumentException("Socket not created by this factory: "
477                     + socket);
478         }
479 
480         return (OpenSSLSocketImpl) socket;
481     }
482 
483     /**
484      * {@inheritDoc}
485      *
486      * <p>By default, this method returns a <i>connected</i> socket and verifies the peer's
487      * certificate hostname after connecting using the {@link HostnameVerifier} obtained from
488      * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with
489      * {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i>
490      * instead.
491      */
492     @Override
createSocket(Socket k, String host, int port, boolean close)493     public Socket createSocket(Socket k, String host, int port, boolean close) throws IOException {
494         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close);
495         s.setNpnProtocols(mNpnProtocols);
496         s.setAlpnProtocols(mAlpnProtocols);
497         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
498         s.setChannelIdPrivateKey(mChannelIdPrivateKey);
499         if (mSecure) {
500             verifyHostname(s, host);
501         }
502         return s;
503     }
504 
505     /**
506      * Creates a new socket which is <i>not connected</i> to any remote host.
507      * You must use {@link Socket#connect} to connect the socket.
508      *
509      * <p class="caution"><b>Warning:</b> Hostname verification is not performed
510      * with this method.  You MUST verify the server's identity after connecting
511      * the socket to avoid man-in-the-middle attacks.</p>
512      */
513     @Override
createSocket()514     public Socket createSocket() throws IOException {
515         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket();
516         s.setNpnProtocols(mNpnProtocols);
517         s.setAlpnProtocols(mAlpnProtocols);
518         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
519         s.setChannelIdPrivateKey(mChannelIdPrivateKey);
520         return s;
521     }
522 
523     /**
524      * {@inheritDoc}
525      *
526      * <p>This method returns a socket that is <i>not connected</i>.
527      *
528      * <p class="caution"><b>Warning:</b> Hostname verification is not performed
529      * with this method.  You MUST verify the server's identity after connecting
530      * the socket to avoid man-in-the-middle attacks.</p>
531      */
532     @Override
createSocket(InetAddress addr, int port, InetAddress localAddr, int localPort)533     public Socket createSocket(InetAddress addr, int port, InetAddress localAddr, int localPort)
534             throws IOException {
535         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
536                 addr, port, localAddr, localPort);
537         s.setNpnProtocols(mNpnProtocols);
538         s.setAlpnProtocols(mAlpnProtocols);
539         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
540         s.setChannelIdPrivateKey(mChannelIdPrivateKey);
541         return s;
542     }
543 
544     /**
545      * {@inheritDoc}
546      *
547      * <p>This method returns a socket that is <i>not connected</i>.
548      *
549      * <p class="caution"><b>Warning:</b> Hostname verification is not performed
550      * with this method.  You MUST verify the server's identity after connecting
551      * the socket to avoid man-in-the-middle attacks.</p>
552      */
553     @Override
createSocket(InetAddress addr, int port)554     public Socket createSocket(InetAddress addr, int port) throws IOException {
555         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port);
556         s.setNpnProtocols(mNpnProtocols);
557         s.setAlpnProtocols(mAlpnProtocols);
558         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
559         s.setChannelIdPrivateKey(mChannelIdPrivateKey);
560         return s;
561     }
562 
563     /**
564      * {@inheritDoc}
565      *
566      * <p>By default, this method returns a <i>connected</i> socket and verifies the peer's
567      * certificate hostname after connecting using the {@link HostnameVerifier} obtained from
568      * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with
569      * {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i>
570      * instead.
571      */
572     @Override
createSocket(String host, int port, InetAddress localAddr, int localPort)573     public Socket createSocket(String host, int port, InetAddress localAddr, int localPort)
574             throws IOException {
575         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
576                 host, port, localAddr, localPort);
577         s.setNpnProtocols(mNpnProtocols);
578         s.setAlpnProtocols(mAlpnProtocols);
579         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
580         s.setChannelIdPrivateKey(mChannelIdPrivateKey);
581         if (mSecure) {
582             verifyHostname(s, host);
583         }
584         return s;
585     }
586 
587     /**
588      * {@inheritDoc}
589      *
590      * <p>By default, this method returns a <i>connected</i> socket and verifies the peer's
591      * certificate hostname after connecting using the {@link HostnameVerifier} obtained from
592      * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with
593      * {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i>
594      * instead.
595      */
596     @Override
createSocket(String host, int port)597     public Socket createSocket(String host, int port) throws IOException {
598         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
599         s.setNpnProtocols(mNpnProtocols);
600         s.setAlpnProtocols(mAlpnProtocols);
601         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
602         s.setChannelIdPrivateKey(mChannelIdPrivateKey);
603         if (mSecure) {
604             verifyHostname(s, host);
605         }
606         return s;
607     }
608 
609     @Override
getDefaultCipherSuites()610     public String[] getDefaultCipherSuites() {
611         return getDelegate().getDefaultCipherSuites();
612     }
613 
614     @Override
getSupportedCipherSuites()615     public String[] getSupportedCipherSuites() {
616         return getDelegate().getSupportedCipherSuites();
617     }
618 }
619