Skip to content

证书管理:配置 TLS 证书链与验证参数 · 产品配置与操作契约至完整项目说明与依赖声明 ​

返回分篇目录

本篇以TLS 证书链为例;前置是预期服务名、叶子/中间证书和客户端信任锚。源码与输入与下文配置共用同一份文件,示例未执行。

产品配置与操作契约 ​

以下为与离线模型分开的完整产品配置,示例未执行。产品二进制、真实密钥与账户均需读者按前置另行提供;静态解析不等于产品验证。

ini
[req]
prompt = no
distinguished_name = dn
x509_extensions = root_ca
default_md = sha256

[dn]
CN = Isolated Teaching Root CA
O = Offline Lesson

[root_ca]
basicConstraints = critical,CA:true,pathlen:1
keyUsage = critical,keyCertSign,cRLSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
ini
[req]
prompt = no
distinguished_name = dn
default_md = sha256

[dn]
CN = Isolated Teaching Intermediate CA
O = Offline Lesson

[intermediate_ca]
basicConstraints = critical,CA:true,pathlen:0
keyUsage = critical,keyCertSign,cRLSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
ini
[req]
prompt = no
distinguished_name = dn
req_extensions = request_san
default_md = sha256

[dn]
CN = db.example.invalid
O = Offline Lesson

[request_san]
subjectAltName = @names

[names]
DNS.1 = db.example.invalid

[server_cert]
basicConstraints = critical,CA:false
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
subjectAltName = @names

完整OpenSSL证书链配置(未执行) ​

root.cnf、intermediate.cnf、server.cnf覆盖隔离根CA、自签根扩展、中间CA请求/约束以及服务端CSR/SAN/用途扩展。面向OpenSSL3.x,不需要服务或网络;真实私钥由读者在隔离目录生成,不提交仓库、不加入系统信任库。以下Linux Bash步骤会写本地文件,当前会话只记录文本,未执行。Windows读者需使用对应OpenSSL可执行文件并通过ACL限制私钥目录,不能把umask/chmod当成Windows原生权限控制。

根和中间CA私钥使用AES口令加密,命令会交互读取读者自己的口令,不通过参数或仓库文件提供。服务端私钥为非加密教学文件,依靠受限目录保护;真实部署应按服务秘密方案另行设计。先进入仅含三个配置的练习目录:

bash
umask 077
mkdir private public
openssl genpkey -algorithm RSA -aes-256-cbc -pkeyopt rsa_keygen_bits:3072 -out private/root.key
openssl req -new -x509 -sha256 -days 365 -key private/root.key -config root.cnf -out public/root.crt
openssl genpkey -algorithm RSA -aes-256-cbc -pkeyopt rsa_keygen_bits:3072 -out private/intermediate.key
openssl req -new -key private/intermediate.key -config intermediate.cnf -out public/intermediate.csr
openssl x509 -req -sha256 -days 180 -in public/intermediate.csr -CA public/root.crt -CAkey private/root.key -set_serial 0x1001 -extfile intermediate.cnf -extensions intermediate_ca -out public/intermediate.crt
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private/server.key
openssl req -new -key private/server.key -config server.cnf -out public/server.csr
openssl x509 -req -sha256 -days 30 -in public/server.csr -CA public/intermediate.crt -CAkey private/intermediate.key -set_serial 0x2001 -extfile server.cnf -extensions server_cert -out public/server.crt
openssl verify -CAfile public/root.crt -untrusted public/intermediate.crt -purpose sslserver -verify_hostname db.example.invalid public/server.crt

预期最后一条输出public/server.crt: OK;根pathlen为1,中间pathlen为0,叶子CA:false且EKU为serverAuth。最终签发显式指定server_cert扩展,不假设CSR请求扩展自动复制。固定序列号仅用于一次性隔离示例;不能用于反复签发的生产CA。生产还需唯一序列、审计、撤销与CA密钥保护。

两条失败反例只读生成材料:

bash
openssl verify -CAfile public/root.crt -purpose sslserver -verify_hostname db.example.invalid public/server.crt
openssl verify -CAfile public/root.crt -untrusted public/intermediate.crt -purpose sslserver -verify_hostname other.example.invalid public/server.crt

第一条未提供中间证书,预期找不到所需颁发者;第二条链存在但名称不匹配,预期非零退出。不同OpenSSL版本错误文字可能变化,不将某个错误号作为跨版本唯一判据。这里没有TLS握手,也没有测试撤销;链验证成功不能证明服务端实际发送了这条链。

如果签发失败,停止后续步骤、核对配置与口令,在新的空练习目录重做;不要覆盖生产私钥,也不要关闭证书验证。需要服务链文件时按叶子后中间顺序连接public/server.crt和public/intermediate.crt,根由客户端独立信任,不在服务链中强推信任。清理只删除自己生成的private/public副本;如私钥曾泄露,应按组织流程撤销或隔离,文件删除不等于安全擦除。

完整项目说明与依赖声明 ​

以下同源文件完整列出读者前置、自跑命令、正常/失败预期和清理;正文只供阅读,示例未执行。

text
# Python >=3.11; standard library only; no third-party dependencies.
完整 README(与项目文件一致)
markdown
# certificates 离线证据推演

示例未执行。前半的 lab.py 比较服务名、SAN 与带时区的有效期元数据;后半是 OpenSSL 证书链签发和验证步骤。元数据一致不代表证书链、签名或真实 TLS 握手通过。

## 文件与前置

离线部分需要 Python 3.11 以上和标准库,无 OpenSSL 安装、服务或管理员权限。先对照 [case.json](case.json) 中的 service/sans、not_before/not_after、at 与 issuer_trusted,再阅读 [lab.py](lab.py) 的检查顺序。OpenSSL 3.x 和私钥目录只属于后半节证书实验的前置;macOS 未做原生运行验收。

## 读者自跑

先复制全部文件到自己的隔离练习目录并进入该目录。以下仅是读者步骤,本轮未执行。

Windows PowerShell:

```powershell
python .\lab.py .\case.json
```

Linux Bash(macOS若已有Python3也使用此形式):

```bash
python3 ./lab.py ./case.json
```

预期标准输出如下,进程退出0;明确拒绝是正常决策而不是输入错误。

```text
normal: METADATA_CONSISTENT
wrong-name: DENY_NAME
expired: DENY_TIME
```

## 失败路径

把case.json复制为broken.json,再人工删除第一条记录的name字段。使用同一命令把参数换成broken.json,预期标准错误invalid input、退出2,不发布部分判定。破损JSON、非法字段类型、未知字段、空列表或不存在的文件同样退出2。不打印异常原文,防止输入内容意外进入日志。程序严格匹配固定教学字段,不接受任意扩展。

## 恢复与清理

从原仓库重新复制case.json恢复,或撤销练习副本编辑。程序没有写文件、创建用户或启动连接,无需服务清理;只删除自己复制的目录和broken.json,不删除仓库原文件。

## 解释边界

只比较虚构SAN精确名称和带时区时间,不解析PEM、不支持通配符、不验证链签名、撤销、EKU或算法。issuer_trusted是声明,METADATA_CONSISTENT绝不是TLS验证通过。

输入由读者提供,不具有独立真实性。需要真实运行验证时,另行取得授权并采集环境证据,不能用本程序作产品验收工具。

## 完整OpenSSL证书链配置(未执行)

root.cnf、intermediate.cnf、server.cnf覆盖隔离根CA、自签根扩展、中间CA请求/约束以及服务端CSR/SAN/用途扩展。面向OpenSSL3.x,不需要服务或网络;真实私钥由读者在隔离目录生成,不提交仓库、不加入系统信任库。以下Linux Bash步骤会写本地文件,当前会话只记录文本,未执行。Windows读者需使用对应OpenSSL可执行文件并通过ACL限制私钥目录,不能把umask/chmod当成Windows原生权限控制。

根和中间CA私钥使用AES口令加密,命令会交互读取读者自己的口令,不通过参数或仓库文件提供。服务端私钥为非加密教学文件,依靠受限目录保护;真实部署应按服务秘密方案另行设计。先进入仅含三个配置的练习目录:

```bash
umask 077
mkdir private public
openssl genpkey -algorithm RSA -aes-256-cbc -pkeyopt rsa_keygen_bits:3072 -out private/root.key
openssl req -new -x509 -sha256 -days 365 -key private/root.key -config root.cnf -out public/root.crt
openssl genpkey -algorithm RSA -aes-256-cbc -pkeyopt rsa_keygen_bits:3072 -out private/intermediate.key
openssl req -new -key private/intermediate.key -config intermediate.cnf -out public/intermediate.csr
openssl x509 -req -sha256 -days 180 -in public/intermediate.csr -CA public/root.crt -CAkey private/root.key -set_serial 0x1001 -extfile intermediate.cnf -extensions intermediate_ca -out public/intermediate.crt
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private/server.key
openssl req -new -key private/server.key -config server.cnf -out public/server.csr
openssl x509 -req -sha256 -days 30 -in public/server.csr -CA public/intermediate.crt -CAkey private/intermediate.key -set_serial 0x2001 -extfile server.cnf -extensions server_cert -out public/server.crt
openssl verify -CAfile public/root.crt -untrusted public/intermediate.crt -purpose sslserver -verify_hostname db.example.invalid public/server.crt
```

预期最后一条输出public/server.crt: OK;根pathlen为1,中间pathlen为0,叶子CA:false且EKU为serverAuth。最终签发显式指定server_cert扩展,不假设CSR请求扩展自动复制。固定序列号仅用于一次性隔离示例;不能用于反复签发的生产CA。生产还需唯一序列、审计、撤销与CA密钥保护。

两条失败反例只读生成材料:

```bash
openssl verify -CAfile public/root.crt -purpose sslserver -verify_hostname db.example.invalid public/server.crt
openssl verify -CAfile public/root.crt -untrusted public/intermediate.crt -purpose sslserver -verify_hostname other.example.invalid public/server.crt
```

第一条未提供中间证书,预期找不到所需颁发者;第二条链存在但名称不匹配,预期非零退出。不同OpenSSL版本错误文字可能变化,不将某个错误号作为跨版本唯一判据。这里没有TLS握手,也没有测试撤销;链验证成功不能证明服务端实际发送了这条链。

如果签发失败,停止后续步骤、核对配置与口令,在新的空练习目录重做;不要覆盖生产私钥,也不要关闭证书验证。需要服务链文件时按叶子后中间顺序连接public/server.crt和public/intermediate.crt,根由客户端独立信任,不在服务链中强推信任。清理只删除自己生成的private/public副本;如私钥曾泄露,应按组织流程撤销或隔离,文件删除不等于安全擦除。

继续阅读