【问题标题】:How to get signature Value from signed PDF in C#?如何在 C# 中从签名的 PDF 中获取签名值?
【发布时间】:2015-07-17 16:51:11
【问题描述】:

如何从签名的 PDF 文件中获取签名值?我可以从签名中获取除其值之外的所有其他数据。有没有办法在 C# 中获取它?

PdfPKCS7 pk;
PdfReader reader = new PdfReader(PdfFilename);
AcroFields af = reader.AcroFields;

var names = af.GetSignatureNames();
foreach (string name in names)
{
    pk = af.VerifySignature(name);

    var CN_signer = iTextSharp.text.pdf.security.CertificateInfo.GetSubjectFields(pk.SigningCertificate).GetField("CN");
    var C_signer = iTextSharp.text.pdf.security.CertificateInfo.GetSubjectFields(pk.SigningCertificate).GetField("C");
    var CN_issuer = iTextSharp.text.pdf.security.CertificateInfo.GetIssuerFields(pk.SigningCertificate).GetField("CN");
    var OU_issuer = iTextSharp.text.pdf.security.CertificateInfo.GetIssuerFields(pk.SigningCertificate).GetField("OU");
    var O_issuer= iTextSharp.text.pdf.security.CertificateInfo.GetIssuerFields(pk.SigningCertificate).GetField("O");
    var C_issuer = iTextSharp.text.pdf.security.CertificateInfo.GetIssuerFields(pk.SigningCertificate).GetField("C");
    var nr_serial = pk.SigningCertificate.SerialNumber;
    var date = pk.SignDate.ToString();

【问题讨论】:

  • 签名值是指PKCS#7/CMS签名容器?
  • 是的,我的意思是从签名的 pdf 文件中读取 base64 中的签名
  • @Sara 你的评论不清楚。签名不以 base64 格式存储。当您说“签名值”时,请用您自己的话解释您的意思。在 ISO-32000 的上下文中,签名值是签名字段中 /V 条目的值。该值是 PDF 字典。很容易得到那本词典。如果您确认您对“签名值”的解释与 ISO-32000 中描述的签名值相同,则可以提供一个示例。
  • 我不太清楚签名是如何保存在 pdf 中的,或者它在 pdf 结构中有何变化,但对于签名值,我的意思是存储在 PDF 的 /Contents 条目中的字节。也许它就像一个十六进制的值
  • @Bruno 你能帮我获取 PDF 字典吗,因为现在我阅读了 ISO-32000 文件,我认为 /v 条目的值是我正在寻找的。​​span>

标签: c# pdf itextsharp digital-signature


【解决方案1】:

OP 澄清 签名值 是指 PKCS#7/CMS 签名容器。以下示例方法可以做到这一点:

public void showSignatureValues(PdfReader reader)
{
    AcroFields fields = reader.AcroFields;
    foreach (String name in fields.GetSignatureNames())
    {
        Console.Write(" Signature {0}\n", name);

        PdfDictionary sigDict = fields.GetSignatureDictionary(name);
        PdfName subFilter = sigDict.GetAsName(PdfName.SUBFILTER);
        Console.Write("  SubFilter {0}\n", subFilter);

        PdfString contents = sigDict.GetAsString(PdfName.CONTENTS);
        if (contents != null)
        {
            byte[] contentBytes = contents.GetOriginalBytes();
            string contentBas64 = Convert.ToBase64String(contentBytes);
            // contentBytes contains the actual signature container as is,
            // contentBas64 contains it encoded using Base64 for better printability
            Console.Write("  Content {0}\n", contentBas64);
        }
    }
}

不过,请注意:您会发现 contentBytes 通常在签名容器字节之后包含许多 00 字节(在 Base64 表示中,它们显示为一长串字母 A)。这是因为在准备用于签名的 PDF 时,通常会对签名容器的大小进行大量估计,并且为注入它保留了足够多的空间。

根据规范,由于 PKCS#7 对象的长度不能完全预测,因此 Contents 的值应在末尾补零

使用 ASN.1 解析器,您可以确定实际签名容器字节序列的长度以及填充的开始位置。

理论上Contents的值应该是DER编码的PKCS#7二进制数据 对象;由于 DER 编码规则不允许使用不定长方法,因此签名容器的大小应根据前导的前几个字节确定。不幸的是,在野外有许多 PDF,其中包含签名容器的外层,仅 BER 编码,只有某些内部对象 DER 编码。因此,可能需要完整的解析。


事后思考

在上面的答案中,我直截了当地声称示例代码返回一个 PKCS#7/CMS 签名容器。实际上只是在大多数情况下是这样一个签名容器,它取决于签名字段值的SubFilter

让我们看看 ISO 32000-1(PDF 规范)和 ETSI 技术规范 102778 部分 (PAdES) 中定义的 SubFilter 值:

  • adbe.x509.rsa_sha1 ISO 32000-1 - 在这种情况下,内容实际上是 DER 编码的 PKCS#1 二进制数据对象。这是 OP 的图形中描述的情况

    这里的 OP 将内容称为加密摘要,这只是事实的一部分,因为

    1. PKCS#1 数据对象不是从裸摘要构造的,而是从包含该摘要和摘要算法的 OID 的结构构造的,并且

    2. 1234563针对所谓的文档摘要结构进行了测试。
  • 这种格式现在几乎不再使用了。

  • adbe.pkcs7.detached ISO 32000-1, ETSI TS 102778-2 - 内容是 DER 编码的 PKCS#7 二进制文件数据对象直接对字节范围进行签名,即通常字节范围摘要在签名属性MessageDigest中。

  • adbe.pkcs7.sha1 ISO 32000-1,ETSI TS 102778-2 - 内容是 DER 编码的 PKCS#7 二进制文件数据对象间接对字节范围进行签名,即字节范围SHA1摘要作为数据放入容器中,然后正常签名。

  • ETSI.CAdES.detached ETSI TS 102778-3 - 内容是 CMS 中指定的 DER 编码的 SignedData 对象 直接对字节范围进行签名,本质上这是 adbe.pkcs7.detached 的特殊配置变体。

  • ETSI.RFC3161 ETSI TS 102778-4 - 内容是 RFC 3161 中指定的 TimeStampToken 标记字节范围直接地;这是一种与 PKCS#7 密切相关的时间戳格式。 (这是一种特殊情况,因为表单字段类型不是 Sig 而是 DocTimeStamp。)

仅在 adbe.x509.rsa_sha1 的情况下,所涉及的证书才包含在单独的签名字典条目中。在所有其他情况下,证书(和其他与安全相关的材料)都包含在 ContentsSignedData 结构中。

【讨论】:

  • 谢谢@mkl 我正在努力发布 iText 5.5.6,但我没有时间回答这个问题。你的答案比我的更完整:D
  • 谢谢@mkl 的解释,我还有一个问题!您编写的这段代码是应该只显示签名字典的这一部分(上图中用红色签名的部分)还是显示更多,因为当我在我的代码中尝试时可以看到它包括证书和其他一些数据也是
  • 您的图像使用签名类型(子过滤器 adbe.x509.rsa_sha1),其中内容仅包含裸 pkcs#1 签名,其他数据在其他字段中表示。然而,现在主要使用并被认为是可互操作的,只有其他类型的内容包含成熟的 pkcs#7/CMS 签名容器,其中还嵌入了证书和许多其他数据。帮自己一个忙,不要花太多时间在像你图片中那样的异国情调的特殊情况上。
  • 那是不是意味着不能从没有证书和时间戳数据的PDF内容中只获取加密的摘要?
  • 是否意味着无法从没有证书和时间戳数据的 PDF 内容中仅获取加密摘要 - 首先,当我询问是否通过签名值你的意思是 PKCS#7/CMS 签名容器,你说 Yes。因此,答案集中在检索签名容器上,而不是一些裸露的加密摘要。话虽如此,您当然可以从签名容器内部访问一些加密的摘要值。您只需使用一些 PKCS#7/CMS 解析器类,例如由充气城堡提供。但请注意,...
猜你喜欢
  • 2017-10-09
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-02
  • 2011-07-31
相关资源
最近更新 更多