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

Pdf 如何为时间戳签名启用LTV?,pdf,itext,Pdf,Itext,我正在使用iText 5.5.3来签署PDF文档。我需要这些文件是时间戳和LTV启用。我按照说明使用addLtv方法(代码示例5.9,Lowagie白皮书第137页)。我得到一个带有2个签名的PDF,这是正常的:第一个是我自己的签名,第二个是文档级时间戳 但是,Acrobat告诉我我的签名已启用LTV,但时间戳签名未启用: 这是因为时间戳证书的吊销信息未嵌入文档中: 根据我的理解,addLtv方法应该获取所需的所有撤销信息并将其嵌入文档中。这是正确的,还是我必须“手动”获取并嵌入这些信息?

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

但是,Acrobat告诉我我的签名已启用LTV,但时间戳签名未启用:

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


根据我的理解,addLtv方法应该获取所需的所有撤销信息并将其嵌入文档中。这是正确的,还是我必须“手动”获取并嵌入这些信息?

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

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);
}
public void addLtv(String src、String dest、OcspClient ocsp、CrlClient crl、tsa client tsa)抛出IOException、DocumentException、GeneralSecurityException
{
PdfReader r=新PdfReader(src);
FileOutputStream fos=新的FileOutputStream(dest);
PdfStamper stp=PdfStamper.createSignature(r,fos,'\0',null,true);
LTV验证v=stp.getLTV验证();
AcroFields=stp.getAcroFields();
列表名称=字段。getSignatureNames();
String sigName=names.get(names.size()-1);
PdfPKCS7 pkcs7=字段。验证签名(sigName);
if(pkcs7.isTsp())
{
v、 添加验证(sigName、ocsp、crl、,
LTV验证.CertificateOption.SIGNING\u证书,
LTV验证.Level.OCSP_CRL,
LTV验证。证书(包括编号);
}
其他的
{
for(字符串名称:名称)
{
v、 添加验证(名称、ocsp、crl、,
LTV验证。认证操作。整个链,
LTV验证.Level.OCSP_CRL,
LTV验证。证书(包括编号);
}
}
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();
}
public void addLtvNoTS(String src、String dest、OcspClient ocsp、CrlClient crl)抛出IOException、DocumentException、GeneralSecurityException
{
PdfReader r=新PdfReader(src);
FileOutputStream fos=新的FileOutputStream(dest);
PdfStamper stp=新的PdfStamper(r,fos,'\0',真);
LTV验证v=stp.getLTV验证();
AcroFields=stp.getAcroFields();
列表名称=字段。getSignatureNames();
String sigName=names.get(names.size()-1);
PdfPKCS7 pkcs7=字段。验证签名(sigName);
if(pkcs7.isTsp())
{
v、 添加验证(sigName、ocsp、crl、,
LTV验证.CertificateOption.SIGNING\u证书,
LTV验证.Level.OCSP_CRL,
LTV验证。证书(包括编号);
}
其他的
{
for(字符串名称:名称)
{
v、 添加验证(名称、ocsp、crl、,
LTV验证。认证操作。整个链,
LTV验证.Level.OCSP_CRL,
LTV验证。证书(包括编号);
}
}
stp.close();
}
背景 iText
addLtv
示例之所以(不一定)创建支持LTV的PDF,是因为它更接近ETSI在PAdES规范中提出的LTV最佳实践,而不是Adobe的LTV最佳实践

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

通过添加进一步的DSS信息以验证先前的最后一个文档时间戳以及新的文档时间戳,保护的寿命可以进一步延长到应用的最后一个文档时间戳的寿命之外。这如图3所示

另一方面,根据Adobe()

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

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

但既然这句话是真的,唯一的办法就是在场 对于DSS,必须启用LTV的DSS才能显示无时间戳 (常规或文档级别)是必需的。

由于这种差异,根据ETSI,具有LTV的PDF文档通常由Adobe软件提供,以具有一个未启用LTV的文档时间戳

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] ...