[Solved] remote calling three-party interface error: javax.net.ssl.SSLHandshakeException

1. Foreword

Recently, when interfacing with Tencent conference API interface, it started calling the other party’s interface after authentication. During this process, an error occurred: javax.net.ssl.sslhandshakeexception.

2. Cause of occurrence

When you make an HTTPS request, the trust certificate of the third-party service does not exist in the JDK, resulting in the error javax.net.ssl.sslhandshakeexception: sun.security.validator.validatorexception: PKIX path construction failed.

3. Solution

1. Obtain the root certificate and install the certificate into your JRE’s Java cacerts (install the certificate into the pathoyourjdk/JRE/lib directory/cacerts).

2. Ignore verification of SSL certificates.

In many cases, there is no certificate, so the second scheme is used to ignore the SSL certificate verification in your code.

4. Code

Here, you should distinguish between the way you use to call three-party services (resttemplate, okhttpclient).

1.RestTemplate

package com.hikvision.meeting.config;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;


/**
 * @author dongliang7
 * @projectName 
 * @ClassName Config2RestTemplate.java
 * @description: Skip Certificate Validation
 * @createTime 2021年11月23日 09:59:00
 */
@Configuration
public class Config2RestTemplate {

    @Bean
    public RestTemplate restTemplate() throws Exception {
        TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;

        SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
                .loadTrustMaterial(null, acceptingTrustStrategy)
                .build();

//        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(createIgnoreVerifySSL(),
                // Specify the TLS version
                null,
                // Specify the algorithm
                null,
                // Cancel domain validation
                new HostnameVerifier() {
                    @Override
                    public boolean verify(String string, SSLSession ssls) {
                        return true;
                    }
                });

        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(csf)
                .build();

        HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory();

        requestFactory.setHttpClient(httpClient);
        requestFactory.setReadTimeout(60 * 1000);// ms
        requestFactory.setConnectTimeout(60 * 1000);// ms
        // The code means whether the request factory class is applied to buffer the request body internal, the default value is true, when the post or put large files will cause memory overflow situation, set to false will flow data directly into the underlying HttpURLConnection
        requestFactory.setBufferRequestBody(false);
        RestTemplate restTemplate = new RestTemplate(requestFactory);
        return restTemplate;
    }

    /**
     * Skip certificate validation sslcontext
     *
     * @return
     * @throws Exception
     */
    private static SSLContext createIgnoreVerifySSL() throws Exception {
        SSLContext sc = SSLContext.getInstance("TLS");

        // Implement an X509TrustManager interface for bypassing authentication without modifying the methods inside
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] paramArrayOfX509Certificate,
                                           String paramString) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] paramArrayOfX509Certificate,
                                           String paramString) throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        sc.init(null, new TrustManager[] { trustManager }, null);
        return sc;
    }
}

2, OkHttpClient

package com.tencent.wemeet.gateway.restapisdk.util;

import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;

import javax.net.ssl.*;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * @author dongliang7
 * @projectName tenxun-meeting-api
 * @ClassName SSLSocketClient.java
 * @description: Create OkHttpClient without SSL (certificate) validation
 * @createTime 2021年11月19日 09:50:00
 */
@Slf4j
public class SSLSocketClient {

    public static OkHttpClient getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate the certificate chain
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {}
                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {}
                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };
            if (trustAllCerts.length != 1 || !(trustAllCerts[0] instanceof X509TrustManager)) {
                throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustAllCerts));
            }
            X509TrustManager x509TrustManager = (X509TrustManager) trustAllCerts[0];

            // Install the full trust trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            // Create the ssl socket factory using our fully trusted manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient.Builder builder = new OkHttpClient.Builder()
                    .connectTimeout(60 , TimeUnit.SECONDS).readTimeout(60 , TimeUnit.SECONDS).writeTimeout(120 , TimeUnit.SECONDS);
            builder.sslSocketFactory(sslSocketFactory , x509TrustManager);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            OkHttpClient okHttpClient = builder.build();
            return okHttpClient;
        } catch (Exception e) {
            log.error("Failed to create OkHttpClient without SSL (certificate) validation: {}", e.getMessage());
            throw new RuntimeException(e);
        }
    }
}

Get okhttpclient:

 // Create OkHttpClient without SSL (certificate) authentication
    private static final OkHttpClient okHttpClient = SSLSocketClient.getUnsafeOkHttpClient();

Similar Posts: