--------------------sunkaikees@gmail.com-------------------

Java-Keytool

配置https或socket-ssl时等需要用到证书,如果公司没有正规证书,则需要生成自签名证书,以下介绍两种方法。我自己配置nginx https用openssl, socket 加入ssl用Java的keytool。

## java 证书工具keytool生成自签名证书和自签CA证书 

jdk自带的证书管理工具叫keytool,在jdk/bin目录下,可以用来生成自签名证书、导入导出证书、打印证书信息等。

### 1. 名词

自签名证书:用自己的私钥签发自己的公钥即主体信息生成的证书。
证书签名:对证书固定值进行hash后用密钥对中的私钥对hash值加密
keystore:  keytool生成证书的存储库,用来存储若干条目,每一条目包含公私钥,主体信息等。默认为用户目录下.keystore,相当于一个有密码保护的文件。
truststore: 与keystore格式相同,只是为区分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类的相关方法获取到公私钥信息,然后做加解密的验证等。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

## openssl生成证书

由于是给nginx配置https用的,我先在nginx目录下创建一个文件夹。

$sudo mkdir -p /etc/nginx/conf.d/ssl/
$cd /etc/nginx/config.d/ss

- 创建秘钥

openssl genrsa -des3 -out server1.key

输入123456密码创建一个rsa私钥。(此处des3与公私钥对无关。)可以打印查看以下对应的公钥。 openssl rsa -in server1.key -pubout 

- 创建请求文件

sudo openssl req -new -key server1.key -out server1.cs
输入密码123456后回车 依次填写主体信息,大部分可以直接回车略过
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:zhejiang
Locality Name (eg, city) []:hangzhou
Organization Name (eg, company) [Internet Widgits Pty Ltd]:flk
Organizational Unit Name (eg, section) []:flk-test
Common Name (e.g. server FQDN or YOUR name) []: // 这里可以填写服务器对应域名,否则浏览器警告
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

- 删除私钥中的密码

由于生成私钥时指定了des3密码,每次使用私钥都要输入密码,比较麻烦,这里删除掉。

openssl rsa -in server1.key -out server1.key

- 生成证书

openssl x509 -req -days 3650 -in server1.csr -signkey server1.key -out server1.crt

可以看到是用自己的私钥签发的主体信息。生成证书后可以删除crt了。

此时有私钥server1.key和自签名证书server1.crt。如果nginx代理https请求,只要指定此目录对应文件即可。

 

posted @ 2019-01-15 19:35  雪天微风吹  阅读(7625)  评论(0编辑  收藏  举报