Enterprise 版本
受信任列表 — 深度参考
本页是 NextPDF Enterprise 中受信任列表能力面的深度参考。该能力面即 NextPDF\Enterprise\Security\Tsl 命名空间的十二个公开类。NextPDF\Enterprise\Security\Tsl\TslPolicyEnforcer 是经过编排的入口点:仅当 HTTP 获取、XMLDSig 验证、结构解析与 nextUpdate 陈旧度闸门全部通过时,它才返回一个 TslDocument。随后 TslTrustAnchorProvider::buildBundle() 从活跃的 CA/QC 服务派生出一个信任锚捆绑包,并在抽取任何锚之前,以调用方提供的时刻重新断言新鲜度。每一次失败都会抛出一个带类型的异常;没有任何阶段会静默降级。该流水线支持在调用方提供时验证欧盟成员国受信任列表以及源自 LOTL(受信任列表之列表,List of Trusted Lists)的信任锚;自动 LOTL 发现、轮询与 pivot 处理不在范围之内。
可用性与许可
标题为“可用性与许可”的章节此能力随 NextPDF Enterprise(nextpdf/enterprise)发布,并在 Enterprise 级许可证信封下激活。不具备该授权的部署不会加载此能力的类。比较各版本并获取许可证。
公共 API 面
标题为“公共 API 面”的章节| 符号 | 参数 | 默认行为 | 返回 | 抛出或失败于 | 备注 |
|---|---|---|---|---|---|
TslPolicyEnforcer | TslFetcher $fetcher、TslSignatureVerifier $verifier、TslXmlParser $parser | 将获取、签名验证、解析与陈旧度闸门合并为单一入口点 | — | 传播下述流水线异常 | final;按构造即 fail-closed |
TslPolicyEnforcer::fetchAndVerify | string $url | 获取一份 TSL,然后对字节运行 verifyXml() | TslDocument | TslFetchException、NetworkPolicyViolation、TslSignatureException、TslParseException | 仅当全部四个阶段通过时返回 |
TslPolicyEnforcer::verifyXml | string $xml | 验证签名、解析并拒绝陈旧列表 | TslDocument | TslSignatureException、TslParseException | 陈旧度以当前系统时间为准评估 |
TslFetcher | ClientInterface $httpClient、RequestFactoryInterface $requestFactory、?CacheInterface $cache = null、int $defaultTtlSeconds = 3600、int $maxBytes = 16_777_216、NetworkPolicy $networkPolicy = NetworkPolicy::ONLINE | 仅限 HTTPS 的 TSL/LOTL 检索,带基于 ETag 的缓存 | — | — | final;SSRF 防护封禁私有、回环、链路本地与元数据主机,并缓解 DNS 重绑定 |
TslFetcher::fetch | string $url | 携 If-None-Match 重新验证的 GET;在配置的 TTL 下缓存正文与 ETag | string(原始 XML 字节) | TslFetchException、NetworkPolicyViolation | 至多读取 $maxBytes 字节;在 STRICT_OFFLINE 下仅提供缓存正文 |
TslSignatureVerifier | array $trustAnchorsPem、int $clockTolerance = 0 | 固定至所配置信任锚的 XMLDSig 验证器 | — | 锚列表为空时抛出 InvalidArgumentException | final;在 ALLOWED_SIG_ALG 与 ALLOWED_DIGEST_ALG 中设允许清单 |
TslSignatureVerifier::verify | string $xml | fail-closed 地验证 enveloped XMLDSig 签名 | string(签名者证书 PEM) | TslSignatureException,带机器可读的原因码 | KeyInfo 证书本身永不受信任;签名者必须链接到某个已配置的锚 |
TslXmlParser::parse | string $xml | 结构化解析为 TslDocument;与签名无关 | TslDocument | TslParseException | 在解析前 fail-closed 地拒绝任何 DOCTYPE;以 LIBXML_NONET 加载;调用方必须先验证再信任结果 |
TslTrustAnchorProvider::buildBundle | TslDocument $tsl、DateTimeImmutable $now | 先断言新鲜度,然后收集活跃 CA/QC 服务的证书 | EnterpriseCaTrustAnchorBundle | TslParseException | 新鲜度闸门先于任何锚抽取;结果集为空时抛出 |
TslDocument | 八个提升的 readonly 属性(见构造函数代码块) | 不可变的已解析 TSL 值对象 | — | — | final readonly;源码标注 @api |
TslDocument::isStale | DateTimeImmutable $now | 经 fail-closed 的 UTC 解析后,将 nextUpdate 与 $now 比较 | bool | TslParseException | 要求显式的 Z 或数值偏移指示符 |
TslDocument::assertFresh | DateTimeImmutable $now | 当列表陈旧或 nextUpdate 无法解析时抛出 | void | TslParseException | 消费方边界的新鲜度闸门 |
TslDocument::servicesOfType | string $serviceTypeIdentifier | 按 ETSI 服务类型 URI 过滤服务 | list<TspService> | 不抛出 | — |
TslDocument::activeServices | — | 仅返回处于 granted 状态的服务 | list<TspService> | 不抛出 | Granted 即 TspService::STATUS_GRANTED |
TspService | 八个提升的 readonly 属性 | TSL 内的一个信任服务条目 | — | — | final readonly;含状态与服务类型 URI 常量 |
TspService::isGranted | — | 状态与 granted URI 的相等判断 | bool | 不抛出 | — |
TspService::isQualifiedCa | — | 类型与 CA/QC URI 的相等判断 | bool | 不抛出 | — |
TspServiceQualifier | string $qualifierUri、string $criteriaListAssert = 'all'、array $policyOidConditions = []、array $keyUsageConditions = [] | 一个带可选条件的 ETSI 服务限定符 | — | — | final readonly;常量 FOR_ESIG、FOR_ESEAL、FOR_WSA、QSCD_STATEMENT、NO_QSCD |
EnterpriseCaTrustAnchorBundle | array $anchorsPem、string $bundleVersion、string $bundleSha256 | 固定锚捆绑包;构造时以所供锚校验所供摘要 | — | InvalidArgumentException | 从 buildBundle() 获得;勿手工构造;实现 TrustAnchorStoreInterface |
EnterpriseCaTrustAnchorBundle::containsFingerprint | string $anchorDerSha256Hex | 以 DER 正文的十六进制 SHA-256 判断锚成员资格 | bool | 不抛出 | — |
EnterpriseCaTrustAnchorBundle::computeBundleSha256 | array $anchorsPem | 对换行归一化后的 PEM 串接计算规范 SHA-256 | string | 不抛出 | static |
TslFetchException | — | 表示一次 TSL 检索失败 | — | — | final;继承 RuntimeException |
TslParseException | — | 表示一次结构或新鲜度失败 | — | — | final;继承 RuntimeException |
TslSignatureException | string $reason、string $message | 以原因码表示 XMLDSig 验证失败 | — | — | final;公开 readonly $reason(见下方原因码) |
TslPolicyEnforcer
public function fetchAndVerify(string $url): TslDocumentpublic function verifyXml(string $xml): TslDocumentTslFetcher
public function __construct( private readonly ClientInterface $httpClient, private readonly RequestFactoryInterface $requestFactory, private readonly ?CacheInterface $cache = null, private readonly int $defaultTtlSeconds = 3600, private readonly int $maxBytes = 16_777_216, private readonly NetworkPolicy $networkPolicy = NetworkPolicy::ONLINE,) {}
public function fetch(string $url): stringTslSignatureVerifier
public function __construct(private readonly array $trustAnchorsPem, private readonly int $clockTolerance = 0)
public function verify(string $xml): stringTslXmlParser
public function parse(string $xml): TslDocumentTslTrustAnchorProvider
public function buildBundle(TslDocument $tsl, DateTimeImmutable $now): EnterpriseCaTrustAnchorBundleTslDocument
public function __construct( public string $schemeTerritory, public string $schemeOperatorName, public string $tslType, public int $sequenceNumber, public string $issueDateTime, public string $nextUpdate, public array $tspServices, public string $rawXmlSha256,) {}
public function isStale(DateTimeImmutable $now): boolpublic function assertFresh(DateTimeImmutable $now): voidpublic function servicesOfType(string $serviceTypeIdentifier): arraypublic function activeServices(): arrayTspService
public function __construct(public string $tspName, public string $serviceName, public string $serviceTypeIdentifier, public string $serviceStatus, public string $statusStartingTime, public string $serviceCertificatePem, public array $qualifiers, public array $additionalServiceInformation) {}
public function isGranted(): boolpublic function isQualifiedCa(): boolTspServiceQualifier
public function __construct(public string $qualifierUri, public string $criteriaListAssert = 'all', public array $policyOidConditions = [], public array $keyUsageConditions = []) {}EnterpriseCaTrustAnchorBundle
public function __construct(public array $anchorsPem, public string $bundleVersion, public string $bundleSha256)
public function containsFingerprint(string $anchorDerSha256Hex): boolpublic static function computeBundleSha256(array $anchorsPem): stringTslSignatureException
public function __construct(public readonly string $reason, string $message)TslSignatureException 原因码: missing_signature、untrusted_signer、invalid_signature、digest_mismatch、unsupported_algorithm、unsupported_transform、expired_anchor。
行为契约
标题为“行为契约”的章节- 流水线顺序固定:获取、XMLDSig 验证、结构解析、陈旧度闸门。仅当四者全部成功时,
TslPolicyEnforcer才返回一个TslDocument。受信任列表由其方案运营方签名,以便依赖方核验真实性与完整性 — ETSI TS 119 612 §5.7.1。 TslXmlParser在设计上与签名无关。调用方必须在信任任何已解析字段之前先验证签名。TslPolicyEnforcer::verifyXml()强制该顺序。- 新鲜度不变式在每个消费方边界强制执行。
nextUpdate已过的列表即过期并被拒绝 — ETSI TS 119 612 §5.3.15。verifyXml()以当前系统时间设闸;TslDocument::assertFresh()与buildBundle()以调用方提供的时刻设闸。 - 新鲜度解析是 fail-closed 的。日期时间字段是带显式指示符的 ISO 8601 UTC 值 — ETSI TS 119 612 §5.1.3。缺少显式
Z或数值偏移的nextUpdate会抛出TslParseException;该值绝不会按服务器本地时区重新解释。 buildBundle()在抽取任何锚之前先调用assertFresh($now),然后只接纳同时为 granted 且 CA/QC 的服务。Granted 与 withdrawn 是合格服务的状态 URI — ETSI TS 119 612 §5.5.4。CA/QC 是合格 CA 的服务类型 URI — ETSI TS 119 612 §5.5.1.1。- 捆绑包版本由方案辖区与 TSL 序列号派生。序列号在各次发布之间单调递增 — ETSI TS 119 612 §5.3.2。捆绑包摘要是对各锚 PEM 计算的规范 SHA-256,
containsFingerprint()以 DER SHA-256 回答成员资格。 - 验证器只信任已配置的锚。在
KeyInfo中找到的证书充当签名者叶子及候选中间证书;链必须在深度 8 之内到达某个已配置的锚,每一环必须在时间上有效,且签发证书必须携带basicConstraintscA=TRUE(当存在keyUsage时还须keyCertSign)。 - 验证配置是一份允许清单:RSA 或 ECDSA 配 SHA-256、SHA-384 或 SHA-512;摘要方法 SHA-256、SHA-384 或 SHA-512;仅限 exclusive canonicalization;并且在覆盖列表的
ds:Reference上恰为 enveloped-signature 加 exclusive-C14N 的变换对。其他任何情形均以unsupported_algorithm或unsupported_transform失败。 TslFetcher拒绝非 HTTPS 的 URL,并在任何出网之前施加 SSRF 防护。在NetworkPolicy::STRICT_OFFLINE下,它提供先前缓存的正文,否则抛出NetworkPolicyViolation;绝不发出任何出站请求。
边界情形与失败模式
标题为“边界情形与失败模式”的章节- 陈旧列表。 来自
verifyXml()、assertFresh()或buildBundle()的TslParseException意味着该信任源不可用。应将其视为一次运维层面的刷新失败,而非一个签名裁决。 - 非规范的
nextUpdate。 缺少显式Z或数值偏移的值会抛出,而不会宽松解析。ETSI TS 119 612 §5.1.3 强制要求 UTCZ形式;该闸门也接受显式的数值偏移,并拒绝其他一切形式。 - 使用时点漂移。
verifyXml()在验证时点设闸;一份在内存中保留至nextUpdate之后的文档,仍会在其后的buildBundle($tsl, $now)闸门处失败。 - 空锚配置。
TslSignatureVerifier拒绝以空锚列表构造(InvalidArgumentException)。 - 无可用服务。 一份没有 granted CA/QC 服务的新鲜列表会从
buildBundle()抛出TslParseException;绝不会产出空捆绑包。 - 离线态势。
STRICT_OFFLINE且无缓存正文时抛出NetworkPolicyViolation。缓存查找先于策略检查,因此一份已缓存的列表可让气隙验证继续工作。 - 过大或空的响应。
fetch()至多读取$maxBytes字节(默认 16 MiB);一份被截断的列表随后会在下游的摘要验证中失败。空正文会抛出TslFetchException。 - XML 中的 DOCTYPE。 任何 DOCTYPE 都会在 libxml 构建实体表之前被拒绝,加载之后再次拒绝。这封堵了 XXE 与实体扩展(billion-laughs)这类输入类别。
- 多重签名。 只有经过验证的 enveloped
ds:Signature会在摘要计算之前被移除;兄弟签名与反签名予以保留。允许额外的 XAdES 引用,但必须恰有一个ds:Reference覆盖文档根。 - 过期链材料。 过期或尚未生效的签名者、中间证书或锚会以原因
expired_anchor失败。clockTolerance对称地放宽接受窗口,默认为0。
FIPS 模式行为
标题为“FIPS 模式行为”的章节验证器的允许清单固定为 RSA 与 ECDSA 配 SHA-2 系列;SHA-1 与 MD5 在结构上被排除。签名运算运行于内置的软件密码学(phpseclib)。NextPDF 不对该运算作出任何 FIPS 140-3 验证声明。Enterprise 的 FIPS 140-3 密码策略配置随安全模块记录在案;它约束算法选择,但不改变受信任列表结构,也不改变本模块的 fail-closed 行为。
一致性
标题为“一致性”的章节| 声明 | 标准 | 条款 |
|---|---|---|
| Next update 已过的受信任列表作为过期而被丢弃。 | ETSI TS 119 612 | §5.3.15 |
日期时间字段是带 Z 指示符、以 UTC 表示的 ISO 8601 字符串。 | ETSI TS 119 612 | §5.1.3 |
| 方案运营方为真实性与完整性签名受信任列表。 | ETSI TS 119 612 | §5.7.1 |
| 合格服务状态为 granted 或 withdrawn 状态 URI。 | ETSI TS 119 612 | §5.5.4 |
合格 CA 由 Svctype/CA/QC 服务类型 URI 标识。 | ETSI TS 119 612 | §5.5.1.1 |
| TSL 序列号从 1 开始,并在每次发布时递增。 | ETSI TS 119 612 | §5.3.2 |
所有条款均为转述;NextPDF 不复制规范性文本。NextPDF 不作任何 ETSI TS 119 612 一致性声明,也不作任何 eIDAS 认证声明。 消费一份受信任列表并不会使某个签名、某张证书或某个 NextPDF 输出成为“合格”;合格性归属于成员国监管下的信任服务提供方,法律效力在本模块之外。XMLDSig 处理模型约束(enveloped-signature 变换、exclusive canonicalization、覆盖根的引用)依据产品的验证配置记录;W3C XML Signature 规范不在所引证据集之内。本模块只决定一份列表是否可作为信任输入被接受;针对由此得到的锚进行证书路径验证归属于证书验证层。
开发说明
标题为“开发说明”的章节- 依赖为 PSR 接口:一个 PSR-18 客户端、一个 PSR-17 请求工厂,以及一个可选的 PSR-16 缓存。测试中注入内存替身;除冷
fetch()外,没有任何阶段需要活的网络访问。 - 带外固定顶层锚。对成员国列表而言,LOTL 锚为列表签名者授权;验证器绝不从
KeyInfo内容自举信任。 - 后台轮询、pivot-LOTL 处理以及双向 TLS 或代理认证在本版本的 fetcher 范围之外。请在外部安排刷新,并在每个
nextUpdate之前重新获取。 - 向
buildBundle()传入验证时刻,而非构造时刻。每次刷新后重建捆绑包;切勿将捆绑包缓存至源列表的nextUpdate之后。 bundleVersion具有可观察的形状tsl-<territory>-seq<sequenceNumber>;TslDocument上的rawXmlSha256支撑证据记录与重放检测。- 格式错误的服务条目以防御性占位值解析;一个抵达捆绑包构造的格式错误数字身份会以
InvalidArgumentExceptionfail-closed。 - 这些类携带包级
@since 1.10.0源码标注(TslFetchException:3.2.0)。TslDocument、TspService与TspServiceQualifier有源码标注@api。
- eIDAS 保证级别 — 将受信任列表证据映射到各保证级别的能力页。
- ASiC 容器 —
TslTrustAnchorProvider::buildBundle()的一个消费者,用于容器信任绑定。 - 签名验证 — 消费信任锚的 AdES/PAdES 验证侧。
- 安全 — 深度参考 — 合并的 Enterprise 安全能力面。
- 签名 — 深度参考 — PAdES B-LT 与 B-LTA 长期生产者。
发布边界
标题为“发布边界”的章节本页仅记录外部可观察的行为与受支持的公共 API 面。内部命名空间路径、辅助类、机制表、运行手册文件名与工单前缀均不在范围之内。