jdk自带的证书管理工具叫keytool,在jdk/bin目录下,可以用来生成自签名证书、导入导出证书、打印证书信息等。
1. 名词
自签名证书:用自己的私钥签发自己的公钥即主体信息生成的证书。
证书签名:对证书固定值进行hash后用密钥对中的私钥对hash值加密
keystore: keytool生成证书的存储库,用来存储若干条目,每一条目包含公私钥,主体信息等。默认为用户目录下.keystore,相当于一个有密码保护的文件。
truststore: 与keystore格式相同,但是为区分只用来存放信任的证书,不存密钥等信息。
der:证书编码格式,证书结构体转换为二进制格式。
pem:证书编码格式,对der二进制编码的base64字符,包含---begin---,----end----。// 命令中加-rfc可打印和生成此类文件
.csr:证书请求文件格式,包含公钥和主体信息,发给ca,ca用私钥对内容签名并制作成证书返回。keytool在生成csr文件时需要指定证书(即公钥与主体信息)。
.crt:一般用于linux系统的证书格式,包含公钥和主体信息。
.cer:一般用于windows的证书文件格式,包含公钥和主体信息。
.p12:证书交换格式,包含公钥私钥(私用密码加密),用于交换传输。
2.具体使用
可以以一个完整例子来了解keytool命令。在socket或http协议传输数据时,如需加密传输会话内容,会在TCP上加上ssl/tls,http则改为https协议。此时服务端需要给客户端提供证书以供客户端验证并协商会话密钥,如果没有正规CA签发的证书,则需自签名。
客户端用签发证书的根证书验证,如果是自签名一级证书,则客户端需内置此自签名证书,如果是自签名二级证书,则用签发它的跟证书验证
- 生成自签名证书
keytool -genkeypair -alias golove -keysize 2048 -keyalg RSA -validity 3650 -keystore teststore.jks -storetype JKS
- genkeypair:生成公私钥对条目,私钥不可见,公钥会以证书格式保存在keystore中。
- alias: 指定别名,区分不同条目,默认mykey
- keysize: 密钥长度
- keyalg: 公私钥算法
- validity: 证书过期时间
- keystore: 指定存储密钥库,若不存在会创建,若指定则在当前文件夹下生成。默认密钥库为用户目录下.keystore文件
- storetype: 密钥库类型 JKS PKCS等
输入密钥库密码和本条目密码都为123456,以及其他主体信息会生成密钥对保存在teststore.jks中。公钥以证书格式保存,带有主体信息。此时证书库中可以看到公钥信息(私钥无法打印)
第一条主体信息:您的姓名与姓氏中填入服务器域名的完整信息而非name,如:www.golove.com。
- 导出自签名证书
// 如果要生成pem编码格式的证书直接加上 -rfc参数即可,证书详细信息格式用 -v
keytool -export -alias golove -keystore teststore.jks -file golove.crt
现在可以将此证书分发给客户端了,客户端做相应配置,验证域名或直接跳过验证(因为是用它自身公钥验证,不能保证安全性,一般默认信任),使用此证书与服务端交换随机数。
接下来稍微了解下keystore内容并生成一个跟证书来签发二级证书。
- 查看keystore中证书条目列表
keytool -list -v -keystore teststore.jks
再看下刚才根据此条目导出的自签证书,导出后已经包含了公钥等其他信息形成了完整证书,但注意verifiedby字段还是自己
- 生成证书签名请求(CSR文件)
keytool -certreq -alias golove -keystore teststore.jks -file temp_go_love.csr
用keystore中golove条目生成了证书签名请求文件temp_go_love.csr,内包含golove条目的公钥和主体信息,将证书签名请求文件发给正规CA,CA用私钥对公钥和信息签名后制作成证书文件返回就可以使用了。正规CA的公钥浏览器内置,所以此时浏览器可以验签名成功。
但我们要自己模拟CA签发二级证书,CA也是要有公私钥对,所以先生成CA密钥对。
- 生成一个自签名证书作为CA根证书,名字与姓氏选项这里填入root
keytool -genkeypair -alias rootca -keysize 2048 -keyalg RSA -validity 3650 -keystore teststore.jks -storetype JKS
-使用CA证书给golove证书签名,即用CA的私钥签名后与golove的公钥生成一个证书
keytool -gencert -alias rootca -keystore teststore.jks -infile temp_go_love.csr -outfile golove_new.crt
此时已经生成了一个golove_new.crt的二级证书,以文件形式打开golove.crt和golove_new.crt两个证书文件对比下内容。
golove.crt:
golove_new.crt:
可以看到签发者已经变成root,公钥等其他信息不变,但签名值变了,说明已经用新的私钥(root私钥)替换原有(golove)签名,在证书信任连上序号为2,此即二级证书。
- 将二级证书导回teststore库中,并且直接替换原有别名为golove的条目
keytool -import -v -alias golove -file golove_new.crt -keystore teststore.jks
再次打印证书库中条目列表可以看到别名为golovet的条目证书链变为2,发布者变为root.
此时可以将root证书导出给客户端内置,服务端绑定二级证书,这样客户端验证时可以用根证书验证二级证书。其实大部分程序直接使用一级的自签名证书即可,但若需要双向验证,服务端验证客户端时不同客户端最好使用服务端的rootca私钥来签发,这样服务端可以直接用一个rootca的证书验证。实现了动态扩展且客户端的证书不同。
-为了区分teststore,可以新建一个只放信任证书,不存储密钥的仓库。将刚才的rootca证书和golove二级证书导入一个新仓库(如果为了方便,也可以直接用一个密钥库,不需要此库)
// 从teststore导出rootca证书
keytool -export -alias rootca -keystore teststore.jks -file rootca.crt
// 导入rootca证书到新库
keytool -import -v -file rootca.crt -alias rootca -keystore truststore.jks
// 导入golove证书到新库
keytool -import -v -file golove_new.crt -alias golove -keystore truststore.jks
keytool 常用命令:
// 以rfc模式打印,即base64可见字符,与pem编码格式一样。 -v为详细输出
keytool -printcert -rfc -file rootca.ctr
// 查看证书库中证书条目列表 详细信息
keytool -list -v -keystore teststore.jks
// 将证书库中的条目导出为证书文件,如要生成可见字符编码格式的证书文件 加上 -rfc 参数即可。
keytool -export -alias rootca -keystore teststore.jks -file rootca.ctr
// 删除密钥库中的条目
keytool -delete -alias rootca -keystore teststore.keystore
// 修改证书库密码,输入旧密码或加参数 -storepass 111111
keytool -storepasswd -new 123456 -keystore truststore
// 修改某条目密码
keytool -keypasswd -alias myCA -keypass 654321 -new newpass -storepass 123456 -keystore myCALib
还有一个问题,keytool不能打印出密钥对中的私钥,用-list查看密钥库列表也没有完整的私钥信息。要获取私钥,可以在java程序中加载密钥库,用jdk KeyStore类的相关方法获取到公私钥信息,然后做加解密的验证等。
有不对的地方请指出...