在SSL/TLS/HTTPS通信中,证书虽然不是TLS/SSL协议的一部分,却是HTTPS非常关键的一环,网站引入证书才能避免中间人攻击。证书涉及了很多密码学知识,理解证书后,再深入理解TLS/SSL协议,效果会更好。
在前面一篇文章《搭建国密SSL开发测试环境》中,我们制作了一个自签名证书。通常情况下,用作调试简单的客户端/服务器端通信,足够了。然而,现实世界的证书要复杂的多,涉及到CA、证书链、证书的撤销等多种场景。如果我们要实现一个完善的SSL/TLS/HTTPS就需要把这些场景考虑进去,这时仅仅靠自签名证书是不够的。
我们也可以通过CA申请证书,对于个人开发者而言,成本比较高。比如从网上找到的国密证书价格,一年好几千元到几万的都有:
国密证书参考价格
那有没有办法自己制作证书呢?答案是可以的。本文将探讨使用GmSSL制作国密证书,包括制作自签名根证书,并使用根证书签发证书。这样在开发中可以调试证书链的处理流程。
本文所使用的方法在Ubuntu 16.04上验证通过,在其它linux发行版本上,可能命令需要稍微做一些调整。关于国密SSL环境,请参考:
现实世界的CA是分级管理的,层级可以有多层。本文简单起见,只模拟到三级CA管理,具体来说:
Root CA -> Server CA -> Server
Root CA为一级CA,拥有根CA证书,Server CA为二级CA,其CA证书由Root CA签发,Server为最终的用户,其证书由Server CA签发。当然,Root CA也可以直接给Server签发证书,这里是为了演示CA层级需要而做的这样的假定。
gmssl ecparam -genkey -name sm2p256v1 -text -out rootkey.pem
根证书的私钥保存在rootkey.pem中,请妥善保存。
$ gmssl req -new -key rootkey.pem -out rootreq.pem
You are about to be asked to enter information that will be incorporatedinto your certificate request.What you are about to enter is what is called a Distinguished Name or a DN.There are quite a few fields but you can leave some blankFor some fields there will be a default value,If you enter '.', the field will be left blank.-----Country Name (2 letter code) [CN]:State or Province Name (full name) [Some-State]:HubeiLocality Name (eg, city) []:WuhanOrganization Name (eg, company) [Internet Widgits Pty Ltd]:mogowebOrganizational Unit Name (eg, section) []:mogowebCommon Name (e.g. server FQDN or YOUR name) []:mogoweb.comEmail Address []:mogoweb@gmail.com
Please enter the following 'extra' attributesto be sent with your certificate requestA challenge password []:An optional company name []:
上面的命令会要求提供一些信息,因为证书是自签名证书,只用于开发测试,所以填写什么内容无关紧要。
[ v3_ca ]basicConstraints = CA:true[ usr_cert ]subjectAltName = DNS:localhost
注意:相比上一篇文章,这个文件多增加了 "CA:true" 这个扩展,用于指定所签发的证书是否CA证书。
$ gmssl x509 -req -days 365 -in rootreq.pem -signkey rootkey.pem -extfile certext.ext -extensions v3_ca -out rootcert.pemSignature oksubject=C = CN, ST = Hubei, L = Wuhan, O = mogoweb, OU = mogoweb, CN = mogoweb.com, emailAddress = mogoweb@gmail.comGetting Private key
注意:上面的命令行参数多了一个 -extensions v3_ca 参数,指定使用上面 certext.ext 文件 v3_ca 节的扩展项。
注意: 这个步骤并非必要,只是为了开发和调试方便。在实际部署时,私钥需要小心保存,绝不能和证书一起分发出去!
$ cat rootcert.pem rootkey.pem > root.pem
和上面的步骤一样,这里直接把命令总结一下:
$ gmssl ecparam -genkey -name sm2p256v1 -text -out serverCAkey.pem$ gmssl req -new -key serverCAkey.pem -out serverCAreq.pem$ gmssl x509 -req -days 365 -in serverCAreq.pem -extfile certext.ext -extensions v3_ca -CA root.pem -CAkey root.pem -CAcreateserial -out serverCAcert.pem$ cat serverCAcert.pem serverCAkey.pem rootcert.pem > serverCA.pem
需要注意第三个命令多了 -CA 和 -CAkey 参数,表示使用根证书签名。因为上面的步骤中,我们把key和证书合成了一个文件,所以这两个参数值给的同一个文件。
和上面的步骤一样,这里直接把命令总结一下:
$ gmssl ecparam -genkey -name sm2p256v1 -text -out serverkey.pem$ gmssl req -new -key serverkey.pem -out serverreq.pem$ gmssl x509 -req -days 365 -in serverreq.pem -extfile certext.ext -extensions usr_cert -CA serverCA.pem -CAkey serverCA.pem -CAcreateserial -out servercert.pem$ cat servercert.pem serverkey.pem serverCAcert.pem rootcert.pem > server.pem
注意: 第三个命令的 -extensions 给的参数值为 usr_cert ,对应的是 certext.ext 文件 usr_cert 节的扩展项,通常需要给定服务器的DNS名。
这样,生成的 server.pem 包含了根证书、Server CA证书和Server证书,包含了完整的证书链,可以投入测试使用了。
再次声明: 将key和证书打包在一起,只是为了开发和调试方便。在实际部署时,私钥需要小心保存,绝不能和证书一起分发出去!
-Error with certificate at depth: 0 err 18:self signed certificate
原因:CA证书的 Organization Name 值和所签发的证书的 Organization Name 值相同。
解决方法:重新制作server证书,注意其 Organization Name 值不要和Server CA证书相同。
-Error with certificate at depth: 1 err 24:invalid CA certificate
原因:CA证书的 CA:true 扩展属性没加上 解决方法:重新制作root和Server CA证书,注意 CA:true 扩展属性