交叉签名证书(Cross Signed Certificate)是 SSL/TLS 基础设施中一个重要但常被误解的概念。本文深入解释交叉签名的原理、适用场景以及 OpenSSL 操作方法。

什么是交叉签名?

交叉签名是指由一个 CA(证书颁发机构)对另一个 CA 的证书进行签名。签名的对象是 CA 证书本身,而不是终端实体证书。

1
2
3
4
原始链:Root CA → Intermediate CA → Server Certificate
交叉签名链:Root CA (新) → Cross-signed Intermediate CA → Server Certificate
              由新Root CA签名

关键特征:

  • 交叉签名证书的 Subject(主题)与原始中间 CA 相同
  • Issuer(颁发者)变为进行交叉签名的根 CA
  • 公钥与原始中间 CA 完全相同

典型使用场景

1. 多根 CA 信任

企业可能有两个不同的根 CA(如并购后的整合),需要让一张证书同时被两个根 CA 信任。

1
场景:公司有两个根 CA(Root CA 1 和 Root CA 2),都需要信任同一张服务器证书

2. 旧客户端兼容性

某些老旧客户端只信任特定的根 CA,通过交叉签名让新证书也能被这些客户端接受。

3. 证书迁移

在 CA 机构迁移过程中,保持双签名确保平滑过渡。

实战:创建与验证交叉签名证书

步骤 1:创建两个根 CA

1
2
3
4
5
6
7
8
9
# 根 CA 1
openssl genrsa -out /tmp/root-ca1.key 2048
openssl req -x509 -new -nodes -key /tmp/root-ca1.key -days 3650 \
  -subj "/C=CN/O=Company/CN=Root CA 1" -out /tmp/root-ca1.crt

# 根 CA 2
openssl genrsa -out /tmp/root-ca2.key 2048
openssl req -x509 -new -nodes -key /tmp/root-ca2.key -days 3650 \
  -subj "/C=CN/O=Company/CN=Root CA 2" -out /tmp/root-ca2.crt

步骤 2:创建并签名中间 CA

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 创建中间 CA 密钥和 CSR
openssl genrsa -out /tmp/intermediate.key 2048
openssl req -new -key /tmp/intermediate.key \
  -subj "/C=CN/O=Company/CN=Intermediate CA" \
  -out /tmp/intermediate.csr

# 由根 CA 1 签名中间 CA
openssl x509 -req -in /tmp/intermediate.csr \
  -CA /tmp/root-ca1.crt -CAkey /tmp/root-ca1.key \
  -days 1825 -sha256 \
  -extfile <(echo "basicConstraints=critical,CA:TRUE") \
  -out /tmp/intermediate.crt

步骤 3:创建交叉签名证书

关键步骤:使用根 CA 2 对同一个 CSR 进行签名,生成交叉签名版本。

1
2
3
4
5
openssl x509 -req -in /tmp/intermediate.csr \
  -CA /tmp/root-ca2.crt -CAkey /tmp/root-ca2.key \
  -days 1825 -sha256 \
  -extfile <(echo "basicConstraints=critical,CA:TRUE") \
  -out /tmp/intermediate-cross.crt

⚠️ 注意:必须使用与原始 CSR 相同的文件,否则公钥不匹配会导致验证失败。

验证交叉签名证书:

1
openssl x509 -in /tmp/intermediate-cross.crt -noout -subject -issuer

输出示例:

1
2
subject=O = Company, CN = Intermediate CA
issuer=O = Company, CN = Root CA 2

步骤 4:创建服务器证书

1
2
3
4
5
6
7
8
9
# 创建服务器密钥和 CSR
openssl genrsa -out /tmp/server.key 2048
openssl req -new -key /tmp/server.key \
  -subj "/CN=www.example.com" -out /tmp/server.csr

# 由原始中间 CA 签发服务器证书
openssl x509 -req -in /tmp/server.csr \
  -CA /tmp/intermediate.crt -CAkey /tmp/intermediate.key \
  -days 365 -sha256 -out /tmp/server.crt

步骤 5:使用交叉签名证书链验证

方式一:通过根 CA 1 验证(原始链)

1
2
3
openssl verify -CAfile /tmp/root-ca1.crt \
  -untrusted /tmp/intermediate.crt \
  /tmp/server.crt

方式二:通过根 CA 2 验证(交叉签名链)

1
2
3
openssl verify -CAfile /tmp/root-ca2.crt \
  -untrusted /tmp/intermediate-cross.crt \
  /tmp/server.crt

两种方式都应该输出:

1
/tmp/server.crt: OK

证书链可视化

1
2
3
4
5
6
7
8
9
原始证书链(通过 Root CA 1):
Root CA 1
  └─ Intermediate CA (由 Root CA 1 签发)
       └─ Server Certificate

交叉签名证书链(通过 Root CA 2):
Root CA 2
  └─ Intermediate CA - Cross Signed (由 Root CA 2 签发,相同公钥)
       └─ Server Certificate

常见错误与排查

错误:unable to get local issuer certificate

原因:中间 CA 证书链不完整

解决:确保提供正确的中间 CA 证书(交叉签名版本)

错误:invalid CA certificate

原因:中间 CA 缺少 CA 扩展(basicConstraints=CA:TRUE)

解决:签名时添加 -extfile <(echo "basicConstraints=critical,CA:TRUE")

错误:certificate chain too long

原因:中间 CA 的 pathlen 限制

解决:确保 pathlen 足够或设置为 0

最佳实践

  1. 保持密钥一致:交叉签名必须使用与原始证书完全相同的公钥
  2. 设置正确的 CA 扩展:中间 CA 必须包含 basicConstraints=CA:TRUE
  3. 有效期管理:交叉签名证书的有效期不应超过原始证书
  4. 验证双重链:部署后同时验证两个根 CA 的信任链
  5. 文档记录:记录哪些证书使用了交叉签名及原因

查看证书详细信息

1
2
3
4
5
6
# 查看证书扩展
openssl x509 -in intermediate-cross.crt -noout -text | grep -A3 "X509v3"

# 比较两个版本的中间 CA(公钥应该相同)
openssl x509 -in intermediate.crt -noout -modulus
openssl x509 -in intermediate-cross.crt -noout -modulus

总结

交叉签名是实现多 CA 信任和证书平滑迁移的重要技术。核心要点:

  • 交叉签名证书与原始证书共享相同的公钥
  • 不同的 Issuer 允许在不同的信任域中使用
  • OpenSSL 通过 -untrusted 参数指定中间 CA 证书链

理解并正确使用交叉签名,可以解决企业多 CA 环境下的证书信任问题。


参考来源: