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

时间:2015-01-11 22:45:39

标签: pdf itext

我使用iText 5.5.3签署PDF文档。我需要将这些文档加上时间戳并启用LTV。我按照说明使用了addLtv方法(代码示例5.9,Lowagie白皮书中的第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方法应该获取所需的所有吊销信息并将其嵌入到文档中。这是正确的,还是我必须手动"获取并嵌入这些信息?

2 个答案:

答案 0 :(得分:9)

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

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, '\0', 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最近填充的签名字段,并检查它是文档时间戳还是通常的签名。

如果是文档时间戳,则代码仅为此文档时间戳添加验证信息。否则,代码会为所有签名添加验证信息。

(这背后的假设工作流程是文档首先被签署(用于认证和/或批准),然后文档进入LTV循环,添加验证信息和文档时间戳,但不再有通常的签名。您的工作流程可能会有所不同,因此也可能是您的程序逻辑。)

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

对于最终添加的时间戳,没有明确地向PDF添加验证信息(如果来自相同TSA的文档时间戳已经连续应用,则可以应用先前时间戳包括的验证信息)。这就是为什么Adobe 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, '\0', 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的PDF的原因在于它更接近ETSI在PAdES规范中提出的LTV的最佳实践,而不是Adobe的LTV的最佳实践。

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

Figure 2: Illustration of PDF Document with LTV

通过添加更多DSS信息以验证上一个上一个文档的时间戳以及新文档的时间戳,可以进一步延长保护的生命周期。如图3所示。

Figure 3: Illustration of PDF Document with repeated LTV

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

  

启用LTV意味着验证文件所需的所有信息   (减去根证书)包含在。所以这个你的陈述会   是真的。

     
    

PDF已正确签名并包含所有必要的证书,     每个证书的有效CRL或OSCP响应

  
     

但是,因为该陈述的唯一方法是真实存在   对于DSS,您必须具有启用LTV的DSS才能显示。 没有时间戳   (常规或文件级别)是必需的。

由于这种分歧,根据ETSI的LTV PDF文档通常由Adobe软件提供,以便有一个不支持LTV的文档时间戳。

另见

答案 1 :(得分:0)

我所做的是通过请求两个时间戳(使用第一个提取 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] ...

TSA LTV