从 TimeStampTokenInfo 读取 iText 8 中的 TimeStampToken

问题描述 投票:0回答:1

我正在尝试读取 iText 8 (C#) 中的 TimeStampToken,但我在 ASN1 结构转换中迷失了方向。

我试图实现以下代码:

byte[] timestampTokenInfoBytes = pkcs7.GetTimeStampTokenInfo().ToASN1Primitive().GetEncoded();

var content = Asn1Object.FromByteArray(pkcs7.GetTimeStampTokenInfo().ToASN1Primitive().GetEncoded());
// >>>>>>>>  How to create Content Info from Asn1object? <<<<<<<<<<< 
// The following line raises a cast exception...

ContentInfo contentInfo = new ContentInfo(new DerObjectIdentifier(PkcsObjectIdentifiers.IdAAEtsContentTimestamp.Id), content);
c# itext itext7
1个回答
0
投票

确实,似乎没有明确的方法来提取完整的时间戳令牌。因此,必须自己提取并分析签名容器。

对此有两个明显的选择,即使用 iText 的 BouncyCastle 抽象或直接使用特定的 BouncyCastle 变体。

使用前者的优点是代码可以与 BouncyCastle 和 BouncyCastle-FIPS 一起使用。但它有一个缺点,即抽象仅包含 iText 中使用的 BouncyCastle 功能。

PDF 中还有两种时间戳,文档时间戳(独立时间戳)和签名时间戳(嵌入 CMS 签名容器中的时间戳)。

在以下示例代码中,使用 BouncyCastle 抽象提取文档时间戳,并直接使用 BouncyCastle 提取签名时间戳。

文档时间戳

给定 PDF 的

SignatureUtil signatureUtil
和包含文档时间戳的签名字段
string name
,可以使用 iText 的 BouncyCastle 抽象提取时间戳标记,如下所示:

PdfSignature pdfSignature = signatureUtil.GetSignature(name);
PdfString contents = pdfSignature.GetContents();
byte[] bytes = PdfEncodings.ConvertToBytes(contents.GetValue(), null);

IBouncyCastleFactory BOUNCY_CASTLE_FACTORY = BouncyCastleFactoryCreator.GetFactory();
IAsn1Object asn1Object = BOUNCY_CASTLE_FACTORY.CreateASN1InputStream(bytes).ReadObject();
IAsn1Sequence tokenSequence = BOUNCY_CASTLE_FACTORY.CreateASN1Sequence(asn1Object);
IContentInfo contentInfo = BOUNCY_CASTLE_FACTORY.CreateContentInfo(tokenSequence);
ITimeStampToken timeStampToken = BOUNCY_CASTLE_FACTORY.CreateTimeStampToken(contentInfo);
byte[] tstBytes = timeStampToken.GetEncoded();

签名时间戳

再次给定 PDF 的

SignatureUtil signatureUtil
和包含签名时间戳的签名字段
string name
,可以使用 BouncyCastle 提取时间戳令牌,如下所示:

PdfSignature pdfSignature = signatureUtil.GetSignature(name);
PdfString contents = pdfSignature.GetContents();
byte[] bytes = PdfEncodings.ConvertToBytes(contents.GetValue(), null);

CmsSignedData cmsSignedData = new CmsSignedData(bytes);
ICollection signerInfos = cmsSignedData.GetSignerInfos().GetSigners();
foreach (SignerInformation signer in signerInfos.Cast<SignerInformation>())
{
    Org.BouncyCastle.Asn1.Cms.Attribute attribute = signer.UnsignedAttributes[PkcsObjectIdentifiers.IdAASignatureTimeStampToken];
    if (attribute != null)
    {
        foreach (Asn1Encodable asn1Encodable in attribute.AttrValues)
        {
            CmsSignedData tstSignedData = new CmsSignedData(asn1Encodable.GetEncoded());
            TimeStampToken timeStampToken = new TimeStampToken(tstSignedData);
            byte[] tstBytes = timeStampToken.GetEncoded();
        }
    }
}

放在一起

问题是如何判断一个文档是否有时间戳,或者一个可能有签名时间戳的签名。显而易见的方法是检查签名字典的子过滤器,文档时间戳具有子过滤器

ETSI.RFC3161
。由于 iText 也执行该测试,因此我将比较留给 iText:

using (PdfReader pdfReader = new PdfReader(...))
using (PdfDocument pdfDocument = new PdfDocument(pdfReader))
{
    SignatureUtil signatureUtil = new SignatureUtil(pdfDocument);
    foreach (string name in signatureUtil.GetSignatureNames())
    {
        var pdfPkcs7 = signatureUtil.ReadSignatureData(name);
        var tstInfo = pdfPkcs7.GetTimeStampTokenInfo();
        Console.WriteLine(name + ": " + tstInfo.GetGenTime());

        PdfSignature pdfSignature = signatureUtil.GetSignature(name);
        PdfString contents = pdfSignature.GetContents();
        byte[] bytes = PdfEncodings.ConvertToBytes(contents.GetValue(), null);
        if (pdfPkcs7.IsTsp())
        {
            IBouncyCastleFactory BOUNCY_CASTLE_FACTORY = BouncyCastleFactoryCreator.GetFactory();
            IAsn1Object asn1Object = BOUNCY_CASTLE_FACTORY.CreateASN1InputStream(bytes).ReadObject();
            IAsn1Sequence tokenSequence = BOUNCY_CASTLE_FACTORY.CreateASN1Sequence(asn1Object);
            IContentInfo contentInfo = BOUNCY_CASTLE_FACTORY.CreateContentInfo(tokenSequence);
            ITimeStampToken timeStampToken = BOUNCY_CASTLE_FACTORY.CreateTimeStampToken(contentInfo);
            byte[] tstBytes = timeStampToken.GetEncoded();
            File.WriteAllBytes(name + "-doc.tst", tstBytes);
        }
        else
        {
            CmsSignedData cmsSignedData = new CmsSignedData(bytes);
            ICollection signerInfos = cmsSignedData.GetSignerInfos().GetSigners();
            foreach (SignerInformation signer in signerInfos.Cast<SignerInformation>())
            {
                Org.BouncyCastle.Asn1.Cms.Attribute attribute = signer.UnsignedAttributes[PkcsObjectIdentifiers.IdAASignatureTimeStampToken];
                if (attribute != null)
                {
                    foreach (Asn1Encodable asn1Encodable in attribute.AttrValues)
                    {
                        CmsSignedData tstSignedData = new CmsSignedData(asn1Encodable.GetEncoded());
                        TimeStampToken timeStampToken = new TimeStampToken(tstSignedData);
                        byte[] tstBytes = timeStampToken.GetEncoded();
                        File.WriteAllBytes(name + "-sig.tst", tstBytes);
                    }
                }
            }
        }
    }
}

RetrieveTimeStampToken测试

retrieveFromLoremIpsumLta

当然,该代码缺少一些用于生产用途的健全性检查......

© www.soinside.com 2019 - 2024. All rights reserved.