java - ignore expired ssl certificate
Asked Answered
O

3

8
URL myUrl = new URL("https://www.....");

SSL Certificate of website is expired. How to avoid it and make URL() work ?

Oruro answered 1/1, 2012 at 15:59 Comment(2)
does the url throwing CertificateExpiredException ? @OruroHit
See also How to ignore expired certificates from outside a Java application?Shipyard
P
28

You should build a TrustManager that wraps the default trust manager, catches the CertificiateExpiredException and ignores it.

Note: as detailed in this answer, whether or not this is secure is very much implementation dependent. In particular, it relies on the date validation being done last, after everything else has been checked properly.

Something along these lines should work:

TrustManagerFactory tmf = TrustManagerFactory.getInstance(
    TrustManagerFactory.getDefaultAlgorithm());
// Initialise the TMF as you normally would, for example:
tmf.init((KeyStore)null); 

TrustManager[] trustManagers = tmf.getTrustManagers();
final X509TrustManager origTrustmanager = (X509TrustManager)trustManagers[0];

TrustManager[] wrappedTrustManagers = new TrustManager[]{
   new X509TrustManager() {
       public java.security.cert.X509Certificate[] getAcceptedIssuers() {
          return origTrustmanager.getAcceptedIssuers();
       }

       public void checkClientTrusted(X509Certificate[] certs, String authType) {
           origTrustmanager.checkClientTrusted(certs, authType);
       }

       public void checkServerTrusted(X509Certificate[] certs, String authType) {
           try {
               origTrustmanager.checkServerTrusted(certs, authType);
           } catch (CertificateExpiredException e) {}
       }
   }
};

SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, wrappedTrustManagers, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

The trust managers throw CertificateExceptions (see subclasses for details) when something is wrong with a certificate. Be specific in what you want to catch/ignore. Everything you really want validated has to be checked before what you catch is potentially thrown, or you'll have to validate it manually too. Anything more relaxed than this (in particular, not doing anything and therefore not throwing any exception) will ignore the certificate verification and validation altogether, which is about the same as using anonymous cipher suites or ignoring authentication. This would defeat the security purpose of using SSL/TLS (as opposed to being only a bit more flexible on the expiry date).

Presence answered 1/1, 2012 at 17:20 Comment(7)
This code doesn't work at all. You will get an exception of "TrustManagerFactory is not initialized" when the tmf.getTrustManagers() is executed. Please test your code before posting in the future. I spent well over an hour trying to figure out how to solve that problem.Ariew
@AndroidDev, sorry, I was assuming the OP would know that the TMF should be initialised as normally, but you're probably right, it's not obvious. (Just edited.)Presence
always javax.net.ssl.SSLHandshakeException: Connection closed by peerSamellasameness
Beware that in case of ssl client authentication the server itself may check the expiry of the client certificate. There is no cure in this case: #2762580Shipyard
@Presence I am using Retrofit for my network call, from where I have to call this TrustManger in my Android Application?Novia
@Presence thank you for your idea, but I get java.lang.NullPointerException: null cannot be cast to non-null type java.security.KeyStore when call tmf.init((KeyStore)null); in Android. So In Android I use init(KeyStore.getInstance(KeyStore.getDefaultType()))Folderol
@Folderol I haven't looked into this for a while (that answer is more than 11 years old), but suspect this may have a different behaviour. In the Oracle or OpenJDK (at least up to Java 8), initialising with a null KeyStore made it fall back to the default trust store. Here, you're initialising it with an empty trust store: this means it shouldn't in principle trust anything at all.Presence
N
3

You have to create a custom X509 validator that will ignore expired certificates. In fact, no check will be performed.

Code taken from here: http://exampledepot.com/egs/javax.net.ssl/TrustAll.html

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        public void checkClientTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
        }
        public void checkServerTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
        }
    }
};

// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
}

// Now you can access an https URL without having the certificate in the truststore
// It should work with expired certificate as well
try {
    URL myUrl = new URL("https://www.....");
} catch (MalformedURLException e) {
}
Numinous answered 1/1, 2012 at 16:5 Comment(4)
Please avoid to copy/paste/propagate code that disables security checks entirely, as this TrustManager does: this defeats the point of using SSL/TLS in the first place.Presence
When the battery is removed in some mobile devices, the date resets to an old date like 1980 which will cause your SSL certificate to fail due to the expiry date. This can lead to your app failing and if it is vital that your app continues working even with an expired certificate, it is important to ignore the expiry date.Ariew
@AndroidDev If your criticism is meant to address Bruno's comment then please be advised that there's a huge difference between accepting any certificate and outdated trusted certificates. Besides, a serious user adjusts the date for many reasons.Weider
always javax.net.ssl.SSLHandshakeException: Connection closed by peerSamellasameness
T
2

I wrote a custom TrustManager to solve this problem, you can see it at https://gist.github.com/divergentdave/9a68d820e3610513bd4fcdc4ae5f91a1. This TrustManager wraps the offending X509Certificate in another class to disable the expiration check while leaving all other validation in place. (i.e. matches the hostname, chains to a trusted CA, signature valid, etc.)

Tallowy answered 22/7, 2016 at 4:58 Comment(2)
Nice example, I tried it out, just to see that none of the checkValidity methods were called. The only callbacks that were triggered was getEncoded and getPublicKey. Not sure if is has something to do with the fact that I am using a local keystore, loaded with pinned certificates?Potts
@Potts I tried this out locally and I saw several methods being called. I did see checkValidity being called, but I had to set method breakpoints instead of line number breakpoints, since those methods have empty bodies. I'm not sure if pinned certificates would make a difference, but if you're using a self-signed certificate as the server's certificate (not a leaf certificate) that may change the behavior. If the TLS server's public is the same as the public key of a self-signed certificate in your trust store, then the rest of the checks are moot. (haven't tested what happens)Tallowy

© 2022 - 2024 — McMap. All rights reserved.