Skip to content

长期验证(LTV)

Pro — Commercial License Required
长期验证功能需要 Pro 包。

长期验证(Long-Term Validation)确保数字签名在签署者证书过期或 CA 停止服务后仍然可以被验证。Pro 包将所有验证所需数据嵌入 PDF 文件内,使文件具备自足的验证能力。

核心类

说明
LtvManagerLTV 流程协调器,自动执行完整的验证数据嵌入
DssBuilder构建 Document Security Store(DSS)字典
OcspClient查询 OCSP 响应以确认证书状态
CrlFetcher下载并解析证书吊销列表(CRL)

LtvManager

LtvManager 是最上层的协调器,自动完成 DSS 构建、验证数据查询与文档时间戳。

php
use Yeeefang\TcpdfNext\Pro\Security\Ltv\LtvManager;
use Yeeefang\TcpdfNext\Pro\Security\Signature\DigitalSigner;
use Yeeefang\TcpdfNext\Pro\Security\Timestamp\TsaClient;

$tsa = new TsaClient('https://freetsa.org/tsr');

$signer = new DigitalSigner($cert);
$signer->level(SignatureLevel::PAdES_B_LTA);
$signer->timestampAuthority($tsa);

// 一行完成所有 LTV 流程
LtvManager::embed($pdf, $signer);

自定义 LTV 选项

php
LtvManager::embed($pdf, $signer, [
    'includeOcsp' => true,       // 嵌入 OCSP 响应(默认 true)
    'includeCrl'  => true,       // 嵌入 CRL(默认 true)
    'ocspTimeout' => 10,         // OCSP 查询超时(秒)
    'crlTimeout'  => 30,         // CRL 下载超时(秒)
    'retryCount'  => 3,          // 重试次数
]);

DssBuilder

DSS(Document Security Store)是 PDF 2.0 定义的机制,将证书、OCSP 响应与 CRL 集中存储在文档层级。

php
use Yeeefang\TcpdfNext\Pro\Security\Ltv\DssBuilder;

$dss = DssBuilder::create()
    ->addCertificate($caCert)
    ->addCertificate($intermediateCert)
    ->addOcspResponse($ocspResponse)
    ->addCrl($crlData);

$pdf->setDss($dss->build());

验证相关信息(VRI)

每个签名都有对应的 VRI(Validation Related Information)条目,以签名哈希值为键:

php
$dss->addVri(
    signatureHash: 'A1B2C3D4...',
    certificates: [$signerCert, $caCert],
    ocspResponses: [$ocspResponse],
    crls: [$crlData],
    timestamp: $tsToken
);

VRI 让验证器能够精确找到每个签名所需的验证数据,而不需扫描整个 DSS。

OcspClient

OCSP(Online Certificate Status Protocol)用于即时查询证书的吊销状态。

php
use Yeeefang\TcpdfNext\Pro\Security\Ltv\OcspClient;

$ocsp = new OcspClient();
$ocsp->setTimeout(seconds: 10);
$ocsp->setRetryCount(3);

$response = $ocsp->query(
    certificate: $signerCert,
    issuerCertificate: $caCert,
    responderUrl: 'http://ocsp.example.com'
);

if ($response->isGood()) {
    echo "证书状态:有效\n";
    echo "下次更新:{$response->nextUpdate()->format('Y-m-d')}\n";
} elseif ($response->isRevoked()) {
    echo "证书已吊销:{$response->revocationTime()->format('Y-m-d')}\n";
}

自动探索 OCSP 端点

如果未手动指定端点,OcspClient 会自动从证书的 Authority Information Access(AIA)扩展字段获取 OCSP 响应端点。

php
$url = $ocsp->discoverResponder($signerCert);
// 返回如 'http://ocsp.example.com/responder'

CrlFetcher

CRL(Certificate Revocation List)是 CA 定期发布的证书吊销列表,作为 OCSP 的备援机制。

php
use Yeeefang\TcpdfNext\Pro\Security\Ltv\CrlFetcher;

$fetcher = new CrlFetcher();
$fetcher->setTimeout(seconds: 30);

$crlData = $fetcher->fetch('http://crl.example.com/ca.crl');

// 检查 CRL 是否仍在有效期内
if ($fetcher->isExpired($crlData)) {
    $crlData = $fetcher->fetch($crlUrl, forceRefresh: true);
}

自动探索 CRL 端点

php
$urls = $fetcher->discoverDistributionPoints($signerCert);
// 返回如 ['http://crl.example.com/ca.crl']

归档循环

当验证数据(OCSP 响应或 CRL)即将过期时,可以执行归档循环来更新验证数据并加入新的文档时间戳:

php
// 针对已签署的文件执行归档循环
$pdf = Document::open('/output/signed-blta.pdf');

LtvManager::archivalLoop($pdf, [
    'tsaUrl'   => 'https://freetsa.org/tsr',
    'refresh'  => true,    // 重新查询 OCSP/CRL
]);

$pdf->save('/output/signed-blta-refreshed.pdf');

归档循环以增量更新方式附加新的验证数据与文档时间戳,不会破坏既有的签名。这个流程可以定期调度执行,确保文件的验证能力在数十年后仍然有效。

下一步

以 LGPL-3.0-or-later 许可证发布。