从 pdf 中检索 pkcs7 文件并共同签名
retrieve the pkcs7 file from pdf and co-sign
我有一个签名的 PDF 文件和一个 .p7s 文件。我需要从 PDF 中检索 .p7s 并共同签署 PDF(生成其他 .p7s)。
在我需要再次将 p7s 放入 PDF 文件之后。
当我尝试从 PDF 获取 p7s 时出现此错误:
ExceptionConverter:java.security.SignatureException:对象未初始化以进行签名
我的代码:
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
PdfReader pdfReader = new
PdfReader(Files.readAllBytes(inputFile.toPath()));
AcroFields acroFields = pdfReader.getAcroFields();
List<String> signatures = acroFields.getSignatureNames();
for (String name : signatures) {
PdfPKCS7 pdfPkcs7 = acroFields.verifySignature(name, "BC");
Files.write(Paths.get("~/TEST/itext/"+ name +".p7s"),
pdfPkcs7.getEncodedPKCS7());//ERROR HERE!
}
理论上
您想通过从 PDF 中提取嵌入式 CMS 签名容器并向其添加您的签名来[=44=]共同签署 PDF(会签?平行签名?),并重新嵌入扩展容器。
这是错误的方法,PDF 签名被设计为仅包含每个 PDF 签名字段的单个签名,而我们讨论的 CMS 签名容器本质上就是这样一个字段的值,因此每个嵌入的签名容器都应准确包含一个签名。
严格来说 PDF 规范允许您使用任意自定义签名方案,只有“可互操作的签名”是有限的。因此,您的具有多个签名的签名容器可以被认为是有效的 PDF,只是不是“可互操作签名”,即您不应该期望任何其他软件像您一样解释签名。特别是 Adobe Acrobat Reader 将仅识别并显示其中一个签名。
(事实上,一些大型签名解决方案提供商也在 PDF 中嵌入了多重签名 CMS 容器。例如,目前我必须处理由嵌入任意 CAdES-A 签名的此类提供商生成的签名容器(特别是一些有多个签名者)转换为 PDF 并调用此签名格式 PDF/CAdES-A,现在我必须向他们的客户解释他们的签名是 PDF 签名,但不是可互操作的签名,即使那个名字 [=54] =] 听起来像是一些很棒的标准...)
为了实现互操作性,PDF 中的多个签名必须按顺序应用,如本草图所示:
有关一些背景和更多信息的链接,请参见。 this answer.
在实践中
您的代码似乎是 iText 5.5.x 代码,特别是还不是 iText 7.x 代码。在这种情况下,您可以按原样使用 Digital Signatures for PDF Documents white book by Bruno Lowagie 中的代码。
一个非常简单的例子:
public void sign(String src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, CryptoStandard subfilter, String reason, String location)
throws GeneralSecurityException, IOException, DocumentException {
// Creating the reader and the stamper
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '[=10=]');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
// Creating the signature
ExternalDigest digest = new BouncyCastleDigest();
ExternalSignature signature = new PrivateKeySignature(pk, digestAlgorithm, provider);
MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, subfilter);
}
(代码示例 2.1:使用 iText 签名的“Hello World”)
由于您的用例涉及签署已签署的文档,因此您只需将 PdfStamper.createSignature
行更改为
PdfStamper stamper = PdfStamper.createSignature(reader, os, '[=11=]', true);
(注意末尾的新布尔参数)。此更改导致签名以 附加模式 创建,这使以前的修订保留原始签名,不会使该签名无效。
我有一个签名的 PDF 文件和一个 .p7s 文件。我需要从 PDF 中检索 .p7s 并共同签署 PDF(生成其他 .p7s)。 在我需要再次将 p7s 放入 PDF 文件之后。 当我尝试从 PDF 获取 p7s 时出现此错误: ExceptionConverter:java.security.SignatureException:对象未初始化以进行签名 我的代码:
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
PdfReader pdfReader = new
PdfReader(Files.readAllBytes(inputFile.toPath()));
AcroFields acroFields = pdfReader.getAcroFields();
List<String> signatures = acroFields.getSignatureNames();
for (String name : signatures) {
PdfPKCS7 pdfPkcs7 = acroFields.verifySignature(name, "BC");
Files.write(Paths.get("~/TEST/itext/"+ name +".p7s"),
pdfPkcs7.getEncodedPKCS7());//ERROR HERE!
}
理论上
您想通过从 PDF 中提取嵌入式 CMS 签名容器并向其添加您的签名来[=44=]共同签署 PDF(会签?平行签名?),并重新嵌入扩展容器。
这是错误的方法,PDF 签名被设计为仅包含每个 PDF 签名字段的单个签名,而我们讨论的 CMS 签名容器本质上就是这样一个字段的值,因此每个嵌入的签名容器都应准确包含一个签名。
严格来说 PDF 规范允许您使用任意自定义签名方案,只有“可互操作的签名”是有限的。因此,您的具有多个签名的签名容器可以被认为是有效的 PDF,只是不是“可互操作签名”,即您不应该期望任何其他软件像您一样解释签名。特别是 Adobe Acrobat Reader 将仅识别并显示其中一个签名。
(事实上,一些大型签名解决方案提供商也在 PDF 中嵌入了多重签名 CMS 容器。例如,目前我必须处理由嵌入任意 CAdES-A 签名的此类提供商生成的签名容器(特别是一些有多个签名者)转换为 PDF 并调用此签名格式 PDF/CAdES-A,现在我必须向他们的客户解释他们的签名是 PDF 签名,但不是可互操作的签名,即使那个名字 [=54] =] 听起来像是一些很棒的标准...)
为了实现互操作性,PDF 中的多个签名必须按顺序应用,如本草图所示:
有关一些背景和更多信息的链接,请参见。 this answer.
在实践中
您的代码似乎是 iText 5.5.x 代码,特别是还不是 iText 7.x 代码。在这种情况下,您可以按原样使用 Digital Signatures for PDF Documents white book by Bruno Lowagie 中的代码。
一个非常简单的例子:
public void sign(String src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, CryptoStandard subfilter, String reason, String location)
throws GeneralSecurityException, IOException, DocumentException {
// Creating the reader and the stamper
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '[=10=]');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
// Creating the signature
ExternalDigest digest = new BouncyCastleDigest();
ExternalSignature signature = new PrivateKeySignature(pk, digestAlgorithm, provider);
MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, subfilter);
}
(代码示例 2.1:使用 iText 签名的“Hello World”)
由于您的用例涉及签署已签署的文档,因此您只需将 PdfStamper.createSignature
行更改为
PdfStamper stamper = PdfStamper.createSignature(reader, os, '[=11=]', true);
(注意末尾的新布尔参数)。此更改导致签名以 附加模式 创建,这使以前的修订保留原始签名,不会使该签名无效。