签名验证:AdES / PAdES 密码学验证器
快速总览
标题为“快速总览”的章节NextPDF Enterprise 会以密码学方式验证数字签名。验证端从 PDF 读取 CMS SignedData 或 RFC 3161 时间戳令牌,重新计算摘要、检查签名、将每个签名绑定到其签署凭证,并根据调用方提供的信任锚点存储区验证凭证链——包括凭证策略处理。本页属于行为层级文档,说明哪些项目会被验证、哪些项目会以 fail-closed 方式拒绝、支持哪些算法,以及信任边界位于何处。
这不同于 Validation,后者运行只读的结构性策略检查,并有意不执行任何密码学运算。它也是 签名生成器的验证端对应组件,后者会写入 PAdES B-LT / B-LTA 结构。
composer require nextpdf/enterprise:^3概念总览
标题为“概念总览”的章节验证以证据为本,并采用 fail-closed:无法正面确立的检查不会产生正面结果。下列各部分共同构成由 ValidationReport 承载的结果。
CMS / 时间戳令牌的密码学验证。 一个自包含、严格的定长 DER 堆栈会解析 CMS SignedData 与 RFC 3161 时间戳令牌。只有当令牌恰好带有一个 SignerInfo、其签署属性通过严格解析、签署者凭证可解析、message-digest 属性与重新计算的摘要相符、必要的签署凭证(ESS signing-certificate-v2)绑定成立,且 SignerInfo 签名能针对重新标记后的签署属性通过验证时,令牌才会被接受。摘要比对规则遵循 RFC 5652 §5.6 / §5.4 的验证模型:接收端重新计算内容消息摘要,只有当该值等于 messageDigest 签署属性时,签名才有效——验证者绝不信任由生成器提供的摘要。
在 genTime 进行的 TSA 凭证验证。 时间戳的 genTime 是该令牌创建时的 UTC 时刻(RFC 3161 §2.4.2)。TSA 签署凭证会在那个时刻而非「现在」进行验证:其扩展密钥用途必须是单一且关键的 id-kp-timeStamping(RFC 3161 §2.3),并且其有效期间、凭证链、信任锚点来源与撤销都会针对 genTime 进行评估。即使结构上格式良好,只要凭证链无法连接到已配置的信任锚点,就永远无法支撑正面结果。
分离式 PAdES 基本文档签名。 一个具体的提取器会对分离式文档签名运行真正的 AdES / PAdES 基本验证:针对已签署的字节范围重新计算消息摘要并进行比对、验证签名,并将签署凭证绑定作为必要项。这取代了此前仅做结构性检查的回退机制。时间戳验证器与文档签名提取器共用同一个 ESS issuer-and-serial 验证器,因此两者在凭证绑定解析上不会发生漂移。
归档 DocTimeStamp 覆盖链。 validateArchivalTimestampChain() 会验证一条由受信任 DocTimeStamp 令牌构成、覆盖 PDF 字节范围的链,作为 B-LTA 归档证据。每个令牌的印记都绑定到其实际覆盖的 ByteRange 字节,该链遵循严格的 ETSI 排序,每个令牌的 TSA 链都有信任锚点,且该链必须覆盖文件直到其文件结尾标记。只有完整、具信任锚点且覆盖至 EOF 的链,才能达到完全通过的结果。
凭证策略处理(RFC 5280 §6.1.4)。 路径验证会应用完整的凭证策略处理:节点结构化的策略树、带有 anyPolicy 回退的策略映射,以及 policyConstraints / inhibitAnyPolicy 折叠,并由一个 fail-closed 的策略扩展 DER 读取器支撑。路径处理的状态变量 explicit_policy 与 inhibit_anyPolicy(RFC 5280 §6.1.2)决定是否要求非空的有效策略树;收尾步骤会将有效策略树与 user-initial-policy-set 取交集(RFC 5280 §6.1.4)。在无必要策略且接受 anyPolicy 的情况下,处理不受约束——这是默认值,且与此前行为相同。
支持的算法
标题为“支持的算法”的章节验证端接受下列算法集合,并对其外的任何项目以 fail-closed 方式拒绝:不支持的算法会直接导致验证被拒绝,绝不会无声通过。
| 系列 | 支持 | 备注 |
|---|---|---|
| RSA(PKCS#1 v1.5) | rsaEncryption 搭配 SHA-2,以及 sha*WithRSAEncryption OID | 接受 |
| ECDSA | 曲线 P-256、P-384、P-521 | 接受 |
| RSASSA-PSS | — | 不支持 → fail-closed |
| EdDSA | — | 不支持 → fail-closed |
| SHA-3 摘要 | — | 不支持 → fail-closed |
| SHA-1 | — | 弱:使用 SHA-1 通过验证的基本签名会被降级为密码学约束失败,而非通过 |
API 接口
标题为“API 接口”的章节验证端通过公开引擎以及 Core / Pki 契约提供。具体的策略类别为内部使用。
| 类型 | 种类 | 角色 |
|---|---|---|
AdESValidationEngine | class | 验证端的入口点:签名与归档链验证。 |
AdESValidationEngine::validateArchivalTimestampChain() | method | 验证一条覆盖 PDF 字节范围且受信任的 DocTimeStamp 覆盖链。 |
ValidationReport | result | 结构化结果:整体状态加上逐项检查发现。 |
PathValidatorInterface | interface(NextPDF\…\Pki) | 引擎依赖的凭证路径验证 SPI。 |
PathValidationOptions | value object | 策略处理控制项:requireExplicitPolicy、inhibitAnyPolicy、inhibitPolicyMapping、maxPolicyFanout。 |
TrustAnchorStoreInterface | interface | 由调用方提供、用于评估凭证链的受信任锚点集合。 |
归档链方法的签名如下:
public function validateArchivalTimestampChain( string $pdfBytes, array $dssData = [], ?TrustAnchorStoreInterface $anchors = null,): ValidationReport;只有当 DocTimeStamp 链完整通过验证、具信任锚点,且覆盖文件直到其 EOF 标记时,它才会达到完全通过的结果。
CertificateChainValidator::validate() 接受一组初始策略集合(即 RFC 5280 的 user-initial-policy-set)。默认值为 anyPolicy——不受约束——因此一般凭证链不受影响;若要求非空的有效策略树,请传入明确集合,或设置 requireExplicitPolicy。
代码范例——快速上手
标题为“代码范例——快速上手”的章节use NextPDF\Enterprise\Security\Validation\AdESValidationEngine;
$report = $engine->validateArchivalTimestampChain($pdfBytes, [], $trustAnchors);
if ($report->isTotalPassed()) { // A complete, trust-anchored, EOF-covering DocTimeStamp chain.}代码范例——正式环境
标题为“代码范例——正式环境”的章节use NextPDF\Enterprise\Security\Validation\AdESValidationEngine;use Psr\Log\LoggerInterface;
final readonly class ArchivalEvidenceCheck{ public function __construct( private AdESValidationEngine $engine, private LoggerInterface $logger, ) {}
public function check(string $pdfBytes, TrustAnchorStoreInterface $anchors): bool { $report = $this->engine->validateArchivalTimestampChain($pdfBytes, [], $anchors);
foreach ($report->findings as $finding) { $this->logger->info('archival.finding', [ 'check' => $finding->checkId, 'status' => $finding->status->value, ]); }
// A positive result proves byte-range coverage by a trusted timestamp // chain — it is one input to your decision, not a legal conclusion. return $report->isTotalPassed(); }}行为变更与升级注意事项
标题为“行为变更与升级注意事项”的章节验证端已从结构性和时间性接受转为完整的密码学验证。任何依赖旧有宽松行为的调用方,都应查看这些变更。
- 对可识别但无法验证的时间戳采取 fail-closed。 此前仅凭结构性与时间性理由通过的 DocTimeStamp 或归档令牌,现在需要完整的密码学验证——签名、message-digest 以及签署凭证绑定。无法通过验证的令牌不再产生正面的存在证明;它会映射为不确定或失败的结果。
- SHA-1 基本签名会被降级,而非通过。 通过验证但使用 SHA-1 的基本文档签名会被报告为密码学约束失败,而非完全通过。
- RFC 5280 §6.1.4 凭证策略处理会被强制运行。 一条
explicit_policy归零且有效策略树为空的凭证链现在会失败——包括由链内policyConstraintsrequireExplicitPolicy驱动的情况。默认且不受约束的凭证链(无必要策略、接受anyPolicy)不受影响。 - 构造函数签名变更(BC break)。
AdESValidationEngine::__construct()现在将其$chainValidator参数的类型声明为Pki\PathValidatorInterfaceSPI,并以延迟方式默认使用Pki\CertificateChainValidator::withDefaults()。它此前是具体的Ltv\CertificateChainValidator。此前注入具体 LTV 验证器的调用方,必须改为注入 Pki SPI 实现。Pki 验证器包装同一个结构性路径引擎,并增加名称约束与策略处理;对符合规范的默认输入而言,它是无操作(no-op)。
边界情况与陷阱
标题为“边界情况与陷阱”的章节- 不支持的算法 ≠ 无法定论。 RSASSA-PSS、EdDSA 与 SHA-3 会被 fail-closed 拒绝,而非延后处理。若你的签署者使用这些算法,此验证端不会为其返回正面结果。
- 信任是相对于锚点的。 验证永远相对于你提供的信任锚点存储区。空的或错误的锚点集合会产生不受信任的结果,无论密码学检查是否正确。
- genTime,而非现在。 TSA 凭证会在令牌的
genTime进行判定。一个其后已过期的 TSA 凭证,仍可支撑其有效期间内创建的令牌;而在genTime时尚未生效的凭证则不能。 - EOF 覆盖。 归档链必须覆盖文档直到其 EOF 标记。只覆盖文件前缀部分的时间戳,并不能确立整份文档的覆盖。
- 未被证明已撤销,并不等于状态良好(Good)。
Valid判定需要一个确切未撤销的状态。如果 OCSP 与 CRL 都返回 Unknown 或 Unavailable,即使签名在密码学上正确、链有效且具信任锚点,也会判定为Indeterminate——请为签署者凭证提供内嵌的 OCSP/CRL Good 材料,才能达到Valid。
验证在处理进程内、基于所提供的 PDF 字节与内嵌验证材料进行;成本会随链长度与时间戳数量增长。验证期间不进行任何网络往返——撤销与信任材料均取自调用方提供或文档中内嵌的内容。验证具有确定性:相同的输入与相同的信任锚点会产生相同的报告。
安全性注意事项
标题为“安全性注意事项”的章节- fail-closed 是默认行为。 每个接受步骤都会拒绝其无法正面验证的材料。这可防止文档声称具有引擎从未确立的有效性。
- 附加于时间戳之后的内容会被 EOF 覆盖规则击败。 由于每个归档时间戳的印记都绑定到实际的
ByteRange字节,且该链必须到达 EOF,因此在时间戳之后附加的内容不会被它覆盖,也不会取得其证据效力。 - 将输入视为恶意。 来自不受信任来源的 PDF 字节、内嵌 CMS 与时间戳令牌,都会由一个严格的定长 DER 读取器解析;该读取器会拒绝格式错误或不定长的编码。
数据持久化与 PII 缓解
标题为“数据持久化与 PII 缓解”的章节验证在处理进程内、于本机进行,不执行任何网络 I/O。凭证与签名包含主体身份;请对报告及任何提取出的凭证数据应用你自己的保留与最小化控制。
安全的遥测与日志清理
标题为“安全的遥测与日志清理”的章节发现项带有检查标识符与状态。某些诊断可能会回显凭证主体名称或序号;在将日志转送至共享接收端之前,请清理或屏蔽这些字段。
范围界限
标题为“范围界限”的章节请在面向用户的输出中说明这些边界,避免正面结果被过度解读。
validateArchivalTimestampChain()证明的是字节范围覆盖,而非 xref 可达性。 它确立的是:一条受信任的时间戳链以密码学方式覆盖文档的字节范围直到 EOF。它不运行 xref 层级或startxref对象可达性分析;这是有意排除在范围之外的。附加于时间戳之后的攻击,是由 EOF 覆盖规则搭配信任锚定所击败,而非由对象图分析击败。- 有意排除在范围之外。 此验证端不提供 Evidence Records(RFC 4998 / RFC 6283);不提供 RSASSA-PSS、EdDSA 或 SHA-3 时间戳令牌的验证;不提供受信任清单(TSL)与合格 TSA 集成;也不提供在线 TSA 撤销材料获取。撤销会依据验证器已可取得的材料来评估。
一致性
标题为“一致性”的章节| 行为 | 参考 | 状态 |
|---|---|---|
签名值/时间戳令牌以 DER 编码保存于 /Contents | ISO 32000-2 §12.8.1 | 已解析并验证 |
| 文档时间戳字典 | ISO 32000-2 §12.8.5 | 为归档链而读取 |
| 接收端重新计算内容摘要;其值必须等于 messageDigest 属性 | RFC 5652 §5.6 / §5.4 | 已强制运行 |
TSA 凭证带有单一关键的 id-kp-timeStamping EKU | RFC 3161 §2.3 | 在 genTime 检查 |
| genTime 为 UTC 创建时刻 | RFC 3161 §2.4.2 | 作为验证时刻使用 |
策略处理状态变量(explicit_policy、inhibit_anyPolicy) | RFC 5280 §6.1.2 | 已处理 |
| 收尾步骤将有效策略树与 user-initial-policy-set 取交集 | RFC 5280 §6.1.4 | 已强制运行 |
| 针对长期签名的 DSS 项目与文档时间戳 | ETSI EN 319 142-2 §5.5 | 已验证为归档证据 |
所有条款均为意译。NextPDF 不复制规范性文本;如需具权威性的表述,请查阅已发布的标准。NextPDF 不作任何 AdES / PAdES 认证声明。 此验证端实现所引用规格描述的密码学检查;它并非经过认证的验证服务,也不产生任何第三方证明。
FIPS 模式行为
标题为“FIPS 模式行为”的章节当 Enterprise FIPS 配置文件启用时,该约束会应用于验证器所接受的摘要与签名算法。验证逻辑——摘要重新计算、签名检查、凭证绑定与路径验证——保持不变。
威胁模型
标题为“威胁模型”的章节| 资产 | 对手 | 风险 | 缓解 |
|---|---|---|---|
| 时间戳令牌 | 伪造或篡改的令牌 | 虚假的存在证明 | 完整的密码学验证;对任何无法验证者采用 fail-closed |
| TSA 凭证 | 不受信任的签发者 | 验证器不应主张的表面信任 | 凭证链在 genTime 验证至调用方提供的锚点;不受信任的链永不通过 |
| 文档字节 | 附加于时间戳之后 | 内容在未被覆盖的情况下取得时间戳效力 | 印记绑定至实际 ByteRange 字节 + EOF 覆盖规则 |
| 弱算法 | 降级为 SHA-1 / 不支持的方案 | 弱签名被读为有效 | SHA-1 降级;RSASSA-PSS / EdDSA / SHA-3 fail-closed |
版本闸门
标题为“版本闸门”的章节此验证端是 Enterprise 功能,随 nextpdf/enterprise 套件提供。NextPDF Core 会侦测签名是否存在并生成 B-B / B-T 签名;它不提供此密码学验证端。取得授权。
授权功能旗标
标题为“授权功能旗标”的章节此验证端由 Enterprise 版本闸控(license_feature_flag: enterprise)。它通过 Core 与 Pki 契约接入;公开 API 不会因版本升级而改变。
行为契约
标题为“行为契约”的章节- 只有在具备恰好一个
SignerInfo、严格解析的签署属性、已解析的签署者凭证、相符的 message-digest、必要的签署凭证绑定,以及通过验证的SignerInfo签名时,CMS 或时间戳令牌才会被接受。 - TSA 凭证会在令牌的
genTime进行验证:单一关键的id-kp-timeStampingEKU、有效期间、具信任锚点的凭证链,以及撤销。 - 一个
Valid判定还额外要求确切未撤销的状态——至少一个具权威性的 Good(一个经验证为良好的 OCSP 回应,或一份未过期且未列出该序号的最新 CRL)。如果状态只是未被证明已撤销,且 OCSP 与 CRL 皆为 Unknown 或 Unavailable,则会判定为Indeterminate,绝不会是Valid(ETSI EN 319 102-1:撤销状态无法取得 → INDETERMINATE)。由于 CRL 回退路径仅证明清单的新鲜度,而非逐序号的撤销状态,因此一条仅有 CRL、缺少 Good OCSP 的链通常为Indeterminate。 validateArchivalTimestampChain()只有针对完整、具信任锚点且覆盖至 EOF 的 DocTimeStamp 链才会达到完全通过的结果;它证明的是字节范围覆盖,而非 xref 可达性。- 凭证策略处理遵循 RFC 5280 §6.1.4;默认不受约束的凭证链不受影响。
- 支持的算法为 RSA(PKCS#1 v1.5 搭配 SHA-2)与 ECDSA(P-256/384/521);RSASSA-PSS、EdDSA 与 SHA-3 采 fail-closed;SHA-1 会被降级。
NDA 扫描状态
标题为“NDA 扫描状态”的章节此公开页面仅描述外部可观察的验证端行为。它通过受支持的接口点名公开引擎、Pki / 信任锚点契约,以及 validateArchivalTimestampChain() 方法。具体的 DER、CMS、策略处理器与路径验证器内部,位于受 NDA 约束的深度参考中。
Core 回退
标题为“Core 回退”的章节NextPDF Core 会侦测签名是否存在并生成 B-B / B-T 签名,但它不以密码学方式验证 CMS 或时间戳令牌、不验证归档链,也不运行 RFC 5280 §6.1.4 策略处理。仅部署 Core 的环境没有对等的验证端;请参阅 Security / Signing (Core)。
Pro 回退
标题为“Pro 回退”的章节NextPDF Pro 增加了签署策略与电子发票处理,但不提供此密码学验证端;归档链验证与凭证策略处理仅在 nextpdf/enterprise 中提供。
Enterprise 边界说明
标题为“Enterprise 边界说明”的章节此验证端按行为层级描述。严格 DER 堆栈、CMS 解析器、策略处理器与路径验证器内部,超出公开接口范围,且不会在此重述。
部署边界
标题为“部署边界”的章节验证取决于信任锚点存储区,以及调用方提供或文档中内嵌的任何撤销材料。NextPDF Enterprise 会评估这些材料;它不运营信任清单、TSA 或撤销服务。操作者负责锚点选择与内嵌撤销材料的新鲜度。
法律合规边界
标题为“法律合规边界”的章节此页面标记为 export_control_class: legal-review-required;它涉及密码学验证。在设置 publish 旗标之前,须取得法务签核。正面的验证结果是关于文档签名与时间戳的密码学陈述——它不是法律意见、不是 eIDAS 合格性判定,也不是认证。NextPDF 不作任何 AdES / PAdES 认证声明。 关于你的法规义务,请咨询你自己的合规与法律顾问。
另请参阅
标题为“另请参阅”的章节- Signature:PAdES B-LT / B-LTA 产生器 —— 生成器端。
- Validation —— 处理进程内的结构性策略检查(无密码学)。
- Archive:DSS、VRI、LTV health —— 长期归档与 LTV 健康状态。
- Security / Signing (Core) —— CMS、RFC 3161、RFC 5280 路径验证、OCSP/CRL。
- PAdES 基准映射 —— 跨版本的 B-B、B-T、B-LT、B-LTA。
- PAdES · DSS · LTV —— 词汇表术语。