简体   繁体   English

Java:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效认证路径

[英]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
  1. Export the SSL certificate using Firefox.使用 Firefox 导出 SSL 证书。 You can export it by hitting the URL in the browser and then select the option to export the certificate.您可以通过在浏览器中点击 URL 来导出它,然后选择导出证书的选项。 Let's assume the cert file name is your.ssl.server.name.crt假设证书文件名是your.ssl.server.name.crt
  2. Go to your JRE_HOME/bin or JDK/JRE/bin转到您的JRE_HOME/binJDK/JRE/bin
  3. Type the command输入命令
  4. keytool -keystore ..\lib\security\cacerts -import -alias your.ssl.server.name -file .\relative-path-to-cert-file\your.ssl.server.name.crt
  5. Restart your Java process重新启动 Java 进程

@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,请执行以下步骤:

  1. In Chrome go to settings.在 Chrome 中转到设置。
  2. In Settings click show advance settings.在设置中单击显示高级设置。
  3. Under HTTPS/SSL Click on Manage Certificates.在 HTTPS/SSL 下单击管理证书。
  4. Export Your Certificate.导出您的证书。
  5. In Windows searchs (Pressing windows key on keyboard) type java.在 Windows 搜索中(按键盘上的 windows 键)输入 java。
  6. Select (Configure Java) Option Which will open Java Control Panel选择(配置 Java)选项,这将打开 Java 控制面板
  7. Select Security tab in Java Control Panel在 Java 控制面板中选择安全选项卡
  8. Select Manage Certificates选择管理证书
  9. Click Import点击导入
  10. Under (User) tab selected and certificate type as (Trusted Certificates)在(用户)选项卡下选择和证书类型为(受信任的证书)
  11. Click import button and browse to downloaded certificate and import it.单击导入按钮并浏览到下载的证书并将其导入。

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:解决方案:

  1. 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.现在你会看到一个锁图标,点击它-->证书-->详细信息-->复制到文件-->下载它。

  2. 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 版本更改为与您在应用程序中使用的相同。

  1. Now use the below command现在使用以下命令

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

  1. Give the default password: changeit给出默认密码: changeit

  2. 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你可以先通过浏览器查看https不安全 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 中出现此错误:

  1. download the certificate from the target website and install certificate on your machine (using keytool as suggested above, or on windows)从目标网站下载证书并在您的机器上安装证书(使用上面建议的 keytool,或在 Windows 上)
  2. add the following content to the maven arguments (command line and/or IDE): -Djavax.net.ssl.trustStore=C:\Users\me.keystore -Djavax.net.ssl.trustStorePassword=X Where X is the password you used at the keytool step.将以下内容添加到 maven 参数(命令行和/或 IDE): -Djavax.net.ssl.trustStore=C:\Users\me.keystore -Djavax.net.ssl.trustStorePassword=X 其中 X 是您的密码在 keytool 步骤中使用。

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.在终端上运行这两个命令。

Download certificate from the remote server从远程服务器下载证书

openssl x509 -in <(openssl s_client -connect server-name:server-port -prexit 2>/dev/null) -out ~/server-name.crt

Import cert to Java keystore将证书导入 Java 密钥库

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 的任何操作系统:

  1. Download the certificate from the remote server :从远程服务器下载证书:

    keytool -printcert -rfc -sslserver <your remote server hostname> > /tmp/remorte-cert.crt

  2. 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 上,请遵循此

  1. Download the certificate.下载证书。
echo -n | openssl s_client -connect <ServerName>:<PORT> -servername <ServerName> \
    | openssl x509 > /tmp/<ServerName>.cert
  1. Find your jdk path.找到你的 jdk 路径。
/usr/libexec/java_home
  1. Now import the cert into the cert-store of jdk.现在将证书导入 jdk 的 cert-store。
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.

相关问题 GCP-PUBSUB:-sun.security.provider.certpath.SunCertPathBuilderException: 无法找到请求目标的有效认证路径 - GCP-PUBSUB:-sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求的目标错误的有效证书路径 - sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target error 引起:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径 - Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target PKIX 构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径 - PKIX building failed:sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target PKIX路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到到请求目标的有效认证路径? - PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target? CXF:PKIX 路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径 - CXF:PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 使用 xmpp 时出现错误“sun.security.provider.certpath.SunCertPathBuilderException:无法找到到所请求目标的有效证书路径” - Error ' sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target' when using xmpp PKIX路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到到请求目标的有效认证路径 - PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 无法找到到请求的目标PKIX路径构建的有效证书路径失败:sun.security.provider.certpath.SunCertPathBuilderException - unable to find valid certification path to requested target PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException 看到SSLFactory使用的密钥库了吗? 异常:“ sun…certpath.SunCertPathBuilderException:无法找到到请求目标的有效证书路径” - See keystore used by SSLFactory? Exception: “sun…certpath.SunCertPathBuilderException: unable to find valid certification path to requested target”
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM