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

PHP如何正确识别数字签名PDF的签名人?

问题诊断与修复方案

常见问题点

  • 误将证书链节点当作签名人:PDF签名的PKCS7数据包含完整证书链(签名人证书+CA证书),若脚本未过滤CA证书,会把CA机构和重复的签名人信息一并返回。
  • 仅读取第一个签名域:多签名PDF存在多个独立签名域,若脚本只遍历第一个域,自然无法获取后续的CAROL签名。
  • 未正确提取叶子证书:签名人信息存储在PKCS7的叶子证书(最底层用户证书)中,脚本可能错误遍历了整个证书链的所有证书。

修复步骤

1. 遍历所有签名域

PDF签名信息存于AcroForm的/Fields数组,需遍历所有类型为Sig的域:

// 示例:用Zend_PDF遍历全部签名域
$pdf = Zend_PDF::load('signed.pdf');
$acroForm = $pdf->getAcroForm();
$signatureFields = [];

if ($acroForm && isset($acroForm->fields)) {
    foreach ($acroForm->fields as $field) {
        if ($field->getType() === 'Sig') {
            $signatureFields[] = $field;
        }
    }
}

2. 从PKCS7中提取签名人证书

解析PKCS7数据时,只取证书链的叶子节点(签名人证书),排除CA证书:

// 解析PKCS7,提取签名人姓名
function getSignerName($pkcs7Data) {
    $certStore = openssl_pkcs7_read($pkcs7Data, $certs);
    if (!$certStore) return null;

    // 证书链第一个节点为签名人叶子证书
    $signerCert = $certs[0];
    $certInfo = openssl_x509_parse($signerCert);
    return $certInfo['subject']['CN'] ?? null;
}

3. 过滤CA证书与去重

通过证书扩展字段判断是否为CA,过滤后去重签名人信息:

// 判断证书是否为CA机构证书
function isCACert($cert) {
    $certInfo = openssl_x509_parse($cert);
    $basicConstraints = $certInfo['extensions']['basicConstraints'] ?? '';
    return str_contains($basicConstraints, 'CA:TRUE');
}

// 整理有效签名人列表
$validSigners = [];
foreach ($signatureFields as $field) {
    $pkcs7 = $field->getSignature()->getContents();
    $certStore = openssl_pkcs7_read($pkcs7, $certs);
    foreach ($certs as $cert) {
        if (!isCACert($cert)) {
            $signerName = openssl_x509_parse($cert)['subject']['CN'];
            if (!in_array($signerName, $validSigners)) {
                $validSigners[] = $signerName;
            }
        }
    }
}

结果验证

修复后用pdfsig命令对比结果:

pdfsig signed.pdf

确保脚本输出的签名人列表与pdfsig返回的Signer字段完全一致。

内容的提问来源于stack exchange,提问作者Vinicius Menezes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 11:00:10