使用 PHP 的 openssl_pkcs7_sign 签署 pdf 时出错

Vic*_*yew 3 pdf-generation openssl cryptography tcpdf php-openssl

我正在使用 TCPDF 生成 pdf 文档并对其进行签名。TCPDF本身只是调用PHP的openssl_pkcs7_sign函数,在我看来这是PKCS7_sign基于源代码调用C的函数。

直到最近,一切都运转良好。然后我改变了证书提供者。我刚刚更新了私钥、证书和证书链:

$pdf->setSignature(
                $this->public_certificate_path, 
                $this->private_key_path, 
                $this->private_key_password, 
                $this->extra_certificates_path, 
                1);
Run Code Online (Sandbox Code Playgroud)

我将 PEM 格式的新根证书和中间证书复制到extra_certificates_path文件内。我使用验证了这个文件openssl,看起来不错。

现在,当我在 Adob​​e Reader 中打开签名的 PDF 时,它会显示以下错误:

  • 打开文件时,它说

    该文件已损坏但正在修复

  • 上面的蓝丝带说

    认证无效

  • 当我打开签名面板时,它说

    已通过 %s 认证

  • 错误的详细信息说

    此签名中包含的格式或信息有错误(支持信息:SigDict /Contents非法数据)

  • 当我点击“证书详细信息”时,没有任何反应

请参阅下面的屏幕截图。

知道可能出了什么问题吗?

在此输入图像描述

mkl*_*mkl 5

分析OP分享的示例文件就可以理解问题所在:嵌入到文档中的签名容器超出了最初为其保留的大小。

因此,解决方案是为签名容器预留更多空间。

事实上,OP 证实:

确实有一个地方指定了最大签名长度。我改变了它,并且有效。

此外,OP 表示他有兴趣如何识别问题。

对于许多 PDF 问题,我们首先使用 PDF 内部浏览器(例如 iText RUPS 或 PDFBox PDFDebugger)检查 PDF。但在这种情况下,文本查看器和十六进制查看器就足够了。

使用文本查看器可以找到签名值字典(此处打印得很漂亮,内容条目已缩短):

10 0 obj
<<
  /Type /Sig
  /Filter /Adobe.PPKLite
  /SubFilter /adbe.pkcs7.detached
  /ByteRange[0 78679 90423 6699]
  /Contents<308217b7...563934bf>
  /Reference [
  <<
    /Type /SigRef
    /TransformMethod /DocMDP
    /TransformParams << /Type /TransformParams /P 1 /V /1.2 >>
  >> ]
  /M (D:20171129170713+00'00')
>>
endobj
Run Code Online (Sandbox Code Playgroud)

ByteRange条目指示Contents值(十六进制编码签名容器)应从文件偏移 78679 到 90423-1。使用十六进制查看器,可以快速验证内容值 ( ) 的起始索引是否匹配,但结束索引的索引晚于预期。<308217b7...563934bf>

就是这样,嵌入了一个太大的签名容器。;)