6

A simple question here.

One application gave me this exception when trying to access a website with a expired certificate: java.security.cert.CertificateExpiredException

So, I renewed the certificated from the website machine and restarted it. When I try to access it from Firefox or Chrome it will load the new certificate (which it's expiration date is set somewhere near 2040).

The problem is, Java applications doesn't seems to renew this certificate, it seems to be stuck in some kind of internal cache. I already tried to add it to the keystore and set options in the application properties like -Dcom.sun.net.ssl.checkRevocation=false. No matter what I do, it always throw me a java.security.cert.CertificateExpiredException

Any ideas?

  • Hello, did it work? – user130370 Dec 26 '12 at 10:28
  • didn't work for me, the server certificate isn't being cached in the keystore (at least not in the two keystores I found on my system). Same issue: web browser shows a certificate that is valid FROM may (the new certificate) and java is complaining about a certificate that is valid UNTIL may (the cached(?) certificate). – user3338098 Jun 8 '18 at 19:38
  • using -Djavax.net.debug=SSL I can see that it is using the old certificate and that the root certificate chain is the same, it's just the main certificate that is outdated (and expired). Could the website be returning the correct certificate to my browser while returning an expired one to my java app?(seems unlikely) – user3338098 Jun 8 '18 at 21:16
  • 2
    @user3338098 - when you connect to the app using something like openssl s_client -connect <host>:<port> does it present the same 'stale' cert that you're seeing when you use the browser? – slm Jun 21 '18 at 0:11
  • 1
    @slm sorry for not responding, my bounty on this question caused me to run out of the reputation required to comment. Your comment sent me in the right direction towards the solution. – user3338098 Jul 27 '18 at 18:32
1

The default Java keystore location is a .keystore file under your home directory (user.home system property) so unless you specify otherwise that is where a Java application will look.

Try running:

$ keytool -list -keystore ~/.keystore -storepass changeit -v

to see if the expired certificate is in there.

If you want to specify a different identity keystore to use then you can do so using the following system properties:

javax.net.ssl.Keystore=/path/to/identity.jks
javax.net.ssl.keyStorePassword=mykeystorepassword

I believe that Firefox uses NSS and you can view its keystore using the certutil utility (from the nss-tools or similar package) - something like:

$ certutil -L -d sql:$HOME/.pki/nssdb

You should be able to use the pk12util utility to extract the key and certificate into a PKCS12 file but you're probably better off just generating a new certificate signing request using the keytool utility.

Note that a revoked certificate is not the same as an expired one which is why your checkRevocation=false doesn't work. The CA can revoke a certificate at any time even if it has not yet expired and this indicates that it should no longer be trusted.

  • might not help but there is also a cacerts file that is used, the path is like /usr/lib/jvm/java-version/jre/lib/security/cacerts on unix based systems – user3338098 Jun 8 '18 at 19:45
1

The issue turns out to be due to a bug which causes HttpsUrlConnection not to use SNI when a custom hostname verifier is used.

Bug workaround

javax.net.ssl.HttpsURLConnection connection = (javax.net.ssl.HttpsURLConnection) new java.net.URL(url).openConnection();
connection.setHostnameVerifier(... hostname verifier which indirectly causes a bug ...);

//the remaining code fixes the bug by forcing the use of SNI even with the custom hostname verifier
final javax.net.ssl.SSLSocketFactory originalSocketFactory = connection.getSSLSocketFactory();
connection.setSSLSocketFactory(new javax.net.ssl.SSLSocketFactory() {
  public String[] getDefaultCipherSuites() {
    return originalSocketFactory.getDefaultCipherSuites();
  }

  public String[] getSupportedCipherSuites() {
    return originalSocketFactory.getSupportedCipherSuites();
  }

  private java.net.Socket convertSocket(javax.net.ssl.SSLSocket socket, String host) {
    javax.net.ssl.SNIHostName serverName = new javax.net.ssl.SNIHostName(host);
    java.util.List<javax.net.ssl.SNIServerName> serverNames = new java.util.ArrayList<>(1);
    serverNames.add(serverName);
    javax.net.ssl.SSLParameters params = socket.getSSLParameters();
    params.setServerNames(serverNames);
    socket.setSSLParameters(params);
    return socket;
  }

  public java.net.Socket createSocket(java.net.Socket s, String host, int port, boolean autoClose) throws IOException {

    //host = new URL(url).getHost();
    javax.net.ssl.SSLSocket socket = (javax.net.ssl.SSLSocket) originalSocketFactory.createSocket(s,host,port,autoClose);
    return convertSocket(socket, host);
  }

  public java.net.Socket createSocket(java.net.InetAddress host, int port) throws IOException {
    //You may need convertSocket here, I didn't
    return originalSocketFactory.createSocket(host, port);
  }

  public java.net.Socket createSocket(java.net.InetAddress address, int port, java.net.InetAddress localAddress, int localPort) throws IOException {
    //You may need convertSocket here, I didn't
    return originalSocketFactory.createSocket(address, port, localAddress, localPort);
  }

  public java.net.Socket createSocket(String host, int port) throws IOException {
    //You may need convertSocket here, I didn't
    return originalSocketFactory.createSocket(host, port);
  }

  public java.net.Socket createSocket(String host, int port, java.net.InetAddress localHost, int localPort) throws IOException {

    //You may need convertSocket here, I didn't
    return originalSocketFactory.createSocket(host, port, localHost, localPort);
  }
});

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.