使用Open SSL自签CA跟SSL证书
生成根 CA
- 为该根 CA 生成一个 4096 位的独立私钥
openssl genrsa -out MyCompanyCA.key 4096
- 使用生成私钥的自签根 CA
openssl req -x509 -new -nodes -key MyCompanyCA.key -sha256 -days 3650 -subj "/C=US/O=MyCompany/CN=MyCompany Root" -out MyCompanyCA.crt
在纯 OpenSSL 命令行中,如果你想在证书里加上国家(Country)和组织(Organization)等详细信息,你只需要在 -subj 参数里面继续往后追加字段即可。
各个标准字段的缩写如下:
-
C:国家 (Country,必须是 2 个字母的大写国家代码,) -
O:组织/公司名称 (Organization) -
OU:部门名称 (Organizational Unit,可选) -
CN:通用名称/所有人 (Common Name)
这些字段在 -subj 参数中通过斜杠 / 进行拼接。
如果还需要一个中间CA就继续给中间证书生成一个独立私钥
- 生成私钥
openssl genrsa -out MyIntermediateCA.key 4096
- 生成中间证书的“证书签名请求”(CSR 申请表)
openssl req -new -key MyIntermediateCA.key -out MyIntermediateCA.csr -sha256 -subj "/C=US/O=MyIntermediateCA/OU=MyIntermediateCA/CN=MyIntermediateCA"
执行完后,你会得到一个 MyIntermediateCA.csr 申请表文件。
- 用 Root CA 批准并签发中间证书
为了强行给中间证书注入CA:true的身份,我们在签发时需要利用 Linux 的echo命令塞一个扩展配置文件进去。
openssl x509 -req -in MyIntermediateCA.csr -CA MyCompanyCA.crt -CAkey MyCompanyCA.key -CAcreateserial -out MyIntermediateCA.crt -days 4000 -sha256 -extfile <(echo -e "basicConstraints=critical,CA:true\nkeyUsage=critical,digitalSignature,keyCertSign,cRLSign")
如果你使用的是Windows系统
1.写一个 Windows 格式的临时扩展文件
(echo basicConstraints=critical,CA:true & echo keyUsage=critical,digitalSignature,keyCertSign,cRLSign) > x509.cnf
2. 拿你的根证书(Root CA)对中间CA进行签名(设为 4000 天有效期)
openssl x509 -req -in MyIntermediateCA.csr -CA MyCompanyCA.crt -CAkey MyCompanyCA.key -CAcreateserial -out MyIntermediateCA.crt -days 4000 -sha256 -extfile x509.cnf
3. 删掉无用的临时配置文件
del x509.cnf
给终端/域名生成证书
- 手动创建一个标准的域名配置文件
server.cnf
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = www.example.com
- 为该域名生成一个 2048 位的独立私钥
openssl genrsa -out server.key 2048
- 生成带有该域名的证书申请表 (CSR)
openssl req -new -nodes -key server.key -subj "/CN=www.example.com" -out server.csr
- 注入 SAN 域名扩展并正式签发
用中间 CA 进行签名,指定 365 天(1年)有效期
openssl x509 -req -in server.csr -CA MyIntermediateCA.crt -CAkey MyIntermediateCA.key -CAcreateserial -out server.crt -days 365 -sha256 -extfile server.cnf -extensions v3_req
:: 清理终端证书的临时文件
del server.cnf server.csr
- 合并完整的证书链
copy /b server.crt+MyIntermediateCA.crt MyFullChain.crt
只要把这两个文件传到你的服务器,并在电脑上信任最顶层的 MyCompanyCA.crt就可以了
-
fullchain.crt:完整的证书链(里面包含了:终端域名 -> 中间CA)。 -
server.key:域名的私钥。
细心的朋友可能会发现这里并没有合并根CA,是因为在标准的Web证书规范(如 RFC 5246 / TLS 1.2+)中,服务器证书链通常是不包含根 CA 的有两个原因
1. 浏览器/操作系统的信任逻辑是根证书必须是本地已知的
当你的电脑访问服务器时,浏览器会收到服务器发来的证书链。浏览器的验证逻辑是:
- 终端证书是不是中间 CA 签发的?(是)
- 中间 CA 是不是根 CA 签发的?(是)
- 这个根 CA,在不在我本地的“受信任的根证书颁发机构”列表里?
如果根 CA 在本地列表里,浏览器就认为整条链合法;如果不在,即使服务器把根 CA 证书主动发给浏览器,浏览器也绝对不会临时信任它,依然会报“证书不可信”。
因此,服务器发送根 CA 属于多此一举了,客户端完全不需要服务器来告诉它根 CA 长什么样,它只认自己本地保存的根 CA。
2. 浪费网络带宽(增加握手延迟)
根 CA 证书一般比较大(因为通常是 4096 位甚至更高)。在 TCP/TLS 握手阶段,服务器发送的数据越多,网络包可能就需要分片传输,这会直接增加网页首次打开的延迟*。所以标准做法是尽量精简证书链,不发送多余的根证书。
💡什么时候需要合并进去?
- 私有内网或特定客户端(如 Curl、Java、OpenVPN): 有些私有服务或后端开发代码在对接时,不支持读取本地系统的证书库。它们要求在配置里直接指定一个包含完整闭环(含根CA)的
.pem文件,通过代码显式加载来建立信任。 - 作为归档和完整备份: 将四张证书打包在一起,方便你完整保存这个多级 PKI 架构的所有资产。
总结来说:如果是配置标准的 Web 服务器(如 Nginx)让普通浏览器访问,证书链写到 中间 CA 即可(即 server + inter1),根证书单独留给客户端去双击安装。
- 如果是内网私有组件对接、OpenVPN 部署或代码调用,直接使用包含了根证书的全面闭环
MyFullChain.pem会更省心、兼容性更好。
评论交流
欢迎留下你的想法