数字签名 (HasSecurity)
HasSecurity trait 提供 setSignature() 方法用于 PAdES 合规的数字签名。TCPDF-Next 通过 PadesOrchestrator、TsaClient 与 LTV 模块支持四种签名等级 — 从基本(B-B)到存档(B-LTA)。所有签名方法皆返回 static 以支持链式串接。
快速参考
| 类 / 枚举 | 用途 |
|---|---|
CertificateInfo | 加载签署证书(PEM 或 PKCS#12) |
SignatureLevel | 枚举:PAdES_B_B、PAdES_B_T、PAdES_B_LT、PAdES_B_LTA |
TsaClient | RFC 3161 时间戳授权客户端 |
SignatureAppearance | 可见或不可见的签名小部件 |
OcspClient | RFC 6960 在线撤销检查 |
CrlFetcher | RFC 5280 CRL 发布点获取 |
签名等级
| 等级 | 包含内容 | 有效性 |
|---|---|---|
| B-B(基本) | 签名 + 签署证书 | 在证书未被撤销期间有效 |
| B-T(时间戳) | B-B + RFC 3161 时间戳 | 证明签名在某个时间点之前已存在 |
| B-LT(长期) | B-T + 包含 OCSP/CRL 响应的 DSS | 证书过期后仍可验证 |
| B-LTA(存档) | B-LT + 文件时间戳 + 存档循环 | 可无限期验证 |
加载证书
从 PEM 文件
php
use Yeeefang\TcpdfNext\Security\Signature\CertificateInfo;
$cert = CertificateInfo::fromFiles(
certPath: '/path/to/certificate.pem',
keyPath: '/path/to/private-key.pem',
password: 'key-password',
extraCerts: '/path/to/ca-chain.pem', // 可选的中间证书
);从 PKCS#12(.p12 / .pfx)
php
use Yeeefang\TcpdfNext\Security\Signature\CertificateInfo;
$cert = CertificateInfo::fromPkcs12(
p12Path: '/path/to/certificate.p12',
password: 'pkcs12-password',
);签署范例
php
use Yeeefang\TcpdfNext\Core\Document;
use Yeeefang\TcpdfNext\Security\Signature\CertificateInfo;
use Yeeefang\TcpdfNext\Contracts\SignatureLevel;
use Yeeefang\TcpdfNext\Security\Timestamp\TsaClient;
$cert = CertificateInfo::fromFiles(
certPath: '/path/to/certificate.pem',
keyPath: '/path/to/private-key.pem',
password: 'key-password',
);
// PAdES B-B(基本)— 仅签名
$pdf = Document::create()
->setSignature($cert, SignatureLevel::PAdES_B_B)
->addPage()
->setFont('Helvetica', '', 12)
->cell(0, 10, 'Signed document (B-B)')
->save('signed-bb.pdf');
// PAdES B-T(时间戳)— 签名 + 时间戳
$tsa = new TsaClient('https://freetsa.org/tsr');
$pdf = Document::create()
->setSignature($cert, SignatureLevel::PAdES_B_T, $tsa)
->addPage()
->cell(0, 10, 'Signed with timestamp (B-T)')
->save('signed-bt.pdf');
// PAdES B-LTA(存档)— 完整长期验证
$pdf = Document::create()
->setSignature($cert, SignatureLevel::PAdES_B_LTA, $tsa)
->addPage()
->cell(0, 10, 'Archival signature (B-LTA)')
->save('signed-blta.pdf');TsaClient — 时间戳授权
TsaClient 支持可选的验证机制。Nonce 验证与 DNS 固定默认启用,以防止重放攻击与 SSRF。
php
$tsa = new TsaClient(
url: 'https://tsa.example.com/timestamp',
user: 'tsa-user',
pass: 'tsa-password',
);B-T 及以上等级皆需要提供 TsaClient。时间戳依据 RFC 3161 标准,向时间戳授权机构(TSA)请求可信的时间证明,确保签名的时间不可否认性。
长期验证(B-LT / B-LTA)
B-LT 与 B-LTA 等级会自动获取并嵌入撤销数据:
- OcspClient — 根据证书的 AIA 扩展,查询 OCSP 响应者(RFC 6960)
- CrlFetcher — 从发布点下载 CRL(RFC 5280)
- DSS(文件安全存储区) — 将 OCSP 响应与 CRL 存储在文件安全存储区中
- VRI(验证相关信息) — 每个签名的验证数据(可选,依 ETSI 建议)
B-LTA 还会额外添加文件时间戳,启动存档循环 — 文件可通过重新加盖时间戳来无限期延长有效性。
签名外观
默认情况下,签名为不可见。若要创建可见的签名小部件:
php
use Yeeefang\TcpdfNext\Security\Signature\SignatureAppearance;
$pdf = Document::create()
->setSignature($cert, SignatureLevel::PAdES_B_T, $tsa)
->setSignatureAppearance(
SignatureAppearance::visible(x: 20, y: 250, w: 80, h: 30)
)
->addPage()
->cell(0, 10, 'Document with visible signature')
->save('visible-signature.pdf');若要明确设置不可见签名:
php
$pdf->setSignatureAppearance(SignatureAppearance::invisible());签名等级比较
| 特性 | B-B | B-T | B-LT | B-LTA |
|---|---|---|---|---|
| 数字签名 | V | V | V | V |
| 签署证书 | V | V | V | V |
| RFC 3161 时间戳 | V | V | V | |
| DSS(OCSP + CRL) | V | V | ||
| 文件时间戳 | V | |||
| 存档循环 | V | |||
| 证书过期后可验证 | V | V | ||
| 无限期可验证 | V |
方法参考
php
$pdf->setSignature(
CertificateInfo $cert, // 证书与私密密钥
SignatureLevel $level, // B-B、B-T、B-LT 或 B-LTA
?TsaClient $tsa = null, // B-T、B-LT、B-LTA 必须提供
);返回 static 以支持链式串接。签名在调用 save() 或 output() 时应用。
签名算法通过 phpseclib3 实现:RSA PKCS#1 v1.5(默认,最广泛的兼容性)与 RSASSA-PSS(更强的填充方案,建议新部署使用)。
完整 PKCS#12 范例
php
use Yeeefang\TcpdfNext\Core\Document;
use Yeeefang\TcpdfNext\Security\Signature\CertificateInfo;
use Yeeefang\TcpdfNext\Security\Signature\SignatureAppearance;
use Yeeefang\TcpdfNext\Contracts\SignatureLevel;
use Yeeefang\TcpdfNext\Security\Timestamp\TsaClient;
// 从 PKCS#12 加载证书
$cert = CertificateInfo::fromPkcs12(
p12Path: '/path/to/certificate.p12',
password: 'pkcs12-password',
);
// 设置时间戳授权
$tsa = new TsaClient('https://freetsa.org/tsr');
// 创建具有 B-LTA 等级签名的文件
$pdf = Document::create()
->setTitle('Signed Contract')
->setAuthor('Legal Department')
->setSignature($cert, SignatureLevel::PAdES_B_LTA, $tsa)
->setSignatureAppearance(
SignatureAppearance::visible(x: 20, y: 250, w: 80, h: 30)
)
->addPage()
->setFont('Helvetica', 'B', 18)
->cell(0, 15, 'Service Agreement', newLine: true)
->setFont('Helvetica', '', 12)
->multiCell(0, 6, 'This document has been digitally signed with a PAdES B-LTA '
. 'archival signature. The signature includes a trusted timestamp and '
. 'embedded revocation data for long-term validation.')
->save('signed-contract.pdf');