[英]Java: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I have a class that will download a file from a https server.我有一个 class 将从https服务器下载文件。 When I run it, it returns a lot of errors.当我运行它时,它会返回很多错误。 It seems that I have a problem with my certificate.看来我的证书有问题。 Is it possible to ignore the client-server authentication?是否可以忽略客户端-服务器身份验证? If so, how?如果是这样,怎么做?
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;
}
}
}
Errors:错误:
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
The problem appears when your server has self signed certificate.当您的服务器具有自签名证书时会出现问题。 To workaround it you can add this certificate to the list of trusted certificates of your JVM.要解决此问题,您可以将此证书添加到 JVM 的受信任证书列表中。
In this article author describes how to fetch the certificate from your browser and add it to cacerts file of your JVM. 在本文中,作者描述了如何从浏览器中获取证书并将其添加到 JVM 的 cacerts 文件中。 You can either edit JAVA_HOME/jre/lib/security/cacerts
file or run you application with -Djavax.net.ssl.trustStore
parameter.您可以编辑JAVA_HOME/jre/lib/security/cacerts
文件或使用-Djavax.net.ssl.trustStore
参数运行您的应用程序。 Verify which JDK/JRE you are using too as this is often a source of confusion.验证您也在使用哪个 JDK/JRE,因为这通常会造成混淆。
See also: How are SSL certificate server names resolved/Can I add alternative names using keytool?另请参阅: 如何解析 SSL 证书服务器名称/我可以使用 keytool 添加替代名称吗? If you run into java.security.cert.CertificateException: No name matching localhost found
exception.如果遇到java.security.cert.CertificateException: No name matching localhost found
异常。
Here's what reliably works for me on macOS.这是在 macOS 上可靠地为我工作的方法。 Make sure to replace example.com and 443 with the actual hostname and port you're trying to connect to, and give a custom alias.确保将 example.com 和 443 替换为您尝试连接的实际主机名和端口,并提供自定义别名。 The first command downloads the provided certificate from the remote server and saves it locally in x509 format.第一个命令从远程服务器下载提供的证书并以 x509 格式保存在本地。 The second command loads the saved certificate into Java's SSL trust store.第二个命令将保存的证书加载到 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
I had the same issue with a valid signed wildcard certificate from symantec.我对来自 symantec 的有效签名通配符证书有同样的问题。
First try running your java application with -Djavax.net.debug=SSL to see what is really going on.首先尝试使用-Djavax.net.debug=SSL运行您的 java 应用程序,看看到底发生了什么。
I ended up importing the intermediate certificate which was causing the cert chain to break.我最终导入了导致证书链中断的中间证书。
I downloaded the missing intermediate cert from symantec (you can see the download link to the missing cert in the ssl handshake log: http://svrintl-g3-aia.verisign.com/SVRIntlG3.cer in my case).我从 symantec 下载了缺少的中间证书(您可以在 ssl 握手日志中看到缺少证书的下载链接:在我的情况下为http://svrintl-g3-aia.verisign.com/SVRIntlG3.cer )。
And I imported the cert in the java keystore.我在 java 密钥库中导入了证书。 After importing the intermediate certificate my wildcard ssl cert finally started working:导入中间证书后,我的通配符 ssl 证书终于开始工作了:
keytool -import -keystore ../jre/lib/security/cacerts -trustcacerts -alias "VeriSign Class 3 International Server CA - G3" -file /pathto/SVRIntlG3.cer
JRE_HOME/bin
or JDK/JRE/bin
转到您的JRE_HOME/bin
或JDK/JRE/bin
keytool -keystore ..\lib\security\cacerts -import -alias your.ssl.server.name -file .\relative-path-to-cert-file\your.ssl.server.name.crt
@Gabe Martin-Dempesy's answer is helped to me. @Gabe Martin-Dempesy 的回答对我有帮助。 And I wrote a small script related to it.我写了一个与之相关的小脚本。 The usage is very simple.用法很简单。
Install a certificate from host:从主机安装证书:
> sudo ./java-cert-importer.sh example.com
Remove the certificate that installed already.删除已安装的证书。
> sudo ./java-cert-importer.sh example.com --delete
java-cert-importer.sh 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 (E.g. 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;
Quoting from No more 'unable to find valid certification path to requested target'引用不再“无法找到到所请求目标的有效认证路径”
when trying to open an SSL connection to a host using JSSE.尝试使用 JSSE 打开与主机的 SSL 连接时。 What this usually means is that the server is using a test certificate (possibly generated using keytool) rather than a certificate from a well known commercial Certification Authority such as Verisign or GoDaddy.这通常意味着服务器正在使用测试证书(可能使用 keytool 生成),而不是来自知名商业证书颁发机构(如 Verisign 或 GoDaddy)的证书。 Web browsers display warning dialogs in this case, but since JSSE cannot assume an interactive user is present it just throws an exception by default.在这种情况下,Web 浏览器会显示警告对话框,但由于 JSSE 无法假定存在交互式用户,因此默认情况下它只会抛出异常。
Certificate validation is a very important part of SSL security, but I am not writing this entry to explain the details.证书验证是 SSL 安全性的一个非常重要的部分,但我写这篇文章并不是为了解释细节。 If you are interested, you can start by reading the Wikipedia blurb.如果您有兴趣,可以从阅读 Wikipedia 简介开始。 I am writing this entry to show a simple way to talk to that host with the test certificate, if you really want to.我写这篇文章是为了展示一个简单的方法来用测试证书与那个主机交谈,如果你真的想的话。
Basically, you want to add the server's certificate to the KeyStore with your trusted certificates基本上,您希望使用受信任的证书将服务器的证书添加到 KeyStore
Try the code provided there.试试那里提供的代码。 It might help.它可能会有所帮助。
This solved my issue,这解决了我的问题,
We need to import the cert onto the local java.我们需要将证书导入本地 java。 If not we could get the below exception.如果没有,我们可以获得以下异常。
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:1949) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
SSLPOKE is a tool where you can test the https connectivity from your local machine. SSLPOKE是一个工具,您可以在其中测试本地机器的 https 连接。
Command to test the connectivity:测试连通性的命令:
"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
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:387) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292) 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:1496) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026) at sun.security.ssl.Handshaker.process_record(Handshaker.java:961) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375) at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:747) at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123) at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:138) at SSLPoke.main(SSLPoke.java:31) 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:382) ... 15 more
keytool -import -alias <anyname> -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -file <cert path>
this would first prompt to "Enter keystore password:" changeit
is the default password.这将首先提示“输入密钥库密码:” changeit
是默认密码。 and finally a prompt "Trust this certificate? [no]:", provide "yes" to add the cert to keystore.最后提示“信任此证书?[否]:”,提供“是”以将证书添加到密钥库。
Verfication:验证:
C:\tools>"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
Successfully connected
I was able to get it working with code only, ie no need to use keytool:我能够让它只使用代码,即不需要使用 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;
}
}
}
For Windows only, follow these steps:仅适用于 Windows,请执行以下步骤:
The source of this error on my Apache 2.4 instance (using a Comodo wildcard certificate) was an incomplete path to the SHA-1 signed root certificate.我的 Apache 2.4 实例(使用 Comodo 通配符证书)上出现此错误的原因是 SHA-1 签名根证书的路径不完整。 There were multiple chains in the issued certificate, and the chain leading to a SHA-1 root certificate was missing an intermediate certificate .颁发的证书中有多个链,指向 SHA-1 根证书的链缺少中间证书。 Modern browsers know how to handle this, but Java 7 doesn't handle it by default (although there are some convoluted ways to accomplish this in code).现代浏览器知道如何处理这个问题,但 Java 7 默认不处理它(尽管在代码中有一些复杂的方法来完成这个)。 The result is error messages that look identical to the case of self-signed certificates:结果是看起来与自签名证书相同的错误消息:
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
In this case, the "unable to find valid certification path to requested target" message is being produced due to the missing intermediate certificate.在这种情况下,由于缺少中间证书,正在生成“无法找到到所请求目标的有效证书路径”消息。 You can check which certificate is missing using SSL Labs test against the server.您可以使用SSL Labs对服务器的测试来检查缺少哪个证书。 Once you find the appropriate certificate, download it and (if the server is under your control) add it to the certificate bundle.找到适当的证书后,下载它并(如果服务器在您的控制之下)将其添加到证书包中。 Alternatively, you can import the missing certificate locally.或者,您可以在本地导入缺少的证书。 Accommodating this issue on the server is a more general solution to the problem.在服务器上解决此问题是该问题的更通用解决方案。
There is a lot of way to solve this...有很多方法可以解决这个问题...
One way is set the TrustStore certificates in a keystore file and put it in the path of the application, and set these system properties in the main method:一种方法是在 keystore 文件中设置 TrustStore 证书并将其放在应用程序的路径中,并在 main 方法中设置这些系统属性:
public static void main(String[] args) {
System.setProperty("javax.net.ssl.trustStore", "trust-store.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "TrustStore");
...
}
Other way is place the keystore as resource file inside the project jar file and load it:另一种方法是将密钥库作为资源文件放在项目 jar 文件中并加载它:
public static SSLContext createSSLContext(String resourcePath, String pass) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException, KeyManagementException {
// initialise the keystore
final char[] password = pass.toCharArray();
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(ThisClass.class.getResourceAsStream(resourcePath
), password);
// Setup the key manager factory.
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, password);
// Setup the trust manager factory.
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
SSLContext sslc = SSLContext.getInstance("TLS");
sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return sslc;
}
public static void main(String[] args) {
SSLContext.setDefault(
createSSLContext("/trust-store.jks", "TrustStore"));
...
}
In windows you can try this solution too: https://stackoverflow.com/a/59056537/980442在 Windows 中,您也可以尝试此解决方案: https ://stackoverflow.com/a/59056537/980442
I created the keystore file from a Certificate authority CA .crt
file in this way:我以这种方式从证书颁发机构 CA .crt
文件创建了密钥库文件:
keytool -import -alias ca -keystore trust-store.jks -storepass TrustStore -trustcacerts -file ca.crt
FYI: https://docs.oracle.com/javadb/10.8.3.0/adminguide/cadminsslclient.html仅供参考: https ://docs.oracle.com/javadb/10.8.3.0/adminguide/cadminsslclient.html
For those who like Debian and prepackaged Java:对于那些喜欢 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
Don't forget to check /etc/default/cacerts
for:不要忘记检查/etc/default/cacerts
是否有:
# enable/disable updates of the keystore /etc/ssl/certs/java/cacerts
cacerts_updates=yes
To remove cert:要删除证书:
sudo rm /usr/share/ca-certificates/test/test.loc.crt
sudo rm /etc/ssl/certs/java/cacerts
sudo update-ca-certificates --fresh --verbose
Simple Steps that I followed.我遵循的简单步骤。
problem: I was trying to connect to an endpoint(https://%s.blob.core.windows.net) using a simple java class(main method).问题:我试图使用简单的 java 类(main 方法)连接到端点(https://%s.blob.core.windows.net)。
So I was getting this certification issue as mentioned above, in the question.因此,在问题中,我遇到了上面提到的这个认证问题。
Solution:解决方案:
Get the certificate using a browser(chrome).使用浏览器(chrome)获取证书。 To do this paste your endpoint URL in the browser and enter.为此,请将您的端点 URL 粘贴到浏览器中并输入。 Now you will see a lock icon, click on that -->certificate--> details --> copy to files--> download it.现在你会看到一个锁图标,点击它-->证书-->详细信息-->复制到文件-->下载它。
open the cmd(i am using windows) as admin and then navigate to the directory where you have downloaded the .cer file.以管理员身份打开 cmd(我使用的是 Windows),然后导航到您下载 .cer 文件的目录。
3.(Optional)If you are using multiple JDK in the same machine then change your JDK version the same as you are using in your application. 3.(可选)如果您在同一台机器上使用多个 JDK,则将 JDK 版本更改为与您在应用程序中使用的相同。
keytool -import -alias mycertificate -keystore "C:\Program Files\Java\jdk-11.0.5\lib\security\cacerts" -file myurlcrt.cer keytool -import -alias mycertificate -keystore "C:\Program Files\Java\jdk-11.0.5\lib\security\cacerts" -file myurlcrt.cer
Give the default password: changeit给出默认密码: changeit
Trust this certificate: yes信任此证书:是
And you are done.你完成了。
Thanks!谢谢!
UPDATE: That a reboot helped was coincidental (I hoped so, hooray!).更新:重启帮助是巧合(我希望如此,万岁!)。 The real cause of the problem was this: When Gradle is directed to use a specific keystore, that keystore must also contain all the official root certificates.问题的真正原因是:当 Gradle 被指示使用特定的密钥库时,该密钥库还必须包含所有官方根证书。 Otherwise it cannot access libraries from regular repositories.否则,它无法从常规存储库访问库。 What I had to do was this:我必须做的是:
Import the self-signed certificate:导入自签名证书:
keytool -import -trustcacerts -alias myselfsignedcert -file /Users/me/Desktop/selfsignedcert.crt -keystore ./privateKeystore.jks
Add the official root certificates:添加官方根证书:
keytool -importkeystore -srckeystore <java-home>/lib/security/cacerts -destkeystore ./privateKeystore.jks
Maybe the Gradle daemon also got in the way.也许 Gradle 守护进程也妨碍了。 Might be worth killing all running daemons found with ./gradlew --status
if things start looking bleak.如果事情开始变得黯淡,可能值得杀死所有使用./gradlew --status
找到的正在运行的守护进程。
ORIGINAL POSTING:原帖:
Nobody will believe this, I know.我知道,没有人会相信这一点。 Still, if all else fails, give it a try: After a reboot of my Mac the problem was gone.不过,如果所有其他方法都失败了,请试一试:重新启动我的 Mac 后,问题就消失了。 Grrr.嗯。
Background: ./gradlew jar kept giving me "unable to find valid certification path to requested target"背景:./gradlew jar 不断给我“无法找到请求目标的有效认证路径”
I am stuck with a self-signed certificate, saved from browser, imported in privateKeystore.jks.我被一个自签名证书卡住了,从浏览器保存,导入到 privateKeystore.jks。 Then instructed Gradle to work with 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
As mentioned, this only worked after a reboot.如前所述,这仅在重新启动后才有效。
Had the issue like this image.有像这张图片这样的问题。
Tried a few solutions.尝试了一些解决方案。 But found that even if it's same project, when it's on other one's working place, it's totally fine.但是发现即使是同一个项目,在别人工作的地方也完全没问题。 No extra settings needed.无需额外设置。 So we guessed it's an enviroment issue.所以我们猜测这是一个环境问题。 We tried changing JDK version, IDE but didn't work.我们尝试更改 JDK 版本、IDE 但没有奏效。 it took about 4 hours for investigation, until we tried the top-rated answer.调查花了大约 4 个小时,直到我们尝试了最受好评的答案。 I didn't find the error mentioned in that answer but I found via my browser about HTTP URL (lock) that there was a certification of Charles.我没有找到该答案中提到的错误,但我通过浏览器发现有关 HTTP URL(锁定)的信息有 Charles 的认证。 Then I realized my charles was on all the time.然后我意识到我的查尔斯一直在工作。 As long as I turned that off, it's working all fine.只要我关闭它,它就可以正常工作。
So I left my experience that could be helpful for your case.因此,我留下了可能对您的案例有所帮助的经验。
This can also be caused by using GoDaddy certs with Java 7 that are signed using SHA2.这也可能是由使用 SHA2 签名的 Java 7 的 GoDaddy 证书引起的。
Chrome and all other browsers are starting to deprecate SSL certs that are signed using SHA1, as it's not as secure. Chrome 和所有其他浏览器开始弃用使用 SHA1 签名的 SSL 证书,因为它不那么安全。
More info on the issue can be found here , as well as how to resolve it on your server if you need to now. 可以在此处找到有关此问题的更多信息,以及如果您现在需要如何在您的服务器上解决它。
I had the same problem with the certificates error and it was because of SNI: the http client that I used didn't have SNI implemented.我对证书错误有同样的问题,这是因为 SNI:我使用的 http 客户端没有实现 SNI。 So a version update did the job所以版本更新完成了这项工作
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
</dependency>
AVG version 18.1.3044 (with Windows 10) interfer with my local Spring application. AVG 版本 18.1.3044(使用 Windows 10)干扰了我的本地 Spring 应用程序。
Solution: enter in AVG section called "Web and email" and disable the "email protection".解决方法:进入 AVG 部分名为“Web 和电子邮件”并禁用“电子邮件保护”。 AVG block the certificate if the site isn't secure.如果站点不安全,AVG 会阻止证书。
Download the certificate from Nexus3 Browser (click on the lock-pad for View Site Information in case of Edge broser)
Click on Connection is secure
Click on the certificate details
Click on Copy To file (it opens up export certificate wizard)
Choose Base-64 encoding
Browse and select a download location and file-name (let’s say mycert)
Open cmd
Goto the download location and execute the below command
keytool -import -alias mycert -keystore "<<your-JAVA_HOME-directory>>\jre\lib\security\cacerts" -file mycert.cer
Restart the machine
Execute maven build again.
您有两个选择,将自签名证书导入到 Java 的密钥库中,用于软件将在其上运行的每个 jvm,或者尝试非验证 ssl 工厂:
jdbc:postgresql://myserver.com:5432/mydatabasename?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory
Make sure that the https://176.66.3.69:6443/ have a valid certificate.确保https://176.66.3.69:6443/具有有效证书。 you can check it via browser firstly你可以先通过浏览器查看 if it works in browser it will work in java.如果它在浏览器中工作,它将在 java 中工作。
that is working for me这对我有用
If getting this error in maven, or maven with TestNG :如果在 maven 或带有 TestNG 的 maven 中出现此错误:
note : C:\Users\me.keystore should also be set to match your machine.注意:C:\Users\me.keystore 也应该设置为匹配你的机器。 For instance :例如 :
mvn -ea -Dtestng.dtd.http=true -Djavax.net.ssl.trustStore=C:\Users\me\.keystore -Djavax.net.ssl.trustStorePassword=X -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true -Dcucumber.features=src/test/resources -Dcucumber.glue=com.myapp -Dcucumber.filter.tags="@MY_TEST"
In my case I'm running MacOs High Sierra with Java 1.6.就我而言,我正在使用 Java 1.6 运行 MacOs High Sierra。 The cacert file is in a different location than referenced above in Gabe Martin-Dempesy's answer. cacert 文件的位置与上面 Gabe Martin-Dempesy 的回答中提到的位置不同。 The cacert file was also already linked to another location (/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/security/cacerts). cacert 文件也已链接到另一个位置(/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/security/cacerts)。
Using FireFox, I exported the certificate from the web site in question to a local file called "exportedCertFile.crt".使用 FireFox,我将证书从相关网站导出到名为“exportedCertFile.crt”的本地文件中。 From there, I used keytool to move the certificate into the cacert file.从那里,我使用 keytool 将证书移动到 cacert 文件中。 This fixed the problem.这解决了问题。
bash-3.2# cd /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/security/
bash-3.2# keytool -importcert -file ~/exportedCertFile.crt -alias example -keystore cacerts -storepass changeit
首先下载 ssl 证书,然后您可以转到您的 java bin 路径,在控制台中执行以下命令。
C:\java\JDK1.8.0_66-X64\bin>keytool -printcert -file C:\Users\lova\openapi.cer -keystore openapistore
In my case I had both keystore and truststore having the same certificate so removing truststore helped.就我而言,我的密钥库和信任库都具有相同的证书,因此删除信任库会有所帮助。 Sometimes the chain of certificates can be an issue if you've multiple copies of certificates.如果您有多个证书副本,有时证书链可能会成为问题。
As original question was - how to ignore the cert error, here is solution for those using SpringBoot and RestTemplate由于最初的问题是 - 如何忽略证书错误,这里是使用 SpringBoot 和 RestTemplate 的解决方案
@Service
public class SomeService {
private final RestTemplate restTemplate;
private final ObjectMapper objectMapper;
private static HttpComponentsClientHttpRequestFactory createRequestFactory() {
try {
SSLContextBuilder sslContext = new SSLContextBuilder();
sslContext.loadTrustMaterial(null, new TrustAllStrategy());
CloseableHttpClient client = HttpClients.custom().setSSLContext(sslContext.build()).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(client);
return requestFactory;
} catch (KeyManagementException | KeyStoreException | NoSuchAlgorithmException var3) {
throw new IllegalStateException("Couldn't create HTTP Request factory ignore SSL cert validity: ", var3);
}
}
@Autowired
public SomeService(RestTemplate restTemplate, ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
this.dimetorURL = dimetorURL;
restTemplate.setRequestFactory(createRequestFactory());
}
public ResponseEntity<ResponseObject> sendRequest(RequestObject requestObject) {
//...
return restTemplate.exchange(url, HttpMethod.GET, ResponseObject.class);
//...
}
}
This is what worked for me on macOS.这就是在 macOS 上对我有用的方法。 Replace server-name and server-port with your own.将 server-name 和 server-port 替换为您自己的。
Run these two commands on your terminal.在终端上运行这两个命令。
openssl x509 -in <(openssl s_client -connect server-name:server-port -prexit 2>/dev/null) -out ~/server-name.crt
sudo keytool -importcert -file ~/server-name.crt -alias server-name -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit
Restart your application and the certs errors should go away!重新启动您的应用程序,证书错误应该会消失!
This works on any OS you just need JDK installed :这适用于您只需要安装 JDK 的任何操作系统:
Download the certificate from the remote server :从远程服务器下载证书:
keytool -printcert -rfc -sslserver <your remote server hostname> > /tmp/remorte-cert.crt
Import the certificate to your JDK keystore :将证书导入您的 JDK 密钥库:
keytool -importcert -file /tmp/remorte-cert.crt -alias <an alias for your remote server> -storepass changeit -keystore "${JAVA_HOME}/lib/security/cacerts" -noprompt
And if you are here in 2022 and are on mac follow this如果您在 2022 年来到这里并且在 Mac 上,请遵循此
echo -n | openssl s_client -connect <ServerName>:<PORT> -servername <ServerName> \
| openssl x509 > /tmp/<ServerName>.cert
/usr/libexec/java_home
sudo keytool -import -alias mycertificate -keystore "<JDK_HOME>/lib/security/cacerts" -file /tmp/<ServerName>.cert
当我遇到这个问题时,我只是将android studio zip提取到相同的旧文件夹中,就解决了我的问题
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.