I have some troubles with ssl using httpclient on android i am trying to access self signed certificate in details i want my app to trust all certificates ( i will use ssl only for data encryption). First i tried using this guide http://hc.apache.org/httpclient-3.x/sslguide.html on Desktop is working fine but on android i still got javax.net.ssl.SSLException: Not trusted server certificate. After searching in google i found some other examples how to enable ssl.
http://groups.google.com/group/android-developers/browse_thread/thread/62d856cdcfa9f16e - Working when i use URLConnection but with HttpClient still got the exception.
http://www.discursive.com/books/cjcook/reference/http-webdav-sect-self-signed.html - on Desktop using jars from apache is working but in android using included in SDK classes can't make it work.
http://mail-archives.apache.org/mod_mbox/hc-httpclient-users/200808.mbox/%3C1218824624.6561.14.camel@ubuntu%3E - also get the same exception
So any ideas how can i trust all certificates on android using HttpClient
If you happen to look at the code of DefaultHttpClient, it looks something like this:
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(
new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(
new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ClientConnectionManager connManager = null;
HttpParams params = getParams();
...
}
Notice the mapping of https scheme to org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory().
You can create a custom implementation for org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory
interface (http://hc.apache.org/httpclient-3.x/apidocs/org/apache/commons/httpclient/protocol/SecureProtocolSocketFactory.html) wherein, you can create java.net.SSLSocket
with a custom TrustManager
that accepts all certificate.
You may want to look into JSSE for more details at http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html
The key idea is to use a customized SSLSocketFactory implementing LayeredSocketFactory. The customized socket doesn't need to HostNameVerifier.
private static final class TrustAllSSLSocketFactory implements
LayeredSocketFactory {
private static final TrustAllSSLSocketFactory DEFAULT_FACTORY = new TrustAllSSLSocketFactory();
public static TrustAllSSLSocketFactory getSocketFactory() {
return DEFAULT_FACTORY;
}
private SSLContext sslcontext;
private javax.net.ssl.SSLSocketFactory socketfactory;
private TrustAllSSLSocketFactory() {
super();
TrustManager[] tm = new TrustManager[] { new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
// do nothing
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
// do nothing
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
} };
try {
this.sslcontext = SSLContext.getInstance(SSLSocketFactory.TLS);
this.sslcontext.init(null, tm, new SecureRandom());
this.socketfactory = this.sslcontext.getSocketFactory();
} catch ( NoSuchAlgorithmException e ) {
Log.e(LOG_TAG,
"Failed to instantiate TrustAllSSLSocketFactory!", e);
} catch ( KeyManagementException e ) {
Log.e(LOG_TAG,
"Failed to instantiate TrustAllSSLSocketFactory!", e);
}
}
@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(
socket, host, port, autoClose);
return sslSocket;
}
@Override
public Socket connectSocket(Socket sock, String host, int port,
InetAddress localAddress, int localPort, HttpParams params)
throws IOException, UnknownHostException, ConnectTimeoutException {
if ( host == null ) {
throw new IllegalArgumentException(
"Target host may not be null.");
}
if ( params == null ) {
throw new IllegalArgumentException(
"Parameters may not be null.");
}
SSLSocket sslsock = (SSLSocket) ( ( sock != null ) ? sock
: createSocket() );
if ( ( localAddress != null ) || ( localPort > 0 ) ) {
// we need to bind explicitly
if ( localPort < 0 ) {
localPort = 0; // indicates "any"
}
InetSocketAddress isa = new InetSocketAddress(localAddress,
localPort);
sslsock.bind(isa);
}
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
InetSocketAddress remoteAddress;
remoteAddress = new InetSocketAddress(host, port);
sslsock.connect(remoteAddress, connTimeout);
sslsock.setSoTimeout(soTimeout);
return sslsock;
}
@Override
public Socket createSocket() throws IOException {
// the cast makes sure that the factory is working as expected
return (SSLSocket) this.socketfactory.createSocket();
}
@Override
public boolean isSecure(Socket sock) throws IllegalArgumentException {
return true;
}
}
You can then continue to use the customized SSLSocketFactory in the supported scheme registry.
private static final BasicHttpParams sHttpParams = new BasicHttpParams();
private static final SchemeRegistry sSupportedSchemes = new SchemeRegistry();
static {
sHttpParams.setParameter("http.socket.timeout", READ_TIMEOUT);
sHttpParams.setParameter("http.connection.timeout", CONNECT_TIMEOUT);
sSupportedSchemes.register(new Scheme("http",
PlainSocketFactory.getSocketFactory(), 80));
sSupportedSchemes.register(new Scheme("https",
TrustAllSSLSocketFactory.getSocketFactory(), 443));
}
Rather than accepting all certificates, I recommend this solution: Trusting all certificates using HttpClient over HTTPS