公钥基础设施(四):证书签发(以OpenSSL为例)

这篇是以OpenSSL为例如何生成证书、自签名以及签发客户证书。

需事先安装OpenSSL。

回顾

前几篇我们已经讲过,证书相当于是权威机构对个人公钥的认证,而个人持有对应的私钥并保密。那么我们如何创建证书呢?

搭建根CA

初始化

先建目录:

1
2
3
mkdir rootCA
cd rootCA
mkdir newcerts private conf requests

再创建序号和记录文件

1
2
3
touch index.txt
echo unique_subject = yes > index.txt.attr
echo 01 > serial

创建私钥

首先我们需要生成一个私钥:

1
openssl genrsa -out private/ca.key 2048

这样生成的私钥是不加密的,当然我们也可以选择一种加密方式(可选的加密方式可以使用 openssl help 查询)
以des3为例,我们生成私钥的命令:

1
openssl genrsa -des3 -out private/ca.key 2048

输入一个不少于4位的密码即可。

注:这样加密的意义是一旦私钥被复制可以不让攻击者直接就能使用私钥,然而只能拖延不能完全防止。原则上私钥被复制需要更换私钥。

创建自签名证书

所谓请求就是将自己的信息和自己需要被签名的公钥打包成的一个文件。这个请求会被提交给CA确认。确认无误后CA会用自己的私钥签名。

接下来我们需要生成一个请求,我们有两种可选方式:

直接生成证书(方式一)

1
openssl req -x509 -key private/ca.key -out ca.crt

接下来按照指引填入相关信息。
这样就生成了一张自签名证书。
其中 -x509 表示生成x509格式的自签名证书。(待会我们生成请求时会使用 -new 而不是 -x509
另外,我们可以通过 -day 参数指定过期时间, -set_serial 参数设置特定序列号。
具体可以使用 openssl req -help 命令查看详细。

通过配置文件生成请求(方式二)

至于配置文件的详细解释可以查阅官方文档

以下只给一个样例:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
[ default ]
name = rootCA
dir = .

base_url = http://your.website.com
crl_url = $base_url/crls/$name.crl

[ ca ]
default_ca = CA_root

####################################################################

[ CA_root ]
new_certs_dir = $dir/newcerts # default place for new certs.

private_key = $dir/private/ca.key # The private key
certificate = $dir/ca.crt # The CA certificate

database = $dir/index.txt # database index file.
serial = $dir/serial # The current serial number
crlnumber = $dir/crlserial # the current crl number
RANDFILE = $dir/private/.rand # private random number file

preserve = no
name_opt = ca_default
cert_opt = ca_default

default_startdate = 170101000000Z
default_enddate = 200201000000Z
default_crl_days = 30
default_md = default

x509_extensions = v3_intermediate_ca

policy = policy_root

[ policy_root ]
countryName = supplied
stateOrProvinceName = optional
organizationName = match
organizationalUnitName = supplied
commonName = supplied
emailAddress = optional

####################################################################

[ req ]
default_bits = 2048
default_keyfile = $dir/private/ca.key
distinguished_name = req_distinguished_root
x509_extensions = v3_ca
string_mask = utf8only

[ req_distinguished_root ]
countryName = Country Name (2 letter code)
countryName_min = 2
countryName_max = 2

stateOrProvinceName = State or Province Name (full name)

localityName = Locality Name (eg, city)

organizationName = Organization Name (eg, company)

organizationalUnitName = Organizational Unit Name (eg, section)

commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_max = 64

countryName_default = CN
stateOrProvinceName_default = Your Province
organizationName_default = Your Company Name
organizationalUnitName_default = Secure Digital Certificate Signing
commonName_default = The Root CA of Your Private Certifications

####################################################################

[ v3_ca ]
subjectKeyIdentifier = hash
basicConstraints = critical,CA:true
keyUsage = critical, cRLSign, keyCertSign

[ v3_intermediate_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:true
keyUsage = critical, cRLSign, keyCertSign
crlDistributionPoints = @crl_info

####################################################################

[ crl_ext ]
authorityKeyIdentifier = keyid:always

[ crl_info ]
URI.0 = $crl_url

保存为 conf/default.cnf

接下来在生成请求时带上配置文件即可。

1
openssl req -x509 -key private/ca.key -out ca.crt -config conf/default.cnf

注:此处如果不带 -key private/ca.key 参数,OpenSSL会在对应目录下创建一个新的private/ca.key文件。也就是说,你也可以选择跳过第一步直接使用配置文件的方式一条命令生成私钥及请求。

现在我们已经有了一个根证书ca.crt,从某种程度上,我们现在已经搭建出了一个根CA。

搭建二级CA

通常情况下,一级CA(即根CA)不直接签发服务器证书,而是签发二级CA。由二级CA签发服务器证书。

初始化

同搭建根CA:

1
2
3
4
5
6
7
cd ..
mkdir secondCA
cd secondCA
mkdir newcerts private conf requests
touch index.txt
echo unique_subject = yes > index.txt.attr
echo 01 > serial

创建私钥

同搭建根CA:

1
openssl genrsa -out private/ca.key 2048

创建证书请求

-x509 被换成 -new 以外其他基本一致。
我们以方式二(使用配置文件)为例。
首先写一个配置文件。(和前一个类似,不再举例)
然后:

1
openssl req -new -key private/ca.key -out ../rootCA/requests/secondCA.csr -config conf/default.cnf

签发二级CA证书

这一步我们需要使用根CA的身份,用根CA的私钥签发二级CA的证书

1
2
cd ../rootCA
openssl ca -in requests/secondCA.csr -out ../secondCA/ca.crt -config conf/default.cnf

确认后,证书签发完成。

至此,二级CA搭建完成

签发服务器证书

类似二级CA:

初始化

1
2
3
4
5
6
7
cd ..
mkdir serverCA
cd serverCA
mkdir newcerts private conf
touch index.txt
echo unique_subject = yes > index.txt.attr
echo 01 > serial

创建私钥

1
openssl genrsa -out private/ca.key 2048

创建证书请求

写好配置文件后:

1
openssl req -new -key private/ca.key -out ../secondCA/requests/serverCA.csr -config conf/default.cnf

注:之后ServerCA签发的客户端证书不具备CA权限,所以注意修改 basicConstraints

签发服务器证书

1
2
cd ../secondCA
openssl ca -in requests/serverCA.csr -out ../serverCA/ca.crt -config conf/default.cnf

签发客户端证书

好吧都是一样的。。。

初始化

1
2
cd ../serverCA
mkdir Client.%x%

生成私钥

1
openssl genrsa -out Client.%x%/client.key 2048

生成请求

1
openssl req -new -key Client.%x%/client.key -out requests/client.%x%.csr -config conf/openssl.cnf

签发

1
openssl ca -in requests/client.%x%.csr -out Client.%x%/client.crt -config conf/default.cnf

打包

为了客户端方便导入,最后需要打包成p12文件

1
openssl pkcs12 -export -clcerts -in Client.%x%/client.crt -inkey Client.%x%/client.key -out Client.%x%/client.p12

废话

写的可能有点草率,很多东西没说清楚,之后有空再完善。