PKIX 路径构建失败~不想将证书添加到 jvm,希望从代码中读取它
PKIX path building failed ~ Dont want to add certificate to the jvm, want it to be read from code
我遇到了上面的错误,看了很多解决方案,实现了代码但还是报错。
Mar 07, 2018 10:17:59 PM <Class> performHttpRequest
SEVERE: IO error while performing HTTP POST to https://<url>/ with data <randomData>
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
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1959)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:328)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:322)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1614)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1052)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:987)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1072)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:141)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
at <our code line>
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access[=10=]0(ParentRunner.java:53)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1596)
... 45 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
... 51 more
我的代码如下:
private String performHttpRequest(Configuration configuration, HttpEntityEnclosingRequestBase httpRequest, String body) {
CloseableHttpClient httpClient = createHttpClient(configuration);
HttpEntity responseEntity = null;
try {
HttpResponse response = httpClient.execute(httpRequest);
responseEntity = response.getEntity();
return EntityUtils.toString(responseEntity);
} catch (Exception e) {
String errorMessage = "IO error while performing HTTP " + httpRequest.getMethod() + " to " + httpRequest.getURI() + " with data " + body;
errorMessage = stringUtil.removeConfidentialData(errorMessage);
log.error(errorMessage, e);
throw new RuntimeException(errorMessage, e);
} finally {
if (responseEntity != null) {
try {
EntityUtils.consume(responseEntity);
} catch (IOException e) {
String errorMessage = "IO Error closing HTTP Client connection";
log.error(errorMessage, e);
throw new RuntimeException(errorMessage, e);
}
}
}
}
private CloseableHttpClient createHttpClient(Configuration configuration) {
return HttpClients.custom().setSSLSocketFactory(getSSLSocketFactory(configuration)).build();
}
public SSLConnectionSocketFactory getSSLSocketFactory(Configuration configuration) {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyManager[] keyStore = getKeyManager("PKCS12",
configuration.getString("keystore.path"),
configuration.getString("keystore.password"));
TrustManager[] trustManager = getTrustManager("jks",
configuration.getString("truststore.path"),
configuration.getString("truststore.password"));
sslContext.init(keyStore, trustManager, new SecureRandom());
return new SSLConnectionSocketFactory(sslContext);
} catch (Exception e) {
throw new RuntimeException("Unable to setup keystore and truststore", e);
}
}
private KeyManager[] getKeyManager(String keyStoreType, String keyStoreFile, String keyStorePassword) throws Exception {
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyStore.load(this.getClass().getClassLoader().getResourceAsStream(keyStoreFile), keyStorePassword.toCharArray());
kmf.init(keyStore, keyStorePassword.toCharArray());
return kmf.getKeyManagers();
}
private TrustManager[] getTrustManager(String trustStoreType, String trustStoreFile, String trustStorePassword) throws Exception {
KeyStore trustStore = KeyStore.getInstance(trustStoreType);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustStore.load(this.getClass().getClassLoader().getResourceAsStream(trustStoreFile), trustStorePassword.toCharArray());
tmf.init(trustStore);
return tmf.getTrustManagers();
}
信任库和密钥库的路径都在类路径中维护。
我们从第 3 方供应商处获得了 .crt,我按照以下说明生成了密钥:https://gist.github.com/mtigas/952344
从生成的 p12 中,我将它们导入到一个 jks 中:https://www.webfarmr.eu/2010/04/import-pkcs12-private-keys-into-jks-keystores-using-java-keytool/
然而,当我 运行 我的测试时,它始终失败,并出现上述错误。我不想手动将我的证书添加到 JVM,是否仍然可以在不向服务器添加证书的情况下进行 HTTPs 调用?
如果我在获取 SSL 上下文时对代码进行以下更改,我的本地单元测试就会通过:
public SSLConnectionSocketFactory getSSLSocketFactory(Configuration configuration) {
try {
SSLContexts.custom().loadKeyMaterial(getKeyManager("PKCS12",
configuration.getString("keystore"),
configuration.getString("keystore.password")),
configuration.getString("keystore.password").toCharArray()).build();
return new SSLConnectionSocketFactory(sslContext);
} catch (Exception e) {
throw new RuntimeException("Unable to setup keystore and truststore", e);
}
}
我不知道当我 运行 它作为集成测试时有什么区别,比如为什么它不加载证书。
问题出在 PKCS12 文件的生成和密钥库的生成中,已更正它们并且它起作用了。
使用的命令是:
keytool -import -trustcacerts -alias root -file <file>.crt -keystore keystore.jks
keytool -importkeystore -srckeystore keystore.jks -destkeystore <new-file>.p12 -srcstoretype JKS -deststoretype PKCS12
这适用于上述两组代码。
我遇到了上面的错误,看了很多解决方案,实现了代码但还是报错。
Mar 07, 2018 10:17:59 PM <Class> performHttpRequest
SEVERE: IO error while performing HTTP POST to https://<url>/ with data <randomData>
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
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1959)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:328)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:322)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1614)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1052)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:987)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1072)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:141)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
at <our code line>
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access[=10=]0(ParentRunner.java:53)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1596)
... 45 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
... 51 more
我的代码如下:
private String performHttpRequest(Configuration configuration, HttpEntityEnclosingRequestBase httpRequest, String body) {
CloseableHttpClient httpClient = createHttpClient(configuration);
HttpEntity responseEntity = null;
try {
HttpResponse response = httpClient.execute(httpRequest);
responseEntity = response.getEntity();
return EntityUtils.toString(responseEntity);
} catch (Exception e) {
String errorMessage = "IO error while performing HTTP " + httpRequest.getMethod() + " to " + httpRequest.getURI() + " with data " + body;
errorMessage = stringUtil.removeConfidentialData(errorMessage);
log.error(errorMessage, e);
throw new RuntimeException(errorMessage, e);
} finally {
if (responseEntity != null) {
try {
EntityUtils.consume(responseEntity);
} catch (IOException e) {
String errorMessage = "IO Error closing HTTP Client connection";
log.error(errorMessage, e);
throw new RuntimeException(errorMessage, e);
}
}
}
}
private CloseableHttpClient createHttpClient(Configuration configuration) {
return HttpClients.custom().setSSLSocketFactory(getSSLSocketFactory(configuration)).build();
}
public SSLConnectionSocketFactory getSSLSocketFactory(Configuration configuration) {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyManager[] keyStore = getKeyManager("PKCS12",
configuration.getString("keystore.path"),
configuration.getString("keystore.password"));
TrustManager[] trustManager = getTrustManager("jks",
configuration.getString("truststore.path"),
configuration.getString("truststore.password"));
sslContext.init(keyStore, trustManager, new SecureRandom());
return new SSLConnectionSocketFactory(sslContext);
} catch (Exception e) {
throw new RuntimeException("Unable to setup keystore and truststore", e);
}
}
private KeyManager[] getKeyManager(String keyStoreType, String keyStoreFile, String keyStorePassword) throws Exception {
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyStore.load(this.getClass().getClassLoader().getResourceAsStream(keyStoreFile), keyStorePassword.toCharArray());
kmf.init(keyStore, keyStorePassword.toCharArray());
return kmf.getKeyManagers();
}
private TrustManager[] getTrustManager(String trustStoreType, String trustStoreFile, String trustStorePassword) throws Exception {
KeyStore trustStore = KeyStore.getInstance(trustStoreType);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustStore.load(this.getClass().getClassLoader().getResourceAsStream(trustStoreFile), trustStorePassword.toCharArray());
tmf.init(trustStore);
return tmf.getTrustManagers();
}
信任库和密钥库的路径都在类路径中维护。
我们从第 3 方供应商处获得了 .crt,我按照以下说明生成了密钥:https://gist.github.com/mtigas/952344
从生成的 p12 中,我将它们导入到一个 jks 中:https://www.webfarmr.eu/2010/04/import-pkcs12-private-keys-into-jks-keystores-using-java-keytool/
然而,当我 运行 我的测试时,它始终失败,并出现上述错误。我不想手动将我的证书添加到 JVM,是否仍然可以在不向服务器添加证书的情况下进行 HTTPs 调用?
如果我在获取 SSL 上下文时对代码进行以下更改,我的本地单元测试就会通过:
public SSLConnectionSocketFactory getSSLSocketFactory(Configuration configuration) {
try {
SSLContexts.custom().loadKeyMaterial(getKeyManager("PKCS12",
configuration.getString("keystore"),
configuration.getString("keystore.password")),
configuration.getString("keystore.password").toCharArray()).build();
return new SSLConnectionSocketFactory(sslContext);
} catch (Exception e) {
throw new RuntimeException("Unable to setup keystore and truststore", e);
}
}
我不知道当我 运行 它作为集成测试时有什么区别,比如为什么它不加载证书。
问题出在 PKCS12 文件的生成和密钥库的生成中,已更正它们并且它起作用了。
使用的命令是:
keytool -import -trustcacerts -alias root -file <file>.crt -keystore keystore.jks
keytool -importkeystore -srckeystore keystore.jks -destkeystore <new-file>.p12 -srcstoretype JKS -deststoretype PKCS12
这适用于上述两组代码。