You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过代码验证TCPDF中setSignature()生成的签名PDF文件?

自行编码验证TCPDF生成的签名PDF方法

先说明:TCPDF只负责生成带签名的PDF,没有内置的签名验证函数。要自己写代码验证,得解析PDF的签名结构,再借助密码学工具完成验证,以下是具体思路和实现步骤:

核心逻辑

PDF签名遵循PKCS#7标准,TCPDF会把签名数据(含证书链、签名算法)嵌入PDF的/Contents字段,同时用/ByteRange标记未被签名覆盖的文档范围。验证流程分三步:

  1. 从PDF里提取签名相关的关键数据
  2. 验证证书链的有效性(信任度、有效期、是否吊销)
  3. 用证书公钥校验签名值和原始文档哈希是否匹配

具体实现步骤

1. 解析PDF的签名结构

首先要定位PDF里的签名域,提取/ByteRange(未签名的字节范围)和/Contents(Base64编码的PKCS#7签名数据)。可以用现成的PDF解析库简化操作,比如PHP环境用FPDI(它能读取PDF结构,虽然不做验证):

// PHP示例:用FPDI读取签名域信息
$pdf = new \setasign\Fpdi\Fpdi();
$pdf->setSourceFile('your_signed.pdf');
$acroForm = $pdf->getAcroForm();
$signatureFields = $acroForm->getFieldsOfType(\setasign\Fpdi\PdfParser\PdfAcroForm::FIELD_TYPE_SIGNATURE);

foreach ($signatureFields as $field) {
    $byteRange = $field->getDictionary()->getValue('/ByteRange')->toPhp();
    $contents = $field->getDictionary()->getValue('/Contents')->toPhp();
    // 后续处理这两个变量
}

如果不想用第三方库,也可以手动解析PDF的对象结构,找到签名字段对应的字典。

2. 计算原始文档的哈希

根据/ByteRange的四个值(格式是[起始偏移1, 长度1, 起始偏移2, 长度2]),读取PDF中这两段的内容,拼接后计算哈希——注意要和TCPDF签名时用的算法一致(比如SHA-256):

// PHP示例:计算原始文档哈希
$file = fopen('your_signed.pdf', 'rb');
// 读取第一段
fseek($file, $byteRange[0]);
$part1 = fread($file, $byteRange[1]);
// 读取第二段
fseek($file, $byteRange[2]);
$part2 = fread($file, $byteRange[3]);
// 拼接并计算哈希
$originalContent = $part1 . $part2;
$calculatedHash = hash('sha256', $originalContent, true);
fclose($file);

3. 验证PKCS#7签名

把/Contents里的Base64字符串解码成PKCS#7数据,用密码学库验证。PHP里可以直接用openssl扩展:

// PHP示例:验证PKCS#7签名并校验证书链
$pkcs7Data = base64_decode($contents);
// 先验证签名本身,PKCS7_NOVERIFY表示先不验证证书链
$verifyResult = openssl_pkcs7_verify($pkcs7Data, PKCS7_NOVERIFY);

if ($verifyResult === 1) {
    // 签名格式合法,接下来验证证书链
    $certInfo = openssl_pkcs7_read($pkcs7Data);
    $certificates = $certInfo['certificates'];
    
    foreach ($certificates as $cert) {
        // 检查证书有效期
        $parsedCert = openssl_x509_parse($cert);
        if (time() > $parsedCert['validTo_time_t'] || time() < $parsedCert['validFrom_time_t']) {
            die('证书已过期或未生效');
        }
        
        // 检查证书是否在信任链里(需要提前导入信任的根证书)
        $trustedRoot = file_get_contents('your_trusted_root_cert.pem');
        $chainVerify = openssl_x509_verify($cert, $trustedRoot);
        if ($chainVerify !== 1) {
            die('证书不受信任');
        }
    }
    echo '签名验证通过';
} else {
    die('签名验证失败:' . openssl_error_string());
}

4. 额外检查项

  • 确认TCPDF签名时用的哈希算法和你验证时一致(建议在生成签名时指定SHA-256:$pdf->setSignature($cert, $key, '', '', 2, array('algorithm' => 'sha256')))
  • 可以查询证书的吊销状态(OCSP或CRL方式),避免使用已吊销的证书
  • 检查签名域的/M字段(签名时间)是否符合预期

其他语言环境的思路

  • Python:用PyPDF2提取签名数据,cryptography库处理PKCS#7验证和证书链校验
  • Java:用BouncyCastle解析PDF签名,iText辅助处理PDF结构,完成证书链和签名验证

内容的提问来源于stack exchange,提问作者Chlaris Butler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:35:00