4、中间证书颁发机构(CA):生成中间CA私钥、使用根证书签发中间CA证书、证书链的层级概念

好,我们继续往下走。上一章我们把根CA建好了,它就像一把藏在保险柜里的万能钥匙。但你想,如果每次签发服务器证书都用这把万能钥匙,万一哪天它被偷了,整个信任体系就全完了。

所以,我们需要一个“中间人”。这就是中间CA。

4.1 为什么非要中间CA不可?

说白了,就是风险隔离。根CA的私钥应该永远处于离线状态,甚至物理隔离。日常签发证书的工作,交给中间CA去做。

我见过一个真实的案例。某大厂早期没做层级隔离,根证书私钥直接放在在线服务器上。结果被拖库,私钥泄露,不得不紧急吊销所有已签发的证书,重新铺信任链。那场面,简直是灾难。

所以,记住这个原则:根CA只签中间CA,中间CA才签终端证书。

核心原则:根CA私钥离线存储,中间CA私钥在线使用。一旦中间CA出问题,可以用根CA吊销它,而根CA本身不受影响。

4.2 生成中间CA的私钥

这一步和生成根CA私钥几乎一样。但有个细节:中间CA的密钥长度,我个人习惯和根CA保持一致,都用4096位。虽然2048位在安全上目前也够用,但既然根CA已经用了4096,中间CA就别降级了,保持统一标准。

# 生成中间CA私钥,带AES-256加密
openssl genrsa -aes256 -out intermediate/private/intermediate.key.pem 4096

# 设置权限,只允许文件所有者读取
chmod 400 intermediate/private/intermediate.key.pem

这里你会被要求输入一个密码。嗯,这个密码一定要记牢。我建议你把它存在密码管理器里,或者写进物理保险柜的文档里。别指望靠脑子记,三个月后你肯定忘。

小技巧:中间CA私钥的密码可以和根CA不同。我个人习惯用不同的密码,这样即使中间CA的密码泄露,根CA依然是安全的。

4.3 生成中间CA的证书签名请求(CSR)

有了私钥,下一步就是生成CSR。这里要注意,中间CA的DN(Distinguished Name)必须和根CA不同。尤其是Common Name,要能清晰区分层级。

# 创建中间CA的配置文件 intermediate/openssl.cnf
# 这里只列出关键部分,完整配置请参考课程附件

[ req ]
prompt = no
distinguished_name = req_distinguished_name

[ req_distinguished_name ]
C = CN
ST = Beijing
L = Beijing
O = My Company Intermediate CA
OU = Certificate Authority
CN = My Company Intermediate CA 2024

# 生成CSR
openssl req -new \
    -key intermediate/private/intermediate.key.pem \
    -out intermediate/csr/intermediate.csr.pem \
    -config intermediate/openssl.cnf

你看,这里的O我写的是“My Company Intermediate CA”,而不是根CA的“My Company Root CA”。这样一眼就能看出层级关系。

4.4 使用根CA签发中间CA证书

这一步是关键。我们要用根CA的私钥去签中间CA的CSR。注意,这里要加一个扩展参数 -extensions v3_ca,告诉OpenSSL:这是一个CA证书,不是终端证书。

# 切换到根CA的工作目录
cd /root/ca

# 使用根CA签发中间CA证书
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

# 设置权限
chmod 444 intermediate/certs/intermediate.cert.pem

这里有个坑,我踩过。如果你在根CA的配置文件中没有定义 v3_intermediate_ca 这个扩展段,OpenSSL会报错。所以,一定要在根CA的 openssl.cnf 里加上这一段:

[ v3_intermediate_ca ]
# 标记为CA证书,关键路径长度为0(表示不能再往下签)
basicConstraints = critical, CA:TRUE, pathlen:0
# 密钥用途
keyUsage = critical, digitalSignature, keyCertSign, cRLSign
# 证书策略(可选)
certificatePolicies = 2.5.29.32.0

注意 pathlen:0。这个参数的意思是:这个中间CA不能再签发下一级CA了。如果你希望中间CA还能再签下级CA,可以设成 pathlen:1。但一般情况下,两层就够了,根CA→中间CA→终端证书。

警告:千万不要把 pathlen 设得太大,或者干脆不设。否则中间CA被攻破后,攻击者可以无限签发下级CA,整个信任链就失控了。我曾经见过一个案例,就是因为没设 pathlen,导致一个被攻破的中间CA签出了几十个伪造的二级CA。

4.5 验证中间CA证书

签发完成后,一定要验证一下。看看证书内容对不对,是不是由根CA签发的。

# 查看中间CA证书内容
openssl x509 -noout -text -in intermediate/certs/intermediate.cert.pem

# 验证证书链:用根CA证书验证中间CA证书
openssl verify -CAfile certs/ca.cert.pem \
    intermediate/certs/intermediate.cert.pem

如果输出 intermediate.cert.pem: OK,那就说明验证通过了。如果报错,多半是扩展字段配置有问题,或者根CA的证书路径没写对。

4.6 证书链的层级概念

好,现在我们来聊聊证书链到底是个什么东西。

你想想看,浏览器访问一个HTTPS网站时,它拿到的是服务器证书。但这个证书是谁签的?中间CA。那浏览器怎么信任中间CA?因为中间CA的证书是根CA签的。而根CA的证书,是预装在操作系统或浏览器里的。

这就形成了一条链:

  • 根证书(自签名,预装在信任库中)
  • ↓ 签发
  • 中间证书(由根CA签发)
  • ↓ 签发
  • 服务器证书(由中间CA签发)

浏览器验证时,会从服务器证书开始,逐级向上找签发者,直到找到一个它信任的根证书。这个过程叫“证书链验证”或“路径构建”。

我画了一张图,帮你理解这个层级关系:

证书链层级结构图 证书链层级结构 根CA (Root CA) 自签名 · 离线存储 · 信任锚点 签发 中间CA (Intermediate CA) 由根CA签发 · 在线使用 · pathlen=0 签发 服务器证书 (Server Cert) 由中间CA签发 · 用于HTTPS等 验证流程: 1. 浏览器获取服务器证书 → 2. 找到签发者(中间CA)→ 3. 获取中间CA证书 → 4. 找到签发者(根CA)→ 5. 根CA在信任库中 → 6. 验证通过 ✅

你看,这个结构就像一棵倒挂的树。根在最上面,中间CA在中间,服务器证书在最下面。每一级都信任上一级,直到根。

4.7 创建证书链文件

在实际部署中,服务器需要把中间CA证书和服务器证书一起发给客户端。因为客户端(比如浏览器)只有根证书,没有中间CA证书。如果不发中间CA证书,客户端就找不到验证路径。

所以,我们需要创建一个证书链文件:

# 将服务器证书和中间CA证书合并
cat intermediate/certs/intermediate.cert.pem \
    certs/ca.cert.pem \
    > intermediate/certs/ca-chain.cert.pem

# 查看合并后的文件
cat intermediate/certs/ca-chain.cert.pem

这个 ca-chain.cert.pem 文件,就是服务器需要配置的证书链。顺序是:先服务器证书,再中间CA证书,最后根CA证书。但注意,有些服务器配置要求顺序反过来,具体看文档。

经验之谈:我建议你在Nginx或Apache上配置时,把证书链文件和服务器私钥分开存放。证书链可以公开,但私钥必须严格保护。我曾经见过有人把私钥和证书链放在同一个文件里,然后不小心提交到了Git仓库……嗯,后果你懂的。

4.8 本章小结

好,我们来快速回顾一下这章的核心内容:

概念 说明 关键点
根CA 信任链的起点,自签名 离线存储,只签中间CA
中间CA 由根CA签发,用于签发终端证书 pathlen=0,防止无限签发
服务器证书 由中间CA签发,用于实际服务 部署时需附带中间CA证书
证书链文件 服务器证书 + 中间CA证书 + 根CA证书 顺序因服务器而异