signed

QiShunwang

“诚信为本、客户至上”

【keytool】How to solve javax.net.ssl.SSLHandshakeException Error?

2021/3/20 23:09:03   来源:

一、背景

 

环境中一个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

 

 

二、问题解析

 

本质上,是java在访问https资源时的证书信任问题。如何解决这个问题呢?

 

为何有这个问题?

解决这个问题前,要了解https通信过程:

 

1) 客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤,如图所示:

(1)客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。

(2)Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。

(3)客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。

(4)客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。

(5)Web服务器利用自己的私钥解密出会话密钥。

(6)Web服务器利用会话密钥加密与客户端之间的通信。

 

2)java程序的证书信任规则

如上文所述,客户端会从服务端拿到证书信息。调用端(客户端)会有一个证书信任列表,拿到证书信息后,会判断该证书是否可信任。

如果是用浏览器访问https资源,发现证书不可信任,一般会弹框告诉用户,对方的证书不可信任,是否继续之类。

Java虚拟机并不直接使用操作系统的keyring,而是有自己的security manager。与操作系统类似,jdk的security manager默认有一堆的根证书信任。

如果你的https站点证书是花钱申请的,被这些根证书所信任,那使用java来访问此https站点会非常方便。但是,如果你的证书是自签的或者不是权威CA签发的,那么用java访问https资源,发现证书不可信任,则会报文章开头说到的错误。

 

CentOS7.x的证书相关目录

  JRE的证书相关目录

 

三、解决问题的方法

 

1)将证书导入到jdk的信任证书中

2)在客户端(调用端)添加逻辑,忽略证书信任问题

 

从运维角度,此处我们选择将站点的证书导入到jdk的信任证书中

我们以站点 简书 www.jianshu.com 为例 

 

这里证书链上有三条,我们分别导出Base64编码文本

 

分别导出命名如下

 

将三个文件上传到jre所在的服务器

 

 

# export LANG="en_US.UTF-8"

# keytool -import -file 111.cer -alias 111 -keystore $JAVA_HOME/jre/lib/security/cacerts --storepass "changeit" --noprompt

# keytool -import -file 222.cer -alias 222 -keystore $JAVA_HOME/jre/lib/security/cacerts --storepass "changeit" --noprompt

# keytool -import -file 333.cer -alias 333 -keystore $JAVA_HOME/jre/lib/security/cacerts --storepass "changeit" --noprompt

导入的证书条目,用alias别名唯一区分,注意定义一个有意义的别名

 

 

四、JRE 证书库的查看和删除

 

查看

# keytool -list -rfc -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass "changeit" 

 

删除

# keytool -delete -alias 111 -keystore $JAVA_HOME/jre/lib/security/cacerts --storepass "changeit"

# keytool -delete -alias 222 -keystore $JAVA_HOME/jre/lib/security/cacerts --storepass "changeit"

# keytool -delete -alias 333 -keystore $JAVA_HOME/jre/lib/security/cacerts --storepass "changeit"

 

 

五、参考

 

How are SSL certificate server names resolved/Can I add alternative names using keytool?

证书服务器的名称是怎样解析的?

https://stackoverflow.com/questions/8443081/how-are-ssl-certificate-server-names-resolved-can-i-add-alternative-names-using/8444863#8444863

 

javax.net.ssl.SSLHandshakeException: No appropriate protocol

https://stackoverflow.com/questions/41101789/javax-net-ssl-sslhandshakeexception-no-appropriate-protocol

 

How to solve javax.net.ssl.SSLHandshakeException Error?

https://stackoverflow.com/questions/6659360/how-to-solve-javax-net-ssl-sslhandshakeexception-error

 

How to bypass javax.net.ssl.SSLHandshakeException

https://ananich.pro/2020/06/how-to-bypass-javax-net-ssl-sslhandshakeexception

 

java在访问https资源时,忽略证书信任问题

https://blog.csdn.net/lizeyang/article/details/18983843

 

无私钥情况下转换pem格式证书为jks格式

https://blog.csdn.net/carcoon/article/details/106133668

 

OpenSSL Certificate Authority

https://jamielinux.com/docs/openssl-certificate-authority/index.html

 

如何将PEM证书转换成JKS证书

https://biteeniu.github.io/ssl/convert_pem_to_jks