基于openssl的证书生成

其实你不知道, 你给我糖的时候,别人给我蛋糕,只是我没要,后来我发现,你也有蛋糕,但你没给我

Posted by yishuifengxiao on 2025-01-17

证书生成流程及密钥关联性

生成根证书(自签名证书)

私钥生成

openssl genrsa -out CA-A.key 2048

生成根证书私钥 CA-A.key(2048位RSA密钥),仅用于签发下级证书‌‌

公钥与证书生成

openssl req -x509 -new -key CA-A.key -out CA-A.crt -days 3650

通过私钥生成自签名根证书CA-A.crt,内含公钥和身份信息,有效期10年‌

生成中间证书B(由根证书签发)

中间私钥生成

openssl genrsa -out Cert-B.key 2048

生成中间证书私钥 Cert-B.key,用于签发终端证书或下一级中间证书‌

生成证书签名请求(CSR)

openssl req -new -key Cert-B.key -out Cert-B.csr

创建包含公钥和身份信息的请求文件 Cert-B.csr

根证书签发中间证书

openssl x509 -req -in Cert-B.csr -CA CA-A.crt -CAkey CA-A.key -out Cert-B.crt -days 365 -CAcreateserial

使用根证书私钥对中间证书签名,生成Cert-B.crt,其公钥由 Cert-B.key派生‌

生成终端证书C(由中间证书签发)

终端私钥生成

openssl genrsa -out Cert-C.key 2048

生成终端私钥Cert-C.key,用于服务端或客户端加密通信‌

生成终端CSR‌:

openssl req -new -key Cert-C.key -out Cert-C.csr

包含终端公钥和域名/IP等信息的请求文件‌

中间证书签发终端证书

openssl x509 -req -in Cert-C.csr -CA Cert-B.crt -CAkey Cert-B.key -out Cert-C.crt -days 365 -CAcreateserial

中间证书私钥对终端证书签名,生成,其公钥由Cert-C.key派生‌


关键关联总结

组件 生成来源 作用场景 安全性要求
根证书私钥 手动生成(openssl) 签发中间证书 最高(建议离线存储)
中间证书私钥 中间证书生成流程 签发终端证书 高(限制访问权限)
终端私钥 终端证书生成流程 加密通信/生成签名 中(服务器端存储)
证书 由上级私钥签发 公钥合法性验证与身份认证 需保护完整性

验证证书链时,需合并根证书和中间证书(cat CA-A.crt Cert-B.crt > chain.crt),确保终端证书的信任链完整‌25。


证书有效性检查

证书有效期验证

检查证书时间范围

  • 使用工具(如 openssl x509 -in cert.crt -dates -noout)查看证书的 ‌生效时间‌(notBefore)和 ‌失效时间‌(notAfter),确保当前时间在有效期内‌12。

  • 示例输出:

    textCopy CodenotBefore=Mar  5 00:00:00 2025 GMT  
    notAfter=Mar 5 00:00:00 2026 GMT

验证证书链有效期

  • 根证书、中间证书和终端证书均需满足有效期要求,任一证书过期均会导致链式失效‌25。

证书链完整性验证

信任链回溯

  • 终端证书的合法性需依赖完整的证书链(根证书 → 中间证书 → 终端证书)。

  • 通过合并根证书和中间证书验证链式签名:

    openssl verify -CAfile <(cat CA-Root.crt Intermediate.crt) Server.crt

    若输出OK,则信任链完整‌

openssl verify -CAfile <(cat CA-A.crt Cert-B.crt) Cert-C.crt  

自签名根证书验证

  • 根证书需为自签名且存在于本地信任存储中(如系统或浏览器的受信任根证书列表)。

签名合法性验证

  1. 验证签发者签名

    • 使用上级证书的公钥验证当前证书的签名是否合法。

    • OpenSSL 示例(验证中间证书是否由根证书签发):

      openssl verify -CAfile CA-A.crt Cert-B.crt

      若返回OK,则签名有效‌

  2. 检查证书用途

    • 确认证书的扩展字段(如 X509v3 Key UsageX509v3 Extended Key Usage)符合预期用途(如服务器认证、代码签名等)。

证书撤销状态检查

  1. CRL(证书撤销列表)查询

    • 从证书中提取 CRL 分发点(X509v3 CRL Distribution Points),下载 CRL 文件并检查证书是否被撤销‌。

    • OpenSSL 示例:

      openssl crl -inform DER -in revoked.crl -text -noout
  2. OCSP(在线证书状态协议)实时验证

    • 使用 OCSP 服务实时验证证书状态:

      openssl ocsp -issuer Intermediate.crt -cert Server.crt -url http://ocsp.example.com -text

      若返回good,则证书未被撤销‌

完整的校验方法

# 将证书按顺序合并(C、B、A)
cat certificateC.pem intermediateB.pem rootA.pem > chain.pem

# 使用OpenSSL验证链
openssl verify -CAfile rootA.pem -untrusted intermediateB.pem certificateC.pem
  1. -CAfile rootA.pem

    • 作用:指定受信任的根证书(Root CA)。
    • 逻辑
      • OpenSSL 将 rootA.pem 视为信任锚点(Trust Anchor)。
      • 根证书必须自签名且存在于系统的信任存储中(或通过 -CAfile 显式指定)。
  2. -untrusted intermediateB.pem

    • 作用:提供中间证书(Intermediate CA),但该证书本身不受自动信任
    • 逻辑
      • OpenSSL 会用 intermediateB.pem 构建证书链,但不会直接信任它。
      • 中间证书的合法性需通过根证书 rootA.pem 的签名验证。
    • 注意-untrusted 参数仅用于传递中间证书,不可省略。
  3. certificateC.pem

    • 作用:待验证的终端实体证书(End-Entity Certificate)。
    • 逻辑
      • OpenSSL 会检查 certificateC.pem 的签名是否由 intermediateB.pem 的私钥签发。
      • 最终通过根证书 rootA.pem 验证整个链的合法性。

    Q1: 为什么要用 -untrusted 参数?

    • 回答:中间证书本身不可被自动信任,必须通过根证书验证其合法性。-untrusted 仅告诉 OpenSSL 使用这些证书来构建链,但不会直接信任它们。

    Q2: 证书顺序是否重要?

    • 合并证书链时:必须按从终端证书到根证书的顺序(C -> B -> A)。
    • 使用 -untrusted:无需严格顺序,OpenSSL 会自动匹配颁发者(Issuer)和主题(Subject)。

    Q3: 如果缺少中间证书会发生什么?

    • OpenSSL 会报错:unable to get issuer certificate,表示无法找到链中的中间环节。

    Q4: 如何验证其他格式的证书(如 DER 格式)?

    • 使用 -inform DER 参数指定格式:

      openssl verify -CAfile rootA.der -inform DER ...

扩展场景

验证 HTTPS 服务器的证书链

openssl s_client \
-connect example.com:443 \
-showcerts \
-CAfile rootA.pem \
-verify_return_error
  • 通过 s_client 连接服务器并实时验证证书链。

检查证书吊销状态(OCSP)

openssl ocsp \
-issuer intermediateB.pem \
-cert certificateC.pem \
-url http://ocsp.example.com
  • 使用 OCSP 协议检查证书是否被吊销。

一个完整的校验场景

有一个根证书A,根据根证书A生成的中间证书B,根据中间证书B生成的证书C,这些证书都是crt格式,怎么校验这三个证书的有效性

验证证书C的签发关系

# 检查证书C是否由中间证书B签发
openssl verify -CAfile CA-A.crt -untrusted Cert-B.crt Cert-C.crt
  • 若输出 Cert-C.crt: OK,表示证书C的签发者为中间证书B,且签名有效‌。

验证中间证书B的签发关系

# 检查中间证书B是否由根证书A签发
openssl verify -CAfile CA-A.crt Cert-B.crt
  • 若输出 Cert-B.crt: OK,表示中间证书B由根证书A签发‌。

验证证书链完整性

# 合并中间证书B和根证书A到链文件(chain.pem)
cat Cert-B.crt Cert-A.crt > chain.pem

# 验证完整证书链(包含根证书)
openssl verify -CAfile chain.pem Cert-C.crt
  • 若输出 Cert-C.crt: OK,表示整个证书链可信‌。

手动验证签发者与主题匹配

# 查看证书C的签发者(Issuer)
openssl x509 -in Cert-C.crt -noout -issuer

# 查看中间证书B的主题(Subject)
openssl x509 -in Cert-B.crt -noout -subject

# 两者应完全匹配,否则签发关系不成

验证有效期

# 检查所有证书的有效期
openssl x509 -in Cert-C.crt -noout -dates
openssl x509 -in Cert-B.crt -noout -dates
openssl x509 -in Cert-A.crt -noout -dates
  • 需确保所有证书的 notBeforenotAfter 时间覆盖当前时间‌

工具与代码示例

验证方式 工具/代码示例
有效期检查 openssl x509 -in cert.crt -dates -noout
证书链验证 openssl verify -CAfile chain.crt Server.crt
签名合法性 openssl verify -CAfile CA-Root.crt Intermediate.crt
CRL/OCSP验证 openssl crlopenssl ocsp 命令

证书生成实例解析

CI证书生成

生成 ECC 私钥

openssl ecparam -name prime256v1 -genkey -out ci_sk.pem
  • 作用‌:生成基于椭圆曲线 prime256v1(即 NIST P-256 曲线)的 ECC 私钥。‌

    关键参数:

    • -name prime256v1:指定椭圆曲线类型(P-256 是广泛使用的安全曲线)。
    • -genkey:生成私钥(默认生成 PEM 格式)‌。
    • -out ci_sk.pem:将私钥保存到文件 ci_sk.pem(PEM 编码,包含 -----BEGIN EC PRIVATE KEY----- 头)‌

生成自签名 X.509 证书

openssl req -config ci_csr.cnf -key ci_sk.pem -new -x509 -days 365 -sha256 -set_serial 01 -extensions extend -out ci_cert.pem
  • 作用‌:直接生成自签名证书(跳过 CSR 步骤),使用上一步生成的私钥签名。

    关键参数:

    • -config ci_csr.cnf:指定配置文件(定义证书主题、扩展字段等)‌。
    • -key ci_sk.pem:使用 ci_sk.pem 中的私钥对证书签名‌。
    • -x509:生成 X.509 自签名证书(而非证书请求 CSR)‌。
    • -days 365:证书有效期 1 年‌。
    • -sha256:使用 SHA-256 哈希算法签名‌。
    • -set_serial 01:设置证书序列号为 01(十六进制需加前缀 0x,如 0x01)‌。
    • -extensions extend:启用配置文件中 [extend] 段的扩展字段(如密钥用途、主题别名等)‌。
    • -out ci_cert.pem:输出证书到 ci_cert.pem(PEM 格式)‌

配置文件 ci_csr.cnf 的作用

假设配置文件内容如下

[req]  
distinguished_name = dn
req_extensions = extend
prompt = no

[dn]
CN = My Server # 通用名称(如域名)
O = My Organization # 组织名称
C = CN # 国家代码

[extend]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = example.com # 域名
IP.1 = 192.168.1.1 # IP 地址

核心功能‌:

  • [dn] 段:定义证书主题信息(如域名、组织等)‌。
  • [extend]段:配置扩展字段:
    • basicConstraints = CA:FALSE:声明非 CA 证书(不可签发下级证书)‌。
    • keyUsage:定义密钥用途(如签名、加密)‌。
    • subjectAltName:指定证书支持的域名/IP(多域名或泛域名证书需在此配置)‌

中间证书生成

生成 ECC 私钥

openssl ecparam -name prime256v1 -genkey -out eum_sk.pem
  • 作用‌:生成基于椭圆曲线 prime256v1(NIST P-256)的 ECC 私钥。

    关键参数:

    • -name prime256v1:指定椭圆曲线类型(安全且广泛支持)。
    • -genkey:直接生成私钥(等价于 -param_enc explicit + -noout)。
    • -out eum_sk.pem:将私钥保存到 eum_sk.pem(PEM 格式,包含 -----BEGIN EC PRIVATE KEY----- 头)。
  • ‌输出文件:

    • eum_sk.pem:ECC 私钥文件(需严格保密)。

生成证书签名请求(CSR)

openssl req -new -nodes -sha256 -config eum_input_csr.cnf -key eum_sk.pem -out eum_csr.cnf
  • 作用‌:使用私钥生成 CSR,用于向 CA 申请证书。
  • ‌关键参数:

    • -new:创建新的 CSR。
    • -nodes:不加密私钥(若省略此参数,默认会加密私钥,但此处已通过 -key 指定私钥文件,因此 -nodes 可能冗余)。
    • -sha256:签名哈希算法为 SHA-256。
    • -config eum_input_csr.cnf:指定 CSR 配置文件(定义主题信息、扩展字段等)。
    • -key eum_sk.pem:使用上一步生成的私钥对 CSR 签名。
    • -out eum_csr.cnf:输出 CSR 到 eum_csr.cnf(通常扩展名为 .csr,此处可能为笔误)。
  • ‌配置文件 eum_input_csr.cnf 示例:

    iniCopy Code[req]  
    distinguished_name = dn
    req_extensions = v3_req
    prompt = no

    [dn]
    CN = My Device # 通用名称(如设备域名)
    O = IoT Company # 组织名称
    C = CN # 国家代码

    [v3_req]
    keyUsage = digitalSignature, keyEncipherment
    subjectAltName = @alt_names

    [alt_names]
    DNS.1 = device.example.com
    IP.1 = 10.0.0.1
  • ‌输出文件‌:

    • eum_csr.cnf:证书签名请求文件(包含公钥和主题信息)。

使用 CA 签发证书

openssl x509 -req -in eum_csr.cnf -CA ci_cert.pem -CAkey ci_sk.pem -set_serial 02 -days 365 -sha256 -extfile eum_ext.cnf -out eum_cert.pem
  • 作用‌:用 CA 的私钥(ci_sk.pem)和证书(ci_cert.pem)对 CSR 签名,生成终端实体证书。

  • 关键参数‌:

    • -req:输入文件是 CSR(而非证书)。

    • -in eum_csr.cnf:指定输入的 CSR 文件(同上,扩展名可能应为 .csr)。

    • -CA ci_cert.pem:指定 CA 的证书文件。

    • -CAkey ci_sk.pem:指定 CA 的私钥文件(用于签名)。

    • -set_serial 02:设置证书序列号为 02(十进制,十六进制需加 0x 前缀,如 0x02)。

    • -days 365:证书有效期为 1 年。

    • -sha256:签名哈希算法为 SHA-256。

    • -extfile eum_ext.cnf:指定扩展字段配置文件(如主题备用名称、密钥用途等)。

    • -out eum_cert.pem:输出最终证书到 eum_cert.pem(PEM 格式)。

扩展文件 eum_ext.cnf 示例

basicConstraints = CA:FALSE  
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = device.example.com
IP.1 = 10.0.0.1

输出文件‌:

  • eum_cert.pem:签发的 X.509 证书(包含公钥、主题信息和 CA 签名)。

流程总结

生成私钥‌ → 2. ‌生成 CSR‌ → 3. ‌CA 签发证书

  • ‌文件关系:
    • 私钥(eum_sk.pem)生成公钥(嵌入在 CSR 中)。
    • CA 用私钥(ci_sk.pem)对 CSR(eum_csr.cnf)签名,生成证书(eum_cert.pem

证书的不同格式

证书格式的区别与共同点

核心编码标准

  • PEM‌(Privacy-Enhanced Mail):
    • 特点‌:Base64 编码的 ASCII 文本文件,包含 -----BEGIN/END xxx----- 头尾标记(如 CERTIFICATEPRIVATE KEY)‌12。
    • 扩展名‌:.pem.crt.cer.key
    • 用途‌:存储证书、私钥、CSR 等,兼容性强,可文本编辑‌12。
  • DER‌(Distinguished Encoding Rules):
    • 特点‌:二进制格式,体积小,不可直接阅读,常用于 Java 和 Windows 系统‌24。
    • 扩展名‌:.der.cer

常见文件类型

扩展名 内容类型 编码格式 典型用途
.key 私钥 PEM 或 DER 存储非对称加密私钥
.crt 证书 PEM 或 DER 存储公钥证书(X.509)
.pem 证书/私钥/CSR PEM(Base64) 通用存储格式
.der 证书/私钥 DER(二进制) 系统特定场景(如 Java)
.csr 证书签名请求 PEM 或 DER 向 CA 申请证书
.pfx/.p12 证书+私钥(PKCS#12) 二进制 多用途加密容器(含密码保护)‌25

共同点

  • 内容本质‌:均基于 ASN.1 数据结构定义‌45。
  • 编码关系‌:PEM 是 DER 的 Base64 文本包装,二者可互相转换‌14。
  • 密钥与证书分离‌:私钥(.key)与证书(.crt)通常独立存储,但 PKCS#12(.pfx)可合并存储‌25。

格式转换方法(基于 OpenSSL)

PEM ↔ DER 互转

证书转换

# PEM 转 DER  
openssl x509 -in cert.pem -outform der -out cert.der

# DER 转 PEM
openssl x509 -inform der -in cert.der -out cert.pem

私钥转换

# PEM 转 DER  
openssl ecparam -in key.pem -outform der -out key.der

# DER 转 PEM
openssl ecparam -inform der -in key.der -out key.pem

注:RSA 私钥使用 openssl rsa 命令‌。

私钥格式转换(PKCS#1 ↔ PKCS#8)

PKCS#1(传统格式)转 PKCS#8(通用格式)

openssl pkcs8 -topk8 -in pkcs1.key -out pkcs8.key -nocrypt

PKCS#1 头尾标记为 -----BEGIN RSA PRIVATE KEY-----,PKCS#8 为 -----BEGIN PRIVATE KEY-----‌34。

合并证书与私钥为 PKCS#12(.pfx

openssl pkcs12 -export -in cert.pem -inkey key.pem -out bundle.pfx

注:需设置密码保护,适用于 Windows 和 Java 环境‌25。

提取 PKCS#12 中的证书/私钥

# 提取证书  
openssl pkcs12 -in bundle.pfx -clcerts -nokeys -out cert.pem

# 提取私钥
openssl pkcs12 -in bundle.pfx -nocerts -out key.pem

关键注意事项

扩展名与编码无关:

  • .crt.cer 可能是 PEM 或 DER 编码,需通过文件内容判断‌。

私钥安全性:

  • PEM 格式私钥建议加密存储(如添加 -aes256 参数)‌。

兼容性问题‌:

  • DER 格式在跨平台传输时需注意二进制兼容性,PEM 更通用‌。‌

ASN.1 结构验证‌:

  • 使用 openssl asn1parse -in file.der 可解析 DER 文件结构‌

证书链的生成与校验

生成证书链(根证书A → 证书B → 证书C)

生成根证书A

# 生成根证书私钥  
openssl genrsa -out rootA.key 4096

# 生成自签名的根证书
openssl req -x509 -new -key rootA.key -sha256 -days 3650 -out rootA.crt

关键配置‌:

  • 根证书的 basicConstraints 必须为 CA:TRUE,表示可签发下级证书 ‌。
  • 默认生成的证书已包含 CA:TRUE,无需额外配置扩展文件 ‌。

生成中间证书B(由根证书A签发)

# 生成中间证书B的私钥  
openssl genrsa -out certB.key 4096

# 创建证书B的CSR(证书签名请求)
openssl req -new -key certB.key -out certB.csr -config <(cat /etc/ssl/openssl.cnf <<< "[ v3_intermediate_ca ]
basicConstraints = CA:TRUE
keyUsage = keyCertSign, cRLSign")

# 使用根证书A签发中间证书B
openssl x509 -req -in certB.csr -CA rootA.crt -CAkey rootA.key -CAcreateserial -out certB.crt -days 365 -sha256 -extensions v3_intermediate_ca :ml-citation{ref="3,4" data="citationList"}

关键配置‌:

  • 中间证书B的 basicConstraints 必须包含 CA:TRUE,允许继续签发下级证书 ‌。
  • keyUsage 需包含 keyCertSign(允许签发证书)和 cRLSign(允许签发吊销列表)‌。

生成终端证书C(由中间证书B签发)

# 生成终端证书C的私钥  
openssl genrsa -out certC.key 2048

# 创建证书C的CSR
openssl req -new -key certC.key -out certC.csr -subj "/CN=example.com"

# 使用中间证书B签发终端证书C
openssl x509 -req -in certC.csr -CA certB.crt -CAkey certB.key -CAcreateserial -out certC.crt -days 365 -sha256 -extfile <(echo "[ v3_end ] subjectAltName = DNS:example.com")

关键配置‌:

  • 终端证书C的 basicConstraints 应为 CA:FALSE(默认值,表示不可签发下级证书)‌。
  • 若需支持HTTPS,需包含 subjectAltName(如域名或IP地址)‌。

构建证书链文件

# 合并证书链(根证书A → 中间证书B → 终端证书C)  
cat certC.crt certB.crt rootA.crt > chain.pem

说明‌:

  • 证书链顺序为:终端证书 → 中间证书 → 根证书 ‌。
  • 服务器部署时需将 chain.pem 与私钥一起配置(如Nginx的 ssl_certificate 指令)‌。

验证证书链有效性

验证单个证书与签发者

bashCopy Code# 验证终端证书C是否由中间证书B签发  
openssl verify -CAfile certB.crt certC.crt

# 验证中间证书B是否由根证书A签发
openssl verify -CAfile rootA.crt certB.crt

验证完整证书链

bashCopy Code# 使用根证书A验证整个链  
openssl verify -CAfile rootA.crt -untrusted certB.crt certC.crt

预期输出‌:

  • 若显示 certC.crt: OK,表示链完整且有效 ‌。

查看证书链结构

openssl x509 -in certC.crt -text -noout

输出内容‌:

  • 签发者(Issuer)应为中间证书B的主题(Subject)。
  • 中间证书B的签发者应为根证书A的主题 ‌。

注意事项

  1. ‌配置文件路径‌:
    • 若未指定 -config,默认使用系统配置文件(如 /etc/ssl/openssl.cnf),需确保路径正确 ‌。
  2. ‌密钥权限‌:
    • 私钥文件(.key)需设置严格权限(如 chmod 400)‌。
  3. ‌证书扩展字段‌:
    • 中间证书必须包含 CA:TRUEkeyCertSign,否则无法签发下级证书 ‌。
  4. ‌证书链顺序‌:
    • 部署时证书链文件必须按终端 → 中间 → 根的顺序排列 ‌

参考文档:

https://learn.microsoft.com/zh-cn/azure/application-gateway/self-signed-certificates