Android and SSL - checking certificate validity - android

I've got the following code making SSL work with my HttpClient connections and such
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("https",
SSLSocketFactory.getSocketFactory(), 443));
HttpParams params = new BasicHttpParams();
SingleClientConnManager mgr = new SingleClientConnManager(params, schemeRegistry);
HttpClient client = new DefaultHttpClient(mgr, params);
However, does this actually validate the cert? It seems like there should be more to it.

Nevermind, the above code does indeed validate the certificate. I tried it with some random self signed certs for different sites, and it failed.

Related

Use simple DefaultHttpClient or a keystore created with BouncyCastle bundled in the app

The server to which the app connected had a temporary certificate, or something like that. I am only taking care of the Android app and in order to make the https web service calls, the app used the unsafe implementation of the interface X509TrustManager. Now the server certificate has been fixed and has a final certificate.
The following code works:
HttpClient mHttpClient = null;
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, 30000);
DefaultHttpClient client = new DefaultHttpClient(httpParameters);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
mHttpClient = new DefaultHttpClient(mgr, client.getParams());
final HttpParams params = mHttpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, HTTP_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, HTTP_TIMEOUT);
ConnManagerParams.setTimeout(params, HTTP_TIMEOUT);
Basically, using this mHttpClient when making the web service calls does not rise any error or complaints and works as expected. However, I've seen implementations like this one which have a more secure approach.
My question is: by using the DefaultHttpClient simple as in the code above, could it rise some problems where on some devices the certificate may not be recognized as valid? Or better, should I go with the stored keystore as in the answer above?

How to make sure in Android we are using HTTPS correctly

To avoid man in the middle attack, we have written following code to talk to our server that has a valid cert issued by Go Daddy
KeyStore trustStore = KeyStore.getInstance("AndroidKeyStore");
SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_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);
Despite using the "AndroidKeyStore", we are able to talk to sites that do not have valid certificate. What are we doing wrong? Any help appreciated?

How to reuse SSL session when I implement trust self-certificate in HttpClient?

I reference this page and implement trust slef-certificate as follows,
SchemeRegistry schemeRegistry = new SchemeRegistry();
// http scheme
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// https scheme
schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
HttpParams params = new BasicHttpParams();
params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
The EasySSLSocketFactory is here, and the EasyX509TrustManager is here.
I found that it would have a lot of SSL hello handshake.
After my studies, this situation may be reduced by using SSLSessionCache.
I search in the forum, but the solution almost using normal ssl connecting not using trust self-certificate.
How can I use SSLSessionCache when I implement trust self-certificate in HttpClient?

Issue with SSL certificate: "No peer certificate"

I'm trying to authenticate through Last.fm's API.
On Android 4.3 it works just by doing
HttpPost post = new HttpPost("https://ws.audioscrobbler.com/2.0/");
post.setEntity(new UrlEncodedFormEntity(params));
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(post);
but on 2.3.3 I get
javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
Then I tried the solution given here:
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
DefaultHttpClient client = new DefaultHttpClient();
SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());
// Set verifier
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
HttpPost post = new HttpPost("https://ws.audioscrobbler.com/2.0/");
post.setEntity(new UrlEncodedFormEntity(params));
HttpResponse response = httpClient.execute(post);
but I still get the same error.
Then I tried that:
HttpParams httpParams = new BasicHttpParams();
HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(httpParams, HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(httpParams, true);
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ClientConnectionManager conMgr = new ThreadSafeClientConnManager(httpParams, schReg);
DefaultHttpClient httpClient = new DefaultHttpClient(conMgr, httpParams);
HttpPost post = new HttpPost("https://ws.audioscrobbler.com/2.0/");
post.setEntity(new UrlEncodedFormEntity(params));
HttpResponse response = httpClient.execute(post);
and failed again.
Anybody can help?
There seems to be some problem with the way the certificates are returned from the server OR may be android system keystore does not have the relevant root certs to validate and complete the handshake.
Looking at the certificate chain information for the site mentioned in the question, it seems to me that the chain is not correctly sorted.
You can try the answer here

Android ThreadSafeClientConnManager Timeouts?

I'm using a ThreadSafeClientConnManager to perform simultaneous requests in background threads on Android, set up with:
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ClientConnectionManager connman = new ThreadSafeClientConnManager(params, registry);
client = new DefaultHttpClient(connman, params);
And executing requests with (note that I'm using outh-signpost):
HttpGet request = new HttpGet("https://" + API_HOST + "/" + API_VERSION + path);
OAuthConsumer consumer = new CommonsHttpOAuthConsumer(key, secret);
consumer.sign(request);
HttpResponse response = client.execute(request);
The problem is that after a while I start getting
java.net.SocketException: The operation timed out
Do I need to do something to explicitly release the connection after the request?
From the usage guide of apache httpclient, you need to make sure to consume all content on any pooled resource to guarantee it returns to the pool to be available for other threads later on -
http://hc.apache.org/httpcomponents-core-4.0.1/tutorial/html/fundamentals.html#d0e244
In case there's an exception thrown by the underlying library, it is best to abort the HttpMethod that you were trying to run, in which case the connection will be terminated.

Categories

Resources