带有 iText 的 PDF 文件的签名无效

Signature is Invalid for PDF File with iText

我正在使用 swisscom 数字签名服务,我们有一个测试帐户。那么该服务需要 pdf 文件的哈希码。我们用

发送

DIGEST_VALUE=$(openssl dgst -binary -SHA256 $FILE | openssl enc -base64 -A)

我收到 PKCS#7 响应。您可以使用此网站解码我的签名响应 https://certlogik.com/decoder/ 签名内容为http://not_need_anymore

我遇到了和下面一样的问题(因为我们使用相同的代码)

我的回复是用 sha256 加密的。 好吧,我正在使用 iText 和 c# 来签署 pdf 文件。我签名并看到一些详细信息(例如原因、位置等)。

这里是创建带有签名字段的pdf文件的方法

public static string GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName)
{
    if (File.Exists(tempPdf))
        File.Delete(tempPdf);

    using (PdfReader reader = new PdfReader(unsignedPdf))
    {
        using (FileStream os = File.OpenWrite(tempPdf))
        {
            PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '[=10=]');
            PdfSignatureAppearance appearance = stamper.SignatureAppearance;
            appearance.SetVisibleSignature(new Rectangle(36, 748, 250, 400), 1, signatureFieldName);

            //IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
            IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
            PdfSignature external2 = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);//ADBE_PKCS7_SHA1);
//as pdf name I tried also PdfName.ETSI_RFC3161
//(ref => https://github.com/SCS-CBU-CED-IAM/itext-ais/blob/master/src/com/swisscom/ais/itext/PDF.java)

            appearance.Reason = "For archive";
            appearance.Location = "my loc";
            appearance.SignDate = DateTime.Now;
            appearance.Contact = "myemail@domain.ch";
            appearance.CryptoDictionary = external2;

            var level = reader.GetCertificationLevel();
            // check: at most one certification per pdf is allowed
            if (level != PdfSignatureAppearance.NOT_CERTIFIED)
                throw new Exception("Could not apply -certlevel option. At most one certification per pdf is allowed, but source pdf contained already a certification.");
            appearance.CertificationLevel = level;

            MakeSignature.SignExternalContainer(appearance, external,30000);

            byte[] array = SHA256Managed.Create().ComputeHash(appearance.GetRangeStream());

            return Convert.ToBase64String(array);
        }
    }
}

其实我没有用什么这个方法returns。因为它已经创建了一个带有签名字段的临时 pdf 文件。

之后,我给出了这个 pdf 文件的哈希码并得到 PKCS#7 响应。然后使用以下函数,我将签名添加到 pdf(它创建另一个 pdf 文件)。

public static void EmbedSignature(string tempPdf, string signedPdf,
                                  string signatureFieldName, string signature)
{
    byte[] signedBytes = Convert.FromBase64String(signature);

    using (PdfReader reader = new PdfReader(tempPdf))
    {
        using (FileStream os = File.OpenWrite(signedPdf))
        {
            IExternalSignatureContainer external = 
                                            new MyExternalSignatureContainer(signedBytes);

            MakeSignature.SignDeferred(reader, signatureFieldName, os, external);
        }
    }
}

方法中的signature参数,我给p7s文件内容如下

string signatureContent = File.ReadAllText(@"mypath\signed_cert.p7s");

signatureContent = signatureContent
                                   .Replace("-----BEGIN PKCS7-----\n", "")
                                   .Replace("-----END PKCS7-----\n","").Trim();

我错过了什么或做错了什么?

与签署整个签名文件的常规分离签名相比,PDF 中的集成签名签署(并且只能签署)除了为签名本身预留的 space 之外的所有内容。

(更多背景阅读this answer

因此,当您准备好带有占位符的 PDF 以嵌入签名时

give the hash code of this pdf file and get PKCS#7 responde

你的散列太多了,因为你的散列包括实际签名的(然后是空的,即填充'0'字符)占位符。该方法 GetBytesToSign 而不是仅 returns 有符号字节范围的散列,即除了占位符之外的所有内容:

byte[] array = SHA256Managed.Create().ComputeHash(appearance.GetRangeStream());

您必须采用此值或类似地仅对签名占位符以外的所有内容进行哈希处理。