tomcat双向认证
数字证书相关的标准和协议
参考:https://en.wikipedia.org/wiki/PKCS
关键词 | 描述 |
---|---|
PEM | PKIX, PKCS, and CMS 结构的文本编码格式。PEM最早是基于“隐私增强邮件”的1993年IETF标准集的用于存储和发送加密密钥,证书和其他数据的事实上的文件格式。 原标准未被采用,但其定义的文本编码非常受欢迎,最终由IETF在RFC 7468中形式化。参考:https:tools.ietf.org/html/rfc7468 |
DER | 可区分编码规则 (Distinguished Encoding Rules) 。可包含所有私钥、公钥和证书。它是大多数浏览器的缺省格式,并按 ASN1 DER 格式存储。它是无报头的(PEM 是用文本报头包围的 DER)。一般使用".cer"做文件后缀 |
JKS | 通常可以将Apache/OpenSSL使用的“KEY文件 + CRT文件”格式”转换为标准的Java Key Store(JKS)文件。一般以".keystore"作为文件后缀。 |
CSR | 证书签名请求(Certificate Signing Request)。发送给CA签名的请求内容标准,一般存储在一个".csr"后缀的文件中。 |
CRT | 证书文件一般以".crt"作为文件后缀。 |
KEY | PEM格式的私钥文件一般以".key"作为文件后缀。 |
CRL | 证书吊销列表 (Certification Revocation List) 。 |
PKCS7 | 加密消息语法标准。(参考:https:www.ietf.org/rfc/rfc2315.txt) |
PKCS12 | 个人信息交换语法标准。定义了一个通用的文件格式标准,用于存储附带公钥证书的私钥,并使用基于密码的对称密钥加密。前身是PFX。一般以".p12"作为文件后缀。 |
X.509 | 公钥证书标准 |
生成证书
使用java自带的keytool工具生成证书。如果文章中有哪些参数不明白的可以参考keytool官方文档
前期规划
涉及的名称比较多,先规划一下,后面会作说明(以下数据纯属测试,如有雷同,请知会)。
组织机构(公司名称):XTBaBa 组织机构部门:XTBaBa CA 根证书名称:XTBaBa Root CA 域名:a.xtbaba.com | b.xtbaba.com
服务端证书密钥库:tomcat.keystore
服务端信任证书列表密钥库:tomcat_trust.keystore
根证书密钥库:root.keystore
客户证书:xiaotian.p12
根证书在密钥库中的别名:root 所有密钥库&密钥的密码:123456
知识扫盲
- keytool 是java自带的提供生成证书、数字签名等功能的小工具
- keytool 生成的密钥库
不能导出非对称算法的私钥
- keytool 导入公钥证书时,如果别名(alias)相同,则认为导入的是CA签名后的证书
- https 单向认证指客户端验证服务端身份,我们平常见的https站点,都属于
单向认证
双向认证
时,浏览器会让用户选择一个证书传递给服务器,由服务器核验客户的证书
更多知识,请参考keytool官方文档
生成根证书
1
2
3
4# 生成根证书密钥对并保存到tomcat.keystore密钥库中
keytool -genkeypair -keystore root.keystore -storepass 123456 -keyalg RSA -keypass 123456 -alias root -dname "CN=XTBaBa Root CA, OU=XTBaBa CA, O=XTBaBa, L=Hangzhou, S=Zhejiang, C=CN"
# 导出根证书
keytool -exportcert -keystore root.keystore -storepass 123456 -file root.crt -alias root -v
客户需要将root.crt
导入到操作系统的受信任的根证书颁发机构
证书分类中,否则 https 单向认证不通过
生成服务端证书
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# 生成服务端证书密钥对
keytool -genkeypair -keystore tomcat.keystore -storepass 123456 -keyalg RSA -keypass 123456 -alias xtbaba_site -dname "CN=XTBaBa Customer Site, OU=XTBaBa RD, O=XTBaBa, L=Hangzhou, S=Zhejiang, C=CN"
# 生成服务端证书签名请求
keytool -certreq -keystore tomcat.keystore -storepass 123456 -alias xtbaba_site -file xtbaba_site.csr
# 使用根证书对服务端证书签名,签名时指定了两个域名
keytool -gencert -keystore tomcat.keystore -storepass 123456 -alias root -infile xtbaba_site.csr -outfile xtbaba_site.cer -ext "san=dns:a.xtbaba.com,dns:b.xtbaba.com" -ext eku="serverAuth,clientAuth"
# 将根证书临时导入到tomcat.keystore密钥库中
keytool -importkeystore -srckeystore root.keystore -srcstorepass 123456 -srcalias root -destkeystore tomcat.keystore -deststorepass 123456 -destalias root
# 将签名后的服务端证书导入到服务端密钥库
keytool -import -keystore tomcat.keystore -storepass 123456 -file xtbaba_site.cer -alias xtbaba_site
# 移除根证书,切记移除掉啊
keytool -delete -keystore tomcat.keystore -storepass 123456 -alias root
生成客户证书
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19# 生成客户证书密钥对,客户证书需要使用"PKCS12"格式
keytool -genkeypair -keystore xiaotian.p12 -storepass 123456 -storetype PKCS12 -keyalg RSA -keypass 123456 -alias xiaotian -dname "CN=Xiaotian, OU=XTBaBa User, O=XTBaBa, L=Hangzhou, S=Zhejiang, C=CN"
# 生成客户证书签名请求
keytool -certreq -keystore xiaotian.p12 -storepass 123456 -alias xiaotian -file xiaotian.csr
# 使用根证书对客户证书签名
keytool -gencert -keystore root.keystore -storepass 123456 -alias root -infile xiaotian.csr -outfile xiaotian.cer -ext eku="serverAuth,clientAuth"
# 导入签名后的客户证书到密钥库
# 1. 首先将根证书导入到客户证书密钥库中
keytool -importkeystore -srckeystore root.keystore -srcstorepass 123456 -srcalias root -destkeystore xiaotian.p12 -deststorepass 123456 -destalias root
# 2. 将签名后的客户证书导入到客户证书密钥库中。导入签名后的证书时,keytool要从密钥库中找到一个证书来验证该签名,所以必须将根证书临时导入到客户证书密钥库中。
keytool -import -keystore xiaotian.p12 -storepass 123456 -file xiaotian.cer -alias xiaotian
# 3. 从客户证书密钥库中移除根证书。千万别把根证书发给用户了
keytool -delete -keystore xiaotian.p12 -storepass 123456 -alias root
- 导入签名后的证书时,keytool要从密钥库中找到一个证书来验证该签名,所以必须将根证书临时导入到客户证书密钥库中
- 生成完毕后,将 xiaotian.p12 文件发送给客户,客户将该证书导入操作系统的证书库即可(一般导入在个人证书分类里)。
- 给客户生成完证书后,一定要从 xiaotian.p12 中删除根证书,千万别把根证书发给用户了
将客户证书添加到服务端的信任证书密钥库
1
2
3
4
5# 导入根证书
keytool -importkeystore -srckeystore root.keystore -srcstorepass 123456 -srcalias root -destkeystore tomcat_trust.keystore -deststorepass 123456 -destalias root
# 导入客户证书
keytool -import -keystore tomcat_trust.keystore -storepass 123456 -file xiaotian.cer -alias xiaotian
必须将根证书导入到
tomcat_trust.keystore
密钥库中,tomcat将用此根证书来验证浏览器提交的根证书
keytool 其它常用命令
1
2
3
4
5# 查看密钥库中的所有密钥
keytool -list -keystore tomcat.keystore -storepass 123456 -v
# 查看证书内容
keytool -printcert -file xiaotian.cer
配置tomcat
修改server.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<!- 设置端口为80,redirectPort 重定向到https端口 -->
<Connector port="80" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="443" />
<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="100"
scheme="https"
secure="true"
SSLEnabled="true"
keyAlias="xtbaba_site"
keystoreFile="D:/www/keys/tomcat.keystore"
keystorePass="123456"
truststoreFile="D:/www/keys/tomcat_trust.keystore"
truststorePass="123456"
clientAuth="true"
sslProtocol="TLS"
/>
xml文件配置说明:
protocol
必须配置为org.apache.coyote.http11.Http11NioProtocol
keyAlias
服务器证书别名keystoreFile
服务器证书密钥库keystorePass
服务器证书密钥库密码truststoreFile
服务器信任证书列表密钥库truststorePass
服务器信任证书列表密钥库密码clientAuth
客户端认证:true
:客户端必须提供证书;false
:客户端不必提供证书;want
:客户端提不提供证书都可以
sslProtocol
SSL协议
读取客户证书内容
maven依赖配置:
1
2
3
4
5
6<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-coyote</artifactId>
<version>7.0.8</version>
<scope>provided</scope>
</dependency>
通过HttpServletRequest提取证书内容时需要依赖tomcat-coyote
jar包,该jar包由tomcat提供,必须指定scope
为provided
。否则运行时会报错(报错内容为找不到SSLSupport
)。java代码如下:
1
2
3
4
5
6
7
8
9
10
11X509Certificate[] certificates = (X509Certificate[]) request.getAttribute(SSLSupport.CERTIFICATE_KEY);
if(certificates != null && certificates.length > 0){
X509Certificate certificate = certificates[0];
logger.debug("使用者唯一名称 = {}", certificate.getSubjectDN());
logger.debug("颁布者唯一名称 = {}", certificate.getIssuerDN());
logger.debug("证书序列号 = {}", certificate.getSerialNumber());
logger.debug("证书类型 = {}", certificate.getType());
logger.debug("证书有效期 : {}", DateFormatUtils.format(certificate.getNotBefore(), "yyyy-MM-dd HH:mm:ss.SSS"),
DateFormatUtils.format(certificate.getNotAfter(), "yyyy-MM-dd HH:mm:ss.SSS"));
logger.debug("证书签名 = {}", Hex.encodeHexString(certificate.getSignature()));
}
运行结果:
1
2
3
4
5
62017-07-04 18:14:29.480 HomeController - 使用者唯一名称 = CN=Xiaotian, OU=XTBaBa User, O=XTBaBa, L=Hangzhou, ST=Zhejiang, C=CN
2017-07-04 18:14:29.480 HomeController - 颁布者唯一名称 = CN=XTBaBa Root CA, OU=XTBaBa CA, O=XTBaBa, L=Hangzhou, ST=Zhejiang, C=CN
2017-07-04 18:14:29.480 HomeController - 证书序列号 = 1327706204
2017-07-04 18:14:29.480 HomeController - 证书类型 = X.509
2017-07-04 18:14:29.480 HomeController - 证书有效期 = 2017-07-04 15:46:18.000
2017-07-04 18:14:29.920 HomeController - 证书签名 = 9c2fc47626621378f0f47d62e2b337265d3042495a259b5230ea2336ec990e9e2073fa817f2bb3d72a64565601b5f0171c77685d3ca616df4fcc46b8d6c4aed0101c21e0eaa22fd747b311eea5a781f721d47d621b0543bc3de442830e1c34a272b7960a97766df23f7955c6bdbf13013cf76b9e4233270ad78514d3afc59d442e4298b4fb2c19ab656a38d41ace261f24f4ba63e14c9d368aa7393b808b91ca19115c6578903bfeb3feb3173d68ff