发布于 

Java导入信任证书

问题背景

在使用SSL连接时,应用程序如果遇到不信任的证书,一般会拒绝连接。当我们使用浏览器访问此应用程序的时候,我们可以在浏览器的设置中导入证书,把证书加入到信任列表中从而实现访问。而在Java中,我们没有界面去导入这个信任证书,Java在进行不信任的连接时,会报如下错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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:439)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306)
at sun.security.validator.Validator.validate(Validator.java:271)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:312)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:221)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:128)
at sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:636)
at sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:471)
at sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:367)
at sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:376)
at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:479)
at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:457)
at sun.security.ssl.TransportContext.dispatch(TransportContext.java:200)
at sun.security.ssl.SSLTransport.decode(SSLTransport.java:154)
at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1290)
at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1199)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:401)
at sun.security.ssl.SSLSocketImpl.ensureNegotiated(SSLSocketImpl.java:819)
at sun.security.ssl.SSLSocketImpl.access$200(SSLSocketImpl.java:75)
at sun.security.ssl.SSLSocketImpl$AppOutputStream.write(SSLSocketImpl.java:1104)
at sun.security.ssl.SSLSocketImpl$AppOutputStream.write(SSLSocketImpl.java:1076)
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:434)
... 21 more

判断方式

在上方我通过java SSLPoke {url} {port}方式去检验我们的Java环境是否包含对应的信任证书访问到HTTPS,IMAPS,LADPS等,具体的使用方式如下:

  • 下载 SSLPoke.class

  • 运行java SSLPoke {url} {port}

    如果连接成功,则会提示Successfully connected

    如果连接失败,则会提示问题背景中图片展示的错误信息

解决方法

通过java提供的keytool工具帮助我们导入信任证书

keytool基本使用

创建证书库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
keytool -genkeypair -keyalg RSA -alias thekeystore -keystore keystore.jks -storepass changeit -keysize 2048
What is your first and last name?
[Unknown]: localhost # 此处一般是域名,本机开发就是localhost
What is the name of your organizational unit?
[Unknown]: Development Dept.
What is the name of your organization?
[Unknown]: Example
What is the name of your City or Locality?
[Unknown]: Beijing
What is the name of your State or Province?
[Unknown]: Beijing
What is the two-letter country code for this unit?
[Unknown]: CN
Is CN=localhost, OU=Development Dept., O=Example, L=Beijing, ST=Beijing, C=CN correct?
[no]: yes
  • -genkeypair生成密钥对
  • keyalg RSA使用RSA算法
  • -alias thekeystore给密钥库起别名
  • -keystore keystore.jks给生成的秘钥文件起别名
  • -storepass changeit密钥库的密码,默认情况下为changeit
  • -keysize 2048密钥长度
  • -validity 360(本例中没有,但可以加)

查看证书库信息

1
keytool -list -keystore thekeystore # 通过证书库名称查看证书库信息
1
keytool -lsit -keystore keystore.jks # 通过生成的证书库文件查看证书库信息

证书库文件格式转换

将jks文件转化为crt文件,然后就可以导入java的cacerts文件中了

1
keytool -export -alias thekeystore -file keystore.crt -keystore keystore.jks

导入到JRE证书文件

jre的位置不同系统不同版本的位置都不一样

1
keytool -import -alias thekeystore -file keystore.crt ${JRE_HOME}/security/cacerts

导入后Java就可以使用该证书了

使用openssl获取别人的证书文件

获取别人的证书文件

此处以google.com为例,实际中将google换成想要获取证书的域名即可,获取证书后可以通过上述keytool基本使用中最后的导入证书库操作

Unix方式:

1
openssl s_client -connect google.com:443 < /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > public.crt

Windows方式:

1
openssl s_client -connect google.com:443 < NUL | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > public.crt



Copyright © 2023 ChenWei | Powered By Stellar
本站已运行 00 小时 00