构建自己的CA

  最近的项目在做通过银联接入牛逼哄哄的人行之CNAPS2系统,不过他们强制要求通信报文采用国家标准SM2进行硬件签名,所以公司折腾了两家硬件签名机设备来玩,这边就做了相关的机器评测,看看相关的指标是否虚标了。不过CNAPS2系统的业务算是相当的复杂的,而其性能、并发性到底怎么样也就不得而知了,毕竟互联网交易的压力都被银联、网联这样的清算组织挡下来了。
  因为SM2实在是太非主流了,而且密码学相关的东西本来就复杂的要死,所以这边就先用RSA进行签名和验签测试。同时因为硬件签名机其证书所用的私钥是通过硬件产生并保存在机器当中(而且通常都导不出来),然后通过硬件产生证书请求文件来让CA核发证书的,所以这边为了折腾方便就自己建了一个CA,然后可以按照各种姿势核发证书了!

一、构建CA步骤

1.1 openssl相关配置

  对于几乎所有的Linux系统都会默认已经安装好了openssl工具了,而其相关配置文件和工作路径在系统的/etc/pki/目录下面。
  openssl默认情况下就可以使用,不过通过修改/etc/pki/tls/openssl.conf配置文件的一些配置信息,比如证书的有效期、默认国家地区等参数,以及对新证书请求的规则检查策略配置好,后面在签发新证书会比较方便,很多参数直接使用默认值变可以一路回车了。

1
2
3
4
5
6
7
8
default_days = 1095 # how long to certify for, 3 years
dir = /etc/pki/CA # Where everything is kept

countryName_default = CN
stateOrProvinceName_default = Guangdong
localityName_default = Shenzhen
0.organizationName_default = cpplus.cc Co.LTD
organizationalUnitName_default = R&D

  从上面的配置可知,/etc/pki/CA是整个CA的工作路径,然后我们切换到该目录下,执行如下操作:

1
2
[root@cpplus CA] touch index.txt serial
[root@cpplus CA] echo 0001 > serial

  上面的index.txt文件会罗列出后面新签发证书的序列号和DN信息,而serial是一个全局递增的索引记录文件,每签发一个证书该文件中的序列号就会执行递增操作。

1.2 根证书的构建

  其实真正执行签名-验签、加密-解密功能,是通过私钥和公钥机制来实现的,而证书则是用来标识这对公私钥的合法身份的。证书的管理是一个强集权组织形式,各个层级的根证书为其所核发的证书负责,而最顶层的根证书都是由信誉良好的公司或者组织管理的,这些根证书被预先内置于操作系统或浏览器中,而私人核发的根证书只能由用户手动导入到系统中去。
  下面的命令产生了根证书所需要的私钥,这个一定要保存好了!同时由于证书会跟主机进行绑定,所以这边设置一下主机名,除了hostname命令之外还包括/etc/sysconfig/network文件的对应修改。

1
2
3
4
5
6
7
8
9
[root@cpplus CA]# openssl genrsa -out private/cakey.pem 2048
Generating RSA private key, 2048 bit long modulus
..........................+++
.....................+++
e is 65537 (0x10001)
[root@cpplus CA]# chmod go-rwx private/cakey.pem
[root@cpplus CA]# ls -l private/cakey.pem
-rw------- 1 root root 1679 Nov 15 09:46 private/cakey.pem
[root@cpplus CA]# hostname cpplus.cc

  然后我们跳过证书请求文件,根据上面的私钥文件直接产生根证书,证书的有效期被设置为3年,命令执行成功后会在当前目录生成根证书文件cacert.pem。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@cpplus CA]# openssl req -new -x509 -days 1095 -key private/cakey.pem -out cacert.pem    
You are about to be asked to enter information that will be incorporated
into 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 blank
For 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) [Guangdong]:
Locality Name (eg, city) [Shenzhen]:
Organization Name (eg, company) [cpplus.cc Co.LTD]:
Organizational Unit Name (eg, section) [R&D]:
Common Name (eg, your name or your server's hostname) []:cpplus.cc
Email Address []:admin@cpplus.cc
[root@cpplus CA]#

  使用下面的命令可以以人类阅读更友好的方式查看证书的相关信息和描述。

1
[root@cpplus CA]# openssl x509 -in cacert.pem -text -noout

  这个cacert.pem证书是可以发布给任何人或任何机构的,他们只要将这个证书设置成信任的根证书,那么此后基于该根证书核发的所有证书就默认都被信任了。在Windows环境下我们可以将cacert.pem重新命名为cpplus.cc.cer,然后就可以通过双击安装该证书了。同时,如果需要在硬件签名机上使用,也可以将其作为信任的根证书导入到签名机上去。

二、签发证书

  现在CA已经搭建完毕,可以帮应用或客户签发新证书了,这里切换到其他目录操作。

2.1 客户生成证书请求文件

  这里虽然和上面构建CA写在一篇文章中,其实这部操作是由证书的申请者在自己本地执行的,其产生的私钥自己保留,不需要提供给CA,客户只需要生成私钥后,再根据私钥创建证书申请文件,拿着证书申请文件就可以让CA签发新证书了。
  创建私钥和证书请求文件通过openssl工具都可以“软件”完成,就如下面例子操作的两个步骤一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[root@cpplus sz.cpplus.cc]# openssl genrsa -out sz.cpplus.cc.key 2048         
Generating RSA private key, 2048 bit long modulus
.............................................................................................+++
....................................................+++
e is 65537 (0x10001)
[root@cpplus sz.cpplus.cc]# openssl req -new -key sz.cpplus.cc.key -out sz.cpplus.cc.csr
You are about to be asked to enter information that will be incorporated
into 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 blank
For 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) [Guangdong]:
Locality Name (eg, city) [Shenzhen]:
Organization Name (eg, company) [cpplus.cc Co.LTD]:
Organizational Unit Name (eg, section) [R&D]:
Common Name (eg, your name or your server's hostname) []:sz.cpplus.cc
Email Address []:admin@sz.cpplus.cc

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

  如果要使用到硬件签名,那么就需要通过签名机管理工具的形式让签名机生成私钥,再根据私钥生成证书请求文件。拿着证书请求文件向CA索取新签发的证书后,再将证书对应到原始的私钥导入到签名机就可以使用了。所以使用签名机的好处一方面是专用的硬件执行签名验签速度更快,同时私钥会强制保存在机器中而不会存在于某个电脑磁盘上,所以不容易造成私钥泄漏的问题。

2.2 签发新证书

  当CA拿到申请者的证书请求文件后,就可以向其核发新证书了。虽然这里只需一步操作,但是在这之前CA要严格核查证书申请者的身份信息,因为CA需要对自己签发的证书负责,滥发证书将会影响自己的信誉,严重时候CA的根证书可能会被主流设备或软件厂商置为不信任状态,则此时CA就再也无法核发被信任的证书了。
  关于信息审核也应不同的应用场景各不相同,大多数普通网站的话可能只需要验证证书申请者是对应域名所有者就可以了,而针对安全性要求更高的网站,可能需要申请者亲自到场,附带营业执照等来确认相关信息的合法性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[root@cpplus sz.cpplus.cc]# openssl ca -in sz.cpplus.cc.csr -out sz.cpplus.cc.crt
Using configuration from /etc/pki/tls/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 1 (0x1)
Validity
Not Before: Nov 15 01:58:27 2018 GMT
Not After : Nov 14 01:58:27 2021 GMT
Subject:
countryName = CN
stateOrProvinceName = Guangdong
organizationName = cpplus.cc Co.LTD
organizationalUnitName = R&D
commonName = sz.cpplus.cc
emailAddress = admin@sz.cpplus.cc
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
DD:FC:EF:3D:12:43:F1:9D:93:E0:F1:F0:E8:C8:FE:CD:7A:CB:D6:66
X509v3 Authority Key Identifier:
keyid:C7:6F:BB:75:8F:5C:75:F5:E5:81:BD:BA:EB:23:18:CB:DD:FC:56:F0

Certificate is to be certified until Nov 14 01:58:27 2021 GMT (1095 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

  从上面的日志可以看出,该签发已经提交,在当前目录下面生成新证书了。然后再查看之前描述的几个记录文件,相关数据也更新了:

1
2
3
4
5
6
[root@cpplus sz.cpplus.cc]# ls /etc/pki/CA/newcerts/        
01.pem
[root@cpplus sz.cpplus.cc]# cat /etc/pki/CA/serial
02
[root@cpplus sz.cpplus.cc]# cat /etc/pki/CA/index.txt
V 211114015827Z 01 unknown /C=CN/ST=Guangdong/O=cpplus.cc Co.LTD/OU=R&D/CN=sz.cpplus.cc/emailAddress=admin@sz.cpplus.cc

  然后在Windows下看一下这个新证书——嗯,像个样子啦!
cert

三、相关测试

  在新证书sz.cpplus.cc.crt产生后就可以交付给客户了。申请者拿到新证书后再结合之前的私钥就可以做很多事,尝试很多的测试了。比如,我们就可以使用CA的根证书校验当前生成的新证书是否有效:

1
2
[root@cpplus sz.cpplus.cc]# openssl verify -CAfile /etc/pki/CA/cacert.pem sz.cpplus.cc.crt                            
sz.cpplus.cc.crt: OK

  同时openssl工具集本身还提供了简单的https测试服务端,可以模拟该证书用于HTTP SSL是否正常。使用下面的命令可以尝试体验一下这个小功能:

1
[root@cpplus sz.cpplus.cc]# openssl s_server -accept 443 -cert sz.cpplus.cc.crt -key sz.cpplus.cc.key

  下面的截图是访问过程中打印的相关请求和认证信息:
server
client
  如果需要签发相关证书测试或者把玩的,可以联系我;-)

四、后话

  通过上面的方式,自己签发签名机请求的证书,导入到硬件签名机中签名和验签的功能都是有效的。
  关于签名机,我们选用的两家设备价格相对都比较便宜,也印证了那句老话——便宜没好货。一家的设备是使用MFC写的管理工具,只能在Windows环境下使用不说,其界面丑陋、操作反人类简直连刚上计算机课程大学生做的作业都不如;另外一家用tomcat作了个Web UI倒也还进步了,但链接经常响应出错误页面,而且部分页面还提示语乱码。难道现在只有互联网行业才讲究软件的用户体验么?
  对比两家相同价位的设备在相同环境下的吞吐量,居然有近十倍只差,然后一家设备供应商说他们的设备是完全使用密码卡进行全硬件计算实现的签名和验签,而很多厂家直接使用服务器CPU软实现签名和验签,他们的性能完全没有可比性。唉,外行傻傻看不清,也只能说有中国人的地方就有江湖。
  如果抛开界面说底层API,两家的C/C++接口居然没有使用一个const关键字!
  当然,就正如当时跟一个厂家服务代表聊的一样:密码机(签名机、加密机等),也是一个相对封闭、圈子很小的行业。其实这也是很多特色行业的一个缩影,这些行业不是任何人都可以参与进来,友商们都互相看看感觉大家做的只要说得过去也就行了,毕竟目标客户采购招标还有很多的因素存在。他们在国内就可以活的很滋润了,或许也没有走出国门的雄心和抱负了,就是这么回事儿……

本文完!