Home > Article > Backend Development > Exception when httpclient sends data to HTTPS to establish SSL connection
The exception information is as follows:
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
Cause: The server's certificate is not trusted. This is generally caused.
Use the KEYTOOL tool to create a certificate, and then start it with TOMCAT. When you open the website in the browser, a prompt that the certificate is not trusted will appear. Of course, when HTTPCLIENT is used to send data to the server HTTPS, HTTPCLIENT will also detect whether the server's certificate is trusted. If it is not trusted, the above exception will be thrown.
There are two solutions. One is to make the certificate trusted by the client. The other is to use HTTPCLIENT to send data without checking whether the server certificate is trusted.
The first method is to make the certificate trusted.
Find a formal CA to issue a certificate, or issue the certificate yourself (it can only be trusted on that client). I won’t talk about finding a formal CA to issue a certificate. For how to issue a certificate yourself, see my other articles.
I found that after I completed the certificate signed by myself, when I opened the server address from the client, the above error was no longer prompted, but I still could not send data. what is the reason? Because the certificate is trusted on the client operating system, but not trusted in JAVA's KEYSTORE, you need to import the server's certificate into the KEYSTORE library
Import method:
Open the command line window and go to da284876f27c53e46b6c19e1a00f381blibsecurity directory, run the following command:
keytool -import -noprompt -keystore cacerts -storepass changeit -alias yourEntry1 -file your.cer
The last one is the certificate exported by the server, and the others can be defaulted.
It should be noted that if there are many JAVA versions installed on the client computer, make sure that the JAVA version of the certificate you import is the one used by your TOMCAT. Generally, TOMCAT uses the JAVA version pointed to by the environment variable.
If it is a TOMCAT server created in ECLIPSE, you will be asked to choose the default JRE or the pointed JAVA when creating a new one. You must choose the path pointing to the JAVA you just imported. Otherwise, the certificate library you imported will have no effect.
The second method is not to check whether the server certificate is trustworthy when using HTTPCLIENT
Extend the HttpClient class to automatically accept the certificate
Because this method automatically receives all certificates, there are certain security issues. So please carefully consider the security requirements of your system before using this method. The specific steps are as follows:
• Provide a custom socket factory (test.MySecureProtocolSocketFactory). This custom class must implement the interface org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory and call the custom X509TrustManager (test.MyX509TrustManager) in the class that implements the interface. These two classes can be obtained in the attachment attached to this article.
•Create an instance of org.apache.commons.httpclient.protocol.Protocol, specify the protocol name and default port number
Protocol myhttps = new Protocol("https", new MySecureProtocolSocketFactory (), 443);
•Register the https protocol object just created
Protocol.registerProtocol("https ", myhttps);
•Then open the https target address in the normal programming way, the code is as follows:
MySecureProtocolSocketFactory.java
import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.SocketFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.commons.httpclient.ConnectTimeoutException; import org.apache.commons.httpclient.params.HttpConnectionParams; import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; public class MySecureProtocolSocketFactory implements SecureProtocolSocketFactory { private SSLContext sslcontext = null; private SSLContext createSSLContext() { SSLContext sslcontext=null; try { sslcontext = SSLContext.getInstance("SSL"); sslcontext.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } return sslcontext; } private SSLContext getSSLContext() { if (this.sslcontext == null) { this.sslcontext = createSSLContext(); } return this.sslcontext; } public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { return getSSLContext().getSocketFactory().createSocket( socket, host, port, autoClose ); } public Socket createSocket(String host, int port) throws IOException, UnknownHostException { return getSSLContext().getSocketFactory().createSocket( host, port ); } public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException, UnknownHostException { return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort); } public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException { 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; } } //自定义私有类 private static class TrustAnyTrustManager implements X509TrustManager { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; } } }