Reputation: 11688
I'm trying to connect to my secured server using HTTPS using DefaultHttpClient.
My server is using PositiveSSL certificate and every check i've made through the SSL checkers online - gives an A grade for the certificate.
Apperantly, PositiveSSL is not a verified CA Root in Android so when i'm ever i'm trying to connect to my server I'm receiving the javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
which is discussed here in various questions.
One of the given solution (that was the best for me) is to create a custom SSLFactory and to allow it to accept the unverified certificate, in case this certificate is coming from my server (to set the allowed server's name).
I couldn't find any code examples on how to do it.. would be great if someone will be kind to help me with that
Upvotes: 1
Views: 3906
Reputation: 25858
Yopu can Write you Custom SSLSocketFactory as given below
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[]{tm}, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port,
autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
Now Create a Custom HttpClient using the SocketFactory to by Pass the certificate. You can also accept some particular Certificate as well using your SockeFactory.
public static DefaultHttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (UnrecoverableKeyException e) {
return new DefaultHttpClient();
} catch (NoSuchAlgorithmException e) {
return new DefaultHttpClient();
} catch (CertificateException e) {
return new DefaultHttpClient();
} catch (IOException e) {
return new DefaultHttpClient();
} catch (KeyStoreException e) {
return new DefaultHttpClient();
} catch (KeyManagementException e) {
return new DefaultHttpClient();
}
}
Now Use instantiate httpclient as mentioned :
DefaultHttpClient client = getNewHttpClient();
Check emmby Answer on this post
Trusting all certificates using HttpClient over HTTPS
UPDATED :
If you want to verify only some particular server. Open the url in browser with Https and download the certificate from the url bar , Its easy Google it how to do that. It will give you a certificate file.
Copy that certificate in your assest folder. and do the following.
private X509Certificate getCertFromFile(String path) throws Exception {
AssetManager assetManager = MyActivity.this.getResources().getAssets();
InputStream inputStream = null;
try {
inputStream = assetManager.open(path);
} catch (IOException e) {
e.printStackTrace();
}
InputStream caInput = new BufferedInputStream(inputStream);
X509Certificate cert = null;
CertificateFactory cf = CertificateFactory.getInstance("X509");
cert = (X509Certificate) cf.generateCertificate(caInput);
cert.getSerialNumber();
return cert;
}
Now in above code for socket Factory return this certificate instead of null.
@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] certificates=new X509Certificate[]{getCertFromFile(PATH_OF_CERTIFICATE_FILE)};
return certificates;
//asset folder path is taken in method.Only provide path respective to asset folder like /certificate/MyCertificate.crt inside assest.
}
Upvotes: 1
Reputation: 42710
You can place the custom server certificate in a custom trust store (BKS file), include it in your app and initialize your SSLSocketFactory with it:
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(trustStore);
Afterwards use that SSLSocketFactory for creating your connections.
In such a case only connections to servers which certificate is included in the key store.
A very good example how this can be used with HttpClient can be found on Nikolay Elenkov's home page (section Using your own trust store: HttpClient):
http://nelenkov.blogspot.de/2011/12/using-custom-certificate-trust-store-on.html
Upvotes: 0