My app communicates with a server over an internal network through HTTPS. The SSL certificate on this server is listed for the host as its external host name. I want to accept this certificate, but I don't want to accept ANY certificate as many workarounds I've seen seem to do. I would also like to have it so that later on, in the strong possibility that his app is accessing a different server with a correct SSL certificate, that I don't have to change it. I have it working as I would like it seems, but I am very unsure of myself when it comes to implementing my own methods to override a library used for secure communications, and I am not very strong in my knowledge of SSL communications.
I would basically like input on security loopholes and its effectiveness at doing what I need.
Here is the code I have:
HttpClient httpclient = new DefaultHttpClient();
SSLSocketFactory ssf = SSLSocketFactory.getSocketFactory();
ssf.setHostnameVerifier( new X509HostnameVerifier() {
@Override
public void verify( String host, String[] cns, String[] subjectAlts )
throws SSLException
{
}
@Override
public void verify( String host, X509Certificate cert ) throws SSLException
{
}
@Override
public void verify( String host, SSLSocket ssl ) throws IOException
{
boolean foundHost = false;
for( javax.security.cert.X509Certificate cert : ssl.getSession().getPeerCertificateChain() )
{
String[] tokens = cert.getSubjectDN().getName().split( "," );
for( String token : tokens )
{
String[] keyVal = token.split( "=" );
if( keyVal.length > 1 && keyVal[0].equals( "CN" ) )
{
foundHost = keyVal[1].equals( context.getString( R.string.CertHostName ) );
if(!foundHost)
{
foundHost = keyVal[1].equals( host );
}
}
if(foundHost)
{
break;
}
}
if(foundHost)
{
break;
}
}
if(!foundHost)
{
throw new IOException( "Mismatched host in SSL certificate" );
}
}
@Override
public boolean verify( String host, SSLSession session )
{
return false;
}
} );
httpclient.getConnectionManager().getSchemeRegistry().unregister( "https" );
httpclient.getConnectionManager().getSchemeRegistry().register( new Scheme( "https", ssf, 443 ) );
Basically, I found out which method to override through some log statements to see which one was being used in the anonymous inner X509HostnameVerifier
class, and hopefully handled it appropriately. Input would be appreciated.