PDF 签名无效但带有 PDFBox2 的 Verfiy 签名有效 (true)

PDF Signature invalid but Verfiy Signature with PDFBox2 is valid (true)

示例 PDF 下载:https://drive.google.com/file/d/12wv1Pb7gh4vCKOGhX4cZ3aOrLSiOo4If/view?usp=sharing

因此,当在 A.Reader(连续发布)中打开 PDF 时,它说证书无效,因为对该文档进行了更改,导致签名无效。

但我看不到 what/where 已更改。我们自己的应用程序只添加了一个签名(证书),它为数以千计的其他 PDF 添加了正确的签名。没有执行其他更改。 使用我们自己的代码验证哈希或使用带有以下代码的 PDFBox2 表明签名有效(true)。

那么为什么 A.Reader 抱怨?

非常感谢您的帮助,因为我已经用头撞墙好几天了...

public static void main(String [] args) throws IOException, CMSException, OperatorCreationException, CertificateException
{
    System.out.println("\nValidate signature in SignatureVlidationTest.pdf; original code.");
    byte[] pdfByte;
    PDDocument pdfDoc = null;
    SignerInformationVerifier verifier = null;
    try
    {
        pdfByte = FileUtils.readFileToByteArray(new File(FOLDEROUT, "102089-5913E701-5EE6-AC3F-7B03-A8D27A7CD9FA.pdf"));  
        pdfDoc = PDDocument.load(new File(FOLDEROUT, "102089-5913E701-5EE6-AC3F-7B03-A8D27A7CD9FA.pdf"));  
       // pdfDoc = Loader.loadPDF(new ByteArrayInputStream(pdfByte));
        PDSignature signature = pdfDoc.getSignatureDictionaries().get(0);

        byte[] signatureAsBytes = signature.getContents();
        byte[] signedContentAsBytes = signature.getSignedContent(pdfByte);
        CMSSignedData cms = new CMSSignedData(new CMSProcessableByteArray(signedContentAsBytes), signatureAsBytes);
        SignerInformation signerInfo = (SignerInformation) cms.getSignerInfos().getSigners().iterator().next();
        X509CertificateHolder cert = (X509CertificateHolder) cms.getCertificates().getMatches(signerInfo.getSID())
                .iterator().next();
        verifier = new JcaSimpleSignerInfoVerifierBuilder().setProvider(new BouncyCastleProvider()).build(cert);

        // result if false
        boolean verifyRt = signerInfo.verify(verifier);
        System.out.println("Verify result: " + verifyRt);
    }
    finally
    {
        if (pdfDoc != null)
        {
            pdfDoc.close();
        }
    }
}

第一次 PDF 修订中的交叉引用损坏

第一次修订结束时的交叉引用 table 如下所示:

xref
0 19
0000000000 65535 f
0000000018 00000 n
0000000348 00000 n
0000000422 00000 n
0000000481 00000 n
0000000776 00000 n
0000003138 00000 n
0000032630 00000 n
0000033308 00000 n
0000033489 00000 n
0000033723 00000 n
0000033932 00000 n
0000056202 00000 n
0000056645 00000 n
0000056837 00000 n
0000070988 00000 n
0000071312 00000 n
0000071521 00000 n
0000071543 00000 n
20 26
0000071844 00000 n
0000080069 00000 n
0000080373 00000 n
0000080556 00000 n
0000097791 00000 n
0000097813 00000 n
0000097833 00000 n
0000097853 00000 n
0000097876 00000 n
0000097899 00000 n
0000097922 00000 n
0000097945 00000 n
0000097968 00000 n
0000097991 00000 n
0000098014 00000 n
0000098037 00000 n
0000098059 00000 n
0000098083 00000 n
0000104407 00000 n
0000104444 00000 n
0000104483 00000 n
0000104565 00000 n
0000104704 00000 n
0000104728 00000 n
0000111035 00000 n
0000111072 00000 n
48 1
0000111098 00000 n
50 2
0000111296 00000 n
0000113066 00000 n

如您所见,它由多个子部分组成,对象编号为 0..18、20..45、48 和 50..51。特别是对象编号 19、46、47 和 49 没有映射。

这是不允许的,原因有二:

  • 对于从未增量更新的文件, 尤其是每个 PDF 文件的第一次修订,cross-reference节只包含一个小节,其对象编号从0开始。

  • cross-referencetable(包括原始cross-reference部分和所有更新部分)应包含每个对象编号的一个条目来自0 到文件中定义的最大对象编号,即使此范围内的一个或多个对象编号实际上并未出现在文件中。

(ISO 32000-1 第 7.5.4 节“Cross-Reference Table”)

因此,常规 PDF 的第一个交叉引用 table 必须仅包含一个小节。即使这不是必需的,也不允许存在未映射对象编号的间隙。

通常 Adob​​e Reader 会忽略违反这些要求的行为,但在签名验证的情况下会更严格。通常这会出现在对相关 PDF 进行签名然后添加一些任意增量更新的情况下。

例如,我对您的第一个修订版(文件的前 114510 个字节)进行了签名,然后将其扩展为 LTA:

only signed signed and extended

这是关于堆栈溢出的多个问题的主题:

  • After add LTV signature got corrupted for some pdf file

其他问题

不过,您的示例 PDF 中很可能还有其他问题有待发现。如上所述,在您的第一个修订版中的交叉引用通常只会在向已签名的 PDF 添加增量更新后 引起问题。您的示例 PDF 情况并非如此。因此,我希望其中有其他奇怪之处。

备注

一些额外的观察:

  • 从第一次修订开始,文档信息字典中有许多额外的条目:SIG_PAGE, SIG_LLX, SIG_LLY, SIG_URX,以及 SIG_URY。 IMO 这不是合适的地方,虽然符合要求的读者可能会在文档信息字典中存储自定义元数据,但他们可能不会在那里存储私人内容或结构信息。此类信息应存储在文档目录中。(ISO 32000-1 第 14.3.3 节“文档信息字典”)IMO 这些条目看起来像是您的工作流程私有的处理指令,而不是 [=113 的元数据=]兴趣

  • 您的签名字典包含一个 R 值。由于 PDF 1.5 不应使用此条目,信息应存储在 Prop_Build 字典中。 (ISO 32000-1 table 252 "条目在 a签名词典")