8

I am calling web service from my android client via https. I got to validate the certificate receive from server side. How do I do that ? At present this is my code that I use to call a web service.

private static String SendPost(String url, ArrayList<NameValuePair> pairs) {   // url = "https://....."   
    errorMessage = "";   
    String response = "";   

    DefaultHttpClient hc=new DefaultHttpClient();      
    ResponseHandler <String> res=new BasicResponseHandler();      
    HttpPost postMethod=new HttpPost(url);   

    try {   
postMethod.setEntity(new UrlEncodedFormEntity(pairs));   
        response = hc.execute(postMethod, res);   
    } catch (UnsupportedEncodingException e) {   
        e.printStackTrace();   
    } catch (ClientProtocolException e) {   
        e.printStackTrace();   
    } catch (IOException e) {   
        e.printStackTrace();   
    }        

    return response;   
}  

How do I validate a self-signed certificate received from server during performing Post ? I got to do testing via public/private keys. Client will have a CA file. Ijust need the client to verify the server certificate using the CA, the service is public .This has to do with public/private key. How can I receive the certificate from the server before calling the post ?

Their are several options and code snippets available on stackoverflow. Couple of links I found with multiple answers is : Accepting a certificate for HTTPs on Android HTTPS GET (SSL) with Android and self-signed server certificate

But I can't make out which is good/applicable for me ! I don't want to disable all or accept any. Have to check the public/private keys/

Any help is highly appreciated.

Community
  • 1
  • 1
Tvd
  • 4,463
  • 18
  • 79
  • 125

1 Answers1

4

Bob Lee wrote a nice blog post on how using SSL certificates with Android. I think it is applicable to your case: http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html

You just have to create a KeyStore containing your self-signed certificate and use the custom HttpClient implementation described in that post.


UPDATE:

Host name validation can be customizez by setting a custom X509HostnameVerifier on the SSLSocketFactory. Some implementations are already available in android: AllowAllHostnameVerifier, BrowserCompatHostnameVerifier, StrictHostnameVerifier

/* ... */
public class MyHostnameVerifier extends AbstractVerifier {
  boolean verify(String hostname, SSLSession session) {
    X509Certificate[] chain = session.getPeerCertificateChain();
    /* made some checks... */
    return checked;
  }
}
sslSocketFactory.setHostnameVerifier(new MyHostnameVerifier());
Jcs
  • 13,279
  • 5
  • 53
  • 70
  • 1
    How do I receive certificate from server and test data from it ? – Tvd Apr 18 '11 at 11:02
  • You do not have to do anything. The certificate is sent by the server during the SSL handshake and is automatically validated by the client application against the KeyStore content. The handshake is performed before any HTTP data is exchanged. If you want to perform more complex or custom certificate validation this is also possible (but a bit long to explain that in this comment) – Jcs Apr 18 '11 at 11:14
  • @ Jcs, I already have the certificate.cer file that I have to use. I don't understand that part with the Bouncy Castle part. Plus I don't have any password to pass to trusted.load(); ???? Am stuck up at these points. – Tvd Apr 18 '11 at 13:29
  • The SSLSocketFactory constructor is expecting a KeysStore that's why you cannot directly pass the certificate.cer file and you have to wrap it into a KeyStore object. Android does not support the old java keystore format (aka JKS) but it supports a BouncyCastle's designed keystore format (aka BKS). By adding the BouncyCastle lib to the classpath, keytool is able to create a keystore with the BKS format. The password is optional when creating the keystore; you can ignore this option and pass null to the load() method. – Jcs Apr 18 '11 at 13:48
  • Thanks Jcs for this explaination. I was successful in creating the bks file and accepting the vert from the server and access the web service. But 2 problems : 1) Default domain is "aa-e3.mysite.com". I have a alist of domains and list any domain and connect to that domain it may be "we-e3.mysite.com" or something else. Am able to access the WS only when the selected domain by prg is the default one, for other all I get SSLExcep "hostname in certi didn't match: != ". How to handle this ? – Tvd Apr 20 '11 at 08:35
  • @Jcs 2) When I get the server certificate, I got to verify using a CA .crt file i.e. performing SSL Peer Verification. I have the .crt file. Where and how to handle this part ? – Tvd Apr 20 '11 at 08:37
  • For #1 I updated my answer. For #2 I do not understand what do you want to do. The SSL implementation validates the chain sent by the server, verifies the chain can be linked to a trust anchor present in the keystore. – Jcs Apr 20 '11 at 09:05
  • @Jcs, Thanks for update 1. That solved my 1st problem. The signature of verfy() is final method, so can't override that one, but overrided one with verify(String host, String[] cns, String[] subjectAlts). I just need the host to perform checks. FOR #2, I need the client to verify the server certificate using the CA, I am not using a client certificate. – Tvd Apr 20 '11 at 09:56
  • In .NET, such SSL ServerManager tasks has to be done only once in the whole application. Over here, every time I call SendPost, MyHttpClient is created that calls createClientConnectionManager() & MyHostVerifier. Is this fine, or I should create an instance of MyHttpClient once and use the same object till the end of the app ? – Tvd Apr 20 '11 at 10:23
  • @Jcs, I got that my point 2 was totally wrong. I was handling that part only and got confused unnecessarily. THANKS a lot for all the help, support and excellent explaination. – Tvd Apr 20 '11 at 13:16