当前位置: 首页 > 知识库问答 >
问题:

C#Itext7签名的pdf签名在Foxit pdf Reqader中无效,但在Acrobat reader中有效

凌炜
2023-03-14

我找不到为什么Foxit PDF阅读器显示我的签名文件无效。首先,我将空白签名容器插入pdf

public class BlankSignatureContainer2: IExternalSignatureContainer
{
    private readonly PdfName filter;
    private readonly PdfName subFilter;
    private byte[] docBytesHash;
    private byte[] docDigest;
    private const String HASH_ALGORITHM = DigestAlgorithms.SHA256;
    private X509Certificate[] chain;

    public BlankSignatureContainer2(PdfName filter, PdfName subFilter, X509Certificate[] chain)
    {
        this.filter = filter;
        this.subFilter = subFilter;
        this.chain = chain;
    }

    public virtual byte[] GetDocBytesHash()
    {
        return docBytesHash;
    }

    public virtual byte[] GetDocBytesDigest()
    {
        return docDigest;
    }

    public virtual byte[] Sign(Stream docBytes)
    {
        PdfPKCS7 sgn = new PdfPKCS7(null, chain, HASH_ALGORITHM, false);
        docDigest = DigestAlgorithms.Digest(docBytes, DigestAlgorithms.GetMessageDigest(HASH_ALGORITHM));
        docBytesHash = sgn.GetAuthenticatedAttributeBytes(docDigest, PdfSigner.CryptoStandard.CADES, null, null);
        using (SHA256 sha256 = SHA256.Create())
        {
            docBytesHash = sha256.ComputeHash(docBytesHash);
        }

        return new byte[0];
    }

    public virtual void ModifySigningDictionary(PdfDictionary signDic)
    {
        signDic.Put(PdfName.Filter, filter);
        signDic.Put(PdfName.SubFilter, subFilter);
    }
}

docbytesshash我发送到外部Web服务以使用合格的签名进行签名。

using (MemoryStream stream = new MemoryStream())
using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(value.pdfFile))) //pdf file to sign
using (PdfReader pdfReader = new PdfReader(ms))
{
    //Get signers and CA certificates
    X509Certificate[] chain = await _signPdf.GetMidChain(certificate.Cert);

    // creating empty signature container, getting file digest and hash
    var blankSignature = new BlankSignatureContainer2(PdfName.Adobe_PPKLite, PdfName.ETSI_CAdES_DETACHED, chain);
    var stamper = new PdfSigner(pdfReader, stream, new StampingProperties().UseAppendMode());
    var appearance = stamper.GetSignatureAppearance();

    //Method to add signature appearance    
    var sigAppearance = new SigAppearance("stamp1.svg", chain[0].SubjectDN.GetValueList(X509Name.CN).Cast<string>().FirstOrDefault() ?? "", DateTime.Now, "Sign", stamper.GetDocument());

    appearance.SetPageRect(new iText.Kernel.Geom.Rectangle(sigAppearance.GetPosition()));
    stamper.SetFieldName(new GetSignatureToSign(stamper.GetDocument()).GetSignatureName());
    new PdfCanvas(appearance.GetLayer2(), stamper.GetDocument()).AddXObjectFittedIntoRectangle(sigAppearance.GetXObject(), sigAppearance.GetRectangle());
    stamper.SignExternalContainer(blankSignature, 8192*2+2);

    //Call external webservice to sign blankSignature.GetDocBytesHash()
    var msrp = await _clientMID.SignAsync(new MidSignReqModel() {
        NationalIdentityNumber = value.personalCode,
        PhoneNumber = value.phone,
        Language = value.language,
        DisplayText = value.ShortMessage(),
        DisplayTextFormat = "UCS-2",
        Hash = Convert.ToBase64String(blankSignature.GetDocBytesHash()),
        HashType = "SHA256"
    });

接下来,我使用webservice的结果对pdf进行了签名。这是外部签名容器

public class ExternalSignatureContainer2: IExternalSignatureContainer
{
    private X509Certificate[] chain;
    private byte[] signature;
    private string hashAlgorithm;

    public ExternalSignatureContainer2(X509Certificate[] chain, byte[] signature, string hashAlgorithm)
    {
        this.chain = chain;
        this.signature = signature;
        this.hashAlgorithm = hashAlgorithm;
    }

    public void ModifySigningDictionary(PdfDictionary signDic)
    {
        //throw new NotImplementedException();
    }

    public byte[] Sign(Stream data)
    {
        //create TimeStamp Client
        ITSAClient tsa = new TSAClientBouncyCastle(@"http://demo.sk.ee/tsa/");

        string hashAlgorithm = "SHA256";
        PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, false);
        byte[] digest = DigestAlgorithms.Digest(data, DigestAlgorithms.GetMessageDigest(hashAlgorithm));
        sgn.SetExternalDigest(signature, null, "ECDSA");
        return sgn.GetEncodedPKCS7(digest, PdfSigner.CryptoStandard.CADES, tsa, null, null);
    }
}

这是签名代码:

public async Task<byte[]> Sign2(string file, byte[] signature, X509Certificate[] chain, string hashAlgorithm)
{
    using (var tempStream = new MemoryStream(File.ReadAllBytes(Path.Combine(Directory.GetCurrentDirectory(), @"drafts", file))))
    using (var destination = new MemoryStream())
    {
        var tempReader = new PdfReader(tempStream);
        var gsContainer = new ExternalSignatureContainer2(chain, signature, hashAlgorithm);
        var signer = new PdfSigner(tempReader, destination, new StampingProperties().UseAppendMode());
        signer.SetCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING);
        PdfSigner.SignDeferred(signer.GetDocument(), new GetSignatureToSign(signer.GetDocument()).GetSignatureName(), destination, gsContainer);

        using (MemoryStream LTV = new MemoryStream())
        using (var newSource = new MemoryStream(destination.ToArray()))
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfReader(newSource), new PdfWriter(LTV), new StampingProperties().UseAppendMode());

            LtvVerification v = new LtvVerification(pdfDoc);
            SignatureUtil signatureUtil = new SignatureUtil(pdfDoc);

            IList<string> names = signatureUtil.GetSignatureNames();
            String sigName = names[(names.Count - 1)];

            PdfPKCS7 pkcs7 = signatureUtil.ReadSignatureData(sigName);

            if (pkcs7.IsTsp())
            {
                v.AddVerification(sigName, new OcspClientBouncyCastle(null), new CrlClientOnline(), LtvVerification.CertificateOption.WHOLE_CHAIN,
                    LtvVerification.Level.OCSP_CRL, LtvVerification.CertificateInclusion.YES);
            }
            else
            {
                foreach (String name in names)
                {
                    v.AddVerification(name, new OcspClientBouncyCastle(null), new CrlClientOnline(), LtvVerification.CertificateOption.WHOLE_CHAIN,
                        LtvVerification.Level.OCSP_CRL, LtvVerification.CertificateInclusion.YES);
                }
            }

            v.Merge();
            pdfDoc.Close();
            return await Task.FromResult( LTV.ToArray());
        }
    }
}

并且有结果:

找不到我做错了什么。

共有1个答案

卓致远
2023-03-14

你的问题与这个问题有关,比如在这种情况下,ECDSA签名格式存在问题。因此,要了解更多细节,请阅读这里的答案。

正如在回答上述问题时所解释的,ECDSA签名值有两种主要的编码格式,

  • 作为两个整数值和
  • 作为两个固定长度的整数的串联

根据我的经验,Adobe Reader支持这两种格式,而Foxit显然只支持前一种。

嵌入的签名值使用后一种格式。因此,Foxit不接受它。

要使您的签名与Foxit(以及iText自己的验证)兼容,您应该切换到前一种格式。检查您的web服务是否可以以TLV格式返回签名。或者,您必须在代码中从普通格式转换为TLV格式。

实际上,在这里可以看到,对于数字签名,Foxit声称与底层操作系统紧密集成。正如文中所解释的,虽然这确实可能具有使操作系统识别的任何证书能够被Foxit使用的优点,但它的缺点是,由不依赖操作系统的签名软件生成的签名可能存在问题,甚至由Foxit在其他操作系统上生成或成功验证的签名也可能存在问题。。。

旁白:就像上述问题一样,签名容器中还有另一个问题:在签名算法字段中,它有ECDSA公钥的OID,而不是实际签名算法的OID。虽然Adobe Reader和Foxit都接受这一点,但其他不太松散的验证器将拒绝这一点。

使用此错误的OID是当前iText版本中的一个已知问题。目前,您可以使用BouncyCastle或. Net安全API类而不是iText的PdfPKCS7来创建CMS签名容器。

 类似资料:
  • PDF下载示例:https://drive.google.com/file/d/12wv1Pb7gh4vCKOGhX4cZ3aOrLSiOo4If/view?usp=sharing 因此,当PDF在A.Reader(连续版本)中打开时,它表示证书无效,因为对该文档所做的更改导致签名无效。 但我看不出有什么变化。我们自己的应用程序只添加了一个签名(证书),为数千个其他PDF添加了正确的签名。未执行其

  • 当我使用带电子令牌的IText对PDF进行签名时,签名的PDF在Acrobat Adobe Reader中显示“至少一个签名无效”。我正在使用有效的电子代币。以下是签署Pdf的代码。

  • 我有一个私人钥匙在档案里。“privatekey.pem”并且不知道如何创建谁能帮助我吗?我正在尝试使用IText7签名pdf。

  • 我对iTextSharp有意见。我有一个带有表单字段的文档,并且我已经为签名生成了字段。当第一个人在文件上签字时,它就会正常工作。Adobe Reader显示有效签名。当我让第二个人在文档上签名时,Adobe Reader显示签名1现在是“未知签名”,签名无效。Adobe reader显示: 此签名中包含的格式或信息有错误(支持信息:SigDict/Contents非法数据)

  • 作为我对客户机/服务器pdf签名研究的一部分,我测试了itext pdf延迟签名示例。不幸的是,我得到的合并空签名pdf和哈希值的pdf ie输出显示无效签名。 下面是我的代码片段 我正在使用pkcss11 usb令牌进行签名

  • 我正在将代码从iText5迁移到iText7,目前我正在努力将一个签名添加到已经包含另一个签名的PDF中。这些签名是用我们的国民身份证(公民卡)进行的。 在iText5中,我使用了PdfStamper,但它在Itext7中丢失了... 这是我目前所掌握的: POReID(https://github.com/POReID/POReID)是用于与智能卡交互的库。 当第一次签署文件时,它工作得很好。再