准备工具
安装keytool(jdk自带)、openssl、nginx、web服务
有两种方法生成数字证书,一种是用JDK带的keytool,另一种是用openssl。
我们将利用openssl完成以下表格内容:
完成项 | 输出文件 |
---|---|
CA服务器根证书 | cacert.pem 证书 |
服务器证书 | servercert.pem 证书 serverkey.pem 私钥 |
客户端证书 | clientcert.pem 证书 clientkey.pem 私钥 |
先做一个服务端单向认证,最后完成一个服务端客户端双向认证。
制作根证书
制作一个CA私服,取名叫testca。
准备CA工作目录
mkdir "$HOME/testca"
cd "$HOME/testca"
mkdir newcerts private conf
chmod g-rwx,o-rwx private
echo "01" > serial
touch index.txt
$HOME/testca为待建CA的主目录
newcerts子目录将存放CA签署(颁发)过的数字证书(证书备份目录)
private目录用于存放CA的私钥
conf只是用于存放一些简化参数用的配置文件
serial和index.txt分别用于存放下一个证书的序列号和证书信息数据库
生成根证书
配置根证书
创建testca根证书配置文件及内容
vi "$HOME/testca/conf/gentestca.conf"
内容如下
####################################
[ req ]
default_keyfile = $ENV::HOME/testca/private/cakey.pem
default_md = md5
prompt = no
distinguished_name = ca_distinguished_name
x509_extensions = ca_extensions
[ ca_distinguished_name ]
organizationName = dong
organizationalUnitName = dong
commonName = ca.dong.com
emailAddress = 55@qq.com
[ ca_extensions ]
basicConstraints = CA:true
########################################
申请根证书
CA服务器,自己给自己颁发证书,生成CA的私钥和自签名证书,即根证书。
cd "$HOME/testca"
openssl req -x509 -newkey rsa:2048 -out cacert.pem -outform PEM -days 2190 -config "$HOME/testca/conf/gentestca.conf"
# req 表示发起一个证书签名请求
# -x509 用x509结构替代cert
# -nwekey rsa:2048,新建一个2048 bit的rsa秘钥
# -out 输出的证书文件
# -outform 输出的格式,DER或者PEM
# -days 有效时间2190天
# -config 请求的配置文件,这里是根证书的配置信息
执行过程中需要输入CA私钥的保护密码,假设我们输入密码: 123456
查看一下自己CA证书的内容
openssl x509 -in cacert.pem -text -noout
内容如下:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
f5:b7:91:04:6a:34:13:46
Signature Algorithm: md5WithRSAEncryption
Issuer: O=dong, OU=dong, CN=ca.dong.com/emailAddress=55@qq.com
Validity
Not Before: Feb 23 03:02:01 2021 GMT
Not After : Feb 22 03:02:01 2027 GMT
Subject: O=dongnaoedu, OU=dong, CN=ca.dong.com/emailAddress=55@qq.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:c0:32:b5:88:87:bd:ad:ef:0d:a1:92:da:22:d3:
cc:2b:91:6c:44:60:f3:15:71:1e:87:e1:82:b9:9b:
91:55:08:59:11:0c:93:d0:2d:99:7b:bd:e2:43:82:
10:6e:f3:48:1e:23:b7:a2:69:d7:6d:c5:bc:0d:c9:
b0:fa:7e:3d:fb:6f:f5:03:1f:3e:b4:80:79:aa:c8:
13:33:3f:a9:e7:6a:d1:1c:b4:02:e0:5e:7c:b5:58:
ac:90:86:89:0e:38:fd:2e:e1:b9:1c:bb:b9:bf:74:
e7:b9:58:07:e2:f0:2c:ba:44:76:b3:59:9a:9e:ed:
b2:84:02:6b:57:69:f3:5a:1f:7e:0f:76:29:3f:da:
8d:f3:72:43:6d:bb:7d:26:6f:6e:31:ce:e5:6f:b5:
92:d9:af:65:ea:f4:11:55:10:6d:d6:0f:85:e2:7e:
1c:cc:28:96:52:3c:cc:7f:de:c1:50:38:1d:9f:cd:
d0:56:15:30:ef:b3:8f:4c:be:9f:e0:f6:ef:01:a4:
01:a8:26:33:dc:b6:ab:c3:ed:1a:52:58:54:9d:7b:
f2:f7:6f:a2:14:9b:0d:c9:44:62:3e:8d:35:5e:db:
88:45:64:65:f3:4b:5e:10:ed:ab:e5:9b:c7:c4:4a:
bf:a8:06:c8:36:5f:1e:f1:46:8a:e5:cf:ba:a8:95:
91:43
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: md5WithRSAEncryption
6e:78:44:58:ee:00:77:87:b8:21:f7:ab:88:dc:a1:d9:b0:a4:
43:18:fc:3a:d5:17:5e:22:a7:43:99:41:9c:21:39:87:72:cb:
aa:42:7b:c2:e1:99:2d:2b:b9:6c:ac:5f:d9:db:7e:3d:6b:b2:
d6:8c:ab:87:9c:ce:19:ad:e4:e6:43:db:6d:56:85:13:f3:46:
55:e1:03:53:9b:aa:18:87:d6:aa:a6:e5:5f:3a:fa:ca:eb:ec:
1e:0e:fc:4e:96:17:61:3b:51:f7:3f:b0:5e:33:c1:c4:2e:b9:
d2:d3:3a:80:d2:c7:22:c7:aa:ec:86:37:3d:79:cc:88:6a:da:
d5:6b:6e:d0:23:ca:a4:7b:7e:11:0a:7e:bb:9d:21:cb:db:33:
d9:ab:1f:be:98:c6:25:ad:87:11:e3:26:00:36:5a:09:f8:2e:
80:35:30:73:d6:9c:9f:b6:74:3d:1a:b7:5f:9c:53:fd:f6:bb:
a4:53:4b:ac:f1:6c:af:8c:21:09:56:eb:41:a0:a3:8e:03:72:
dc:97:20:a6:b1:e8:0e:b5:64:10:9b:c6:dc:a6:b0:fb:cd:98:
dd:48:6b:0e:56:1e:d4:92:6e:c9:f5:92:e5:79:3a:c2:b5:cd:
d2:60:a4:ce:88:74:dc:d9:37:83:7d:ed:49:9e:dc:75:22:fb:
74:d9:81:72
准备根证书配置文件
方便以后用它来生成,在它下面的子证书
vi "$HOME/testca/conf/testca.conf"
写入文件内容
####################################
[ ca ]
default_ca = testca # The default ca section
[ testca ]
dir = $ENV::HOME/testca # top dir
database = $dir/index.txt # index file.
new_certs_dir = $dir/newcerts # new certs dir
certificate = $dir/cacert.pem # The CA cert
serial = $dir/serial # serial no file
private_key = $dir/private/cakey.pem # CA private key
RANDFILE = $dir/private/.rand # random number file
default_days = 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = md5 # message digest method to use
unique_subject = no # Set to 'no' to allow creation of
# several ctificates with same subject.
policy = policy_any # default policy
[ policy_any ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
########################################
单向认证
我们可以用openssl为服务器或用户生成公钥密钥,并用上面创建的CA根证书cacert.pem签发对应的私钥(密钥)的数字证书。
准备目录
我们把服务器相关的东西生成到CA的$HOME/testca/test/server目录里。
mkdir -p "$HOME/testca/test/server"
cd "$HOME/testca/test/server"
创建服务器私钥,并生成testca的证书请求文件
通过req命令,生成一个签名证书申请,使用rsa:1024生成新秘钥,申请证书为testkey.pem,格式为PEM,证书签名参数为-subj指定的内容
openssl req -newkey rsa:1024 -out serverreq.pem -keyout serverkey.pem -keyform PEM -outform PEM -subj "/O=ABCom/OU=servers/CN=servername"
# req 表示发起一个证书签名请求
# -nwekey rsa:1024,新建一个1024 bit的rsa秘钥
# -out 输出的证书请求文件
# -keyout 表示存放生成私钥的文件
# -keyform 表示生成的秘钥文件格式,这里是PEM
# -outform 输出的格式,DER或者PEM
# -subj 设置或修改请求证书签名主题
执行命令过程中输入密钥保护密码,我们输入:949494
serverkey.pem为的私钥,serverreq.pem为CA签名证书请求文件。
查看请求文件内容
openssl req -in serverreq.pem -text -noout
内容如下:
Certificate Request:
Data:
Version: 0 (0x0)
Subject: O=ABCom, OU=servers, CN=servername
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:b1:c0:a8:e3:ec:1a:75:bc:d9:81:5e:5d:ce:f6:
8c:27:16:8b:31:86:95:93:52:b9:68:a0:c1:e2:ce:
58:f8:11:40:c7:a2:ae:de:c9:d4:82:0a:d1:8c:1b:
66:8c:0e:f8:d8:bf:0f:91:d4:c2:93:02:22:2b:f2:
f6:5e:54:99:ac:54:4c:78:1b:ed:5c:64:bb:96:6b:
80:03:70:35:ae:18:43:1c:1c:be:09:bd:dc:a2:6b:
6c:fe:a3:a9:f7:a0:d9:2b:e6:7d:f2:e9:4d:df:34:
11:68:c7:c8:1d:22:76:cd:e0:70:9b:c4:59:69:01:
fd:5a:b1:a6:ef:79:c9:f3:fd
Exponent: 65537 (0x10001)
Attributes:
a0:00
Signature Algorithm: sha256WithRSAEncryption
6b:77:27:aa:94:a3:2d:d5:ff:8e:a2:7c:4c:f8:58:35:13:67:
f2:87:2e:f5:f3:f5:b5:8d:72:83:a9:cd:f4:6d:0b:bc:21:1d:
8e:8c:d8:3c:a3:6d:71:05:ec:2e:5f:e3:4b:93:e6:0b:bb:5b:
fe:b8:3a:55:de:8c:f5:d2:01:dd:69:ab:24:a3:d3:0b:30:d5:
df:c6:81:34:a7:c7:6a:b8:12:bc:89:2a:53:79:1c:a4:41:bd:
77:0d:62:e4:60:ca:94:80:13:79:37:70:b4:6c:3d:87:cf:bd:
a6:91:67:08:5f:0d:be:95:fa:ee:b2:e0:c0:55:cd:77:61:f9:
5e:9f
CA签发证书
openssl ca -in serverreq.pem -out servercert.pem -config "$HOME/testca/conf/testca.conf"
执行过程中需要输入CA私钥的保护密码,前面设置的123456。
查看证书内容
openssl x509 -in servercert.pem -text -noout
内容如下:
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 2 (0x2)
Signature Algorithm: md5WithRSAEncryption
Issuer: O=dong, OU=dong, CN=ca.dong.com/emailAddress=55@qq.com
Validity
Not Before: Feb 23 06:36:18 2021 GMT
Not After : Feb 23 06:36:18 2022 GMT
Subject: O=ABCom, OU=servers, CN=servername
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:b1:c0:a8:e3:ec:1a:75:bc:d9:81:5e:5d:ce:f6:
8c:27:16:8b:31:86:95:93:52:b9:68:a0:c1:e2:ce:
58:f8:11:40:c7:a2:ae:de:c9:d4:82:0a:d1:8c:1b:
66:8c:0e:f8:d8:bf:0f:91:d4:c2:93:02:22:2b:f2:
f6:5e:54:99:ac:54:4c:78:1b:ed:5c:64:bb:96:6b:
80:03:70:35:ae:18:43:1c:1c:be:09:bd:dc:a2:6b:
6c:fe:a3:a9:f7:a0:d9:2b:e6:7d:f2:e9:4d:df:34:
11:68:c7:c8:1d:22:76:cd:e0:70:9b:c4:59:69:01:
fd:5a:b1:a6:ef:79:c9:f3:fd
Exponent: 65537 (0x10001)
Signature Algorithm: md5WithRSAEncryption
b4:d0:fc:4c:ec:87:c8:79:c6:27:b0:8b:e0:0b:5b:12:00:10:
25:81:92:70:94:8a:aa:1e:29:dd:9f:b5:1a:5d:72:aa:21:e5:
b9:15:7c:41:fe:4f:25:b6:b4:20:a6:3f:93:23:5e:33:c5:0c:
54:54:8c:21:9e:dc:9a:f3:f9:44:13:8c:b5:91:05:01:51:56:
00:96:0e:d5:ff:1a:62:f6:ac:7b:36:ba:a4:09:d4:72:b5:8b:
65:e3:c0:84:ca:fc:1f:b2:65:a4:d7:75:3c:3c:cb:ae:4c:31:
88:9f:c9:d0:0e:1e:15:5f:cb:5e:a9:28:2f:86:86:2b:76:d5:
3d:78:f2:84:8e:ae:d2:53:ea:a0:f9:dd:c7:12:d7:f6:66:9d:
cc:cc:20:c0:3e:20:c2:d3:56:52:a5:2a:45:e9:b1:a3:23:2a:
9d:ff:27:1a:70:97:24:06:6f:67:0f:30:5f:4b:67:24:0f:5e:
f5:9b:07:01:84:29:68:97:5c:9c:15:38:74:46:ce:c8:aa:55:
c8:a9:e7:f0:84:3e:30:59:6a:a4:bb:69:50:0b:e9:85:45:3a:
ca:2b:6b:e8:c8:fe:7f:ff:ca:fa:11:d4:91:a6:27:70:69:1c:
d0:20:c7:70:f0:ff:10:4a:52:b6:d8:2f:8b:b1:56:4c:2a:7d:
7e:59:c7:c1
Nginx配置
找到nginx运行的配置文件,将证书servercert.pem及私钥serverkey.pem放到配置目录下,修改内容如下
http {
# 配置https服务
server {
# 开启443端口,ssl安全协议
listen 443 ssl;
server_name localhost;
# 配置证书及服务器私钥
ssl_certificate servercert.pem;
ssl_certificate_key serverkey.pem;
# 会话参数的缓存,所有工作进程之间共享的缓存
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# 启用的密码
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
# SSLv3和TLS协议时,服务器密码优先于客户端密码
ssl_prefer_server_ciphers on;
location / {
root /data/www/;
index welcome.html;
}
}
}
双向认证
前面我们已经制作了服务器的证书,下面我只需要制作客户端证书就可以了。
创建客户端证书
用openssl创建客户端证书,只有这些CA签发的客户端证书才被服务器信任,才能通过HTTPS访问服务器。这就是“HTTPS服务器验证客户端证书”的关键配置。讲
mkdir -p "$HOME/testca/test/client"
cd "$HOME/testca/test/client"
openssl req -newkey rsa:1024 -keyout clientkey.pem -keyform PEM -out clientreq.pem -outform PEM -subj "/O=client/OU=client/CN=client"
openssl ca -in clientreq.pem -out clientcert.pem -config "$HOME/testca/conf/testca.conf"
设定执行过程中的密码都是:654321
制作PKCS12格式的客户端证书
PKCS12格式的证书包含私钥和公钥内容,它是描述个人信息交换的语法标准。描述了将用户公钥、私钥、证书和其他相关信息打包的语法或格式。我们制作的这个PKCS#12文件将包含密钥、证书和颁发该证书的CA证书。
openssl pkcs12 -export -in clientcert.pem -inkey clientkey.pem -out client.p12 -name hash -CAfile "$HOME/testca/cacert.pem"
我们将导出密码也设置为:654321
将生成的.p12文件导入到浏览器个人证书列表或USB秘钥U盘中,客户端就能用它来通过服务的验证。
Nginx配置
找到nginx运行的配置文件,将服务器证书servercert.pem、钥serverkey.pem、ca根证书cacert.pem放到配置目录下,修改内容如下
http {
# 配置https服务
server {
# 开启443端口,ssl安全协议
listen 443 ssl;
server_name localhost;
# 配置证书及服务器私钥
ssl_certificate servercert.pem;
ssl_certificate_key serverkey.pem;
ssl_client_certificate cacert.pem; # 根级证书公钥,用于验证各个二级client
ssl_verify_client on; #开启客户端证书验证
# 会话参数的缓存,所有工作进程之间共享的缓存
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# 启用的密码
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
# SSLv3和TLS协议时,服务器密码优先于客户端密码
ssl_prefer_server_ciphers on;
location / {
root /data/www/;
index welcome.html;
}
}
}
其中ssl_ciphers通过命令
openssl ciphers
来查看,包含有:
ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:SRP-DSS-AES-256-CBC-SHA:SRP-RSA-AES-256-CBC-SHA:SRP-AES-256-CBC-SHA:DH-DSS-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:DH-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:DH-RSA-AES256-SHA256:DH-DSS-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DH-RSA-AES256-SHA:DH-DSS-AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSS-CAMELLIA256-SHA:DH-RSA-CAMELLIA256-SHA:DH-DSS-CAMELLIA256-SHA:ECDH-RSA-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDH-RSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA:ECDH-ECDSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:CAMELLIA256-SHA:PSK-AES256-CBC-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:SRP-DSS-AES-128-CBC-SHA:SRP-RSA-AES-128-CBC-SHA:SRP-AES-128-CBC-SHA:DH-DSS-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DH-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-DSS-AES128-SHA256:DH-RSA-AES128-SHA256:DH-DSS-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:DH-RSA-AES128-SHA:DH-DSS-AES128-SHA:DHE-RSA-SEED-SHA:DHE-DSS-SEED-SHA:DH-RSA-SEED-SHA:DH-DSS-SEED-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:DH-RSA-CAMELLIA128-SHA:DH-DSS-CAMELLIA128-SHA:ECDH-RSA-AES128-GCM-SHA256:ECDH-ECDSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:ECDH-RSA-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:SEED-SHA:CAMELLIA128-SHA:IDEA-CBC-SHA:PSK-AES128-CBC-SHA:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:RC4-SHA:RC4-MD5:PSK-RC4-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:SRP-DSS-3DES-EDE-CBC-SHA:SRP-RSA-3DES-EDE-CBC-SHA:SRP-3DES-EDE-CBC-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DH-RSA-DES-CBC3-SHA:DH-DSS-DES-CBC3-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA:PSK-3DES-EDE-CBC-SHA
‘ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE’这个的大概含义是:
优先级逻辑(摘自https://www.jb51.net/article/68452.htm)
首先选择 ECDHE + AESGCM 密码。这些都是 TLS 1.2 密码并没有受到广泛支持。这些密码目前没有已知的攻击目标。
PFS 密码套件是首选,ECDHE 第一,然后 DHE。
AES 128 更胜 AES 256。有讨论是否 AES256 额外的安全是值得的成本,结果远不明显。目前,AES128 是首选的,因为它提供了良好的安全,似乎真的是快,更耐时机攻击。
向后兼容的密码套件,AES 优先 3DES。暴力攻击 AES 在 TLS1.1 及以上,减轻和 TLS1.0 中难以实现。向后不兼容的密码套件,3DES 不存在.
RC4 被完全移除. 3DES 用于向后兼容。
强制性的丢弃
aNULL 包含未验证 diffie - hellman 密钥交换,受到中间人这个攻击
eNULL 包含未加密密码(明文)
EXPORT 被美国法律标记为遗留弱密码
RC4 包含了密码,使用废弃ARCFOUR算法
DES 包含了密码,使用弃用数据加密标准
SSLv2 包含所有密码,在旧版本中定义SSL的标准,现在弃用
MD5 包含所有的密码,使用过时的消息摘要5作为散列算法
CA的日常操作
签发证书
假设收到一个证书请求文件名为req.pem,文件格式应该是PKCS#10格式(标准证书请求格式)
先查看证书请求的内容
openssl req -in req.pem -text -noout
签发证书
openssl ca -in req.pem -out cert.pem -config "$HOME/testca/conf/testca.conf"
执行过程中会要求输入访问CA的私钥密码,前面设置的123456
命令执行完毕,cert.pem就是签发好的证书,在$HOME/testca/newcerts里也会有一个相同的证书副本,文件名为证书序列号。
查看生成的证书的内容
openssl x509 -in cert.pem -text -noout
作废证书
由于用户私钥泄露或其他情况,需要吊销一个未过期的证书。假设需要被吊销的证书文件为cert.pem,则执行以下命令吊销证书:
openssl ca -revoke cert.pem -config "$HOME/testca/conf/testca.conf"
生成证书作废列表CRL
公开被吊销的证书列表,可以生成证书吊销列表(CRL),执行命令如下
openssl ca -gencrl -out testca.crl -config "$HOME/testca/conf/testca.conf"
还可用-crldays和-crlhours参数来说明下一个吊销列表将在未来某个时候(多少天或多少小时后)发布。
查看检查testca.crl的内容
openssl crl -in testca.crl -text -noout
服务端如何检查该客户端证书是否已经被吊销?我们可以通过检查CRL(Certification Revocation List)即证书吊销列表来做这个工作。