iText 7 将 ltv 添加到现有签名

iText 7 adding ltv to existing signature

我是 iText 7 的新手, 我已经尝试使用 addLtv() 方法(下面提供的代码)将 ltv 信息添加到现有签名...如果我理解正确,此方法将 crl 或 ocsp 参数添加到现有签名或时间戳,然后为文档添加时间戳,但 pdf 文档生成的未启用 ltv。但是,如果我首先使用 ocsp 或 crl 列表签署文档,我能够生成启用 ltv 的签名,这使我相信此问题与某些证书丢失或未正确添加无关。所以 addLtv() 方法,出于某种原因对我不起作用。我希望我说得有道理:D 非常感谢任何帮助或建议:)

    private void addLtv(String src, String dest, IOcspClient ocsp, ICrlClient crl, ITSAClient tsa) throws Exception {
    PdfReader r = new PdfReader(src);
    FileOutputStream fos = new FileOutputStream(dest);
    PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
    PdfSigner ps= new PdfSigner(r, fos, true);

    LtvVerification v = new LtvVerification(pdfDoc);
    SignatureUtil signatureUtil = new SignatureUtil(pdfDoc);

    List<String> names =   signatureUtil.getSignatureNames();
    String sigName = names.get(names.size() - 1);

    PdfPKCS7 pkcs7 = signatureUtil.verifySignature(sigName);

    if (pkcs7.isTsp()) {
        v.addVerification(sigName, ocsp, crl,
                LtvVerification.CertificateOption.WHOLE_CHAIN,
                LtvVerification.Level.CRL,
                LtvVerification.CertificateInclusion.YES);
    }
    else {
        for (String name : names) {
            v.addVerification(name, ocsp, crl,
                    LtvVerification.CertificateOption.WHOLE_CHAIN,
                    LtvVerification.Level.OCSP,
                    LtvVerification.CertificateInclusion.YES);
            v.merge();
        }
    }
    ps.timestamp(tsa, null);
}

您代码中的概念性问题是,在添加 LTV 信息后,您希望通过时间戳来完成流程。虽然这是您想要对已经在 LTV 工作流程中的 PDF 执行的操作,但这不是您想要对 PDF 执行的操作,您希望 Adob​​e Reader 将其所有签名声明为 "LTV-enabled".

(可以将 Adob​​e 的术语 "LTV-enabled" 理解为 "ready to enter a LTV workflow," 即尚未真正进入 LTV 工作流程,但包含输入它所需的所有验证信息,无需任何进一步的麻烦.)

您的方法中还有其他问题,例如您创建了两个单独的对象,它们通过 fos 写入 dest,通过 fos 写入 PdfSigner ps,通过其 PdfWriter 写入 PdfDocument pdfDoc。最终您将在文件中找到这些对象中只有一个的输出,或者两者的混合。

因此,这是我的旧 iText 5 方法 addLtvNoTS(从 )到 iText 7 的工作端口:

void addLtvNoTS(InputStream src, OutputStream dest, IOcspClient ocsp, ICrlClient crl, LtvVerification.Level timestampLevel, LtvVerification.Level signatureLevel) throws IOException, GeneralSecurityException 
{
    PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest), new StampingProperties().useAppendMode());

    LtvVerification v = new LtvVerification(pdfDoc);
    SignatureUtil signatureUtil = new SignatureUtil(pdfDoc);

    List<String> names = signatureUtil.getSignatureNames();
    String sigName = names.get(names.size() - 1);

    PdfPKCS7 pkcs7 = signatureUtil.verifySignature(sigName);

    if (pkcs7.isTsp())
    {
        v.addVerification(sigName, ocsp, crl, LtvVerification.CertificateOption.WHOLE_CHAIN,
                timestampLevel, LtvVerification.CertificateInclusion.YES);
    }
    else
    {
        for (String name : names)
        {
            v.addVerification(name, ocsp, crl, LtvVerification.CertificateOption.WHOLE_CHAIN,
                    signatureLevel, LtvVerification.CertificateInclusion.YES);
        }
    }

    v.merge();
    pdfDoc.close();
}

(EnableLtv方法addLtvNoTS)

如您所见,我为时间戳和签名方法参数设置了 LtvVerification.Level 值。

这是因为 iText 的方法 LtvVerification.addVerification 只为即时 PDF 签名和文档时间戳添加 LTV 信息,而不为已经嵌入或现在添加的 OCSP 响应或 CRL 签名添加 LTV 信息。

通常这没有问题,用于签署 OCSP 响应的证书通常以指示不需要撤销检查的方式标记,并且用于签署 CRL 的证书通常是隐式受信任的 CA 证书本身。

但是,对于我的测试签名,OCSP 响应是由需要撤销检查的签名签署的。为了让事情在没有大量额外编码的情况下工作,我使用了 CRL,并为此引入了参数。

实际上,我什至不得不将 CRL URL 显式地提供给 CrlClientOnline,因为默认情况下 iText 仅使用证书中的第一个 CRL 分发点,同时不支持 LDAP URLs.

底线:您可能还必须围绕当前的 iText 限制调整代码,或者成为改进 iText 代码本身的代码,以便在给定任意有效输入的情况下可靠地生成支持 LTV 的 PDF...