android: how to accept CA certificate - android

I am trying to make a secure connection to a OCS server through https in android.
I found the EasySSLFactory and EasyX509TrustManager classes to make android trust the certificate but I don't know how to initialize only one time the EasySSLFactory and EasyX509TrustManager objects.
I have the following code to accept a certificate and make a single connection:
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(),
443));
HttpParams params = new BasicHttpParams();
params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 3);
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE,
new ConnPerRouteBean(1));
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "utf8");
int timeoutConnection = 1000;
HttpConnectionParams.setConnectionTimeout(params, timeoutConnection);
int timeoutSocket = 1000;
HttpConnectionParams.setSoTimeout(params, timeoutSocket);
clientConnectionManager = new ThreadSafeClientConnManager(params,
schemeRegistry);
HttpClient client = new DefaultHttpClient(clientConnectionManager,
params);
In order to make a new connection in an new method, I have to do write those lines too...
Is there a way that I can put them in the class constructor and then do connections in that class without writing that before the connection..
Thank you

Look at my blog article. I've posted a detailed description how you can add your desired certificate to a custom keystore and initialize the HttpClient with it.
Hope this helps
EDIT: I havent tried it, but maybe the TrustStrategy interface may help.
You could implement your own TrustStrategy interface and initialize the SSLSocketFactory with the appropriate constructor. Your strategy can just return true (in the isTrusted method), but you should do for security reasons a bit of checking to be sure if the certificate can be considered as trusted (it depends on your needs)
Look at line 35 on my blog article of the SecureHttpClient class. Replace the line with something like this:
SSLSocketFactory sf = new SSLSocketFactory(myTrustStrategy);
Please let me know if this works for you.
Regards

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?

Android and HTTPS calls

I have developed an Android app and it is running smooth. Not yet into production. This app communicates with the server using REST services. Now
arrived an issue. As of now I am using HTTP to communicate with the server and get the info back from the server.
I wish to have the data transmission more secured. Can anyone please shed some light on how to accomplish this? I am clueless about HTTPS and implementing it in Android.
Any pointers and links will be helpful like how to start. Do I need to purchase certificates and get it signed.
Thanks
I fairly certain you don't need to do anything special for HTTPS in Android, just change your url to start with "https". new URL(url).openConnection() should work fine with that. If you're using Apache's HttpClient stuff, you might need to define your own client. Below is code I have from a project I'm currently working on.
public static DefaultHttpClient makeHTTPClient() {
BasicHttpParams mHttpParams = new BasicHttpParams();
// Set the timeout in milliseconds until a connection is established.
// The default value is zero, that means the timeout is not used.
int timeoutConnection = 15000;
HttpConnectionParams.setConnectionTimeout(mHttpParams, timeoutConnection);
// Set the default socket timeout (SO_TIMEOUT)
// in milliseconds which is the timeout for waiting for data.
int timeoutSocket = 20000;
HttpConnectionParams.setSoTimeout(mHttpParams, timeoutSocket);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
final SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory();
sslSocketFactory.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
registry.register(new Scheme("https", sslSocketFactory, 443));
ClientConnectionManager cm = new ThreadSafeClientConnManager(mHttpParams, registry);
DefaultHttpClient defaultHttpClient = new DefaultHttpClient(cm, mHttpParams);
return defaultHttpClient;
}

Handle multiple HttpClient instances

I use connection for server connections as show bleow.
HttpParams params = new BasicHttpParams();
ConnManagerParams.setMaxTotalConnections(params, 10);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, Integer.valueOf(60000));
params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, Integer.valueOf(60000));
params.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true);
//eate and initialize scheme registry
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Create an HttpClient with the ThreadSafeClientConnManager.
// This connection manager must be used if more than one thread will
// be using the HttpClient.
cm = new ThreadSafeClientConnManager(params, schemeRegistry);
httpClient = new DefaultHttpClient(cm, params);
ThreadSafeClientConnManager API says:
ThreadSafeClientConnManager maintains a maximum limit of connection on a per route
basis and in total. Per default this implementation will create no more than than
2 concurrent connections per given route and no more 20 connections in total. For many
real-world applications these limits may prove too constraining, especially if they use
HTTP as a transport protocol for their services. Connection limits, however, can be
adjusted using HTTP parameters.
How can I change the maximum connections per host to more than 2?
Thanks in advance!

Android HttpClient Digest Authentication Authorization header "nc" hard-coded

We try to send several requests to target server in one HttpClient (one session). The target server will first authenticate all requests with digest authentication (based on MD5-sess). The result shows that only first access is successful. The following accesses are rejected by server because server treats later accesses as replay attack as the "nc" value is always "00000001".
It seems Android HttpClient hard-coded digest authorization header attirbute "nc" to "00000001"?
Any way for client to increase this value when new request is sent? Thanks.
public class HttpService {
private static final HttpService instance = new HttpService();
private HttpService() {
client = getHttpClient();
}
public static HttpService getInstance() {
return instance;
}
private DefaultHttpClient getHttpClient() {
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setStaleCheckingEnabled(params, false);
HttpConnectionParams.setConnectionTimeout(params, 15 * 1000);
HttpConnectionParams.setSoTimeout(params, 15 * 1000);
HttpConnectionParams.setSocketBufferSize(params, 8192);
HttpProtocolParams.setUserAgent(params, USER_AGENT);
SchemeRegistry schemeRegistry = new SchemeRegistry();
Scheme httpScheme = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);
Scheme httpsScheme = new Scheme("https", SSLCertificateSocketFactory.getHttpSocketFactory(30 * 1000, null), 443);
schemeRegistry.register(httpScheme);
schemeRegistry.register(httpsScheme);
ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry);
//create client
DefaultHttpClient httpClient = new DefaultHttpClient(manager, params);
httpClient.getCredentialsProvider().setCredentials(new AuthScope(address, port),
new UsernamePasswordCredentials(username, password));
}
}
Android ships with an extremely outdated (pre-BETA) fork of Apache HttpClient. There has been a countless number of changes in the stock version of HttpClient since 4.0 ALPHA, also in the Digest auth area.
The best thing you can do is to copy the DigestScheme from the stock version of Apache HttpClient and configure your application to use the copy instead of the default implementation.
https://github.com/apache/httpcomponents-client/blob/master/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java
For that end you will have to register a custom DigestSchemeFactory instance with the auth scheme registry.
https://github.com/apache/httpcomponents-client/blob/master/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestSchemeFactory.java
It seems you are right. This is from Digest.java:
//TODO: supply a real nonce-count, currently a server will interprete a repeated request as a replay
private static final String NC = "00000001"; //nonce-count is always 1
You should file a bug at http://b.android.com. You have a few options:
calculate the digest and create the header yourself, then set it on every request. You could add a HttpRequestInterceptor to make this authomatic (don't set the credentials to the credential provider)
AFAIK authentication schemes should be pluggable, so implement digest auth properly and configure your client to use it.
use another HTTP client library.
EDIT: Since it's fixed in the stock version, there is another alternative:
Another alternative:
change the Apache HttpClient package name using jarjar, package it with the app, and don't use the Android system one at all.

Is creating HttpClient expensive?

I had seen a few examples in Android implement maybeCreateHttpClient(), especially in Google sample, which it does is to check if HttpClient object is instantiated, if not, instantiate it, and reuse it.
Why this approach? Is creating new HttpClient expensive?
Use a connection pool (eg. ThreadSafeClientConnManager) to manage your clients.
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);
client is a singleton object which can be reused, to fire a request:
HttpResponse response = client.execute(new HttpGet(URL));
A HttpClient is fairly large and complex object. You might make tens (or probably more) http calls in your app. If you created a new one for each http request you would quickly run into memory problems and would certainly notice garbage collection slow downs.
The http client is a generic component to help you make http calls, just reuse it. There is no reason not too.

Categories

Resources