是什么让 Adobe Reader 显示 "Signed" 面板?
What makes Adobe Reader display the "Signed" panel?
我正在使用 PHP 在服务器端签署 PDF 文件,我希望 Adobe Reader 在生成的 PDF 上显示此横幅,说明该文件已成功签署:
我正在使用 TCPDF 库 中的代码来实现此目的(我不得不修改一些代码以满足我的需要)。
我的工作基于 Adobe 官方文档中的这两个文档:doc1 and doc2.
我的工作:
将签名标签添加到 PDF 文件:
// The ID of the last object of the PDF + 1
$sigobjid = preg_match_all("/([0-9]+) 0 obj/", $pdfdoc, $output_array);
$sigobjid = end($output_array[1]) + 1;
// Write the signature tags where needed
$index_to_write = strrpos($pdfdoc,"endobj") + 6;
$signature_tag = PHP_EOL . $sigobjid . ' 0 obj '. PHP_EOL . '<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached '. TCPDF_STATIC::$byterange_string . ' /Contents<'.str_repeat('0', $tcpdf->get_signature_max_length()).'> >>' . PHP_EOL . 'endobj';
$pdfdoc = substr_replace($pdfdoc, $signature_tag, $index_to_write, 0);
计算并替换 ByteRange
像这样计算文件的哈希值:
$hash_result = hash('sha256', $pdfdoc);
使用 forge.js 对生成的哈希客户端进行签名:我使用我解析的 PFX 文件,然后使用包含的数据创建 PKCS7在 PFX 中。
将哈希发送到服务器。
- 将签名添加到 Content 标签中的 PDF。
编辑: 感谢@mkl 的评论,我还尝试使用 AcroForm 将我的 Sig 对象引用到我的 PDF 文件中:
11 0 obj
<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached /ByteRange[0 2846 14590 507] /Contents< ...
endobj
12 0 obj
<</AcroForm 11 0 R >>
endobj
它也不起作用。我应该如何填写 AcroForm 字段?
生成的 PDF 可由 Adobe 阅读 Reader 但蓝色横幅没有出现,为什么?
好的,我自己解决了,所以对于那些想知道的人,您需要这些字段:
1 0 obj
<<
/Type /Catalog /AcroForm << /Fields [12 0 R 13 0 R] /NeedAppearances false /SigFlags 3 /DR << /Font << /F1 14 0 R >> >> /DA (/F1 0 Tf 0 g) /Q 0 >> /Perms << /DocMDP 11 0 R >>
>>
endobj
4 0 obj
<<
/Type /Page
...
endobj
11 0 obj
<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached /ByteRange[0 3153 14897 922] /Contents<...> /Reference [ << /Type /SigRef /DigestMethod /SHA256 /TransformMethod /DocMDP /TransformParams << /Type /TransformParams /P 2 /V /1.2 >> >> ] >>
endobj
12 0 obj
<< /Type /Annot /Subtype /Widget /Rect [510.236220 572.598661 552.755906 615.118346] /P 4 0 R /F 4 /FT /Sig /T (Signer Name) /Ff 0 >>
endobj
13 0 obj
<< /Type /Annot /Subtype /Widget /Rect [510.236220 572.598661 552.755906 615.118346] /P 4 0 R /F 4 /FT /Sig /T (Signer Name) /Ff 0 /V 11 0 R >>
endobj
14 0 obj
<</Type /Font /Subtype /Type1 /BaseFont /Helvetica /Name /F1 /Encoding /WinAnsiEncoding >>
endobj
你基本上需要:
- 1 字体 对象(本例中为对象 14)
- 1 Sig 对象 (obj 11) 在 'contents' 字段中包含签名
- 1 页面 对象(对象 4)
- 2 Annot 对象(对象 12 和 13)引用带有 P 标志的第一个页面对象和带有 V 标志
- 1 AcroForm 主字段 Catalog (obj 1) 在 Fields 数组中引用你的 2 Annot 对象,引用你的字体F1 字段,以及您在 DocMDP 字段中的签名。
编辑: DocMDP 字段不是强制性的,只需要一个 Annot。也不需要 Font。
我正在使用 PHP 在服务器端签署 PDF 文件,我希望 Adobe Reader 在生成的 PDF 上显示此横幅,说明该文件已成功签署:
我正在使用 TCPDF 库 中的代码来实现此目的(我不得不修改一些代码以满足我的需要)。 我的工作基于 Adobe 官方文档中的这两个文档:doc1 and doc2.
我的工作:
将签名标签添加到 PDF 文件:
// The ID of the last object of the PDF + 1 $sigobjid = preg_match_all("/([0-9]+) 0 obj/", $pdfdoc, $output_array); $sigobjid = end($output_array[1]) + 1; // Write the signature tags where needed $index_to_write = strrpos($pdfdoc,"endobj") + 6; $signature_tag = PHP_EOL . $sigobjid . ' 0 obj '. PHP_EOL . '<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached '. TCPDF_STATIC::$byterange_string . ' /Contents<'.str_repeat('0', $tcpdf->get_signature_max_length()).'> >>' . PHP_EOL . 'endobj'; $pdfdoc = substr_replace($pdfdoc, $signature_tag, $index_to_write, 0);
计算并替换 ByteRange
像这样计算文件的哈希值:
$hash_result = hash('sha256', $pdfdoc);
使用 forge.js 对生成的哈希客户端进行签名:我使用我解析的 PFX 文件,然后使用包含的数据创建 PKCS7在 PFX 中。
将哈希发送到服务器。
- 将签名添加到 Content 标签中的 PDF。
编辑: 感谢@mkl 的评论,我还尝试使用 AcroForm 将我的 Sig 对象引用到我的 PDF 文件中:
11 0 obj
<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached /ByteRange[0 2846 14590 507] /Contents< ...
endobj
12 0 obj
<</AcroForm 11 0 R >>
endobj
它也不起作用。我应该如何填写 AcroForm 字段?
生成的 PDF 可由 Adobe 阅读 Reader 但蓝色横幅没有出现,为什么?
好的,我自己解决了,所以对于那些想知道的人,您需要这些字段:
1 0 obj
<<
/Type /Catalog /AcroForm << /Fields [12 0 R 13 0 R] /NeedAppearances false /SigFlags 3 /DR << /Font << /F1 14 0 R >> >> /DA (/F1 0 Tf 0 g) /Q 0 >> /Perms << /DocMDP 11 0 R >>
>>
endobj
4 0 obj
<<
/Type /Page
...
endobj
11 0 obj
<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached /ByteRange[0 3153 14897 922] /Contents<...> /Reference [ << /Type /SigRef /DigestMethod /SHA256 /TransformMethod /DocMDP /TransformParams << /Type /TransformParams /P 2 /V /1.2 >> >> ] >>
endobj
12 0 obj
<< /Type /Annot /Subtype /Widget /Rect [510.236220 572.598661 552.755906 615.118346] /P 4 0 R /F 4 /FT /Sig /T (Signer Name) /Ff 0 >>
endobj
13 0 obj
<< /Type /Annot /Subtype /Widget /Rect [510.236220 572.598661 552.755906 615.118346] /P 4 0 R /F 4 /FT /Sig /T (Signer Name) /Ff 0 /V 11 0 R >>
endobj
14 0 obj
<</Type /Font /Subtype /Type1 /BaseFont /Helvetica /Name /F1 /Encoding /WinAnsiEncoding >>
endobj
你基本上需要:
- 1 字体 对象(本例中为对象 14)
- 1 Sig 对象 (obj 11) 在 'contents' 字段中包含签名
- 1 页面 对象(对象 4)
- 2 Annot 对象(对象 12 和 13)引用带有 P 标志的第一个页面对象和带有 V 标志
- 1 AcroForm 主字段 Catalog (obj 1) 在 Fields 数组中引用你的 2 Annot 对象,引用你的字体F1 字段,以及您在 DocMDP 字段中的签名。
编辑: DocMDP 字段不是强制性的,只需要一个 Annot。也不需要 Font。