【SSL】调用HTTPS://服务遇到错误:unable to find valid certification path to requested target

java 同时被 2 个专栏收录
42 篇文章 0 订阅
18 篇文章 0 订阅

前言

  • OkHttpClient

最近有个需求,需要调用一个https开头的URL服务。
服务方提供了一个demo,但,demo是调用http的服务。
网上找了一大圈,发现盖起来要这样要那样的。都不符合我的想法,试了几个也没成功。
我的想法比较简单:有没有一种方法,让我在不改动demo的前提下,让demo跑起来。
经过我仔细地回想一下,发现这个办法可行,我之前还实现过。

错误内容

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:1959)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514)
	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:1072)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397)
	at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:379)
	at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:337)
	at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:209)
	at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
	at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
	at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
	at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
	at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
	at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
	at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
	at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
	at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
	at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
	at sc.HttpClientUtil.postWithJsonMsg(HttpClientUtil.java:66)
	at sc.appPay.main(appPay.java:105)
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: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)
	... 26 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)
	... 32 more

题外话

对于调用HTTPS的服务,可以参考《java 安全性编程指南》。
在这里插入图片描述

解决思路

将HTTPS的证书添加到本地证书库中。在程序启动时,使用指定的证书库验证证书和CA。

相关知识:

  • 当访问的URL是以https://开头的话,VM将自动地激活JSSE。
  • 服务器会向客户端发送它的证书以供验证。
  • 客户端会验证证书,以确认这个服务器正式他想链接并通信的那个服务器,并且确认签发证书的CA是可信任的。
  • 环境变量javax.net.ssl.trustStore告知客户端的JSSE使用哪个证书库。证书库中有我们可以信任的证书和CA。
  • 环境变量javax.net.ssl.trustStorePassword告知客户端的JSSE证书库的密码。
  • 如果未指定证书库,则使用缺省的证书库。缺省的证书库的位置为%JRE_HOME%/lib/security/cacerts或者%JAVA_HOME%/jre/lib/security/cacerts。默认密码为changeit

操作

  1. 拿到证书。https://开头的地址的证书很容易拿到。在浏览器中打开该地址,将浏览器中显示的证书另存为就拿到了。
  2. 创建证书库。参考 【SSL】java keytool工具创建自己的(localhost)(JKS)证书库。
  3. 将第1步中拿到的证书导入到证书库中。参考 【SSL】java keytool工具操作java带的(JKS)证书库。
  4. 在程序中引入证书库。

在合适的位置添加下面这段静态代码:

	static {
    	File jksFile = new File("localhost.jks");
		System.out.println("jks file : " + jksFile.getAbsolutePath());

		System.setProperty("javax.net.ssl.trustStore", jksFile.getAbsolutePath());
		System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
    }

对应的项目结构为:

项目目录
├─src
│  ├─main
│  │  ├─java
│  │  │  └─sc
│  │  └─resources
│  └─test
│      ├─java
│      └─resources
└─localhost.jks

其它

  1. 如果使用默认的证书库,则可以省略第2步。
  2. 使用默认的证书库时,在win10上导入证书遇到问题。具体原因不明。
  • 0
    点赞
  • 2
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值