从pdf和共同签名中检索pkcs7文件

时间:2018-06-11 17:26:03

标签: pdf itext digital-signature

我有一个PDF文件签名和.p7s文件。我需要从PDF中检索.p7s并共同签署PDF(生成其他.p7s)。 之后我需要再将p7s放入PDF文件中。 当我尝试从PDF获取p7时,我收到此错误: 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!
}

1 个答案:

答案 0 :(得分:0)

理论

您希望通过从PDF中提取嵌入式CMS签名容器,为其添加签名并重新嵌入,来共同签署PDF (反号?并行签名?)扩展容器。

这是错误的方法,PDF签名只针对每个PDF签名字段包含一个签名,而我们所讨论的CMS签名容器本质上就是这样一个字段的值,因此每个嵌入式签名容器应只包含一个签名

严格来说,PDF规范允许您使用任意自定义签名方案,只允许使用#34;可互操作的签名&#34;是有限的。因此,具有多个签名的签名容器可以被视为有效的PDF,而不是#34;互操作签名&#34;,即您不应该期望任何其他软件像您一样解释签名。特别是Adobe Acrobat Reader将只识别和显示其中一个签名。

(事实上,一些大型签名解决方案提供商已经在PDF中嵌入了多签名CMS容器。例如,目前我必须处理由嵌入任意CAdES-A签名容器的某个此类提供程序生成的签名(特别是一些有多个签名者)并将这种签名格式称为PDF / CAdES-A,现在我必须向他们的客户解释他们的签名是PDF签名,但不能互操作,即使这个名称PDF / CAdES-A听起来像一些很棒的标准......)

PDF中用于互操作性的多个签名必须按照此草图中可视化的顺序应用:

对于某些背景和更多信息的链接,请参阅this answer

在实践中

您的代码似乎是iText 5.5.x代码,特别是还没有iText 7.x代码。在这种情况下,您可以按原样使用Digital Signatures for PDF Documents白皮书中的代码{/ 3}}。

一个非常简单的例子:

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, '\0');
    // 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, '\0', true);

(注意最后的新布尔参数)。此更改导致在追加模式中创建签名,这使得前一版本具有原始签名,而不会使该签名无效。