0%

OpenSSL自建CA、自签SSL证书

自签证书

首先约定好文件后缀

  • .key 私钥文件 Private Key
  • .csr 证书请求文件,csr = Certificate Signing Requests
  • .crt 证书文件 crt = Certificate
  • .crl 证书吊销列表 crl = Certificate Revocation List
  • .pem 包含私钥的证书,但是自动生成的不包含

自建CA

生成的私钥

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

生成的证书请求文件,这时会提示交互输入一些信息

1
openssl req -new -key ca/root.key -out root.csr

也可以

1
openssl req -new -key ca/root.key -out ca/root.csr -subj "/C=CN/O=Test/OU=Test CA/CN=Test CA/emailAddress=ca@test.com"

自签名

1
openssl x509 -req -days 3650 -signkey ca/root.key -in ca/root.csr -out ca/root.crt

合成包含私钥的pem证书(文件)

1
cat ca/root.key ca/root.crt > ca/root.pem

这个ca/root.crt和ca/root.pem就是自签名CA,用它可以对其它证书进行签名

RootCA也可以添加扩展信息,比如 basicConstraints = CA:TRUE,下面会提到

用自建CA进行签名

生成server1的key

1
openssl genrsa -des3 -out keys/server1.key 2048

生成server1的证书请求文件

1
openssl req -new -key keys/server1.key -out csrs/server1.csr -subj "/C=CN/O=Test/OU=dev/CN=server1.test.com/emailAddress=ops@test.com"

用CA给server.csr签名

1
openssl ca -in csrs/server1.csr -out certs/server1.crt -config openssl.cnf

查验server1.crt证书

1
2
openssl x509 -in certs/server1.crt -noout -text | less
openssl x509 -in certs/server1.crt -noout -serial -subject

openssl.cnf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[ ca ]
default_ca = TEST_CA

[ TEST_CA ]
dir = .
private_key = $dir/ca/root.key
certificate = $dir/ca/root.crt
new_certs_dir = $dir/newcerts
certs = $dir/certs
database = $dir/index.txt
serial = $dir/serial
default_md = sha256
default_days = 365
policy = policy_match

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

目录结构tree

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.
|-- ca
| |-- root.crt
| |-- root.csr
| |-- root.key
| `-- root.pem
|-- certs
| `-- server1.crt
|-- csrs
| `-- server1.csr
|-- index.txt
|-- index.txt.attr
|-- index.txt.old
|-- keys
| `-- server1.key
|-- newcerts
| `-- 01.pem
|-- openssl.cnf
|-- serial
`-- serial.old

5 directories, 14 files

配置文件中提到的文件或目录都是手工创建,其中还需要

1
echo '01' > serial

配置文件中未提到的文件系自动生成

  • index.txt.attr 签发证书时的属性, unique_subject = yes; 当然也可以写到配置文件中
  • index.txt.old 最近一次的index.txt
  • serial.old 最近一次签发证书的serial number

中间过程可能遇到的问题

error while loading serial number

serial需初始化一个值

1
echo '01' > serial

failed to update database
TXT_DB error number 2

1
2
index.txt.attr
unique_subject = no

证书吊销

openssl.conf增加一些配置(同步创建crls目录及echo ‘01’ > crls/crlnumber)

1
2
3
crlnumber        = $dir/crls/crlnumber
crl = $dir/crls/certificate.crl
default_crl_days = 30

吊销证书

1
openssl ca -revoke certs/server1.crt -config openssl.cnf

生成吊销证书列表

1
openssl ca -gencrl -out crls/certificate.crl -config openssl.cnf

查看吊销列表

1
openssl crl -in crls/certificate.crl -noout -text | less

CA发布CRL一般都会有周期性,所以客户端不能基于CRL实时检查某证书是否过期

现在一般通过OCSP(Online Certificate Status Protocol),在线证书状态协议

证书扩展

生成待签名的server2.csr

1
2
openssl genrsa -des3 -out keys/server2.key 2048
openssl req -new -key keys/server2.key -out csrs/server2.csr -subj "/C=CN/O=Test/OU=dev/CN=server2.test.com/emailAddress=ops@test.com"

增加openssl.cnf相关配置

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
diff --git a/openssl.cnf b/openssl.cnf
index 2bb77dd..d99eb1e 100644
--- a/openssl.cnf
+++ b/openssl.cnf
@@ -14,7 +14,8 @@ default_days = 365
crlnumber = $dir/crls/crlnumber
crl = $dir/crls/crl.pem
default_crl_days = 30
-policy = policy_match
+x509_extensions = usr_cert
+policy = policy_match
-
[ policy_match ]
countryName = match
@@ -24,6 +25,13 @@ organizationalUnitName = optional
commonName = supplied
emailAddress = supplied
-
+[ usr_cert ]
+basicConstraints = CA:FALSE
+#nsCertType = server
+nsCertType = client, email
+keyUsage = digitalSignature, keyEncipherment
+nsComment = "Certificate Generated by Test CA"
+

如果想给一个Web站点签发,可按需添加

1
2
3
extendedKeyUsage = serverAuth, clientAuth
#subjectAltName = IP:192.168.7.1
subjectAltName = DNS:\*.test.com DNS:test.com

用CA对server2.csr签名

1
openssl ca -in csrs/server2.csr -out certs/server2.crt -config openssl.cnf

可以对比查看server2.crt和server1.crt的区别

1
openssl x509 -in certs/server2.crt -noout -text | less

二级CA

实际生产环境中,很少直接用RootCA直接签发业务证书,一般是二级或多级CA去签发

新创建一工作目录,并复用RootCA的目录结构和配置文件

1
2
mkdir /root/second_ca_test
cd /root/second_ca_test

生成二级CA的key及其证书请求文件

1
2
openssl genrsa -des3 -out ca/second.key 2048
openssl req -new -key ca/second.key -out ca/second.csr -subj "/C=CN/O=Test/OU=Test SecondCA/CN=Test SecondCA/emailAddress=ca@test.com"

使用RootCA签发二级CA前,RootCA的openssl.cnf配置文件需要更改

usr_cert 只保留以下配置即可

1
2
[ usr_cert ]
basicConstraints = CA:FALSE

签发二级CA: 遇到路径问题自行修改,因为’dir = .’没有使用绝对路径

1
openssl ca -in ca/second.csr -out ca/second.crt -config ../openssl/openssl.cnf

二级CA签发的证书一般需要合并,RootCA一般需导入或已内置(浏览器、系统)

1
2
3
4
5
6
7
8
9
-----BEGIN CERTIFICATE-----
server_crt
------END CERTIFICATE------
-----BEGIN CERTIFICATE-----
lower_rt
------END CERTIFICATE------
-----BEGIN CERTIFICATE-----
second_crt
------END CERTIFICATE------

证书校验

1
openssl verify -verbose -CAfile  ...

建议

  • 提前规划,比如多少级CA,分别做什么
  • 私钥一定要加密保存,养成良好习惯
  • 根据实际情况,脚本化签发证书
  • 按需对证书有效期进行监控并预警

配置文件示例

openssl.cnf

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
[ ca ]
default_ca = TEST_CA

[ TEST_CA ]
dir = .
private_key = $dir/ca/root.key
certificate = $dir/ca/root.crt
new_certs_dir = $dir/newcerts
certs = $dir/certs
database = $dir/index.txt
serial = $dir/serial
default_md = sha256
default_days = 365
crlnumber = $dir/crls/crlnumber
crl = $dir/crls/crl.pem
default_crl_days = 30
x509_extensions = usr_cert
policy = policy_match

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

[ usr_cert ]
basicConstraints = CA:FALSE
#nsCertType = server
nsCertType = client, email
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
#subjectAltName = IP:192.168.7.1
subjectAltName = DNS:\*.test.com DNS:test.com
nsComment = "Certificate Generated by Test CA"

[ req ]
distinguished_name = req_distinguished_name

[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = CN
countryName_min = 2
countryName_max = 2

stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default =
localityName = Locality Name (eg, city)
localityName_default =
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Test
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = Dev
commonName = Common Name (e.g. server FQDN or YOUR name)
emailAddress = Email Address
commonName_max = 64

其它

去除key的密码

1
openssl rsa -in keys/server1.key -out keys/server1_nopass.key

生成公钥

1
openssl rsa -in keys/server1_nopass.key -pubout > server1.pub

更多

man x509

man x509v3_config或’https://www.openssl.org/docs/manmaster/man5/x509v3_config.html'

man req