FileDocCategorySizeDatePackage
SSLCertificateSocketFactory.javaAPI DocAndroid 5.1 API22616Thu Mar 12 22:22:10 GMT 2015android.net

SSLCertificateSocketFactory

public class SSLCertificateSocketFactory extends SSLSocketFactory
SSLSocketFactory implementation with several extra features:
  • Timeout specification for SSL handshake operations
  • Hostname verification in most cases (see WARNINGs below)
  • Optional SSL session caching with {@link SSLSessionCache}
  • Optionally bypass all SSL certificate checks
The handshake timeout does not apply to actual TCP socket connection. If you want a connection timeout as well, use {@link #createSocket()} and {@link Socket#connect(SocketAddress, int)}, after which you must verify the identity of the server you are connected to.

Most {@link SSLSocketFactory} implementations do not verify the server's identity, allowing man-in-the-middle attacks. This implementation does check the server's certificate hostname, but only for createSocket variants that specify a hostname. When using methods that use {@link InetAddress} or which return an unconnected socket, you MUST verify the server's identity yourself to ensure a secure connection.

One way to verify the server's identity is to use {@link HttpsURLConnection#getDefaultHostnameVerifier()} to get a {@link HostnameVerifier} to verify the certificate hostname.

On development devices, "setprop socket.relaxsslcheck yes" bypasses all SSL certificate and hostname checks for testing purposes. This setting requires root access.

Fields Summary
private static final String
TAG
private static final TrustManager[]
INSECURE_TRUST_MANAGER
private SSLSocketFactory
mInsecureFactory
private SSLSocketFactory
mSecureFactory
private TrustManager[]
mTrustManagers
private KeyManager[]
mKeyManagers
private byte[]
mNpnProtocols
private byte[]
mAlpnProtocols
private PrivateKey
mChannelIdPrivateKey
private final int
mHandshakeTimeoutMillis
private final com.android.org.conscrypt.SSLClientSessionCache
mSessionCache
private final boolean
mSecure
Constructors Summary
public SSLCertificateSocketFactory(int handshakeTimeoutMillis)

deprecated
Use {@link #getDefault(int)} instead.


          
    
       
        this(handshakeTimeoutMillis, null, true);
    
private SSLCertificateSocketFactory(int handshakeTimeoutMillis, SSLSessionCache cache, boolean secure)

        mHandshakeTimeoutMillis = handshakeTimeoutMillis;
        mSessionCache = cache == null ? null : cache.mSessionCache;
        mSecure = secure;
    
Methods Summary
private static com.android.org.conscrypt.OpenSSLSocketImplcastToOpenSSLSocket(java.net.Socket socket)

        if (!(socket instanceof OpenSSLSocketImpl)) {
            throw new IllegalArgumentException("Socket not created by this factory: "
                    + socket);
        }

        return (OpenSSLSocketImpl) socket;
    
public java.net.SocketcreateSocket(java.net.Socket k, java.lang.String host, int port, boolean close)
{@inheritDoc}

This method verifies the peer's certificate hostname after connecting (unless created with {@link #getInsecure(int, SSLSessionCache)}).

        OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close);
        s.setNpnProtocols(mNpnProtocols);
        s.setAlpnProtocols(mAlpnProtocols);
        s.setHandshakeTimeout(mHandshakeTimeoutMillis);
        s.setChannelIdPrivateKey(mChannelIdPrivateKey);
        if (mSecure) {
            verifyHostname(s, host);
        }
        return s;
    
public java.net.SocketcreateSocket()
Creates a new socket which is not connected to any remote host. You must use {@link Socket#connect} to connect the socket.

Warning: Hostname verification is not performed with this method. You MUST verify the server's identity after connecting the socket to avoid man-in-the-middle attacks.

        OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket();
        s.setNpnProtocols(mNpnProtocols);
        s.setAlpnProtocols(mAlpnProtocols);
        s.setHandshakeTimeout(mHandshakeTimeoutMillis);
        s.setChannelIdPrivateKey(mChannelIdPrivateKey);
        return s;
    
public java.net.SocketcreateSocket(java.net.InetAddress addr, int port, java.net.InetAddress localAddr, int localPort)
{@inheritDoc}

Warning: Hostname verification is not performed with this method. You MUST verify the server's identity after connecting the socket to avoid man-in-the-middle attacks.

        OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
                addr, port, localAddr, localPort);
        s.setNpnProtocols(mNpnProtocols);
        s.setAlpnProtocols(mAlpnProtocols);
        s.setHandshakeTimeout(mHandshakeTimeoutMillis);
        s.setChannelIdPrivateKey(mChannelIdPrivateKey);
        return s;
    
public java.net.SocketcreateSocket(java.net.InetAddress addr, int port)
{@inheritDoc}

Warning: Hostname verification is not performed with this method. You MUST verify the server's identity after connecting the socket to avoid man-in-the-middle attacks.

        OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port);
        s.setNpnProtocols(mNpnProtocols);
        s.setAlpnProtocols(mAlpnProtocols);
        s.setHandshakeTimeout(mHandshakeTimeoutMillis);
        s.setChannelIdPrivateKey(mChannelIdPrivateKey);
        return s;
    
public java.net.SocketcreateSocket(java.lang.String host, int port, java.net.InetAddress localAddr, int localPort)
{@inheritDoc}

This method verifies the peer's certificate hostname after connecting (unless created with {@link #getInsecure(int, SSLSessionCache)}).

        OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
                host, port, localAddr, localPort);
        s.setNpnProtocols(mNpnProtocols);
        s.setAlpnProtocols(mAlpnProtocols);
        s.setHandshakeTimeout(mHandshakeTimeoutMillis);
        s.setChannelIdPrivateKey(mChannelIdPrivateKey);
        if (mSecure) {
            verifyHostname(s, host);
        }
        return s;
    
public java.net.SocketcreateSocket(java.lang.String host, int port)
{@inheritDoc}

This method verifies the peer's certificate hostname after connecting (unless created with {@link #getInsecure(int, SSLSessionCache)}).

        OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
        s.setNpnProtocols(mNpnProtocols);
        s.setAlpnProtocols(mAlpnProtocols);
        s.setHandshakeTimeout(mHandshakeTimeoutMillis);
        s.setChannelIdPrivateKey(mChannelIdPrivateKey);
        if (mSecure) {
            verifyHostname(s, host);
        }
        return s;
    
public byte[]getAlpnSelectedProtocol(java.net.Socket socket)
Returns the Application Layer Protocol Negotiation (ALPN) protocol selected by client and server, or null if no protocol was negotiated.

param
socket a socket created by this factory.
throws
IllegalArgumentException if the socket was not created by this factory.
hide

        return castToOpenSSLSocket(socket).getAlpnSelectedProtocol();
    
public static javax.net.SocketFactorygetDefault(int handshakeTimeoutMillis)
Returns a new socket factory instance with an optional handshake timeout.

param
handshakeTimeoutMillis to use for SSL connection handshake, or 0 for none. The socket timeout is reset to 0 after the handshake.
return
a new SSLSocketFactory with the specified parameters

        return new SSLCertificateSocketFactory(handshakeTimeoutMillis, null, true);
    
public static javax.net.ssl.SSLSocketFactorygetDefault(int handshakeTimeoutMillis, SSLSessionCache cache)
Returns a new socket factory instance with an optional handshake timeout and SSL session cache.

param
handshakeTimeoutMillis to use for SSL connection handshake, or 0 for none. The socket timeout is reset to 0 after the handshake.
param
cache The {@link SSLSessionCache} to use, or null for no cache.
return
a new SSLSocketFactory with the specified parameters

        return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true);
    
public java.lang.String[]getDefaultCipherSuites()

        return getDelegate().getDefaultCipherSuites();
    
private synchronized javax.net.ssl.SSLSocketFactorygetDelegate()

        // Relax the SSL check if instructed (for this factory, or systemwide)
        if (!mSecure || isSslCheckRelaxed()) {
            if (mInsecureFactory == null) {
                if (mSecure) {
                    Log.w(TAG, "*** BYPASSING SSL SECURITY CHECKS (socket.relaxsslcheck=yes) ***");
                } else {
                    Log.w(TAG, "Bypassing SSL security checks at caller's request");
                }
                mInsecureFactory = makeSocketFactory(mKeyManagers, INSECURE_TRUST_MANAGER);
            }
            return mInsecureFactory;
        } else {
            if (mSecureFactory == null) {
                mSecureFactory = makeSocketFactory(mKeyManagers, mTrustManagers);
            }
            return mSecureFactory;
        }
    
public static org.apache.http.conn.ssl.SSLSocketFactorygetHttpSocketFactory(int handshakeTimeoutMillis, SSLSessionCache cache)
Returns a socket factory (also named SSLSocketFactory, but in a different namespace) for use with the Apache HTTP stack.

param
handshakeTimeoutMillis to use for SSL connection handshake, or 0 for none. The socket timeout is reset to 0 after the handshake.
param
cache The {@link SSLSessionCache} to use, or null for no cache.
return
a new SocketFactory with the specified parameters
deprecated
Use {@link #getDefault()} along with a {@link javax.net.ssl.HttpsURLConnection} instead. The Apache HTTP client is no longer maintained and may be removed in a future release. Please visit this webpage for further details.

        return new org.apache.http.conn.ssl.SSLSocketFactory(
                new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true));
    
public static javax.net.ssl.SSLSocketFactorygetInsecure(int handshakeTimeoutMillis, SSLSessionCache cache)
Returns a new instance of a socket factory with all SSL security checks disabled, using an optional handshake timeout and SSL session cache.

Warning: Sockets created using this factory are vulnerable to man-in-the-middle attacks!

param
handshakeTimeoutMillis to use for SSL connection handshake, or 0 for none. The socket timeout is reset to 0 after the handshake.
param
cache The {@link SSLSessionCache} to use, or null for no cache.
return
an insecure SSLSocketFactory with the specified parameters

        return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, false);
    
public byte[]getNpnSelectedProtocol(java.net.Socket socket)
Returns the Next Protocol Negotiation (NPN) protocol selected by client and server, or null if no protocol was negotiated.

param
socket a socket created by this factory.
throws
IllegalArgumentException if the socket was not created by this factory.

        return castToOpenSSLSocket(socket).getNpnSelectedProtocol();
    
public java.lang.String[]getSupportedCipherSuites()

        return getDelegate().getSupportedCipherSuites();
    
private static booleanisSslCheckRelaxed()

        return "1".equals(SystemProperties.get("ro.debuggable")) &&
            "yes".equals(SystemProperties.get("socket.relaxsslcheck"));
    
private javax.net.ssl.SSLSocketFactorymakeSocketFactory(javax.net.ssl.KeyManager[] keyManagers, javax.net.ssl.TrustManager[] trustManagers)

        try {
            OpenSSLContextImpl sslContext = new OpenSSLContextImpl();
            sslContext.engineInit(keyManagers, trustManagers, null);
            sslContext.engineGetClientSessionContext().setPersistentCache(mSessionCache);
            return sslContext.engineGetSocketFactory();
        } catch (KeyManagementException e) {
            Log.wtf(TAG, e);
            return (SSLSocketFactory) SSLSocketFactory.getDefault();  // Fallback
        }
    
public voidsetAlpnProtocols(byte[][] protocols)
Sets the Application Layer Protocol Negotiation (ALPN) protocols that this peer is interested in.

For servers this is the sequence of protocols to advertise as supported, in order of preference. This list is sent unencrypted to all clients that support ALPN.

For clients this is a list of supported protocols to match against the server's list. If there is no protocol supported by both client and server then the first protocol in the client's list will be selected. The order of the client's protocols is otherwise insignificant.

param
protocols a non-empty list of protocol byte arrays. All arrays must be non-empty and of length less than 256.
hide

        this.mAlpnProtocols = toLengthPrefixedList(protocols);
    
public voidsetChannelIdPrivateKey(java.security.PrivateKey privateKey)
Sets the private key to be used for TLS Channel ID by connections made by this factory.

param
privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables TLS Channel ID). The private key has to be an Elliptic Curve (EC) key based on the NIST P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
hide

        mChannelIdPrivateKey = privateKey;
    
public voidsetHostname(java.net.Socket socket, java.lang.String hostName)
Turns on Server Name Indication (SNI) on a given socket.

param
socket a socket created by this factory.
param
hostName the desired SNI hostname, null to disable.
throws
IllegalArgumentException if the socket was not created by this factory.

        castToOpenSSLSocket(socket).setHostname(hostName);
    
public voidsetKeyManagers(javax.net.ssl.KeyManager[] keyManagers)
Sets the {@link KeyManager}s to be used for connections made by this factory.

        mKeyManagers = keyManagers;

        // Clear out any existing cached factories since configurations have changed.
        mSecureFactory = null;
        mInsecureFactory = null;
    
public voidsetNpnProtocols(byte[][] npnProtocols)
Sets the Next Protocol Negotiation (NPN) protocols that this peer is interested in.

For servers this is the sequence of protocols to advertise as supported, in order of preference. This list is sent unencrypted to all clients that support NPN.

For clients this is a list of supported protocols to match against the server's list. If there is no protocol supported by both client and server then the first protocol in the client's list will be selected. The order of the client's protocols is otherwise insignificant.

param
npnProtocols a non-empty list of protocol byte arrays. All arrays must be non-empty and of length less than 256.

        this.mNpnProtocols = toLengthPrefixedList(npnProtocols);
    
public voidsetSoWriteTimeout(java.net.Socket socket, int writeTimeoutMilliseconds)
Sets this socket's SO_SNDTIMEO write timeout in milliseconds. Use 0 for no timeout. To take effect, this option must be set before the blocking method was called.

param
socket a socket created by this factory.
param
timeout the desired write timeout in milliseconds.
throws
IllegalArgumentException if the socket was not created by this factory.
hide

        castToOpenSSLSocket(socket).setSoWriteTimeout(writeTimeoutMilliseconds);
    
public voidsetTrustManagers(javax.net.ssl.TrustManager[] trustManager)
Sets the {@link TrustManager}s to be used for connections made by this factory.

        mTrustManagers = trustManager;

        // Clear out all cached secure factories since configurations have changed.
        mSecureFactory = null;
        // Note - insecure factories only ever use the INSECURE_TRUST_MANAGER so they need not
        // be cleared out here.
    
public voidsetUseSessionTickets(java.net.Socket socket, boolean useSessionTickets)
Enables session ticket support on the given socket.

param
socket a socket created by this factory
param
useSessionTickets {@code true} to enable session ticket support on this socket.
throws
IllegalArgumentException if the socket was not created by this factory.

        castToOpenSSLSocket(socket).setUseSessionTickets(useSessionTickets);
    
static byte[]toLengthPrefixedList(byte[] items)
Returns an array containing the concatenation of length-prefixed byte strings.

        if (items.length == 0) {
            throw new IllegalArgumentException("items.length == 0");
        }
        int totalLength = 0;
        for (byte[] s : items) {
            if (s.length == 0 || s.length > 255) {
                throw new IllegalArgumentException("s.length == 0 || s.length > 255: " + s.length);
            }
            totalLength += 1 + s.length;
        }
        byte[] result = new byte[totalLength];
        int pos = 0;
        for (byte[] s : items) {
            result[pos++] = (byte) s.length;
            for (byte b : s) {
                result[pos++] = b;
            }
        }
        return result;
    
public static voidverifyHostname(java.net.Socket socket, java.lang.String hostname)
Verify the hostname of the certificate used by the other end of a connected socket. You MUST call this if you did not supply a hostname to {@link #createSocket()}. It is harmless to call this method redundantly if the hostname has already been verified.

Wildcard certificates are allowed to verify any matching hostname, so "foo.bar.example.com" is verified if the peer has a certificate for "*.example.com".

param
socket An SSL socket which has been connected to a server
param
hostname The expected hostname of the remote server
throws
IOException if something goes wrong handshaking with the server
throws
SSLPeerUnverifiedException if the server cannot prove its identity
hide

        if (!(socket instanceof SSLSocket)) {
            throw new IllegalArgumentException("Attempt to verify non-SSL socket");
        }

        if (!isSslCheckRelaxed()) {
            // The code at the start of OpenSSLSocketImpl.startHandshake()
            // ensures that the call is idempotent, so we can safely call it.
            SSLSocket ssl = (SSLSocket) socket;
            ssl.startHandshake();

            SSLSession session = ssl.getSession();
            if (session == null) {
                throw new SSLException("Cannot verify SSL socket without session");
            }
            if (!HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session)) {
                throw new SSLPeerUnverifiedException("Cannot verify hostname: " + hostname);
            }
        }