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

380

我有一个类可以从https服务器下载文件。当我运行它时,会返回很多错误。看起来我有证书的问题。是否可能忽略客户端和服务器的身份验证?如果可以,怎么做?

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

4
有一次我遇到了这个错误,联系了我们的安全团队,结果发现我需要打补丁来修复我们正在使用的JAR文件,因为我们的团队正在使用公司提供的过时版本。这只是给那些可能处于类似情况的人一个提示。 - kayleeFrye_onDeck
我在两种情况下遇到了PKIX问题,一是直接从互联网下载Maven依赖项而不是从我的组织缓存中下载。这个问题通过更正setting.xml文件得以解决。第二次,当我尝试访问Microsoft的oAuth令牌URI时,我遇到了这个问题,通过在我的JDK路径中添加cacert文件来解决。 - lucky
29个回答

287

当您的服务器使用自签名证书时,会出现问题。为了解决这个问题,您可以将此证书添加到JVM的受信任证书列表中。

在本文中,作者描述了如何从浏览器中获取证书,并将其添加到JVM的cacerts文件中。您可以编辑JAVA_HOME/jre/lib/security/cacerts文件,或者使用-Djavax.net.ssl.trustStore参数运行应用程序。还要验证您正在使用哪个JDK/JRE,因为这经常是混淆的原因。

另请参阅:如何解析SSL证书服务器名称/我可以使用keytool添加备用名称吗?如果遇到java.security.cert.CertificateException: No name matching localhost found异常。


9
这对我没有起作用。我已经安装了根证书和链证书,但 Tomcat-7 仍然报告验证器异常,原因是“无法找到请求目标的有效认证路径”。有什么调试方法吗? - Cheruvim
1
该问题也会出现在由其他人签名但未受信任的证书上。 - user207421
3
好的!它起作用了!只是不要忘记你可能同时拥有jre和jdk,它们各自的cacerts都必须更新。 - Dima Fomin
在我的案例中,根 CA 是存在的,但下一个 CA 却不存在。添加下一个 CA 就解决了问题 - 谢谢。 - java-addict301
1
在我的情况下,我使用的是Netbeans + Apache Tomcat(集成),因此将.cer添加到Jdk / jre(C:\ Program Files \ Java \ jdk1.8.0_152 \ jre \ lib \ security)和Jre(C:\ Program Files \ Java \ jre1.8.0_91 \ lib \ security)的信任存储“cacerts”对我有用。 - Jnn
1
提供“-Djavax.net.ssl.trustStore”参数非常重要,以确保您的应用程序加载正确的cacerts文件。(如果出现问题,我建议首先尝试这个。)这解决了Dima Fomin所描述的情况。 - primehunter

195

以下是在macOS上对我可靠的工作方法。确保将 example.com 和 443 替换为您尝试连接的实际主机名和端口,并提供自定义别名。第一个命令从远程服务器下载提供的证书并以 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

在Windows上通过Git Bash或WSL,第一个命令看起来有点不同:
openssl s_client -connect git.css.ch:443  -prexit > ~/cert.txt
openssl x509 -in ~/cert.txt -out ~/example.crt

4
对我来说可以。为什么?你需要提供解释。 - user207421
3
".crt"和".pem"是同一文件格式的常用文件扩展名。如果你已经有了该文件,只需运行第二个命令并将其传递到"-file"参数中即可。 - Gabe Martin-Dempesy
1
很棒的东西。唯一的问题是:由于某些原因,我不得不使用最新的openssl 1.0.Xx版本,旧的9.X.Xx版本无法工作。 - zbstof
2
这在SNI端点上不起作用。对于这种情况,您需要在获取证书时添加:-servername example.com - Patrik Beck
太棒了。在Windows 10和JDK 1.8上也适用于我。 - RayCh
显示剩余2条评论

58
  1. 使用Firefox导出SSL证书。您可以通过在浏览器中输入URL并选择导出证书选项来导出它。假设证书文件名为your.ssl.server.name.crt
  2. 进入JRE_HOME/binJDK/JRE/bin
  3. 键入命令
  4. keytool -keystore ..\lib\security\cacerts -import -alias your.ssl.server.name -file .\relative-path-to-cert-file\your.ssl.server.name.crt
  5. 重启Java进程

22
如果要求输入密码,请使用默认的 cacerts 密钥库密码 changeit(https://dev59.com/GWQn5IYBdhLWcg3wXGKr#22782035)。此外,请确保以管理员身份运行 cmd。 - Fr4nz

55

我遇到了使用来自赛门铁克的有效签名通配符证书的相同问题。

首先尝试使用-Djavax.net.debug=SSL运行您的Java应用程序,以查看实际发生了什么。

最终,我导入了中间证书,这导致证书链断裂。

我从赛门铁克下载了丢失的中间证书(在我的情况下,在SSL握手日志中可以看到缺少证书的下载链接: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

这是情况: - kisna
5
为避免混淆,请使用调试参数运行java(或jcurl),以便在日志中查看远程“证书链”,然后按以下方式显式地在传递的信任库中搜索“CN”(而不是默认值),如果不存在,则需要添加。如果https://www.ssllabs.com/ssltest/analyze.html显示服务器端证书具有不完整的链,并包括需要添加的中间认证路径证书。请使用以下参数运行java(或jcurl): -Djavax.net.debug=ssl,handshake -Djavax.net.ssl.keyStoreType=PKCS12 -Djavax.net.ssl.keyStore=our-client-certs -Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStore=their-server-certs - kisna
当然,还有官方文章来调试SSL问题: http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/ReadDebug.html https://blogs.oracle.com/java-platform-group/entry/diagnosing_tls_ssl_and_https - kisna
我曾经遇到过同样的问题,这个方法非常有用。但在我的情况下,你只需要将服务器证书添加到JDK版本的cacerts文件中即可。 - Pigritia
请记住,还有另一个工具叫做portecle,可以打开cacert文件(证书存储)并轻松导入证书。只需记得在此之后保存cacert文件即可。 - will824

38

@Gabe Martin-Dempesy的答案对我有所帮助。我写了一个相关的小脚本。使用方法非常简单。

从主机安装证书:

> 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 (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;

1
无瑕地运行。做得好!它是这样工作的:启动您的 SSL 服务(如果它没有运行),并按照说明执行命令(例如 ./java-cert-importer.sh example.com 1234)。就这样。 - lepe
1
非常好用。我在一个连接到外部API的Jenkins服务器上遇到了错误,该API更改了其证书并导致我的构建失败。这解决了我的问题。 - user9869932
2
Oracle本应该一开始就提供这样的东西,或者根本不应该创建他们自己可怕的SSL解决方案。SSL证书处理应该是操作系统的工作。 - Wolfgang Fahl
谢谢 @bhdrk。 - Joe - ElasticsearchBook.com
非常感谢!我想进行一些编辑,这对我很有帮助。1. 不要忘记,当从su开始时,JAVA_HOME是不同的。2. 在cacertspath = $ {javahome}/lib/security/cacerts中,您可能需要插入/jre/,即cacertspath =${javahome}/jre/lib/security/cacerts。 - S.Daineko

18
引自No more 'unable to find valid certification path to requested target' 尝试使用JSSE打开到主机的SSL连接时,可能会遇到“无法找到有效证书路径到请求的目标”的错误。这通常意味着服务器正在使用测试证书(可能是使用keytool生成的证书),而不是来自知名商业认证机构(如Verisign或GoDaddy)的证书。在这种情况下,Web浏览器会显示警告对话框,但由于JSSE无法假定存在交互式用户,因此默认情况下会抛出异常。
证书验证是SSL安全性的重要组成部分,但我写这篇文章并非为了解释详情。如果您感兴趣,可以从阅读维基百科入手。我写这篇文章是为了展示一种简单的方法,以便与具有测试证书的主机进行通信,如果您真的想要这样做。
基本上,您需要将服务器证书添加到包含受信任证书的密钥库中。
尝试其中提供的代码。它可能会有所帮助。

6
“证书验证是SSL安全性的非常重要的一部分”这句话并不一定正确。SSL提供两个保障:(1)你的通信是私密的,(2)你正在与NSA认可的服务器通信。有时你只关心对话的私密性,这时自签名证书就足够了。请参考http://social-biz.org/2011/10/16/the-anti-ssl-conspiracy/。 - AgilePro
2
@AgilePro SSL 给您 四个 保证:身份验证、隐私、完整性和授权的可能性。它并不能保证您正在与 NSA 知道的服务器通信。只关心隐私而不进行身份验证是自相矛盾的。 - user207421
如果您使用客户端证书,则可以获得身份验证和可能的授权...但大多数情况下不使用客户端证书。您如何区分“自签名”证书和来自签名机构的证书?签名机构是否提供“完整性”?我对NSA的玩笑是所有签名机构都不能绝对保证独立于一切。并不是真的很偏执,但重点是您的证书只有签名机构可以使其保密。自签名可以更保密。 - AgilePro
1
@AgilePro使用服务器证书对服务器进行身份验证,这是使SSL安全所必需的,正如RFC 2246中所述。证书根本不是秘密:因此,您评论的其余部分毫无意义。 - user207421

10

我所遵循的简单步骤。

问题:我正在尝试使用一个简单的java类(main方法)连接到一个端点(https://%s.blob.core.windows.net)。

所以,我在上面的问题中提到了这个证书问题。

解决方案:

  1. 使用浏览器(chrome)获取证书。为此,请将您的终端节点URL粘贴到浏览器中并输入。现在您将看到一个锁图标,请单击该图标--> 证书--> 详细信息--> 复制到文件--> 下载它。

  2. 以管理员身份打开cmd(我正在使用windows),然后导航到您下载.cer文件的目录。

3.(可选)如果您在同一台机器上使用多个JDK,则将JDK版本更改为与您在应用程序中使用的版本相同。

  1. 现在使用以下命令

keytool -import -alias mycertificate -keystore "C:\Program Files\Java\jdk-11.0.5\lib\security\cacerts" -file myurlcrt.cer

  1. 给出默认密码:changeit

  2. 信任此证书:是

这样就完成了。

谢谢!


9
这解决了我的问题,
我们需要将证书导入本地java中。如果不这样做,我们可能会遇到以下异常。
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是一个工具,您可以使用它从本地机器测试https连接性。
测试连接的命令:
"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
sun.security.validator.ValidatorException: PKIX 路径构建失败:
sun.security.provider.certpath.SunCertPathBuilderException: 无法找到请求目标的有效认证路径
    在 sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
    在 sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
    在 sun.security.validator.Validator.validate(Validator.java:260)
    在 sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
    在 sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
    在 sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
    在 sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496)
    在 sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
    在 sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
    在 sun.security.ssl.Handshaker.process_record(Handshaker.java:961)
    在 sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
    在 sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    在 sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:747)
    在 sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
    在 sun.security.ssl.AppOutputStream.write(AppOutputStream.java:138)
    在 SSLPoke.main(SSLPoke.java:31)
由于:sun.security.provider.certpath.SunCertPathBuilderException: 无法找到请求目标的有效认证路径
    在 sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
    在 sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
    在 java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
    在 sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
    ... 15 more
keytool -import -alias <anyname> -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -file <cert path>

这会先提示“输入密钥库密码:”,changeit是默认密码。最后会出现一个提示:“信任该证书?[no]:”,请输入“yes”以将证书添加到密钥库。

验证:

C:\tools>"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
Successfully connected    

1
我做了这个,但不知何故它总是显示错误日志。 - dhS

6

仅适用于Windows,请按照以下步骤进行操作:

  1. 在Chrome中进入设置。
  2. 在设置中点击显示高级设置。
  3. 在HTTPS/SSL下单击"管理证书"。
  4. 导出您的证书。
  5. 在Windows搜索栏(按键盘上的Windows键)中输入java。
  6. 选择(配置Java)选项,这将打开Java控制面板。
  7. 在Java控制面板中选择安全选项卡。
  8. 选择管理证书。
  9. 点击导入按钮。
  10. 在(User)选项卡中,选择证书类型为(受信任的证书)。
  11. 点击导入按钮并浏览下载的证书,然后将其导入。

6
在我的Apache 2.4实例(使用Comodo通配符证书)中,这个错误的来源是到SHA-1签名根证书的不完整路径。颁发的证书中有多个链,而导致到SHA-1根证书的链缺少一个中间证书。现代浏览器知道如何处理这个问题,但Java 7默认情况下无法处理它(尽管在代码中有一些复杂的方法可以解决这个问题)。结果就是出现了与自签名证书相同的错误消息:
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

在这种情况下,“无法找到请求目标的有效认证路径”消息是由于缺少中间证书而产生的。您可以使用SSL Labs测试来检查缺少哪个证书。一旦找到适当的证书,下载它并将其添加到证书包中(如果服务器在您的控制下)。或者,您可以在本地导入缺失的证书。在服务器上解决此问题是解决问题的更一般性解决方案。

https://www.ssllabs.com/ssltest/ 是一个救星,只需要将其与有效的证书验证进行比较。 - kisna

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接