public class TlsSniSocketFactory extendsSSLSocketFactory {private final String TAG = TlsSniSocketFactory.class.getSimpleName();
HostnameVerifier hostnameVerifier=HttpsURLConnection.getDefaultHostnameVerifier();
String peerHost;publicTlsSniSocketFactory(String peerHost) {this.peerHost =peerHost;
}publicTlsSniSocketFactory() {
}
@OverridepublicSocket createSocket() {return null;
}
@Overridepublic Socket createSocket(String host, intport) {return null;
}
@Overridepublic Socket createSocket(String host, int port, InetAddress localHost, intlocalPort) {return null;
}
@Overridepublic Socket createSocket(InetAddress host, intport) {return null;
}
@Overridepublic Socket createSocket(InetAddress address, int port, InetAddress localAddress, intlocalPort) {return null;
}//TLS layer
@OverridepublicString[] getDefaultCipherSuites() {return new String[0];
}
@OverridepublicString[] getSupportedCipherSuites() {return new String[0];
}
@Overridepublic Socket createSocket(Socket plainSocket, String host, int port, boolean autoClose) throwsIOException {
if(TextUtils.isEmpty(peerHost)) {
peerHost=host;
peerHost=....;
} Log.i(TAG, "customized createSocket. host: " +peerHost);
InetAddress address=plainSocket.getInetAddress();if(autoClose) {//we don't need the plainSocket
plainSocket.close();
}//create and connect SSL socket, but don't do hostname/certificate verification yet
SSLCertificateSocketFactory sslSocketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(0);
SSLSocket ssl=(SSLSocket) sslSocketFactory.createSocket(address, port);//enable TLSv1.1/1.2 if available
ssl.setEnabledProtocols(ssl.getSupportedProtocols());//set up SNI before the handshake
if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.JELLY_BEAN_MR1) {
Log.i(TAG,"Setting SNI hostname");
sslSocketFactory.setHostname(ssl, peerHost);
}else{
Log.d(TAG,"No documented SNI support on Android <4.2, trying with reflection");try{
java.lang.reflect.Method setHostnameMethod= ssl.getClass().getMethod("setHostname", String.class);
setHostnameMethod.invoke(ssl, peerHost);
}catch(Exception e) {
Log.w(TAG,"SNI not useable", e);
}
}//verify hostname and certificate
SSLSession session =ssl.getSession();if (!hostnameVerifier.verify(peerHost, session))throw new SSLPeerUnverifiedException("Cannot verify hostname: " +peerHost);
Log.i(TAG,"Established " + session.getProtocol() + " connection with " + session.getPeerHost() +
" using " +session.getCipherSuite());returnssl;
}
}