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