使用Open SSL自签CA跟SSL证书

生成根 CA

  1. 为该根 CA 生成一个 4096 位的独立私钥
openssl genrsa -out MyCompanyCA.key 4096
  1. 使用生成私钥的自签根 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就继续给中间证书生成一个独立私钥

  1. 生成私钥
openssl genrsa -out MyIntermediateCA.key 4096
  1. 生成中间证书的“证书签名请求”(CSR 申请表)
openssl req -new -key MyIntermediateCA.key -out MyIntermediateCA.csr -sha256 -subj "/C=US/O=MyIntermediateCA/OU=MyIntermediateCA/CN=MyIntermediateCA"

执行完后,你会得到一个 MyIntermediateCA.csr 申请表文件。

  1. 用 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

给终端/域名生成证书

  1. 手动创建一个标准的域名配置文件 server.cnf
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = www.example.com
  1. 为该域名生成一个 2048 位的独立私钥
openssl genrsa -out server.key 2048
  1. 生成带有该域名的证书申请表 (CSR)
openssl req -new -nodes -key server.key -subj "/CN=www.example.com" -out server.csr
  1. 注入 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
  1. 合并完整的证书链
copy /b server.crt+MyIntermediateCA.crt MyFullChain.crt

只要把这两个文件传到你的服务器,并在电脑上信任最顶层的 MyCompanyCA.crt就可以了

  1. fullchain.crt:完整的证书链(里面包含了:终端域名 -> 中间CA)。
  2. 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 握手阶段,服务器发送的数据越多,网络包可能就需要分片传输,这会直接​增加网页首次打开的延迟*。所以标准做法是尽量精简证书链,不发送多余的根证书。

💡什么时候需要合并进去?

  1. ​私有内网或特定客户端(如 Curl、Java、OpenVPN): 有些私有服务或后端开发代码在对接时,不支持读取本地系统的证书库。它们要求在配置里直接指定一个包含完整闭环(含根CA)的 .pem 文件,通过代码显式加载来建立信任。
  2. 作为归档和完整备份​: 将四张证书打包在一起,方便你完整保存这个多级 PKI 架构的所有资产。

总结来说:如果是​配置标准的 Web 服务器(如 Nginx)让普通浏览器访问,证书链写到 中间 CA 即可(即 server + inter1),根证书单独留给客户端去双击安装。

  • 如果是​内网私有组件对接、OpenVPN 部署或代码调用​,直接使用包含了根证书的全面闭环 MyFullChain.pem 会更省心、兼容性更好。