Friday, May 7, 2010

Mutual Authentication with Client Certificate over HTTPS/SSL using Java

This blog is about SSL/TLS mutual authentication using Java. I am on the client side with a client certificate signed by an intermediate issuer and finally by Verisign. (aha, a certificate chain is here to make the situation not vanilla already.) The server requests a client certificate and recognizes Verisign as a Certification Authority (CA). You can safely ignore this blog if you have a self-certified certificate.

During the implementation, I got tripped more than a couple of times over error messages like:
403.7 Forbidden: Client Certificate Required.
javax.net.ssl.SSLException: HelloRequest followed by an unexpected handshake message
To save somebody some time in the future, a step by step instruction is provided below:
  1. I assume you have a valid certificate or a chain of certificates, whose root is acceptable by the server. The valid certificate contains its private key. Run the following command to verify:
    keytool -list -v -keystore "your certificate file"
    ...
    Entry type: PrivateKeyEntry
  2. Import your certificate and intermediate certificates into a browser like IE or Firefox and test out the https URL. This step will validate the certificates and save you a lot of troubles down the road. Java version of the SSL implementation is not as simple/mature as the browsers'. Please make sure all the certificates have not expired.
  3. Backup your keystore located at /your_home_directory/.keystore by default and the truststore located at somewhere similar to \Java\jre6\lib\security\cacerts
  4. Use not-yet-commons-ssl utility to import your certificates into the Java keystore format. Sample command is:
    java -cp not-yet-commons-ssl-0.3.9.jar org.apache.commons.ssl.KeyStoreBuilder 
  5. Customize the following java code, replace the static final Strings to fit in your needs. Note that this implementation forcefully use a specific alias to present the corresponding certificate/certificate chain to the server. Somehow the default KeyManager simply disqualifies my certificate to be presented to the server.
    public class Main {

    private static final Logger logger = Logger.getLogger(Main.class.getName());
    private static final String LINE_BREAKER = System.getProperty("line.separator");

    private static final String CERTIFACATE_FILE = "your keystore location";
    private static final String CERTIFACATE_PASS = "changeit";
    private static final String CERTIFACATE_ALIAS = "your alias";
    private static final String TARGET_URL = "https://xyz.com";


    public static void main(String[] args) {
    String targetURL = TARGET_URL;
    URL url;
    HttpsURLConnection connection = null;
    BufferedReader bufferedReader = null;
    InputStream is = null;

    try {
    //Create connection
    url = new URL(targetURL);
    //Uncomment this in case server demands some unsafe operations
    //System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");
    connection = (HttpsURLConnection) url.openConnection();

    connection.setRequestMethod("POST");
    connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    connection.setRequestProperty("Content-Language", "en-US");

    SSLSocketFactory sslSocketFactory = getFactory(new File(CERTIFACATE_FILE), CERTIFACATE_PASS, CERTIFACATE_ALIAS);
    connection.setSSLSocketFactory(sslSocketFactory);

    //Process response
    is = connection.getInputStream();

    bufferedReader = new BufferedReader(new InputStreamReader(is));
    String line;
    StringBuffer lines = new StringBuffer();
    while ((line = bufferedReader.readLine()) != null) {
    lines.append(line).append(LINE_BREAKER);
    }
    logger.info("response from " + targetURL + ":" + LINE_BREAKER + lines);

    } catch (Exception e) {
    ...
    }
    }

    private static SSLSocketFactory getFactory(File pKeyFile, String pKeyPassword, String certAlias) throws Exception {
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
    KeyStore keyStore = KeyStore.getInstance("JKS");

    InputStream keyInput = new FileInputStream(pKeyFile);
    keyStore.load(keyInput, pKeyPassword.toCharArray());
    keyInput.close();
    keyManagerFactory.init(keyStore, pKeyPassword.toCharArray());

    //Replace the original KeyManagers with the AliasForcingKeyManager
    KeyManager[] kms = keyManagerFactory.getKeyManagers();
    for (int i = 0; i < kms.length; i++) {
    if (kms[i] instanceof X509KeyManager) {
    kms[i] = new AliasForcingKeyManager((X509KeyManager) kms[i], certAlias);
    }
    }

    SSLContext context = SSLContext.getInstance("TLS");
    context.init(kms, null, null);
    return context.getSocketFactory();
    }

    /*
    * This wrapper class overwrites the default behavior of a X509KeyManager and
    * always render a specific certificate whose alias matches that provided in the constructor
    */
    private static class AliasForcingKeyManager implements X509KeyManager {

    X509KeyManager baseKM = null;
    String alias = null;

    public AliasForcingKeyManager(X509KeyManager keyManager, String alias) {
    baseKM = keyManager;
    this.alias = alias;
    }

    /*
    * Always render the specific alias provided in the constructor
    */
    public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
    return alias;
    }

    public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
    return baseKM.chooseServerAlias(keyType, issuers, socket);
    }

    public X509Certificate[] getCertificateChain(String alias) {
    return baseKM.getCertificateChain(alias);
    }

    public String[] getClientAliases(String keyType, Principal[] issuers) {
    return baseKM.getClientAliases(keyType, issuers);
    }

    public PrivateKey getPrivateKey(String alias) {
    return baseKM.getPrivateKey(alias);
    }

    public String[] getServerAliases(String keyType, Principal[] issuers) {
    return baseKM.getServerAliases(keyType, issuers);
    }
    }
    }


  6. Try to set
    -Dsun.security.ssl.allowUnsafeRenegotiation=true
    if you get the error message like:
    javax.net.ssl.SSLException: HelloRequest followed by an unexpected  handshake message
  7. If anything goes wrong, turn on -Djavax.net.debug=all to debug. Verify the keystore and truststore locations. Verify the presence of the certificates. Here is a sample log file with successful connection: http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/ReadDebug.html

64 comments:

  1. Denis, whilst I myself have authenticated on SSL Certificates from a leading authority (GlobalSign) a contact of mine has self-signed SSL authentication. To what extent does this change the authentication process? With low cost SSL certification from SSL247.co.uk and other resellers, to what extent is self-signed certification actually beneficial? Thanks in advance!

    ReplyDelete
    Replies
    1. Great Article android based projects

      Java Training in Chennai Project Center in Chennai Java Training in Chennai projects for cse The Angular Training covers a wide range of topics including Components, Angular Directives, Angular Services, Pipes, security fundamentals, Routing, and Angular programmability. The new Angular TRaining will lay the foundation you need to specialise in Single Page Application developer. Angular Training Project Centers in Chennai

      Delete
  2. Who is on the server side?
    Does the client expect the server to be certified by a CA or self-certification is sufficient?
    Does the server expect the client to be certified by a CA or self-certification is sufficient?

    ReplyDelete
  3. Denis,
    What alias did you force the key manager to use? I'm also having trouble getting the KeyManager (or something) to send my cert to the server.

    ReplyDelete
    Replies
    1. According to the code:
      private static final String CERTIFACATE_ALIAS = "your alias";

      Delete
  4. hi Deni, i used this one ans getting following error
    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

    can anyone tell me the problem???

    ReplyDelete
    Replies
    1. From the exception, it says the certification chain is broken somewhere.

      Delete
  5. Next time, please include your import statements. I am having a hell-of-a-time trying to get your code to complie without ClassCastExceptions

    ReplyDelete
    Replies
    1. In Eclipse, the shortcut ctrl-shift-o will resolve all your import errors.

      Delete
  6. WOW, thank you, thank you, thank you!!!!!! this resolved our issue.

    ReplyDelete
  7. Awesome stuff. Helped me solve the issue as well! Kudos

    ReplyDelete
  8. Hi,
    Thank you all for posting timely updates, your reviews would indeed help simplifying the complex procedures.



    Certificate Authentication

    ReplyDelete
  9. Hi,
    This is the nice post and this post is really appreciable and informatics .I like this post too much.
    Thanks a lot for sharing such a good source with all, i appreciate your efforts taken for the same. I found this worth sharing and must share this with all.
    Authentication Certificate

    ReplyDelete
  10. This might be useful as well.

    http://ankursinghal86.blogspot.in/2014/06/authentication-with-client-certificate.html

    ReplyDelete
  11. Hi,
    Great blog nice n useful information , it is very helpful for me , I realy appreciate thanks for sharing. I would like to read more information thanks.
    Certificate Authentication

    ReplyDelete
  12. this is good example.. it worked in my env..thanks a bunch

    ReplyDelete
  13. I got this error: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure.
    How do i resolve this?

    ReplyDelete
  14. Nice post. I was working on it last 6 month but currently its solve.

    ReplyDelete
  15. nice article
    very useful information.
    keep sharing.

    ReplyDelete
  16. Nice information, valuable and excellent design, as share good stuff with good ideas and concepts, lots of great information and inspiration, both of which I need, thanks to offer such a helpful information here.
    java training in Bangalore

    ReplyDelete

  17. We provide best Selenium training in Bangalore, automation testing with live projects. Cucumber, Java Selenium and Software Testing Training in Bangalore.

    ReplyDelete
  18. Thanks for sharing this fantastic Article, really very informative. Your writing skill is very good, you must keep writing this type of Article.

    digital marketing course in hubli

    ReplyDelete
  19. Visit cognex website to know more about aws and microsoft azure certification and training in chennai. We are the best in AWS Training in chennai.

    ReplyDelete
  20. This is excellent information. It is amazing and wonderful to visit your site. Thanks for sharing this information, this is useful to me...

    Looking for the best PPC course in Bangalore India? Learn PPC from Ranjan Jena, 10+ Years Expert Google Ads Trainer. 1000+ Students Trained @ eMarket Education, Koramangala, Bangalore.
    Best Online Digital Marketing Courses in Bangalore
    Digital Marketing Course

    ReplyDelete
  21. I pay a visit every day a few blogs and sites to read articles, but this weblog offers feature based writing.
    leather sofa set

    ReplyDelete
  22. I read this article fully on the topic of the resemblance of most recent and preceding technologies, it’s remarkable article.

    Study in Ireland Consultants

    ReplyDelete
  23. Fiducia Solutions is an ISO 9001:2015 certified institute providing course certifications to all its students. We, at Fiducia Solutions, see to it that the candidate is certified and entitled to bag a good position in acclaimed companies. We provide certificates that are valued, and our alumni reputation proves that we are good at what we offer.

    And that is not all! We are known to provide 100% live project training and 100% written guaranteed placements to our students. That’s what makes us the best PHP/ HR/ Digital Marketing training institutes in Noida and Ghaziabad.

    PHP Training Institute in Noida
    HR Training Institute in Noida
    Digital Marketing Training Institute in Noida
    Android Training Institute in Noida

    ReplyDelete
  24. This is most informative and also this post most user-friendly and super navigation to all posts.
    Best RPA Training in Pune
    AWS Training in Pune

    ReplyDelete
  25. It is very useful blog. Thanks for sharing. Keep updating new posts on your blog!!
    Who needs help in Digital Marketing for your Business? You can also visit my website. I hope to help you
    Digital Marketing Course AchieversIT

    ReplyDelete
  26. interesting information.keep up the good work.Angular training in Chennai

    ReplyDelete
  27. These are truly fantastic ideas regarding blogging. You have touched on some pleasant points here. Any way keep up writing.
    Bada Business

    ReplyDelete
  28. Admiring the dedication you put into your blog and in depth information you provide.
    It’s awesome to come across a blog every once in a while that isn’t the same old rehashed information. Fantastic read! Software Security Solutions

    ReplyDelete
  29. Hi there, yeah this post is genuinely nice and I have learned a lot of things from it concerning blogging. thanks.
    Bathroom Mirrors

    ReplyDelete
  30. Thanks for your marvelous posting! I really enjoyed reading it, you could be a great author. I will be sure to bookmark your blog and definitely will come back in the foreseeable future. I want to encourage you to continue your great posts, have a nice afternoon! Best Digital Marketing Courses in Bangalore

    ReplyDelete
  31. Wonderful blog! Thanks for the information, Also if anyone is interested for Jobs in Aviation field do visit the institute which provides Air Hostess course

    ReplyDelete
  32. Thanks for this amazing blog , it is very useful content for us
    keep sharing this type of informtion if anyone is looking for the best training institute in nodia visit us.

    Python Training Institute
    data science training in noida
    machine learning institute in noida
    java training institute in noida
    data science training in noida

    ReplyDelete