You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PKCS12证书调用API时遭遇PKIX路径构建失败问题求助

解决PKIX路径构建失败的SSL握手异常

问题描述

执行以下Java代码后,遇到SSL握手异常:

javax.net.ssl.SSLHandshakeException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

使用的代码:

import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.classic.methods.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.core5.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.ssl.SSLContexts;
import org.apache.hc.core5.http.io.entity.StringEntity;

import javax.net.ssl.SSLContext;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyStore;

public class CurlToJava {
    private static final String P12_FILE_PATH = "path/to/your/pfa-data-service.p12";
    private static final String P12_PASSWORD = "PassPhrase";
    private static final String TARGET_URL
            = "http://B17121-"+
            "vip.nam.nsroot:100/monitoringDaily/api/download" +
            "/cs/cars/system%20Views/Obliger%20fund%20Details" +
            "(as69734_202405080737)?soeId=system&delimiter=%7C"
            + "&addHeadandTail=true&filename=testDownload";
    private static final String AUTH_TOKEN = "0cb93babee5f6370007632b93365109a8";

    private static SSLContext createSSLContext() throws Exception {
        // Load the PKCS12 KeyStore
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        try (FileInputStream keyStoreInputStream = new FileInputStream(P12_FILE_PATH)) {
            keyStore.load(keyStoreInputStream, P12_PASSWORD.toCharArray());
        }

        return SSLContexts.custom()
                .loadKeyMaterial(keyStore, P12_PASSWORD.toCharArray())
                .build();
    }

    public static void main(String[] args) {
        try {
            SSLContext sslContext = createSSLContext();
            SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext);

            CloseableHttpClient httpClient = HttpClients.custom()
                    .setConnectionManager(
                            PoolingHttpClientConnectionManagerBuilder.create()
                                    .setSSLSocketFactory(sslSocketFactory)
                                    .build()
                    )
                    .build();

            HttpPost httpPost = new HttpPost(TARGET_URL);

            // Set your headers
            httpPost.setHeader("accept", "*/*");
            httpPost.setHeader("AUTH_TOKEN", AUTH_TOKEN);
            httpPost.setHeader("Content-type", "application/json");

            // Execute HTTP POST request
            try (CloseableHttpResponse response = httpClient.execute(httpPost);
                 InputStream responseStream = response.getEntity().getContent();
                 OutputStream outputStream = new FileOutputStream("testDownload.csv")) {

                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = responseStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }

                System.out.println("Response Code: " + response.getCode());
                System.out.println("Response downloaded to testDownload.csv");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

问题原因

当前代码仅加载了客户端证书(PKCS12)用于身份验证,但未配置信任服务器端的SSL证书。JVM默认会从系统信任库(如cacerts)中查找可信证书,如果服务器证书不在默认信任库,就会抛出PKIX路径构建失败的异常。

解决方案

方案1:将服务器证书导入JVM默认信任库

  1. 获取服务器的SSL证书:
    • 使用openssl命令导出证书:
      openssl s_client -connect B17121-vip.nam.nsroot:100 < /dev/null | openssl x509 -outform PEM > server-cert.pem
      
    • 或通过浏览器访问目标HTTPS地址,导出证书为PEM格式。
  2. 将证书导入JVM的cacerts信任库:
    keytool -import -alias server-cert -file server-cert.pem -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit
    
    (默认cacerts密码是changeit,若已修改请使用对应密码)

方案2:在代码中加载自定义信任库

如果不想修改系统信任库,可以在代码中加载包含服务器证书的信任库(支持PKCS12或JKS格式),修改createSSLContext方法:

private static SSLContext createSSLContext() throws Exception {
    // 加载客户端证书密钥库
    KeyStore keyStore = KeyStore.getInstance("PKCS12");
    try (FileInputStream keyStoreInputStream = new FileInputStream(P12_FILE_PATH)) {
        keyStore.load(keyStoreInputStream, P12_PASSWORD.toCharArray());
    }

    // 加载信任库(包含服务器证书)
    KeyStore trustStore = KeyStore.getInstance("JKS");
    String trustStorePath = "path/to/your/truststore.jks";
    String trustStorePassword = "truststorePass";
    try (FileInputStream trustStoreInputStream = new FileInputStream(trustStorePath)) {
        trustStore.load(trustStoreInputStream, trustStorePassword.toCharArray());
    }

    return SSLContexts.custom()
            .loadKeyMaterial(keyStore, P12_PASSWORD.toCharArray())
            .loadTrustMaterial(trustStore, null) // 加载信任库
            .build();
}

方案3:临时跳过证书验证(仅测试环境使用)

注意:生产环境绝对禁止使用此方法,会带来严重安全风险

修改createSSLContext方法,创建信任所有证书的SSLContext:

private static SSLContext createSSLContext() throws Exception {
    // 加载客户端证书密钥库
    KeyStore keyStore = KeyStore.getInstance("PKCS12");
    try (FileInputStream keyStoreInputStream = new FileInputStream(P12_FILE_PATH)) {
        keyStore.load(keyStoreInputStream, P12_PASSWORD.toCharArray());
    }

    // 信任所有证书
    return SSLContexts.custom()
            .loadKeyMaterial(keyStore, P12_PASSWORD.toCharArray())
            .loadTrustMaterial((chain, authType) -> true) // 信任所有证书
            .build();
}

同时,创建不验证主机名的SSLConnectionSocketFactory:

SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
        sslContext,
        (hostname, session) -> true // 跳过主机名验证
);

额外检查点

  • 确认目标URL是否应为https而非http:当前代码中URL是http,若服务器实际使用HTTPS,需改为https://B17121-vip.nam.nsroot:100/...,否则SSL配置不会生效。
  • 确认PKCS12文件路径正确、密码无误、文件未损坏。

内容的提问来源于stack exchange,提问作者ravish kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 00:27:33