Java:sun.security.provider.certpath.SunCertPathBuilderException:找不到要求的目标的有效证书path
我有一个类将从https服务器下载文件。 当我运行它时,它会返回很多错误。 我的证书似乎有问题。 是否可以忽略客户端服务器身份validation? 如果是这样,怎么样?
package com.da; import java.io.FileOutputStream; import java.io.IOException; import java.nio.CharBuffer; import java.util.concurrent.Future; import org.apache.http.HttpResponse; import org.apache.http.client.utils.URIUtils; import org.apache.http.impl.nio.client.DefaultHttpAsyncClient; import org.apache.http.nio.IOControl; import org.apache.http.nio.client.HttpAsyncClient; import org.apache.http.nio.client.methods.AsyncCharConsumer; import org.apache.http.nio.client.methods.HttpAsyncGet; import org.apache.http.nio.client.methods.HttpAsyncPost; public class RSDDownloadFile { static FileOutputStream fos; public void DownloadFile(String URI, String Request) throws Exception { java.net.URI uri = URIUtils.createURI("https", "176.66.3.69:6443", -1, "download.aspx", "Lang=EN&AuthToken=package", null); System.out.println("URI Query: " + uri.toString()); HttpAsyncClient httpclient = new DefaultHttpAsyncClient(); httpclient.start(); try { Future<Boolean> future = httpclient.execute( new HttpAsyncGet(uri), new ResponseCallback(), null); Boolean result = future.get(); if (result != null && result.booleanValue()) { System.out.println("\nRequest successfully executed"); } else { System.out.println("Request failed"); } } catch(Exception e){ System.out.println("[DownloadFile] Exception: " + e.getMessage()); } finally { System.out.println("Shutting down"); httpclient.shutdown(); } System.out.println("Done"); } static class ResponseCallback extends AsyncCharConsumer<Boolean> { @Override protected void onResponseReceived(final HttpResponse response) { System.out.println("Response: " + response.getStatusLine()); System.out.println("Header: " + response.toString()); try { //if(response.getStatusLine().getStatusCode()==200) fos = new FileOutputStream( "Response.html" ); }catch(Exception e){ System.out.println("[onResponseReceived] Exception: " + e.getMessage()); } } @Override protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl) throws IOException { try { while (buf.hasRemaining()) { //System.out.print(buf.get()); fos.write(buf.get()); } }catch(Exception e) { System.out.println("[onCharReceived] Exception: " + e.getMessage()); } } @Override protected void onCleanup() { try { if(fos!=null) fos.close(); }catch(Exception e){ System.out.println("[onCleanup] Exception: " + e.getMessage()); } System.out.println("onCleanup()"); } @Override protected Boolean buildResult() { return Boolean.TRUE; } } }
错误:
URI Query: https://176.66.3.69:6443/download.aspx?Lang=EN&AuthToken=package Aug 2, 2011 3:47:57 PM org.apache.http.impl.nio.client.NHttpClientProtocolHandler exception SEVERE: I/O error: General SSLEngine problem javax.net.ssl.SSLHandshakeException: General SSLEngine problem at com.sun.net.ssl.internal.ssl.Handshaker.checkThrown(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLEngineImpl.checkTaskThrown(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLEngineImpl.writeAppRecord(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLEngineImpl.wrap(Unknown Source) at javax.net.ssl.SSLEngine.wrap(Unknown Source) at org.apache.http.impl.nio.reactor.SSLIOSession.doHandshake(SSLIOSession.java:154) at org.apache.http.impl.nio.reactor.SSLIOSession.isAppInputReady(SSLIOSession.java:276) at org.apache.http.impl.nio.client.InternalClientEventDispatch.inputReady(InternalClientEventDispatch.java:79) at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:161) at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:335) at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315) at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:275) at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104) at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:542) at java.lang.Thread.run(Unknown Source) Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(Unknown Source) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source) at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source) at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source) at com.sun.net.ssl.internal.ssl.Handshaker$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at com.sun.net.ssl.internal.ssl.Handshaker$DelegatedTask.run(Unknown Source) at org.apache.http.impl.nio.reactor.SSLIOSession.doHandshake(SSLIOSession.java:180) ... 9 more 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(Unknown Source) at sun.security.validator.PKIXValidator.engineValidate(Unknown Source) at sun.security.validator.Validator.validate(Unknown Source) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source) at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(Unknown Source) ... 16 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source) at java.security.cert.CertPathBuilder.build(Unknown Source) ... 21 more onCleanup() [DownloadFile] Exception: javax.net.ssl.SSLHandshakeException: General SSLEngine problem Shutting down Done
当您的服务器拥有自签名证书时出现问题。 要解决此问题,您可以将此证书添加到JVM的可信证书列表中。
在本文中,作者描述了如何从浏览器中获取证书并将其添加到JVM的cacerts文件中。 您可以编辑JAVA_HOME/jre/lib/security/cacerts
文件或使用-Djavax.net.ssl.trustStore
参数运行您的应用程序。 validation您正在使用哪个JDK / JRE,因为这往往是混淆的来源。
另请参阅: 如何解决SSL证书服务器名称/我可以使用keytool添加替代名称? 如果遇到java.security.cert.CertificateException: No name matching localhost found
exception。
这是macOS上可靠的工作。 确保将example.com和443replace为您尝试连接的实际主机名和端口,并给出自定义别名。 第一个命令从远程服务器下载提供的证书,并以x509格式本地保存。 第二个命令将保存的证书加载到Java的SSL信任存储中。
openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2>/dev/null) -out ~/example.crt sudo keytool -importcert -file ~/example.crt -alias example -keystore $(/usr/libexec/java_home)/jre/lib/security/cacerts -storepass changeit
我与来自赛门铁克的有效签名通配符证书有同样的问题。
首先尝试使用-Djavax.net.debug = SSL运行您的java应用程序,以查看真正发生的事情。
我最终导入了导致证书链中断的中间证书 。
我从赛门铁克下载了缺失的中间证书(您可以在ssl握手日志中看到下载链接到缺less的证书: http : //svrintl-g3-aia.verisign.com/SVRIntlG3.cer )。
我将这个证书导入到java密钥库中。 在导入中间证书后,我的通配符ssl证书终于开始工作了:
keytool -import -keystore ../jre/lib/security/cacerts -trustcacerts -alias "VeriSign Class 3 International Server CA - G3" -file /pathto/SVRIntlG3.cer
- 使用Firefox导出SSL证书。 您可以通过在浏览器中打开URL来导出它,然后select导出证书的选项。 假设证书文件名是your.ssl.server.name.crt
- 转到您的
JRE_HOME/bin
或JDK/JRE/bin
- input命令
-
keytool -keystore ..\lib\security\cacerts -import -alias your.ssl.server.name -file .\relative-path-to-cert-file\your.ssl.server.name.crt
- 重新启动Java进程
从没有更多“无法find有效的authenticationpath到要求的目标”
尝试使用JSSE打开与主机的SSL连接时。 这通常意味着服务器正在使用testing证书(可能使用keytool生成),而不是来自众所周知的商业authentication机构(如Verisign或GoDaddy)的证书。 在这种情况下,Web浏览器会显示警告对话框,但是由于JSSE不能假设交互式用户存在,所以它只是默认引发exception。
证书validation是SSL安全的一个非常重要的部分,但我不写这个条目来解释细节。 如果你有兴趣,你可以从阅读维基百科开始。 我正在写这个条目,以显示一个简单的方法来与testing证书的主机谈话,如果你真的想。
基本上,你想用服务器证书把证书添加到KeyStore中
尝试在那里提供的代码。 这可能有帮助。
加贝·马丁·德佩西的答案对我有帮助。 我写了一个与之相关的小脚本。 用法很简单。
从主机安装证书:
> sudo ./java-cert-importer.sh example.com
删除已经安装的证书。
> sudo ./java-cert-importer.sh example.com --delete
java-cert-importer.sh
#!/usr/bin/env bash # Exit on error set -e # Ensure script is running as root if [ "$EUID" -ne 0 ] then echo "WARN: Please run as root (sudo)" exit 1 fi # Check required commands command -v openssl >/dev/null 2>&1 || { echo "Required command 'openssl' not installed. Aborting." >&2; exit 1; } command -v keytool >/dev/null 2>&1 || { echo "Required command 'keytool' not installed. Aborting." >&2; exit 1; } # Get command line args host=$1; port=${2:-443}; deleteCmd=${3:-${2}} # Check host argument if [ ! ${host} ]; then cat << EOF Please enter required parameter(s) usage: ./java-cert-importer.sh <host> [ <port> | default=443 ] [ -d | --delete ] EOF exit 1 fi; if [ "$JAVA_HOME" ]; then javahome=${JAVA_HOME} elif [[ "$OSTYPE" == "linux-gnu" ]]; then # Linux javahome=$(readlink -f $(which java) | sed "s:bin/java::") elif [[ "$OSTYPE" == "darwin"* ]]; then # Mac OS X javahome="$(/usr/libexec/java_home)/jre" fi if [ ! "$javahome" ]; then echo "WARN: Java home cannot be found." exit 1 elif [ ! -d "$javahome" ]; then echo "WARN: Detected Java home does not exists: $javahome" exit 1 fi echo "Detected Java Home: $javahome" # Set cacerts file path cacertspath=${javahome}/lib/security/cacerts cacertsbackup="${cacertspath}.$$.backup" if ( [ "$deleteCmd" == "-d" ] || [ "$deleteCmd" == "--delete" ] ); then sudo keytool -delete -alias ${host} -keystore ${cacertspath} -storepass changeit echo "Certificate is deleted for ${host}" exit 0 fi # Get host info from user #read -p "Enter server host (Eg example.com) : " host #read -p "Enter server port (Default 443) : " port # create temp file tmpfile="/tmp/${host}.$$.crt" # Create java cacerts backup file cp ${cacertspath} ${cacertsbackup} echo "Java CaCerts Backup: ${cacertsbackup}" # Get certificate from speficied host openssl x509 -in <(openssl s_client -connect ${host}:${port} -prexit 2>/dev/null) -out ${tmpfile} # Import certificate into java cacerts file sudo keytool -importcert -file ${tmpfile} -alias ${host} -keystore ${cacertspath} -storepass changeit # Remove temp certificate file rm ${tmpfile} # Check certificate alias name (same with host) that imported successfully result=$(keytool -list -v -keystore ${cacertspath} -storepass changeit | grep "Alias name: ${host}") # Show results to user if [ "$result" ]; then echo "Success: Certificate is imported to java cacerts for ${host}"; else echo "Error: Something went wrong"; fi;
我能够得到它只与代码工作,即不需要使用keytool:
import com.netflix.config.DynamicBooleanProperty; import com.netflix.config.DynamicIntProperty; import com.netflix.config.DynamicPropertyFactory; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.ssl.SSLContexts; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.conn.ssl.X509HostnameVerifier; import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import org.apache.http.impl.nio.client.HttpAsyncClients; import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager; import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor; import org.apache.http.impl.nio.reactor.IOReactorConfig; import org.apache.http.nio.conn.NoopIOSessionStrategy; import org.apache.http.nio.conn.SchemeIOSessionStrategy; import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import java.io.IOException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; public class Test { private static final DynamicIntProperty MAX_TOTAL_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40); private static final DynamicIntProperty ROUTE_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40); private static final DynamicIntProperty CONNECT_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connect.timeout", 60000); private static final DynamicIntProperty SOCKET_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.socket.timeout", -1); private static final DynamicIntProperty CONNECTION_REQUEST_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connectionrequest.timeout", 60000); private static final DynamicBooleanProperty STALE_CONNECTION_CHECK = DynamicPropertyFactory.getInstance().getBooleanProperty("X.checkconnection", true); public static void main(String[] args) throws Exception { SSLContext sslcontext = SSLContexts.custom() .useTLS() .loadTrustMaterial(null, new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }) .build(); SSLIOSessionStrategy sslSessionStrategy = new SSLIOSessionStrategy(sslcontext, new AllowAll()); Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create() .register("http", NoopIOSessionStrategy.INSTANCE) .register("https", sslSessionStrategy) .build(); DefaultConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(IOReactorConfig.DEFAULT); PoolingNHttpClientConnectionManager connectionManager = new PoolingNHttpClientConnectionManager(ioReactor, sessionStrategyRegistry); connectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS.get()); connectionManager.setDefaultMaxPerRoute(ROUTE_CONNECTIONS.get()); RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(SOCKET_TIMEOUT.get()) .setConnectTimeout(CONNECT_TIMEOUT.get()) .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT.get()) .setStaleConnectionCheckEnabled(STALE_CONNECTION_CHECK.get()) .build(); CloseableHttpAsyncClient httpClient = HttpAsyncClients.custom() .setSSLStrategy(sslSessionStrategy) .setConnectionManager(connectionManager) .setDefaultRequestConfig(requestConfig) .build(); httpClient.start(); // use httpClient... } private static class AllowAll implements X509HostnameVerifier { @Override public void verify(String s, SSLSocket sslSocket) throws IOException {} @Override public void verify(String s, X509Certificate x509Certificate) throws SSLException {} @Override public void verify(String s, String[] strings, String[] strings2) throws SSLException {} @Override public boolean verify(String s, SSLSession sslSession) { return true; } } }
在我的Apache 2.4实例(使用Comodo通配符证书)上出现此错误的来源是SHA-1签名的根证书的不完整path。 发行的证书中有多个链,导致SHA-1根证书的链缺less中间证书 。 现代浏览器知道如何处理这个问题,但是Java 7并没有默认处理它(尽pipe在代码中有一些复杂的方法)。 结果是错误消息看起来与自签名证书的情况相同:
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380) ... 22 more
在这种情况下,由于缺less中间证书,正在产生“无法find要求的目标的有效证书path”消息。 您可以使用SSL Labs对服务器进行testing来检查缺less哪个证书。 find适当的证书后,下载它(如果服务器在您的控制之下),将其添加到证书包中。 或者,您可以在本地导入丢失的证书。 在服务器上容纳这个问题是一个更一般的解决scheme。
对于那些喜欢Debian和预打包Java的人来说:
sudo mkdir /usr/share/ca-certificates/test/ # don't mess with other certs sudo cp ~/tmp/test.loc.crt /usr/share/ca-certificates/test/ sudo dpkg-reconfigure --force ca-certificates # check your cert in curses GUI! sudo update-ca-certificates --fresh --verbose
不要忘记检查/etc/default/cacerts
:
# enable/disable updates of the keystore /etc/ssl/certs/java/cacerts cacerts_updates=yes
删除证书:
sudo rm /usr/share/ca-certificates/test/test.loc.crt sudo rm /etc/ssl/certs/java/cacerts sudo update-ca-certificates --fresh --verbose
这也可能是由于使用了使用SHA2签名的Java 7的GoDaddy证书。
Chrome和所有其他浏览器都开始弃用使用SHA1签名的SSL证书,因为它不够安全。
有关这个问题的更多信息可以在这里find ,以及如何在您的服务器上解决它,如果你需要现在。
更新:重启帮助是巧合(我希望如此,万岁!)。 问题的真正原因是这样的:当Gradle指向使用特定的密钥库时,该密钥库还必须包含所有官方的根证书。 否则,它将无法访问常规存储库中的库。 我所要做的是这样的:
导入自签名证书:
keytool -import -trustcacerts -alias myselfsignedcert -file /Users/me/Desktop/selfsignedcert.crt -keystore ./privateKeystore.jks
添加官方的根证书:
keytool -importkeystore -srckeystore <java-home>/lib/security/cacerts -destkeystore ./privateKeystore.jks
也许Gradle守护进程也挡道了。 如果事情开始看起来惨淡,可能值得用./gradlew --status
来杀死所有正在运行的守护进程。
原帖:
我知道,没有人会相信这一点。 不过,如果一切都失败了,试试看:在我的Mac 重新启动后,问题消失了。 哎呀。
背景:./gradlew jar一直给我“无法find有效的authenticationpath到要求的目标”
我坚持使用从privateKeystore.jks导入的从浏览器保存的自签名证书。 然后指示Gradle使用privateKeystore.jks:
org.gradle.jvmargs=-Djavax.net.debug=SSL -Djavax.net.ssl.trustStore="/Users/me/IntelliJ/myproject/privateKeystore.jks" -Djavax.net.ssl.trustStorePassword=changeit
如上所述,这只在重新启动后才起作用。
我有与证书错误相同的问题,是因为SNI,我使用的HTTP客户端没有实施SNI。 所以版本更新完成了这项工作
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.3.6</version> </dependency>
您有两个select,将自签名的证书导入到java的keystore中,以便运行该软件的每个jvm或者尝试不validation的ssl工厂:
jdbc:postgresql://myserver.com:5432/mydatabasename?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory
仅适用于Windows
按照下面的步骤
1)在Chrome中进入设置。
2)在设置点击显示高级设置。
3)在HTTPS / SSL下点击pipe理证书。
4)导出您的证书。
5)在Windowssearch(按键盘上的Windows键)键入Java。
6)select(configurationJava)选项这将打开Java控制面板
7)在Java控制面板中select安全选项卡
8)selectpipe理证书
9)点击导入
10)在(用户)选项卡下select,证书types为(可信证书)
11)点击导入button,浏览下载的证书并导入。
完成享受。
如果您在目标服务器上使用Let's Encrypt证书并且使用JRE / JDK <8u101,请按照此答案解决此问题。
检查$PATH
的javapath是否可用。
如果不行,使用PATH=$PATH:\xxx\xxx\jre\bin
更新PATH