基于自签名 CA 实现 Nginx Server 与 浏览器 Client 端的双向认证与加密通信
环境介绍
1、系统及组件版本信息
[root@x9 ~]# openssl version
#> OpenSSL 1.0.2k-fips 26 Jan 2017
[root@x9 ~]#
[root@x9 ~]# cat /etc/redhat-release
#> CentOS Linux release 7.9.2009 (Core)
[root@x9 ~]#
[root@x9 ~]# uname -r
#> 3.10.0-1160.el7.x86_64
2、本文涉及的相关证书及信息
# 根证书
#> ca-cert.pem
#> ca-key.pem
# client 端证书
#> example.com-client-key.pem
#> example.com-client-csr.pem
#> example.com-client-cert.pem
#> example.com-client.p12
# Server 端证书
#> example.com-key.pem
#> example.com-csr.pem
#> example.com-cert.pem
#> example.com-pub-key.pem
TLS 认证流程图
TLS 加密通信单向及双向认证流程架构图
OpenSSL.conf
openssl.cnf 文件是 OpenSSL 用来存储配置信息的文件,它可以用来配置证书签名请求(CSR)和数字证书生成过程中使用的各种选项,例如域名证书中的各种信息和扩展
1、编辑 vim /etc/pki/tls/openssl.cnf,添加 x509 v3 扩展信息到证书签名文件
[ req ]
………………
# 去除注释,启用 req_extensions
req_extensions = v3_req # The extensions to add to a certificate request
………………
[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
# 添加如下行
subjectAltName = @san_names
# 同时增加如下信息
[san_names]
DNS.1 = example.com
DNS.2 = *.example.com # 通配符证书,或泛域名证书
# IP.1 = 192.168.31.11
# IP.2 = 192.168.31.12
创建根证书
# 创建 CA 私钥 ca-key.pem
openssl genrsa -out ca-key.pem 2048
# 创建 CA 证书 ca-cert.pem
openssl req -sha256 -new -x509 -days 36500 -key ca-key.pem -out ca-cert.pem -subj "/C=CN/ST=SiChuan/L=ChengDu/O=Mycompany/OU=JiaWen/CN=JiaWen-CA/emailAddress=admin@163.com" -config /etc/pki/tls/openssl.cnf
创建服务器证书
1、编辑 vim /etc/pki/tls/openssl.cnf,注释 clientAuth ,启用 serverAuth
[ v3_req ]
extendedKeyUsage = serverAuth # TLS Web Server Authentication 保证远程计算机的身份
# extendedKeyUsage = clientAuth
# 生成域名私钥
openssl genrsa -out example.com-key.pem 2048
# 生成证书签发请求文件,可以使用证书签名请求文件向证书颁发机构申请数字证书
# common name 一定要在 SubjectAlternativeName 中包含
openssl req -new -sha256 -key example.com-key.pem -out example.com-csr.pem -subj "/C=CN/ST=SiChuan/L=ChengDu/O=Mycompany/OU=JiaWen/CN=*.example.com/emailAddress=admin@163.com" -config /etc/pki/tls/openssl.cnf
# 使用自签署的 CA,生成域名证书(包含域名公钥、域名信息、CA 签名)
# 进行 CA 签名获取证书时,需要注意国家、省、单位需要与 CA 证书相同,否则会报异常 !! 不过可用通过 openssh.cnf 调整配置 policy_match
openssl ca -in example.com-csr.pem -md sha256 -days 36500 -cert ca-cert.pem -keyfile ca-key.pem -extensions v3_req -out example.com-cert.pem -config /etc/pki/tls/openssl.cnf
#> 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: Oct 18 08:18:13 2023 GMT
#> Not After : Sep 24 08:18:13 2123 GMT
#> Subject:
#> countryName = CN
#> stateOrProvinceName = SiChuan
#> organizationName = Mycompany
#> organizationalUnitName = JiaWen
#> commonName = *.example.com
#> emailAddress = admin@163.com
#> X509v3 extensions:
#> X509v3 Basic Constraints:
#> CA:FALSE
#> X509v3 Key Usage:
#> Digital Signature, Non Repudiation, Key Encipherment
#> X509v3 Extended Key Usage:
#> TLS Web Server Authentication
#> X509v3 Subject Alternative Name:
#> DNS:example.com, DNS:*.example.com
#> Certificate is to be certified until Sep 24 08:18:13 2123 GMT (36500 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
openssl pkcs12 -export -in example.com-cert.pem -inkey example.com-key.pem -out example.com.p12
创建客户端证书(可选)
1、编辑 vim /etc/pki/tls/openssl.cnf,注释 serverAuth ,启用 clientAuth
[ v3_req ]
# extendedKeyUsage = serverAuth
extendedKeyUsage = clientAuth # TLS Web Client Authentication 向远程计算机证明你的身份
2、创建客户端私钥及证书,并将二者转换为 p12 格式证书,最后将证书 example.com-client.p12 导入到浏览器端的" 个人 “证书存储位置即可
openssl genrsa -out example.com-client-key.pem 2048
# CN=192.168.31.219 可任意,标识该证书
openssl req -new -sha256 -key example.com-client-key.pem -out example.com-client-csr.pem -subj "/C=CN/ST=SiChuan/L=ChengDu/O=Mycompany/OU=JiaWen/CN=192.168.31.219/emailAddress=admin@163.com" -config /etc/pki/tls/openssl.cnf
# 使用 ca 签发证书
openssl ca -in example.com-client-csr.pem -md sha256 -days 36500 -cert ca-cert.pem -keyfile ca-key.pem -extensions v3_req -out example.com-client-cert.pem -config /etc/pki/tls/openssl.cnf
# 将证书及私钥合并为 p12 格式的证书 example.com-client.p12。提示设置密码,可直接回车,则密码为空
openssl pkcs12 -export -in example.com-client-cert.pem -inkey example.com-client-key.pem -out example.com-client.p12
#> Enter Export Password:
#> Verifying - Enter Export Password:
3、当启用 Nginx Client 认证后,且浏览器端未导入客户端证书及私钥时,访问 https://mobile.example.com/ 将提示如下错误:
400 Bad Request
No required SSL certificate was sent
nginx/1.24.0
安装 Nginx 服务
1、安装 Nginx
# cat /etc/yum.repos.d/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
# 安装 Nginx
yum install nginx -y
2、修改配置
# cat /etc/nginx/conf.d/default.conf
server {
listen 443 ssl;
server_name example.com www.example.com mobile.example.com;
ssl_certificate /etc/nginx/ssl/example.com-cert.pem;
ssl_certificate_key /etc/nginx/ssl/example.com-key.pem;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
# 启用 client 端验证,并设置根证书
ssl_verify_client on;
ssl_client_certificate /etc/nginx/ssl/ca-cert.pem;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
测试系统 Windows 设置
1、将自签名根证书 ca-cert.pem
导入到系统” 受信任的根证书颁发机构
“中,然后重启浏览器,这样每次通过浏览器访问该域名时,就不再提示 https 不安全等信息 !!
2、cat 添加 hosts 解析记录
192.168.31.89 example.com
192.168.31.89 www.example.com
192.168.31.89 mobile.example.com
3、启用 client 身份验证时,每次重启浏览器,访问站点 *.example.com,浏览器都会弹框提示,选择安装在浏览器端的 client 端证书 (该证书必须为 p12 格式) !!!
常用证书管理(可选)
查看 ca 根证书
使用命令openssl x509 -text -in ca-cert.pem -noout
查看
#> Certificate:
#> Data:
#> Version: 3 (0x2)
#> Serial Number:
#> d4:2b:90💿da:5a:15:d8
# 说明签名算法为:使用哈希算法 sha256 计算消息摘要, 使用非对称加密算法 RSA 的私钥(ca)加密摘要信息
#> Signature Algorithm: sha256WithRSAEncryption
#> Issuer: C=CN, ST=SiChuan, L=ChengDu, O=Mycompany, OU=JiaWen, CN=JiaWen-CA/emailAddress=admin@163.com
# 证书有效期范围
#> Validity
#> Not Before: Oct 18 08:45:13 2023 GMT
#> Not After : Sep 24 08:45:13 2123 GMT
# Subject 与 Issuer 相同,说明该证书是一个自签名证书
#> Subject: C=CN, ST=SiChuan, L=ChengDu, O=Mycompany, OU=JiaWen, CN=JiaWen-CA/emailAddress=admin@163.com
#> Subject Public Key Info:
# 说明公钥算法为 rsa ,且强度为 2048
#> Public Key Algorithm: rsaEncryption
#> Public-Key: (2048 bit)
#> Modulus:
#> 00:dd:82:46:44:cf:f0:57:41:11:9a:83:4a:24:2a:
#> ...
#> 6b:94:f3:19:78:b6:03:c5:ff:7c:96:5a:32:1c:18:
#> 62:67
#> Exponent: 65537 (0x10001)
# x509 v3 扩展配置项
#> X509v3 extensions:
#> X509v3 Subject Key Identifier:
#> F7:B9:73:65:20:E8:09:16:2E:D2:79:C5:26:B6:1B:F0:7D:7C:CA:2D
#> X509v3 Authority Key Identifier:
#> keyid:F7:B9:73:65:20:E8:09:16:2E:D2:79:C5:26:B6:1B:F0:7D:7C:CA:2D
#> X509v3 Basic Constraints:
#> CA:TRUE # 说明该证书为 根证书
#> Signature Algorithm: sha256WithRSAEncryption
#> d7:a7:f1:57:90:81:8c:da:20:89:74:2e:8b:03:89:3d:d9:84:
#> ...
#> 05:08:d2:53:16:51:9d:5b:05:ce:e7:ff:b2:68:1e:4d:de:a6:
#> 2e:e5:cb:68
查看 ca 签发的 server 端证书
使用命令 openssl x509 -text -in example.com-cert.pem -noout
查看
#> Certificate:
#> Data:
#> Version: 3 (0x2)
#> Serial Number: 1 (0x1)
#> Signature Algorithm: sha256WithRSAEncryption
# Issuer 为 根证书的 subject 设置
#> Issuer: C=CN, ST=SiChuan, L=ChengDu, O=Mycompany, OU=JiaWen, CN=JiaWen-CA/emailAddress=admin@163.com
#> Validity
#> Not Before: Oct 18 08:45:54 2023 GMT
#> Not After : Sep 24 08:45:54 2123 GMT
# 当前证书的 subject 设置
# CN 设置 *.example.com 须在 X509v3 扩展配置项 X509v3 Subject Alternative Name 的范围内
#> Subject: C=CN, ST=SiChuan, O=Mycompany, OU=JiaWen, CN=*.example.com/emailAddress=admin@163.com
#> Subject Public Key Info:
#> Public Key Algorithm: rsaEncryption
#> Public-Key: (2048 bit)
#> Modulus:
#> 00:e7:3a:ff:6b:bd:65:98:4e:94:c9:81:e9:3f:87:
#> ...
#> 43:a8:1c:a9:a7:95:99:30:82🆎f0:98:fd:ac:ba:
#> 67:4b
#> Exponent: 65537 (0x10001)
#> X509v3 extensions:
#> X509v3 Basic Constraints:
#> CA:FALSE
#> X509v3 Key Usage:
#> Digital Signature, Non Repudiation, Key Encipherment
# 说明是一个用于 tls web Server 端的认证证书,用于 client 端验证 server 身份
#> X509v3 Extended Key Usage:
#> TLS Web Server Authentication
#> X509v3 Subject Alternative Name:
#> DNS:example.com, DNS:*.example.com
#> Signature Algorithm: sha256WithRSAEncryption
#> 3b:2e:d6:89:93:6b:ae:98:02:81:da:f6:60:16:b6:2d:62:d8:
#> ...
#> 7c:97:45:e9:b3:5f:ac:30:a0:67:1a:7d:28:74:ae:0a:21:a9:
#> be:9f:ac:75
查看 ca 签发的 client 端证书
使用命令 openssl x509 -text -in example.com-client-cert.pem -noout
查看
#> Certificate:
#> Data:
#> Version: 3 (0x2)
#> Serial Number: 2 (0x2)
#> Signature Algorithm: sha256WithRSAEncryption
#> Issuer: C=CN, ST=SiChuan, L=ChengDu, O=Mycompany, OU=JiaWen, CN=JiaWen-CA/emailAddress=admin@163.com
#> Validity
#> Not Before: Oct 18 09:22:12 2023 GMT
#> Not After : Sep 24 09:22:12 2123 GMT
# CN 设置 192.168.31.219 为任意
#> Subject: C=CN, ST=SiChuan, O=Mycompany, OU=JiaWen, CN=192.168.31.219/emailAddress=admin@163.com
#> Subject Public Key Info:
#> Public Key Algorithm: rsaEncryption
#> Public-Key: (2048 bit)
#> Modulus:
#> 00:bc:26:13:28:21:50:0f:85:cc:4a:f8:c4:19:b5:
#> ...
#> 1d:5e:a1:f1:03:5a:4e:fb:f9:93:92:6e:e5:1e:4b:
#> 1d:77
#> Exponent: 65537 (0x10001)
#> X509v3 extensions:
#> X509v3 Basic Constraints:
#> CA:FALSE
#> X509v3 Key Usage:
#> Digital Signature, Non Repudiation, Key Encipherment
# 说明是一个用于 tls web Client 端的认证证书,用于 server 端验证 client 身份
#> X509v3 Extended Key Usage:
#> TLS Web Client Authentication
# 该扩展配置项需与 server 端证书的扩展配置项对应
#> X509v3 Subject Alternative Name:
#> DNS:example.com, DNS:*.example.com
#> Signature Algorithm: sha256WithRSAEncryption
#> 3f:0d:83:39:d0:62:7e:8e:e3:8a:e6:5b:78:97:29:65:ba:24:
#> ...
#> 7a:e1:d8:69:96:c7:79:b1:c1:b5:ec:d3:dc:89:92:e6:96:f3:
#> 7d:3c:6f:42
其它命令
# 查看证书签名请求文件 example.com-csr.pem 的内容
openssl req -text -in example.com-csr.pem -noout
# 查看私钥文件 example.com-key.pem 的内容
openssl rsa -text -in example.com-key.pem -noout
# 从私钥文件 example.com-key.pem 提取公钥信息,并保存到 example.com-pub-key.pem
openssl rsa -in example.com-key.pem -out example.com-pub-key.pem -pubout
# 查看公钥文件信息
openssl rsa -text -in example.com-pub-key.pem -pubin -noout
参考
在 Linux 下如何根据域名自签 发 OpenSSL 证书与常用证书转换
创建 CA、申请证书、吊销证书 !!!