解决异常:sun.security.provider.certpath.SunCertPathBuilderException

转:https://blog.youkuaiyun.com/sheng_Mu555/article/details/100103789

问题

使用HttpClient请求Https网址时报异常:

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:1946)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639)
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
	at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:396)
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:355)
	at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:373)
	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:381)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
	at com.bjpowernode.vinfo.util.HttpClientUtil.doGet(HttpClientUtil.java:44)
	at com.bjpowernode.vinfo.util.HttpClientUtil.main(HttpClientUtil.java:60)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
	at sun.security.validator.Validator.validate(Validator.java:262)
	at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:330)
	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:237)
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621)
	... 21 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
	at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
	... 27 more

解决方法:

1、运行如下java文件(InstallCert.java),生成 jssecacerts 文件。
2、然后将生成的 jssecacerts 文件,拷贝到jdk目录中,目录位置:%JAVA_HOME%\jre\lib\security
(例如D:\SOFTWARE\Program File\Jdk\Jdk8\jre\lib\security)

/* 
 * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 * 
 *   - Redistributions of source code must retain the above copyright 
 *     notice, this list of conditions and the following disclaimer. 
 * 
 *   - Redistributions in binary form must reproduce the above copyright 
 *     notice, this list of conditions and the following disclaimer in the 
 *     documentation and/or other materials provided with the distribution. 
 * 
 *   - Neither the name of Sun Microsystems nor the names of its 
 *     contributors may be used to endorse or promote products derived 
 *     from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */  
  
import java.io.BufferedReader;  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.FileOutputStream;  
import java.io.InputStream;  
import java.io.InputStreamReader;  
import java.io.OutputStream;  
import java.security.KeyStore;  
import java.security.MessageDigest;  
import java.security.cert.CertificateException;  
import java.security.cert.X509Certificate;  
  
import javax.net.ssl.SSLContext;  
import javax.net.ssl.SSLException;  
import javax.net.ssl.SSLSocket;  
import javax.net.ssl.SSLSocketFactory;  
import javax.net.ssl.TrustManager;  
import javax.net.ssl.TrustManagerFactory;  
import javax.net.ssl.X509TrustManager;  
  
public class InstallCert {  
	//修改,不使用命令行的方法传入host
	public static void main(String[] args) throws Exception {
//        args = new String[]{"view.inews.qq.com"};
        args = new String[]{"ncov.dxy.cn"};
        main0(args);
    }
  
    public static void main0(String[] args) throws Exception {  
        String host;  
        int port;  
        char[] passphrase;  
        if ((args.length == 1) || (args.length == 2)) {  
            String[] c = args[0].split(":");  
            host = c[0];  
            port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);  
            String p = (args.length == 1) ? "changeit" : args[1];  
            passphrase = p.toCharArray();  
        } else {  
            System.out  
                    .println("Usage: java InstallCert <host>[:port] [passphrase]");  
            return;  
        }  
  
        File file = new File("jssecacerts");  
        if (file.isFile() == false) {  
            char SEP = File.separatorChar;  
            File dir = new File(System.getProperty("java.home") + SEP + "lib"  
                    + SEP + "security");  
            file = new File(dir, "jssecacerts");  
            if (file.isFile() == false) {  
                file = new File(dir, "cacerts");  
            }  
        }  
        System.out.println("Loading KeyStore " + file + "...");  
        InputStream in = new FileInputStream(file);  
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());  
        ks.load(in, passphrase);  
        in.close();  
  
        SSLContext context = SSLContext.getInstance("TLS");  
        TrustManagerFactory tmf = TrustManagerFactory  
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());  
        tmf.init(ks);  
        X509TrustManager defaultTrustManager = (X509TrustManager) tmf  
                .getTrustManagers()[0];  
        SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);  
        context.init(null, new TrustManager[] { tm }, null);  
        SSLSocketFactory factory = context.getSocketFactory();  
  
        System.out  
                .println("Opening connection to " + host + ":" + port + "...");  
        SSLSocket socket = (SSLSocket) factory.createSocket(host, port);  
        socket.setSoTimeout(10000);  
        try {  
            System.out.println("Starting SSL handshake...");  
            socket.startHandshake();  
            socket.close();  
            System.out.println();  
            System.out.println("No errors, certificate is already trusted");  
        } catch (SSLException e) {  
            System.out.println();  
            e.printStackTrace(System.out);  
        }  
  
        X509Certificate[] chain = tm.chain;  
        if (chain == null) {  
            System.out.println("Could not obtain server certificate chain");  
            return;  
        }  
  
        BufferedReader reader = new BufferedReader(new InputStreamReader(  
                System.in));  
  
        System.out.println();  
        System.out.println("Server sent " + chain.length + " certificate(s):");  
        System.out.println();  
        MessageDigest sha1 = MessageDigest.getInstance("SHA1");  
        MessageDigest md5 = MessageDigest.getInstance("MD5");  
        for (int i = 0; i < chain.length; i++) {  
            X509Certificate cert = chain[i];  
            System.out.println(" " + (i + 1) + " Subject "  
                    + cert.getSubjectDN());  
            System.out.println("   Issuer  " + cert.getIssuerDN());  
            sha1.update(cert.getEncoded());  
            System.out.println("   sha1    " + toHexString(sha1.digest()));  
            md5.update(cert.getEncoded());  
            System.out.println("   md5     " + toHexString(md5.digest()));  
            System.out.println();  
        }  
  
        System.out  
                .println("Enter certificate to add to trusted keystore or 'q' to quit: [1]");  
        String line = reader.readLine().trim();  
        int k;  
        try {  
            k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;  
        } catch (NumberFormatException e) {  
            System.out.println("KeyStore not changed");  
            return;  
        }  
  
        X509Certificate cert = chain[k];  
        String alias = host + "-" + (k + 1);  
        ks.setCertificateEntry(alias, cert);  
  
        OutputStream out = new FileOutputStream("jssecacerts");  
        ks.store(out, passphrase);  
        out.close();  
  
        System.out.println();  
        System.out.println(cert);  
        System.out.println();  
        System.out  
                .println("Added certificate to keystore 'jssecacerts' using alias '"  
                        + alias + "'");  
    }  
  
    private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();  
  
    private static String toHexString(byte[] bytes) {  
        StringBuilder sb = new StringBuilder(bytes.length * 3);  
        for (int b : bytes) {  
            b &= 0xff;  
            sb.append(HEXDIGITS[b >> 4]);  
            sb.append(HEXDIGITS[b & 15]);  
            sb.append(' ');  
        }  
        return sb.toString();  
    }  
  
    private static class SavingTrustManager implements X509TrustManager {  
  
        private final X509TrustManager tm;  
        private X509Certificate[] chain;  
  
        SavingTrustManager(X509TrustManager tm) {  
            this.tm = tm;  
        }  
  
        public X509Certificate[] getAcceptedIssuers() {  
            throw new UnsupportedOperationException();  
        }  
  
        public void checkClientTrusted(X509Certificate[] chain, String authType)  
                throws CertificateException {  
            throw new UnsupportedOperationException();  
        }  
  
        public void checkServerTrusted(X509Certificate[] chain, String authType)  
                throws CertificateException {  
            this.chain = chain;  
            tm.checkServerTrusted(chain, authType);  
        }  
    }  
  
} 

编译InstallCert.java,然后执行:java InstallCert hostname,比如:
java InstallCert www.twitter.com
会看到如下信息:

Loading KeyStore jssecacerts...
Opening connection to ncov.dxy.cn:443...
Starting SSL handshake...

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:1946)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639)
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
	at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
	at xyz.lyuan.yytools.https.InstallCert.main0(InstallCert.java:98)
	at xyz.lyuan.yytools.https.InstallCert.main(InstallCert.java:46)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
	at sun.security.validator.Validator.validate(Validator.java:262)
	at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:330)
	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:237)
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:113)
	at xyz.lyuan.yytools.https.InstallCert$SavingTrustManager.checkServerTrusted(InstallCert.java:194)
	at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:1099)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621)
	... 9 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
	at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
	... 17 more

Server sent 1 certificate(s):

 1 Subject CN=*.dxy.cn
   Issuer  CN=GlobalSign Root CA, C=EN
   sha1    84 fb 78 c6 68 27 eb 13 8f ed 36 9c ff cc 3a 00 e2 79 a7 85 
   md5     34 68 59 6f 7d 6a f8 cd fc ef 9f 28 d9 35 66 fb 

Enter certificate to add to trusted keystore or 'q' to quit: [1]

输入1,回车,然后会在当前的目录下产生一个名为“ssecacerts”的证书。

将证书拷贝到**$JAVA_HOME/jre/lib/security**目录下,或者通过以下方式:
System.setProperty(“javax.Net.ssl.trustStore”, “你的jssecacerts证书路径”);

注意:因为是静态加载,所以要重新启动你的Web Server,证书才能生效。


如果有多个网址需要生成证书,则多运行几遍即可,生成的证书是追加到jssecacerts文件中的

可以按照以下方法操作:
1、运行 InstallCert 生成 jssecacerts (这步是为了知道 InstallCert 生成 jssecacerts 的位置,如果知道生成位置可以不需要这步)
2、拷贝原来的 %JAVA_HOME%\jre\lib\security\jssecacerts 文件,替换刚刚生成的 jssecacerts 文件(这是为了保存以前的证书信息)
3、再重新运行 InstallCert 将新的域名,追加到 jssecacerts 中

整体来说,其实就是一个追加 host 的过程。

注意:操作之前最好备份,并且 jssecacerts 是一个固定的名字,不要随意修改。


最后,原文中的运行是使用命令行的方式(但运行老是失败),进行了稍微的修改,不使用命令行的方式传入host

<think>嗯,用户遇到了Android Studio中的SunCertPathBuilderException问题,需要解决证书路径无法找到的异常。我记得这类问题通常和SSL证书验证有关,可能发生在构建项目或下载依赖时。用户提供的引用资料里提到了几种解决方法,比如手动导入证书、配置Gradle使用HTTP绕过SSL检查、或者更新JDK的证书库。 首先,用户可能需要检查网络环境是否有中间人攻击或者公司防火墙的拦截,这可能导致证书不被信任。不过用户可能没有这样的环境,所以应该直接考虑解决方案。 根据引用[1]和[4],手动导入证书到Android Studio的JDK信任库可能有效。步骤应该是从浏览器导出证书,然后使用keytool命令导入到cacerts文件中。不过需要注意JDK版本和路径是否正确,尤其是Android Studio自带的JDK可能和系统环境变量中的不同,用户可能会在这里出错。 另外,引用[2]提到使用HTTP替代HTTPS的Maven仓库,但这样不安全,可能不适合所有情况,特别是如果仓库不支持HTTP的话。不过作为临时解决方案可能有效,用户需要修改build.gradle文件,将url改为http,并设置allowInsecureProtocol为true。 还有禁用SSL验证的方法,比如在gradle.properties里设置禁用,但同样存在安全隐患,用户可能不太愿意这么做,尤其是在生产环境中。 更新Android Studio和Gradle版本也是一个建议,因为新版本可能包含更新的证书库,引用[4]提到旧方法过时,推荐查看最新解决方案,所以可能需要用户检查更新。 用户可能需要分步骤尝试不同的方法,先尝试导入证书,如果不行再考虑临时解决方案。同时提醒用户注意安全,不要长期使用不安全的配置。另外,确保JDK路径正确是关键,用户可能不清楚Android Studio使用的是哪个JDK,需要指导他们找到正确的路径,比如在项目结构设置里查看SDK位置,然后找到对应的jre目录下的cacerts文件。 最后,如果所有方法都无效,建议用户检查项目配置或联系网络管理员,确认是否有特殊证书需要处理。同时,引用中的链接可能有更详细的步骤,用户可以参考。</think>### 分步解决方案:Android Studio SunCertPathBuilderException 异常处理 #### **问题原因** 此异常表示Android Studio的JDK无法验证服务器SSL证书的有效性,常见于以下场景: 1. 企业网络使用自签名证书拦截HTTPS流量 2. Gradle依赖仓库(如Maven Central)的证书未正确安装 3. JDK证书库(cacerts)未包含根证书颁发机构的证书[^1][^3] --- #### **解决方案** ##### **方法1:手动导入证书(推荐)** 1. **获取证书文件** - 浏览器访问目标URL(如`https://services.gradle.org`) - 点击地址栏锁图标 → 导出证书为`.cer`或`.pem`格式 2. **定位JDK证书库** - Android Studio使用的JDK路径通常为: `$ANDROID_STUDIO_PATH/jre/jre/lib/security/cacerts` (可通过`File → Project Structure → SDK Location`确认路径) 3. **执行证书导入命令** ```bash keytool -importcert -alias gradle_cert -keystore "路径/cacerts" -file 证书文件路径 -storepass changeit ``` - 默认密码为`changeit` - 出现`Trust this certificate? [no]:`时输入`yes`[^1][^2] ##### **方法2:配置Gradle绕过SSL验证(临时方案)** 在`build.gradle`中添加: ```groovy repositories { maven { url "http://repo.maven.apache.org/maven2" // 改用HTTP allowInsecureProtocol = true } } ``` ⚠️ 注意:这会降低连接安全性,仅建议临时使用[^2] ##### **方法3:更新证书库** 1. 更新Android Studio至最新版(`Help → Check for Updates`) 2. 在`gradle-wrapper.properties`中使用新版Gradle: ```properties distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip ``` --- #### **补充说明** - 若使用代理,需同时在`gradle.properties`配置代理设置: ```properties systemProp.https.proxyHost=proxyhost systemProp.https.proxyPort=proxyport ``` - 企业用户建议联系网络管理员获取合规证书[^4] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值