I am having an issue with a api that I communicate to via SSL. I am thinking the exception is coming due to the fact that the SSL cert has expired. The problem is that I do
i think you can download the cert and add it to your store. You then configure your jvm with environment properties to indicate where the store is.
It is not safe to alter the default SSLContext since it affects the entire process. This lowers the security setting of every connection indiscriminately. It may also not be thread-safe although I am not sure.
I recommend delegating such operations to a separate process per-request.
String content = new HttpsNoVerify.fetch(URL.create(myURL));
Listing of com/example/HttpsNoVerify.java:
package com.example;
import org.apache.commons.io.IOUtils;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.net.URL;
public class HttpsNoVerify {
public static void main(String... args) throws Exception {
URL url = new URL(args[0]);
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){}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
IOUtils.copy(url.openStream(), System.out);
}
public String fetch(URL url) throws Exception {
return new SubProcess(HttpsNoVerify.class).run(url.toString());
}
}
Listing of com/example/SubProcess.java:
package com.example;
import org.apache.commons.io.IOUtils;
import java.util.Arrays;
public class SubProcess {
private final Class<?> classToRun;
public SubProcess(Class<?> classToRun) {
this.classToRun = classToRun;
}
public String run(String... args) throws Exception {
ProcessBuilder processBuilder = new ProcessBuilder("java",
"-Djava.library.path=" + System.getProperty("java.library.path"),
"-classpath", System.getProperty("java.class.path"),
classToRun.getCanonicalName());
for (String arg : args) processBuilder.command().add(arg);
processBuilder.redirectErrorStream();
Process process = processBuilder.start();
String output = IOUtils.toString(process.getInputStream());
process.waitFor();
if (process.exitValue() != 0)
throw new IllegalStateException(
String.format("Running %s with %s failed", classToRun, Arrays.toString(args)));
return output;
}
}
I'm not aware of a property that would let you ignore the time validity check on the remote certificate for the default X509TrustManager
s, but if you have access to the client code, you can probably configure a different SSLContext
with your own X509TrustManager
, within which you could catch this exception.
If you want to use something like jSSLutils and its SSLContextFactory
, you could write a wrapper along these lines:
PKIXSSLContextFactory sslContextFactory = new PKIXSSLContextFactory();
sslContextFactory.setTrustManagerWrapper(new X509TrustManagerWrapper() {
@Override
public X509TrustManager wrapTrustManager(final X509TrustManager origManager) {
return new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return origManager.getAcceptedIssuers();
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
try {
origManager.checkServerTrusted(chain, authType);
} catch (CertificateExpiredException e) {
// TODO log or do something else to rethrow
// the exception if chain[0] isn't the certificate
// for which you want to make this special case.
}
}
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
origManager.checkClientTrusted(chain, authType);
}
};
}
});
SSLContext sslContext = sslContextFactory.buildSSLContext();
Making use of this SSLContext
then really depends on what uses SSL in your application. In the worst case, you can configure it globally using SSLContext.setDefault(sslContext)
with Java 6 and above. Otherwise, some libraries will let you configure an SSLContext
.