自己创建 CA,并用 CA 为各服务签发证书
这篇文章是基于 常用 OpenSSL 命令 的一个补充,主要是介绍如何自己创建 CA,并用 CA 为各服务签发证书。
生成 CA 私钥
openssl ecparam -name prime256v1 -genkey -out ca.key
生成 CA 证书
为了让根证书的信息看起来漂亮一点,参考了几个有名的根证书,使用了 Organization、Organizational Unit、Common Name 这几个字段。
把这几个字段写进一个配置文件(这里命名为 ca.conf),后面生成 CA 证书时会用到。
[ req ]
prompt = no
distinguished_name = req_distinguished_name
x509_extensions = v3_req
[ req_distinguished_name ]
OU = My Service, Inc.
O = My Service, Inc.
CN = My Service Root CA
[ v3_req ]
keyUsage = keyCertSign, cRLSign
basicConstraints = critical,CA:true
- 因为私钥是
ECDSA算法生成的,所以[req]段下面的default_bits = 2048就不起作用了,可以不写。 - keyUsage:keyUsage 扩展定义了证书的公钥可以用于哪些操作。对于根证书和中间CA证书,以下两个值通常是必须的:
- keyCertSign:证明证书的公钥可以用来签署其他证书。这是CA证书的关键功能,因为CA的主要作用就是签发证书。
- cRLSign:证明证书的公钥可以用来签署证书撤销列表(CRL)。CRL是由CA发布的列表,包含了被撤销(不再有效)的证书序列号。
- basicConstraints:basicConstraints 是一个关键扩展,它指示证书是否是CA证书以及是否有权签发其他证书。
- CA:true:指示证书是CA证书,并且可以用来签发其他证书。
- critical:这个关键字表示这个扩展是“关键的”,意味着如果证书使用者或者验证证书链的软件不能理解这个扩展,那么应该拒绝这个证书。对于 basicConstraints,这是非常重要的,因为它定义了证书的基本信任结构。
然后用这个配置文件生成 CA 证书。
openssl req -new -x509 -key ca.key -out ca.crt -days 3650 -sha256 -config ca.conf
-sha256:指定签名时使用的摘要算法(新版 OpenSSL 默认就是 SHA-256,写上是为了明确)。- 网上的例子里常见的
-nodes(不加密私钥)在这里不需要:它只在让openssl req顺便生成私钥(-newkey)时才有意义,这里私钥已经单独生成好了。
生成服务私钥
openssl ecparam -name prime256v1 -genkey -out server.key
生成服务证书请求(CSR)
openssl req -new -key server.key -out server.csr
不加 -config 时,OpenSSL 会以交互方式询问 Common Name 等信息。
注意:Chrome 等现代浏览器校验证书时只认 SAN(Subject Alternative Name),不再看 Common Name。所以只要证书是给浏览器访问的服务用的,就应该配置 SAN,而不只是「多个域名」的场景才需要。SAN 配置文件(san.cnf)的写法参考 常用 OpenSSL 命令,然后在生成 CSR 时加上 -config 选项。
openssl req -new -key server.key -out server.csr -config san.cnf
用自己的 CA 为服务签发证书
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650 -sha256
需要 SAN 时有一个很容易踩的坑:openssl x509 -req 默认不会把 CSR 里的扩展复制进证书。也就是说即使上一步的 CSR 里已经带了 SAN,直接用上面的命令签出来的证书里也没有 SAN。签发时必须用 -extfile 和 -extensions 把扩展再指定一遍(req_ext 是 san.cnf 里扩展段的名字)。
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650 -sha256 -extfile san.cnf -extensions req_ext
-CAcreateserial:序列号文件(ca.srl)不存在时自动创建。CA 用它给每张签出的证书分配唯一的序列号。- OpenSSL 3.0 起也可以用
-copy_extensions copy直接复制 CSR 里的扩展,代替-extfile/-extensions。
签完可以验证一下证书链和 SAN 是否正确:
openssl verify -CAfile ca.crt server.crt
openssl x509 -in server.crt -noout -text | grep -A 1 "Subject Alternative Name"
关于 398 天有效期限制
从 2020 年 9 月 1 日起,Apple 和 Google 等厂商不再信任有效期超过 398 天(大约 13 个月)的新签发 SSL/TLS 证书,超过会触发 NET::ERR_CERT_VALIDITY_TOO_LONG 错误。
不过这个限制只针对系统预装(公共信任)的根 CA 签发的证书。像本文这样自己创建、再手动添加到信任列表的 CA 不受影响——Apple 的官方说明里明确写了 "This change will not affect certificates issued from user-added or administrator-added Root CAs"。所以上面给服务证书设置 -days 3650 是没有问题的。