You can still verify the certificate by running your own trust manager. I ran into a similar problem here . I also tried adding a certificate to cacerts
, but to no avail.
In your trusted manager, you need to explicitly upload the certificates. Essentially, I needed something like this:
First I create a trust manager that uses the actual certificate files:
public class ValicertX509TrustManager implements X509TrustManager { X509TrustManager pkixTrustManager; ValicertX509TrustManager() throws Exception { String valicertFile = "/certificates/ValicertRSAPublicRootCAv1.cer"; String commwebDRFile = "/certificates/DR_10570.migs.mastercard.com.au.crt"; String commwebPRODFile = "/certificates/PROD_10549.migs.mastercard.com.au.new.crt"; Certificate valicert = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(valicertFile)); Certificate commwebDR = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(commwebDRFile)); Certificate commwebPROD = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(commwebPRODFile)); KeyStore keyStore = KeyStore.getInstance("JKS"); keyStore.load(null, "".toCharArray()); keyStore.setCertificateEntry("valicert", valicert); keyStore.setCertificateEntry("commwebDR", commwebDR); keyStore.setCertificateEntry("commwebPROD", commwebPROD); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX"); trustManagerFactory.init(keyStore); TrustManager trustManagers[] = trustManagerFactory.getTrustManagers(); for(TrustManager trustManager : trustManagers) { if(trustManager instanceof X509TrustManager) { pkixTrustManager = (X509TrustManager) trustManager; return; } } throw new Exception("Couldn't initialize"); } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { pkixTrustManager.checkServerTrusted(chain, authType); } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { pkixTrustManager.checkServerTrusted(chain, authType); } public X509Certificate[] getAcceptedIssuers() { return pkixTrustManager.getAcceptedIssuers(); } }
Now, using this trust manager, I had to create a factory socket:
public class ValicertSSLProtocolSocketFactory implements ProtocolSocketFactory { private SSLContext sslContext = null; public ValicertSSLProtocolSocketFactory() { super(); } private static SSLContext createValicertSSLContext() { try { ValicertX509TrustManager valicertX509TrustManager = new ValicertX509TrustManager(); SSLContext context = SSLContext.getInstance("TLS"); context.init(null, new ValicertX509TrustManager[] { valicertX509TrustManager}, null); return context; } catch(Exception e) { Log.error(Log.Context.Net, e); return null; } } private SSLContext getSSLContext() { if(this.sslContext == null) { this.sslContext = createValicertSSLContext(); } return this.sslContext; } public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException { return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort); } public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort, final HttpConnectionParams params) throws IOException { if(params == null) { throw new IllegalArgumentException("Parameters may not be null"); } int timeout = params.getConnectionTimeout(); SocketFactory socketFactory = getSSLContext().getSocketFactory(); if(timeout == 0) { return socketFactory.createSocket(host, port, localAddress, localPort); } else { Socket socket = socketFactory.createSocket(); SocketAddress localAddr = new InetSocketAddress(localAddress, localPort); SocketAddress remoteAddr = new InetSocketAddress(host, port); socket.bind(localAddr); socket.connect(remoteAddr, timeout); return socket; } } public Socket createSocket(String host, int port) throws IOException { return getSSLContext().getSocketFactory().createSocket(host, port); } public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); } public boolean equals(Object obj) { return ((obj != null) && obj.getClass().equals(ValicertSSLProtocolSocketFactory.class)); } public int hashCode() { return ValicertSSLProtocolSocketFactory.class.hashCode(); } }
Then I just registered a new protocol:
Protocol.registerProtocol("vhttps", new Protocol("vhttps", new ValicertSSLProtocolSocketFactory(), 443)); PostMethod postMethod = new PostMethod(url); for (Map.Entry<String, String> entry : params.entrySet()) { postMethod.addParameter(entry.getKey(), StringUtils.Nz(entry.getValue())); } HttpClient client = new HttpClient(); int status = client.executeMethod(postMethod); if (status == 200) { StringBuilder resultBuffer = new StringBuilder(); resultBuffer.append(postMethod.getResponseBodyAsString()); return new HttpResponse(resultBuffer.toString(), ""); } else { throw new IOException("Invalid response code: " + status); }
The only drawback is that I had to create a specific protocol ( vhttps
) for this particular certificate.