0. 准备工作
- 一个Linux的机器,安装好openssl,大部分机器都已经默认安装好了,你可以试试执行看看
openssl version。我这里使用的是Ubuntu 24.04 LTS。
- 一个足够强度的根证书密码,本文用
gwIQpfpItKSBJ0bvH3hQ,该密码仅作为示例用,你需要创建自己的密码并妥善保管。
- 一个足够强度的中间证书密码,并妥善保管,本文用
Fqvgw9GlCrOlXwkym3kQ作为示例。
基础知识
graph LR
A[根证书(Root CA)
----------------------------------
•信任链的起点
• 主要用于签发中间证书
• 离线保存,降低被攻击风险] -- 签发 --> B B[中间证书(Intermediate CA)
----------------------------------
• 服务器证书的实际签发者] -- 签发 --> C C[服务器证书(Server Cert)
----------------------------------
• 终端实际使用者
• 可用于网站加密等,包含域名信息]
----------------------------------
•信任链的起点
• 主要用于签发中间证书
• 离线保存,降低被攻击风险] -- 签发 --> B B[中间证书(Intermediate CA)
----------------------------------
• 服务器证书的实际签发者] -- 签发 --> C C[服务器证书(Server Cert)
----------------------------------
• 终端实际使用者
• 可用于网站加密等,包含域名信息]
- 根证书(Root CA)不直接签发业务证书,而只签发中间证书(Intermediate CA)。
- 下级证书的信任来源于上级证书
- 根证书私钥离线存储,中间证书私钥严格保护,且各级证书都有独立的吊销机制(CRL/OCSP)
1. 创建CA证书项目
1.1 初始化项目
为了方便演示,我把该项目命名为cert_maintains,并且放在home目录。当然你可以放在任意目录,注意调整命令中的路径即可。
mkdir -p ~/cert_maintains/ca/{root,intermediate}/{certs,crl,newcerts,private,csr}
cd ~/cert_maintains
touch ca/root/index.txt ca/intermediate/index.txt
echo 1000 > ca/root/serial
echo 1000 > ca/intermediate/serial
echo 1000 > ca/root/crlnumber
echo 1000 > ca/intermediate/crlnumber
1.2 Root CA证书
1.2.1 创建Root CA的配置文件
Root CA配置文件路径:~/cert_maintains/ca/root/openssl.cnf
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = .
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
crlnumber = $dir/crlnumber
certificate = $dir/certs/ca.cert.pem
private_key = $dir/private/ca.key.pem
crl = $dir/crl/ca.crl.pem
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 7300
preserve = no
policy = policy_strict
[ policy_strict ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
string_mask = utf8only
default_md = sha256
prompt = no
distinguished_name = dn
[ dn ]
C = CN
ST = Guangdong
L = Shenzhen
O = Linhancai
OU = Root CA
CN = Linhancai Root CA
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_intermediate_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
1.2.2 签发Root CA
# 1. 切换到Root CA目录
cd ~/cert_maintains/ca/root
# 2. 生成Root CA私钥,回车后提示输入两次数据密码(gwIQpfpItKSBJ0bvH3hQ)
openssl genrsa -aes256 -out private/ca.key.pem 4096
# 3. 使用Root CA私钥签发Root CA证书
openssl req -config openssl.cnf \
-key private/ca.key.pem \
-new -x509 -days 7300 \
-extensions v3_ca \
-out certs/ca.cert.pem
本步骤得到Root CA私钥private/ca.key.pem和Root CA证书certs/ca.cert.pem
1.3. 中间CA
1.3.1 创建中间CA配置文件
中间CA配置文件路径为:~/cert_maintains/ca/intermediate/openssl.cnf
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = .
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
crlnumber = $dir/crlnumber
certificate = $dir/certs/intermediate.cert.pem
private_key = $dir/private/intermediate.key.pem
crl = $dir/crl/intermediate.crl.pem
default_md = sha256
default_days = 375
policy = policy_loose
preserve = no
[ policy_loose ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
string_mask = utf8only
default_md = sha256
prompt = no
distinguished_name = dn
[ dn ]
C = CN
ST = Guangdong
L = Shenzhen
O = Linhancai
OU = Intermediate CA
CN = Linhancai Intermediate CA
[ v3_intermediate_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ server_cert ]
basicConstraints = CA:false
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[ client_cert ]
basicConstraints = CA:false
nsCertType = client
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = clientAuth
1.3.2 签发中间证书
# 1. 切换到中间证书目录
cd ~/cert_maintains/ca/intermediate
# 2. 生成中间CA私钥,同样回车后提示输入两次数据密码(Fqvgw9GlCrOlXwkym3kQ)
openssl genrsa -aes256 -out private/intermediate.key.pem 4096
# 3. 利用中间CA私钥,生成中间CA CSR文件
openssl req -config openssl.cnf \
-new -key private/intermediate.key.pem \
-out csr/intermediate.csr.pem
# 4. **切换回Root CA目录**,用Root CA签发中间CA证书
# 执行命令需要输入Root CA私钥的密码(gwIQpfpItKSBJ0bvH3hQ)
# 输入密码后根据提示输入y确认签发
cd ca/root
openssl ca -config openssl.cnf \
-extensions v3_intermediate_ca \
-days 3650 \
-notext -md sha256 \
-in ../intermediate/csr/intermediate.csr.pem \
-out ../intermediate/certs/intermediate.cert.pem
1.4 设置好权限
cd ~/cert_maintains
chmod 700 ca/root/private
chmod 700 ca/intermediate/private
chmod 600 ca/root/private/*.key.pem
chmod 600 ca/intermediate/private/*.key.pem
至此CA证书签发已经签发完成,项目结构为:
cert_maintains
└── ca
├── intermediate
│ ├── certs
│ │ └── intermediate.cert.pem
│ ├── crl
│ ├── crlnumber
│ ├── csr
│ │ └── intermediate.csr.pem
│ ├── index.txt
│ ├── newcerts
│ ├── openssl.cnf
│ ├── private
│ │ └── intermediate.key.pem
│ └── serial
└── root
├── certs
│ └── ca.cert.pem
├── crl
├── crlnumber
├── csr
├── index.txt
├── index.txt.attr
├── index.txt.old
├── newcerts
│ └── 1000.pem
├── openssl.cnf
├── private
│ └── ca.key.pem
├── serial
└── serial.old
2. 签发业务证书
2.1 为nginx签发https证书
现在我想要用自签名CA为域名 example.linhancai.cn签发一个证书,用于配置nginx的https。
2.1.1 创建域名证书配置文件
证书的路径放在~/cert_maintains/ca/intermediate/csr/example.linhancai.cn.cnf,内容如下
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = req_ext
[ dn ]
C = CN
ST = Guangdong
L = Shenzhen
O = Linhancai
OU = Domain Cert
CN = example.linhancai.cn
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = example.linhancai.cn
DNS.2 = www.example.linhancai.cn
IP.1 = 192.168.100.20
2.2.2 签发域名证书
# 1. 切换到中间证书目录
cd ~/cert_maintains/ca/intermediate
# 2. 创建一个域名证书私钥,这里就不设置密码了
openssl genrsa -out private/example.linhancai.cn.key.pem 2048
# 3. 生成域名的CSR文件
openssl req \
-config csr/example.linhancai.cn.cnf \
-key private/example.linhancai.cn.key.pem \
-new \
-out csr/example.linhancai.cn.csr.pem
# 4. 中间CA签发证书,需要输入中间CA的私钥密码(Fqvgw9GlCrOlXwkym3kQ),然后输入y确认签发。
openssl ca \
-config openssl.cnf \
-extensions server_cert \
-in csr/example.linhancai.cn.csr.pem \
-out certs/example.linhancai.cn.cert.pem
# 5. 生成证书链,就是把中间CA证书和域名证书打包到一个证书文件。
cat \
certs/example.linhancai.cn.cert.pem \
certs/intermediate.cert.pem > certs/example.linhancai.cn.fullchain.pem
# 6. 验证证书的有效性
# 得到输出`ca/intermediate/certs/example.linhancai.cn.cert.pem: OK` 说明证书有效
cd ~/cert_maintains
openssl verify \
-CAfile ca/root/certs/ca.cert.pem \
-untrusted ca/intermediate/certs/intermediate.cert.pem \
ca/intermediate/certs/example.linhancai.cn.cert.pem
2.2.3 配置nginx使用证书
server {
listen 443 ssl;
server_name example.linhancai.cn www.example.linhancai.cn;
ssl_certificate /etc/nginx/ssl/example.linhancai.cn.fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/example.linhancai.cn.key.pem;
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security "max-age=31536000" always;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
return 200 "TLS OK\n";
}
}
3. 其他问题
3.1 为什么我配置了证书后,浏览器还是提示不安全?
因为Root CA的证书是我们自签的,客户端系统不认识这个证书,你可以把它导入操作系统的信任证书列表中。