Skip to content

证书管理:配置 TLS 证书链与验证参数 · 前置、依赖与输入至综合练习与分开的解答 ​

返回分篇目录

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

证书管理:配置 TLS 证书链与验证参数 ​

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

前置、依赖与输入 ​

证书管理完整示例是离线证据处理器,示例未执行。需要Python3.11以上标准库,第三方依赖为零,不需要服务、管理员或网络。输入JSON只含虚构记录,程序不调用系统命令、不建立连接、不修改主机。完整文件位于examples/m5-next-certificates,必须一起阅读README、lab.py和case.json。

完整源码与配置 ​

下面包括完整源码与全部输入;这不是产品配置验证器,也不执行协议、密码学或系统策略。判断只依据输入声明,不能用输出证明真实环境。

python
"""Offline teaching model. No network, subprocesses, or system mutations."""
import json
from pathlib import Path
import sys


def require(value, schema):
    if type(value) is not dict or set(value) != set(schema):
        raise ValueError("unexpected or missing fields")
    for key, expected in schema.items():
        if type(value[key]) is not expected:
            raise ValueError("wrong field type: " + key)


def decide(row):
    require(row, {"name": str, "service": str, "sans": list, "issuer_trusted": bool, "not_before": str, "not_after": str, "at": str})
    from datetime import datetime
    if not row["service"] or not all(type(item) is str and item for item in row["sans"]):
        raise ValueError("invalid service name")
    def instant(value):
        result = datetime.fromisoformat(value)
        if result.tzinfo is None or result.utcoffset() is None:
            raise ValueError("timezone required")
        return result
    start, end, now = (instant(row[key]) for key in ("not_before", "not_after", "at"))
    if end <= start:
        raise ValueError("invalid validity interval")
    if not row["issuer_trusted"]:
        return "CHECK_TRUST_ANCHOR"
    if row["service"] not in row["sans"]:
        return "DENY_NAME"
    if now < start or now > end:
        return "DENY_TIME"
    return "METADATA_CONSISTENT"


def main(args):
    if len(args) != 1:
        print("usage: python lab.py case.json", file=sys.stderr)
        return 2
    try:
        source = Path(args[0]).read_text(encoding="utf-8")
        data = json.loads(source)
        if type(data) is not list or not data:
            raise ValueError("nonempty list required")
        # Validate every row before publishing any decisions.
        results = [(row, decide(row)) for row in data]
        for row, result in results:
            print(row["name"] + ": " + result)
        return 0
    except (OSError, ValueError, KeyError, TypeError, OverflowError):
        print("invalid input", file=sys.stderr)
        return 2


if __name__ == "__main__":
    raise SystemExit(main(sys.argv[1:]))
json
[
  {
    "name": "normal",
    "service": "db.example.invalid",
    "sans": [
      "db.example.invalid"
    ],
    "issuer_trusted": true,
    "not_before": "2026-01-01T00:00:00+00:00",
    "not_after": "2026-12-31T00:00:00+00:00",
    "at": "2026-10-17T00:00:00+00:00"
  },
  {
    "name": "wrong-name",
    "service": "other.example.invalid",
    "sans": [
      "db.example.invalid"
    ],
    "issuer_trusted": true,
    "not_before": "2026-01-01T00:00:00+00:00",
    "not_after": "2026-12-31T00:00:00+00:00",
    "at": "2026-10-17T00:00:00+00:00"
  },
  {
    "name": "expired",
    "service": "db.example.invalid",
    "sans": [
      "db.example.invalid"
    ],
    "issuer_trusted": true,
    "not_before": "2026-01-01T00:00:00+00:00",
    "not_after": "2026-12-31T00:00:00+00:00",
    "at": "2027-01-01T00:00:00+00:00"
  }
]

读者自跑、成功和失败 ​

证书管理离线推演先复制三个文件到独立目录。Windows PowerShell使用python,Linux Bash使用python3调用lab.py case.json;命令在README完整列出。正常输入输出逐行判定并以0结束;缺字段、非法类型或JSON损坏输出invalid input并以2结束。预期拒绝是业务判定,不等同输入错误,仍以0结束。

恢复、清理与边界 ​

恢复时从仓库还原case.json,重新核对变更前后字段。程序不写结果文件,不产生系统资源,不需要关闭端口或停止服务。清理只删除读者自己复制的练习目录;不要删除仓库示例。修改输入不会改变真实授权、证书或路由。

综合练习与分开的解答 ​

练习:先不看参考答案,解释输入中每个正常和失败判定,修改一项条件让一个判定改变,再写出该变化仍不能证明的现实条件。

参考解答

normal的服务名在虚构SAN列表内、信任声明为真且观察时间在期限内,输出METADATA_CONSISTENT。wrong-name先发现名称不在SAN中,DENY_NAME。expired的观察时刻超过not_after,DENY_TIME。源码不验证签名或真实信任链,所以正常结果不能用于放行TLS。

具体变体:只把 wrong-name 的 service 改为 db.example.invalid,其余字段不变,将由 DENY_NAME 变为 METADATA_CONSISTENT。虚构SAN与时间虽然一致,但链签名、EKU和实际TLS名称验证仍完全没有执行。

继续阅读