Skip to content

Digital Certificate

downgoon edited this page Oct 17, 2017 · 3 revisions

数字证书 与 keystore 详解

密码在配置文件中明文存储不安全,于是JDK层面提供了keystore机制,它是一个特殊的文件,里面可以存储多个秘钥。为了保护信息安全,提供两级口令,一个是keystore文件级口令;另一个是秘钥口令(文件中可以存多个秘钥,每个秘钥可以有不同的口令)。

这个文件的后缀叫.jks,表示Java Key Store。管理它的工具叫keytool,JDK自带。

  • 秘钥:密码的高级形式。它的特点是:二进制不可显;很长。秘钥还分对称与非对称。
  • 证书:对于非对称的秘钥,私钥部分是不传递的,公钥是需要传播的。同时,公钥需要CA签名,被签名的公钥就是证书。

提供的功能

$ keytool

  // 创建秘钥,查看秘钥,删除秘钥
  -genkeypair         生成密钥对
  -delete             删除条目
  -list               列出密钥库中的条目
  -changealias        更改条目的别名

  // 两级口令管理:store级 与 key级
  -storepasswd        更改密钥库的存储口令
  -keypasswd          更改条目的密钥口令


  // 导入导出:Java领域 与 C领域互通
  -exportcert         导出证书
  -printcert          打印证书内容
  -importcert         导入证书或证书链  

  // CA给证书签名相关
  -certreq            生成证书请求
  -printcertreq       打印证书请求的内容
  -gencert            根据证书请求生成证书


  // 跟其他JKS互通
  -importkeystore     从其他密钥库导入一个或所有条目
 -genseckey          生成密钥
 -importpass         导入口令
 -printcrl           打印 CRL 文件的内容


使用 "keytool -command_name -help" 获取 command_name 的用法

演示操作

图中第4步,分发证书的passport.cer的时候,既可以从1步到第4步,通过CA签发;也可以直接自己导出证书,相当于自签发(只不过没有CA担保)。

秘钥实操

生成秘钥

downgoon站点的passport系统和livecam系统分别创建一个秘钥,并集中保存在downgoon.jks文件中:

keytool -genkey -alias passport -keystore downgoon.jks
keytool -genkey -alias livecam -keystore downgoon.jks

敲回车后,会有交互画面让输入各种信息。比如口令信息:

  • keystore 的口令:ks1234
  • passport 的口令:ppt123
  • livecam 的口令:lcm123

注意:

  • keytool -genkey等效于keytool -genkeypair

当然,也可以以非交互方式创建秘钥:

keytool -genkeypair -alias product -keypass pdt123 -keystore downgoon.jks -storepass ks1234 -validity 180 -dname "cn=downgoon Lee, ou=product, o=downgoon, c=CN"
  • 指定秘钥名字与口令: -alias product -keypass pdt123
  • 指定库文件与口令:-keystore downgoon.jks -storepass ks1234
  • 指定秘钥有效天数:-validity 180

帮助信息:

$ keytool -genkeypair --help
keytool -genkeypair [OPTION]...

生成密钥对

选项:

 -alias <alias>                  要处理的条目的别名
 -keyalg <keyalg>                密钥算法名称
 -keysize <keysize>              密钥位大小
 -sigalg <sigalg>                签名算法名称
 -destalias <destalias>          目标别名
 -dname <dname>                  唯一判别名
 -startdate <startdate>          证书有效期开始日期/时间
 -ext <value>                    X.509 扩展
 -validity <valDays>             有效天数
 -keypass <arg>                  密钥口令
 -keystore <keystore>            密钥库名称
 -storepass <arg>                密钥库口令
 -storetype <storetype>          密钥库类型
 -providername <providername>    提供方名称
 -providerclass <providerclass>  提供方类名
 -providerarg <arg>              提供方参数
 -providerpath <pathlist>        提供方类路径
 -v                              详细输出
 -protected                      通过受保护的机制的口令

显示列表

$ keytool -list -keystore downgoon.jks -storepass ks1234

product, 2017-10-17, PrivateKeyEntry,
证书指纹 (SHA1): 13:FD:C2:D3:0B:34:9E:3F:B8:CA:8E:90:AF:D5:40:E2:82:F7:7D:A2
passport, 2017-10-17, PrivateKeyEntry,
证书指纹 (SHA1): 0F:D3:E9:27:49:89:F7:BA:99:34:A3:DC:0F:09:C8:B2:73:EE:FC:3C
livecam, 2017-10-17, PrivateKeyEntry,
证书指纹 (SHA1): 2A:8C:CD:1C:A2:54:79:1F:C4:76:38:60:B8:2D:7B:28:8F:52:60:36

如果要详细显示,请用-v选项:

$ keytool -list -keystore downgoon.jks -storepass ks1234 -v

证书实操

导出证书

秘钥对既包含公钥,也包含私钥。但是安全通信过程中,需要把公钥部分,发布给合作方。于是我们需要从秘钥对中导出公钥。 举个例子,从downgoon.jks秘钥库中,导出passport的公钥,并输出到文件passport.cer

$ keytool -exportcert -alias passport -keystore downgoon.jks -file passport.cer
输入库口令:ks1234

查看证书

导出后,我们不放心,想肉眼查看一下,怎么打开passport.cer呢?

$ keytool -printcert -file passport.cer
  • 适合人类看的格式

输出信息:

$ keytool -printcert -file passport.cer
所有者: CN=Lee, OU=downgoon.com, O=downgoon, L=bj, ST=bj, C=CN
发布者: CN=Lee, OU=downgoon.com, O=downgoon, L=bj, ST=bj, C=CN
序列号: 7f41b1cd
有效期开始日期: Tue Oct 17 09:47:18 CST 2017, 截止日期: Mon Jan 15 09:47:18 CST 2018
证书指纹:
	 MD5: B4:6F:E6:52:BC:DF:E3:2E:CE:5E:6D:5C:AC:5D:80:E9
	 SHA1: 0F:D3:E9:27:49:89:F7:BA:99:34:A3:DC:0F:09:C8:B2:73:EE:FC:3C
	 SHA256: 68:BB:89:97:71:AD:09:76:0C:10:13:52:2A:25:47:66:30:2B:06:69:F2:BD:22:27:18:A8:D6:63:61:BF:29:26
	 签名算法名称: SHA1withDSA
	 版本: 3

扩展:

1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 2C 48 D5 1F F2 DE 25 80   25 3E DB 4F F2 DF D8 48  ,H....%.%>.O...H
0010: 80 23 64 AF                                        .#d.
]
]
  • 适合机器看的格式:RFC格式
$ keytool -printcert -file passport.cer -rfc
-----BEGIN CERTIFICATE-----
MIIDGzCCAtigAwIBAgIEf0GxzTALBgcqhkjOOAQDBQAwXzELMAkGA1UEBhMCQ04xCzAJBgNVBAgT
AmJqMQswCQYDVQQHEwJiajERMA8GA1UEChMIZG93bmdvb24xFTATBgNVBAsTDGRvd25nb29uLmNv
bTEMMAoGA1UEAxMDTGVlMB4XDTE3MTAxNzAxNDcxOFoXDTE4MDExNTAxNDcxOFowXzELMAkGA1UE
BhMCQ04xCzAJBgNVBAgTAmJqMQswCQYDVQQHEwJiajERMA8GA1UEChMIZG93bmdvb24xFTATBgNV
BAsTDGRvd25nb29uLmNvbTEMMAoGA1UEAxMDTGVlMIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/
U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00
b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith
1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmU
r7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOu
HiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQA
AoGAKKIKfCZ+AAcSco9MKnnorSc704+l79jYLF3eqgK2H4YkQPlfZMD4EPPlNMexXvwL/Gew6jGD
Kg1+EaHjTmsZuzC0gyBYVsh9WkqSL5cN9GMdfslCqH7ufrqmGPOgHZmBXTWqzIE1teJS+SwNBXeR
PHfZxFY+Ud9sa9VeF/9AM8OjITAfMB0GA1UdDgQWBBQsSNUf8t4lgCU+20/y39hIgCNkrzALBgcq
hkjOOAQDBQADMAAwLQIVAIn4KDCmnqwiKiVzc/3Yh6vo+YwxAhRy+mMJN6m+/5CfRlRmcgnQwxB6
mg==
-----END CERTIFICATE-----

导入证书

我们导出的证书,需要发给合作商,合作商则需要把我们的证书导入(这样合作商只知道我们的公钥,并不知道我们的私钥)。 加入我们的合作商是百度,那么我们模拟百度的行为,把passport.cer证书导入到baidu.jks文件中,并起名叫downgoon_passport

$ keytool -import -alias downgoon_passport -file passport.cer -keystore baidu.jks
输入库口令:bd1234
提示是否信任此证书?:yes

导入的时候,为什么会提示“是否信任此证书呢”? 因为这个证书没有被CA签名。 另外我们会发现,导入.cer文件的时候,并不需要key级口令。因为公钥本来就是公开的呀,没必要口令保护。

导入完成后,作为合作伙伴的百度,也可以查看一下:

$ keytool -list -keystore baidu.jks
输入密钥库口令: bd1234

密钥库类型: JKS
密钥库提供方: SUN

您的密钥库包含 1 个条目

downgoon_passport, 2017-10-17, trustedCertEntry,   (显示受信任的证书实体)
证书指纹 (SHA1): 0F:D3:E9:27:49:89:F7:BA:99:34:A3:DC:0F:09:C8:B2:73:EE:FC:3C

如果非交互的导入,可以:

keytool -import -alias downgoon_passport -file passport.cer -keystore baidu.jks -storepass bd1234 -v -trustcacerts -noprompt

注意两点:(1)-trustcacerts强制信任该证书,无论是否CA签名;(2)-noprompt不提示。

CA签名实操

前面说道,我们的passport.cer是没有被CA签名的。那么怎么让CA签名呢?很简单,你得先生成一个证书签名请求文件,拿着它和钱,给CA机构去签名,CA会返回我们一个 带有CA盖章 的证书文件。

为了不收钱,我们可以自己做CA。

模拟一个CA

模拟的CA叫myca

创建CA秘钥

keytool -genkeypair -alias rootkey -keypass rky123 -keystore myca.jks -storepass mc1234 -validity 180 -dname "cn=myca, ou=根秘钥, o=myca认证中心, c=CN"

生成证书签名请求

作为downgoon公司,不需要直接导出公钥了,而是需要导出证书的签名请求文件,以便拿去给CA机构签名:

  • 生成签名请求文件:passport.csr
keytool -certreq -alias passport -keypass ppt123 -keystore downgoon.jks -storepass ks1234 -file passport.csr
  • 对比直接导出证书
$ keytool -exportcert -alias passport -keystore downgoon.jks -storepass ks1234 -file passport.cer
  • 查看签名请求文件:passport.csr
$ keytool -printcertreq -file passport.csr

PKCS #10 证书请求 (版本 1.0)
主题: CN=Lee, OU=downgoon.com, O=downgoon, L=bj, ST=bj, C=CN
公共密钥: X.509 格式 DSA 密钥   (默认类型是DSA,不是RSA)

扩展请求:

1: ObjectId: 2.5.29.14 Criticality=false   (没有被签名)
SubjectKeyIdentifier [
KeyIdentifier [
0000: 2C 48 D5 1F F2 DE 25 80   25 3E DB 4F F2 DF D8 48  ,H....%.%>.O...H
0010: 80 23 64 AF                                        .#d.
]
]

CA签发证书

CA签发就是把downgoon公司提交过来的passport.csr,盖章后,输出passport.cer文件。下面我们扮演CA公司的操作员:

$ keytool -gencert -alias rootkey -keypass rky123 -keystore myca.jks -storepass mc1234 -infile passport.csr -outfile passport.cer

其中:

  • keytool -gencert 表示生成证书指令,是依据证书签名请求passport.csr文件来生成。
  • -infile passport.csr 指定证书签名请求文件是passport.csr
  • -outfile passport.cer 指定输出被CA签名的证书文件。

分发给申请方

作为申请方,我们可以查看下这个证书,到底有没有CA签名,我们执行查看证书指令:

$ keytool  -printcert -file passport.cer

显示的内容:

所有者: CN=Lee, OU=downgoon.com, O=downgoon, L=bj, ST=bj, C=CN
发布者: CN=myca, OU=根秘钥, O=myca认证中心, C=CN  (提示了证书签发机构)
序列号: 72010deb
有效期开始日期: Tue Oct 17 11:06:55 CST 2017, 截止日期: Mon Jan 15 11:06:55 CST 2018
证书指纹:
	 MD5: B6:38:AE:09:4E:07:00:06:8E:6D:CB:48:F3:00:7A:52
	 SHA1: D9:44:25:27:93:B7:33:A2:B1:B3:BD:D9:53:83:0E:85:31:C2:D9:85
	 SHA256: 17:19:7E:00:2A:66:0F:E2:EE:B1:DE:A0:11:10:F5:C2:41:66:E5:9A:52:37:BF:10:21:62:6B:2B:8D:73:94:13
	 签名算法名称: SHA1withDSA
	 版本: 3


   扩展:

   #1: ObjectId: 2.5.29.35 Criticality=false
   AuthorityKeyIdentifier [      (证书签发机构的公钥索引)
   KeyIdentifier [
   0000: 7D 26 51 F2 2C C7 88 F7   CC 70 3D DF 26 D7 93 72  .&Q.,....p=.&..r
   0010: 84 0D EC 0B                                        ....
   ]
   ]

   2: ObjectId: 2.5.29.14 Criticality=false
   SubjectKeyIdentifier [
   KeyIdentifier [
   0000: 2C 48 D5 1F F2 DE 25 80   25 3E DB 4F F2 DF D8 48  ,H....%.%>.O...H
   0010: 80 23 64 AF                                        .#d.
   ]
   ]

两个重要信息:

  • 发布者: CN=myca, OU=根秘钥, O=myca认证中心, C=CN
  • AuthorityKeyIdentifier 表示证书签发机构的公钥索引,证书接收方可以依据这个信息,去CA公司做鉴定。

我们可以对比,在第一章节,我们直接导出的,没有被CA签名的证书:

$ keytool  -printcert -file passport.cer.unsign
所有者: CN=Lee, OU=downgoon.com, O=downgoon, L=bj, ST=bj, C=CN
发布者: CN=Lee, OU=downgoon.com, O=downgoon, L=bj, ST=bj, C=CN
序列号: 7f41b1cd
有效期开始日期: Tue Oct 17 09:47:18 CST 2017, 截止日期: Mon Jan 15 09:47:18 CST 2018
证书指纹:
	 MD5: B4:6F:E6:52:BC:DF:E3:2E:CE:5E:6D:5C:AC:5D:80:E9
	 SHA1: 0F:D3:E9:27:49:89:F7:BA:99:34:A3:DC:0F:09:C8:B2:73:EE:FC:3C
	 SHA256: 68:BB:89:97:71:AD:09:76:0C:10:13:52:2A:25:47:66:30:2B:06:69:F2:BD:22:27:18:A8:D6:63:61:BF:29:26
	 签名算法名称: SHA1withDSA
	 版本: 3

扩展:

1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 2C 48 D5 1F F2 DE 25 80   25 3E DB 4F F2 DF D8 48  ,H....%.%>.O...H
0010: 80 23 64 AF                                        .#d.
]
]

相比之下,就是缺少刚才的两个东西。

生产注意事项

系统层面证书管理工具

操作系统层面,一般都有一个集中管理证书的:比如window以IE为入口;mac以safari为入口。在Mac下,以Mac工具打开passport.cer证书文件:

这个功能就好比:keytool -printcert

为什么有了系统级的,Java还要搞自己的呢?因为Java定位是跨平台的。自然不能依赖某个操作系统的证书管理。

为什么这个证书虽然有CA签发,但是依然会警告呢?因为CA本身就不被系统证书管理工具信任。免费的CA,且被大多数系统信任的有:letsencryt

更换RSA算法

默认生成的是DSA算法,可以选RSA算法。

增加选项参数:-keyalg RSA -keysize 1024,秘钥长度可以调整为:512或2048等。

参考资料

http://blog.csdn.net/fengwind1/article/details/52191520