如何为时间戳签名启用 LTV?

How to enable LTV for a timestamp signature?

我正在使用 iText 5.5.3 签署 PDF 文档。我需要为这些文档加上时间戳并启用 LTV。我按照说明使用了 addLtv 方法(Lowagie 白皮书中的代码示例 5.9,第 137 页)。我得到一个带有2个签名的PDF,这很正常:第一个是我自己的签名,第二个是文档级时间戳。

但是,Acrobat 告诉我我的签名启用了 LTV,但时间戳签名没有:

Image from Acrobat Pro XI http://img15.hostingpics.net/pics/727285so2.jpg

这是因为时间戳证书的吊销信息没有嵌入文档中:

Missing revocation info 1 http://img15.hostingpics.net/pics/491507so2a.jpg

Missing revocation info 2 http://img15.hostingpics.net/pics/312720so2b.jpg

据我了解,addLtv 方法应该 获取所需的所有撤销信息并将其嵌入到文档中。这是正确的,还是我必须 "manually" 获取并嵌入这些信息?

这是这个问题的示例代码:

public void addLtv(String src, String dest, OcspClient ocsp, CrlClient crl, TSAClient tsa) throws IOException, DocumentException, GeneralSecurityException
{
    PdfReader r = new PdfReader(src);
    FileOutputStream fos = new FileOutputStream(dest);
    PdfStamper stp = PdfStamper.createSignature(r, fos, '[=10=]', null, true);
    LtvVerification v = stp.getLtvVerification();
    AcroFields fields = stp.getAcroFields();
    List<String> names = fields.getSignatureNames();
    String sigName = names.get(names.size() - 1);
    PdfPKCS7 pkcs7 = fields.verifySignature(sigName);
    if (pkcs7.isTsp())
    {
        v.addVerification(sigName, ocsp, crl,
            LtvVerification.CertificateOption.SIGNING_CERTIFICATE,
            LtvVerification.Level.OCSP_CRL,
            LtvVerification.CertificateInclusion.NO);
    }
    else
    {
        for (String name : names)
        {
            v.addVerification(name, ocsp, crl,
                LtvVerification.CertificateOption.WHOLE_CHAIN,
                LtvVerification.Level.OCSP_CRL,
                LtvVerification.CertificateInclusion.NO);
        }
    }
    PdfSignatureAppearance sap = stp.getSignatureAppearance();
    LtvTimestamp.timestamp(sap, tsa, null);
}

此代码识别 PDF 最近填写的签名字段,并检查它是文档时间戳还是普通签名。

如果是文档时间戳,代码只为这个文档时间戳添加验证信息。否则,代码会为 all 签名添加验证信息。

(这背后假设的工作流程是先对文件进行多次签名(用于认证 and/or 批准),然后文件进入 LTV 周期,添加验证信息和文件时间戳,但没有不再使用通常的签名。您的工作流程可能会有所不同,因此您的程序逻辑也会有所不同。)

只有在完成所有这些之后,才会添加新的文档时间戳。

对于这个最终添加的时间戳,没有向 PDF 明确添加任何验证信息(如果来自同一 TSA 的文档时间戳已在短时间内连续应用,则包含在先前时间戳中的验证信息可能适用)。这就是为什么 Adob​​e Reader/Acrobat 通常不考虑启用此文档时间戳 LTV。

如果您也需要此最终文档时间戳的验证信息,只需将此方法(与上述方法相同,只是不添加文档时间戳)应用于带有文档时间戳的文件:

public void addLtvNoTS(String src, String dest, OcspClient ocsp, CrlClient crl) throws IOException, DocumentException, GeneralSecurityException
{
    PdfReader r = new PdfReader(src);
    FileOutputStream fos = new FileOutputStream(dest);
    PdfStamper stp = new PdfStamper(r, fos, '[=11=]', true);
    LtvVerification v = stp.getLtvVerification();
    AcroFields fields = stp.getAcroFields();
    List<String> names = fields.getSignatureNames();
    String sigName = names.get(names.size() - 1);
    PdfPKCS7 pkcs7 = fields.verifySignature(sigName);
    if (pkcs7.isTsp())
    {
        v.addVerification(sigName, ocsp, crl,
            LtvVerification.CertificateOption.SIGNING_CERTIFICATE,
            LtvVerification.Level.OCSP_CRL,
            LtvVerification.CertificateInclusion.NO);
    }
    else
    {
        for (String name : names)
        {
            v.addVerification(name, ocsp, crl,
                LtvVerification.CertificateOption.WHOLE_CHAIN,
                LtvVerification.Level.OCSP_CRL,
                LtvVerification.CertificateInclusion.NO);
        }
    }
    stp.close();
}

背景

iText addLtv 示例不(必然)创建 LTV-enabled PDF 的原因是它更接近 ETSI 在 PAdES 规范中提出的 LTV 最佳实践,而不是 Adob​​e 的LTV 最佳实践。

根据 ETSI TS 102 778-4 V1.1.2 (2009-12),应用 LTV 的 PDF 文档的结构如图 2 所示。

保护的 life-time 可以进一步扩展到 life-of 最后一个文档 Time-stamp 应用通过添加更多 DSS 信息来验证之前的最后一个文档 Time-stamp以及一个新文档 Time-stamp。如图 3 所示。

另一方面,根据 Adob​​e (as written by their PDF evangelist Leonard Rosenthol on the iText mailing list in January 2013),

LTV enabled means that all information necessary to validate the file (minus root certs) is contained within. So this statement of yours would be true.

the PDF is signed correctly and contains all necessary certificates, a valid CRL or OSCP response for every certificate

但是因为要使该陈述为真,唯一的方法就是存在 的 DSS,您必须有 DSS 才能显示 LTV-enabled。 无时间戳 (常规或文档级别)是必需的。

由于这种差异,根据 ETSI,带有 LTV 的 PDF 文档通常由 Adob​​e 软件呈现,没有 LTV-enabled 文档时间戳。

另见

  • enable LTV in iText
  • LTV enabled signature in PDF
  • Digital signature with timestamp in Java

我所做的是在通过请求两个时间戳(使用第一个提取 LTV 数据并更新 DSS,第二个实际为文档添加时间戳)为文档添加时间戳之前嵌入时间戳的 LTV 数据:

  1. 从 TSA 请求虚拟时间戳令牌
  2. 提取并验证此令牌的信任链
  3. 将链中证书的 OSCP 回复和 CRL 添加到文档 DSS
  4. 现在请求文档的第二个时间戳(包括更新的 DSS)并用它来为 PDF 添加时间戳
  5. 验证两个时间戳是否由同一个证书签名(对于 TSA 使用不同证书的不太可能的情况)

正在从 tsa 令牌中提取签名证书:

        IDigest messageDigest = tsaClient.GetMessageDigest();
        byte[] tsImprint = new byte[messageDigest.GetDigestSize()];
        messageDigest.DoFinal(tsImprint, 0);
        byte[] tsToken;
        try {
            tsToken = tsaClient.GetTimeStampToken(tsImprint);
        } catch(Exception e) {
            throw new GeneralSecurityException(e.Message);
        }
        Asn1Sequence asn1Seq = Asn1Sequence.GetInstance(tsToken);
        ContentInfo sigData = ContentInfo.GetInstance(asn1Seq);
        TimeStampToken token = new TimeStampToken(sigData);
        IX509Store tokenCerts = token.GetCertificates("COLLECTION");
        List<X509Certificate> signingCerts = new List<X509Certificate>();
        foreach(X509Certificate cert in tokenCerts.GetMatches(token.SignerID)) {
            signingCerts.Add(cert);
        }
        // now perform LTV steps for signingCerts[0] ...