使用keytool模拟CA证书颁发过程

本章是HTTPS那些事儿的第四篇文章,其他相关文章请参见:前言
本篇主要介绍怎么使用jdk中的keytool工具模拟HTTPS证书颁发,通过该工具我们可以模拟CA证书的申请过程,CA证书的申请步骤可以参见本系列的第一篇文章HTTPS基础

* 注意

本文纯手工打造,转载请注明出处。

首先,要模拟CA证书的颁发过程以及验证CA证书的有效性,需要定义三个主体对象:CA机构,服务器SERVER和客户端Client,后续我们将依次描述三个主体在该过程中所需要做的工作。

1. 模拟CA机构

作为一个CA机构,我们需要有自己的公私钥:ca.pub和ca.pri。有了公钥后,CA需要将公钥封装成证书(包含公钥和CA本身信息)并发布出去,所有信任该CA机构的客户端会将该证书安装到其信任证书列表中。
下面,我们通过A、B两步来生成CA机构的证书。

A). 生成CA公私钥文件

如果使用keytool生成证书,只会先生成一个同时包含公私钥以及CA本身信息的文件:MyCA.jks,但生成后可以导出CA机构的证书:MyCA.crt。此处的MyCA代表我们模拟的CA机构的名字

keytool -genkeypair -keyalg RSA -keysize 2048 -keystore MyCA.jks -alias MyCA

该命令指定生成一个公私钥对,使用RAS算法,key长度为2048,生成到文件MyCA.jks中,文件中保存的公私钥对的名称为MyCA。使用该命令后会提示输入MyCA本身信息,如下:

Enter keystore password:  
Re-enter new password: 
What is your first and last name?
  [Unknown]:  myca
What is the name of your organizational unit?
  [Unknown]:  mallen's ca          
What is the name of your organization?
  [Unknown]:  mallen
What is the name of your City or Locality?
  [Unknown]:  chengdu
What is the name of your State or Province?
  [Unknown]:  sichuan
What is the two-letter country code for this unit?
  [Unknown]:  CN
Is CN=myca, OU=mallen's ca, O=mallen, L=chengdu, ST=sichuan, C=CN correct?
  [no]:  y
Enter key password for <MyCA>
    (RETURN if same as keystore password):

首先要求输入keystore文件,也就是MyCA.jks文件的访问密码。然后,输入first and last name。再之后输入单位、部门、城市、省份、国家编码,然后要求确认是否正确,最后再输入MyCA私钥的加密密钥,直接回车,使用keystore文件密钥即可。
密钥对文件生成后,可以通过如下命令查看文件内容:

keytool -list -v -keystore MyCA.jks

输入密码后,查看到的内容如下:

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: myca
Creation date: Sep 6, 2018
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=myca, OU=mallen's ca, O=mallen, L=chengdu, ST=sichuan, C=CN
Issuer: CN=myca, OU=mallen's ca, O=mallen, L=chengdu, ST=sichuan, C=CN
Serial number: 4385a752
Valid from: Thu Sep 06 14:59:31 CST 2018 until: Wed Dec 05 14:59:31 CST 2018
Certificate fingerprints:
     MD5:  6E:2F:7E:C0:FA:78:53:95:FD:1C:4D:5C:53:BF:92:30
     SHA1: CD:4E:FF:AA:91:7E:68:AD:24:39:2E:9F:1E:70:85:54:03:63:F6:A2
     SHA256: E8:85:FA:33:85:B7:E9:FE:96:BD:5E:80:CF:00:F6:B5:4A:EA:2D:F7:47:B7:81:3B:60:DF:79:1D:5E:9E:EA:A0
     Signature algorithm name: SHA256withRSA
     Version: 3

Extensions: 

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 61 30 66 A2 7F B6 F1 B5   EA A1 D6 31 1B A5 DC 60  a0f........1...`
0010: 25 9E 04 28                                        %..(
]
]



*******************************************
*******************************************

B) 提取CA的公钥文件

拥有了CA公私钥文件之后,可以提取出CA的证书文件,该文件用户客户端校验服务器端证书时的密钥。后续会介绍怎么使用,提取命令如下:

keytool -exportcert -keystore MyCA.jks -alias MyCA -file MyCA.crt

该命令指定从MyCA.jks密钥对文件中获取名称为MyCA的密钥对的公钥,并将公钥写入到MyCA.crt中。

2. 模拟服务器SERVER

同样,每个Server也会有自己的公私钥:server.pub和server.pri。也需要首先生成公私钥对:

keytool -genkeypair -alias myserver -keyalg RSA -keysize 2048 -keystore MyServer.jks

该命令指定生成一个公私钥对,使用RAS算法,key长度为2048,生成到文件MyServer.jks中,公私钥对的名称为myserver。
后续的输入与生成MyCA.jks一致,但是需要注意的是在What is your first and last name?这一项,作为服务器应该填写服务器的域名,比如www.baidu.com或者*.baidu.com。jdk中,在验证服务器端证书时,首先会取该字段来与当前访问的地址做对比,如果一致才能进入真正的证书验证阶段。
作为测试,建议此处输入localhost,在后续访问时同样使用localhost访问。如果后续方式需要使用ip,此处请输入ip。

3. 证书申请请求

Server有了公私钥对后,便可发起证书申请。证书申请时,需要提交证书申请文件,该文件一般称为CSR文件。生成该文件的命令如下:

keytool -certreq -alias myserver -keystore MyServer.jks -file MyServer.csr

该命令根据MyServer.jks公私钥对生成证书申请文件MyServer.csr,该文件生成后,便可提交到CA机构进行证书的申请。

4. CA颁发证书

CA机构接收到MyServer的证书申请请求时,校验MyServer身份通过后,就可以使用自己的私钥对证书进行认证(签名),命令如下:

keytool -gencert  -alias MyCA -keystore MyCA.jks -infile MyServer.csr -outfile MyServer.crt

该命令使用CA的公私钥对文件MyCA.jks对证书申请文件MyServer.csr进行签名,最终生成MyServer的CA证书文件MyServer.crt。

5. 导入Server证书

CA机构为MyServer颁发认证认证书MyServer.crt后,MyServer即可将证书文件导入到自己的证书库MyServer.jks中,导入命令如下:

keytool -import -alias myserver -file MyServer.crt -keystore MyServer.jks -trustcacerts

该命令会将MyServer.crt证书文件导入到MyServer.jks证书库中,需要注意的是,此处的alias必须与服务器公私钥对名称保持一致,也就是必须为myserver。
但在导入时,会报错:

keytool error: java.lang.Exception: Failed to establish chain from reply

该错误表示证书链不能建立,其原因是由于在导入MyServer.crt证书时会对其签名做验证,以便确认是由信任机构CA颁发的。但是,由于SERVER端当前并未将MyCA的证书导入到的信任证书列表中,导致抛出该错误。因此,需要将MyCA.crt导入到受信任的证书列表中。可以直接将MyCA.crt导入到$JAVA_HOME/jre/lib/security/cacerts文件中。命令为:

keytool -import -alias MyCA -file MyCA.crt -keystore $JAVA_HOME/jre/lib/security/cacerts

导入之后,再运行导入MyServer.crt证书的命令即可成功导入。导入时需要输入cacerts的密码,默认密码为changeit。
由该错误原因可知,哪怕对于权威的CA机构,如果CA结构的公开证书没有安装到本地,同样会报该错误。

6. 配置tomcat

其实前面5步就已经完成证书颁发过程了,但是为了验证证书的颁发过程没有问题,我们还需要将MyServer.crt使用起来。此处我们服务器端使用tomcat来提供HTTPS服务,需要进行如下配置:
打开tomcat的配置文件$CATALINA_HOME/conf/server.xml,打开https的配置,填入证书文件地址、密码和证书名称,修改后的内容如下:


tomcat https配置

修改完成,保存启动tomcat即可。

  • TIPS:如果需要查看tomcat的SSL日志,可以通过配置项javax.net.debug来开启。只需要在bin目录下创建一个setenv.sh脚本,并写入:
JAVA_OPTS="$JAVA_OPTS -Djavax.net.debug=ssl"

当然该配置项还可以进行更细粒度的控制,请参考:https://access.redhat.com/solutions/973783

7. 编写HTTPS客户端

有了HTTPS服务器端,我们需要验证客户端是否能正确校验通过我们颁发的MyServer.crt。首先,我们模拟HTTPS客户端的机器需要安装MyCA.crt到信任证书中:

keytool -import -alias MyCA -file MyCA.crt -keystore $JAVA_HOME/jre/lib/security/cacerts

证书安装成功后,编写访问代码:


java实现的HTTPS客户端

这段代码会访问tomcat的examples项目中的页面,注意访问地址使用的域名是localhost,该域名与MyServer.jks中的域名保持一致。如果访问成功,会打印如下信息:


访问结果

获取到该信息后,表示我们的HTTPS通信是正确的,服务器端的证书MyServer.crt是被信任的,因为我们本地信任了MyCA,而MyServer.crt是由MyCA颁发的。如果我们要验证MyServer.crt是不被信任的,我们可以卸载掉之前安装的MyCA.crt,再次访问就会出现如下错误:
javax.net.ssl.SSLHandshakeException: 
      sun.security.validator.ValidatorException: 
        PKIX path building failed: 
          sun.security.provider.certpath.SunCertPathBuilderException: 
            unable to find valid certification path to requested target

该错误的原因是服务器的证书不能被正确的验证,也就是通过JDK默认的信任证书不能验证MyServer的证书。
如果想校验不通过的情况,可以通过命令删除jdk中的MyCA.crt,命令如下:

keytool -delete -alias MyCA -keystore $JAVA_HOME/jre/lib/security/cacerts

总结

本文通过使用jdk自带的keytool工具,模拟了服务器端CA证书的颁发过程。如果在项目中暂时不能在受信任的CA机构申请到证书,但是却需要开启HTTPS功能,可以使用该文中介绍的方式来自己颁发CA证书。另外,通过这种方式,就可以在家自己进行HTTPS相关的技术研究了。
本文是HTTPS那些事儿系列的最后一篇文章,如需查看本系列其他文章,请转至前言
本人程序猿一枚,语言能力有限,本系列的文章是在工作过程中积累而来的,原意仅供自己备忘。现公开出来,也仅是想帮助有需要的人,如有问题,可随时留言,如果我懂我会不定期回复。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容