首页 > 解决方案 > 原因:javax.net.ssl.SSLHandshakeException:PKIX 路径构建失败,无法找到请求目标的有效证书路径

问题描述

我正在尝试调用托管在需要代理调用的其他域中的 https 服务,我设法.pem从浏览器下载格式证书并使用 keytool 将其添加到我的 JVM 但现在我试图keystore在创建对象时将其添加到我的restTemplate对象中但是当我尝试这个时,我仍然得到:

Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed unable to find valid certification path to requested target 

这是我尝试过的:

@Configuration
@Slf4j
public class RestTemplateFactory {
    
    @Value("${certificate.name}")
    private String name;

    @Value("${PROXY_SERVER_HOST}")
    private String proxyServerHost;

    @Value("${PROXY_SERVER_PORT}")
    private Integer proxyServerPort;

    @Value("${NEED_PROXY}")
    private boolean isNeedProxy;

    @Value("${DOS_BASIC_AUTH_USERNAME}")
    private String basicAuthDosUsername;

    @Value("${DOS_BASIC_AUTH_PASSWORD}")
    private String basicAuthDosPassword;


    @Bean
    public RestTemplate restTemplate() throws Exception {
        return new RestTemplate(httpClientRequestFactory());
    }

    @Bean(name = "sslContext")
    public SSLContext sslContext() throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        return SSLContexts.custom()
                .loadTrustMaterial(null, new TrustSelfSignedStrategy())
                .useProtocol("TLS")
                .build();

    }

    @Bean(name = "sslSocketFactory")
    public SSLSocketFactory sslSocketFactory() throws Exception {
        log.debug("Configure CERTIFICATE NAME:----> " + name);
        return new ConnectionFactoryCreator(name, sslContext()).getSocketFactory();
    }

    @Bean(name = "httpClient")
    public CloseableHttpClient httpClient() throws Exception {
        HttpHost proxy = new HttpHost(proxyServerHost, proxyServerPort);
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials(basicAuthDosUsername, basicAuthDosPassword));
        return HttpClientBuilder.create().setSslcontext(sslContext())
                .setSSLSocketFactory(new SSLConnectionSocketFactory(sslSocketFactory(), new AllowAllHostnameVerifier()))
                .setProxy(isNeedProxy ? proxy : null)
                .setDefaultCredentialsProvider(credentialsProvider)
                .build();
    }


    @Bean
    public ClientHttpRequestFactory httpClientRequestFactory() throws Exception {
        return new HttpComponentsClientHttpRequestFactory(httpClient());
    }

}

@Slf4j
public class ConnectionFactoryCreator {

    private String pemName;
    private SSLContext context;

    public ConnectionFactoryCreator(String pemName, SSLContext context) {
        this.pemName = pemName;
        this.context = context;
    }

    public SSLSocketFactory getSocketFactory() throws Exception {
        log.debug("PEM CERTIFICATE NAME:----> " + pemName);
        InputStream resourceAsStream = getClass().getResourceAsStream("/keystore/" + pemName);
        byte[] certAndKey = IOUtils.toByteArray(resourceAsStream);
        byte[] certBytes = parseDERFromPEM(certAndKey, "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");

        X509Certificate cert = generateCertificateFromDER(certBytes);
        KeyStore keystore = KeyStore.getInstance("JKS");
        keystore.load(null);
        keystore.setCertificateEntry("cert-alias", cert);
        //keystore.setKeyEntry("key-alias", key, "changeit".toCharArray(), new Certificate[] { cert });
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(keystore, "changeit".toCharArray());
        KeyManager[] km = kmf.getKeyManagers();
        context.init(km, null, null);
        return context.getSocketFactory();
    }

    private byte[] parseDERFromPEM(byte[] pem, String beginDelimiter, String endDelimiter) {
        String data = new String(pem);
        String[] tokens = data.split(beginDelimiter);
        tokens = tokens[1].split(endDelimiter);
        return DatatypeConverter.parseBase64Binary(tokens[0]);
    }

    private X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException, CertificateException {
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes));
    }
}

YAML 文件:

certificate :
  name : certificate.pem

并添加了pem文件/resources/keystore/certificate.pem

标签: javaspringsslkeystore

解决方案


推荐阅读