CreatePDFEmtySignature

CreatePDFEmtySignature

本文介绍了使用iTextsharp进行外部签名PDF(3)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

需要通过使用外部Web服务对文档哈希进行签名来对PDF进行签名,该过程必须分两步完成,并使用一个临时的空签名.

跟随 Priyanka问题Grazina问题并阅读该帖子上的mkl答案,即使添加了像Grazina这样的哈希前缀,我目前的签名也无效做到了.

iTextSharp版本:5.5.13.1

此程序是我以前的问题的另一种方法.当前代码(编译并开始调用 SignPDF 方法):

public class PDFSigner
{
    private const string SIG_FIELD_NAME = "sigField1";

    private void SignPDF(string pdfFilePath, string userId)
    {
        var preparedSigPdfFilePath = $"{pdfFilePath}.tempsig.pdf";
        var signedPdfFilePath = $"{pdfFilePath}.signed.pdf";

        //Get certificates chain from webservice
        var certificatesChain = this.GetUserCertificates(userId);

        byte[] hash = this.CreatePDFEmtySignature(pdfFilePath, preparedSigPdfFilePath, certificatesChain);

        //Get signature from webservice
        byte[] signedHash = this.GetSignature(hash, userId);

        CreateFinalSignature(preparedSigPdfFilePath, signedPdfFilePath, hash, signedHash, certificatesChain);
    }

    private byte[] CreatePDFEmtySignature(string pdfFilePath, string preparedSigPdfFilePath, List<Org.BouncyCastle.X509.X509Certificate> certificatesChain)
    {
        byte[] hash = null;

        using (PdfReader reader = new PdfReader(pdfFilePath))
        {
            using (FileStream baos = File.OpenWrite(preparedSigPdfFilePath))
            {
                PdfStamper pdfStamper = PdfStamper.CreateSignature(reader, baos, '\0', null, true);
                PdfSignatureAppearance sap = pdfStamper.SignatureAppearance;
                sap.SetVisibleSignature(new iTextSharp.text.Rectangle(36, 720, 160, 780), 1, SIG_FIELD_NAME);

                //TODO: check how to select the correct certificate, have 3 items on list, selected leaf after debug (first one)
                sap.Certificate = certificatesChain.First();

                var externalEmptySigContainer = new MyExternalEmptySignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED, preparedSigPdfFilePath);

                MakeSignature.SignExternalContainer(sap, (IExternalSignatureContainer)externalEmptySigContainer, 8192);

                hash = externalEmptySigContainer.PdfHash;
            }
        }
        return hash;
    }

    private void CreateFinalSignature(string preparedSigPdfFilePath, string signedPdfFilePath,
        byte[] hash, byte[] signedHash, List<Org.BouncyCastle.X509.X509Certificate> certificatesChain)
    {
        using (PdfReader reader = new PdfReader(preparedSigPdfFilePath))
        {
            using (FileStream baos = File.OpenWrite(signedPdfFilePath))
            {
                IExternalSignatureContainer externalSigContainer = new MyExternalSignatureContainer(signedPdfFilePath, hash, signedHash, certificatesChain);
                MakeSignature.SignDeferred(reader, SIG_FIELD_NAME, baos, externalSigContainer);
            }
        }
    }

    public class MyExternalEmptySignatureContainer : ExternalBlankSignatureContainer
    {
        public string PdfTempFilePath { get; set; }
        public byte[] PdfHash { get; private set; }

        public MyExternalEmptySignatureContainer(PdfName filter, PdfName subFilter, string pdfTempFilePath) : base(filter, subFilter)
        {
            this.PdfTempFilePath = pdfTempFilePath;
        }

        override public byte[] Sign(Stream data)
        {
            byte[] sigContainer = base.Sign(data);

            //Get the hash
            IDigest messageDigest = DigestUtilities.GetDigest("SHA-256");
            byte[] messageHash = DigestAlgorithms.Digest(data, messageDigest);

            #region Log
            var messageHashFilePath = $"{this.PdfTempFilePath}.messageHash-b64.txt";
            File.WriteAllText(messageHashFilePath, Convert.ToBase64String(messageHash));
            #endregion Log

            //Add hash prefix
            byte[] sha256Prefix = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 };
            byte[] digestInfo = new byte[sha256Prefix.Length + messageHash.Length];
            sha256Prefix.CopyTo(digestInfo, 0);
            messageHash.CopyTo(digestInfo, sha256Prefix.Length);

            #region Log
            var messageHashWithPrefixFilePath = $"{this.PdfTempFilePath}.messageHash-with-prefix-b64.txt";
            File.WriteAllText(messageHashWithPrefixFilePath, Convert.ToBase64String(digestInfo));
            #endregion Log

            this.PdfHash = digestInfo;

            return sigContainer;
        }
    }

    public class MyExternalSignatureContainer : IExternalSignatureContainer
    {
        public byte[] Hash { get; set; }
        public byte[] SignedHash { get; set; }
        public List<Org.BouncyCastle.X509.X509Certificate> CertificatesList { get; set; }

        public MyExternalSignatureContainer(string signedPdfFilePath, byte[] hash, byte[] signedHash, List<Org.BouncyCastle.X509.X509Certificate> certificatesList)
        {
            this.Hash = hash;
            this.SignedHash = signedHash;
            this.CertificatesList = certificatesList;
        }

        public byte[] Sign(Stream data)
        {
            PdfPKCS7 sgn = new PdfPKCS7(null, this.CertificatesList, "SHA256", false);
            sgn.SetExternalDigest(this.SignedHash, null, "RSA");
            return sgn.GetEncodedPKCS7(this.Hash, null, null, null, CryptoStandard.CMS);
        }

        public void ModifySigningDictionary(PdfDictionary signDic)  {   }
    }

    public byte[] GetSignature(byte[] hash, string userId)
    {
        // Request signature for hash value messageHash and return signature bytes
        byte[] signature = null;

        //CALL WEBSERVICE:
        //signature = WEBSERVICE_CALL_TO_GET_SIGNED_HASH(hash, userId);

        return signature;
    }

    private List<Org.BouncyCastle.X509.X509Certificate> GetUserCertificates(string userId)
    {
        List<Org.BouncyCastle.X509.X509Certificate> certChain = null;

        //CALL WEBSERVICE:
        //certChain = WEBSERVICE_CALL_TO_GET_SIGNED_CERTIFICATES(userId);

        return certChain;
    }
}

获得结果

邮件哈希(BASE 64):

lA2cMByHLkuNdd+aHJRDy3GD2VIeIpVtzlgQGsq3cJw=

带前缀的邮件哈希(BASE 64):

MDEwDQYJYIZIAWUDBAIBBQAEIJQNnDAchy5LjXXfmhyUQ8txg9lSHiKVbc5YEBrKt3Cc

签名哈希(基于64):

LURoF4w3H7uwR3xltjZTBbxBlTCCyD5AqVfseg9F1jn9lfnJ4KAqDL85s2ABSN7iieqjhUd0/U7fReT8gmRV5ZVyjGZcA4BaXr9Lx5E8vLerrHfbE3lsqb4Qm4/3oWX7BjNjfK4ptrBLIaYiDW28sxRKev5mdoo9W2ecIPWAaD8wyrKG/sXj62FQsmetdB0Rzd5rPNbsjVhOeei2V1g1PgF7evJZAz6+1smIWHXPgpxQJ8gZG6KcnHy8N43TGxQ0yV6DKqpl5DGEgqDwiXUY2kGglYNkdaS/5bQy941j7AyEDulni8YXtQ+XH2opuq1OkqVPipLqQnk3DYMPQUzjWqatI1Awfhv4fnceZ2djxgpgtv03tM5PzpHmelXr1gGfcChNDA603SJr+9XVok35mslx13kv+03M4aa2Myp4JKPSNQBuqdeiXKMsXilgv1M13xdbaFL35Omq9ciQbts4kRPpeLj+9PC+kHsyrerRO8pSxHcEjojPqTdYT+pWAmlU

更新使用 mkl测试区域,获得以下结果:

Certificates:
Subject: [REMOVED]
Issuer: [REMOVED]
Serial: 7590871326079402939
Subject: [REMOVED]
Issuer: [REMOVED]
Serial: 1738456118788016053
Subject: [REMOVED]
Issuer: [REMOVED]
Serial: 8957244856106358046

Attribute Certificates: none

CRLs: none

SignerInfo: [REMOVED] 8957244856106358046
Certificate: [REMOVED]
Signed attribute 1.2.840.113549.1.9.4 (PKCS 9 - Message Digest)

Digest:
3031300D060960864801650304020105000420940D9C301C872E4B8D75DF9A1
C9443CB7183D9521E22956DCE58101ACAB7709C

Signed attribute 1.2.840.113549.1.9.3 (PKCS 9 - Content Type)

Signed Attributes Hash:
08767823328F202C1C3E5DB543785ED591C6D84D23DAF3DCBB83684B987008CB
Signed Attributes Hash Hash:
1E2D10B23CD772D16987126182E51BD4D827DB58C497BA4129BB533A576E3548
!!! Decrypted RSA signature is not PKCS1 padded: Decryption error
Decrypted signature bytes: [REMOVED]
!!! Decrypted RSA signature does not end with the PSS 0xbc byte either

!!! Signature does not validate with certificate

将尝试将填充添加到签名中,不胜感激.

解决方案

签名值与签名者证书不匹配

首先,根据结果PDF 判断,尽管使用了相同的userId,但GetUserCertificates调用似乎并未返回GetSignature 之后返回的签名的签名者证书.值.

这可以通过粘贴到问题中的AnalyzeSignatures输出来表明:

 SignerInfo: [REMOVED] 8957244856106358046
Certificate: [REMOVED]
 

签名容器中单个SignerInfo中的SID与所包含的证书集中的单个证书匹配.

 !!! Decrypted RSA signature is not PKCS1 padded: Decryption error
Decrypted signature bytes: [REMOVED]
!!! Decrypted RSA signature does not end with the PSS 0xbc byte either
 

该证书的公共密钥是RSA密钥,并且SignerInfo签名值的长度与密钥长度匹配,但是使用该密钥解密该值既不会返回填充了PKCS#1 v1.5的内容,也不会返回PSS结构.因此,签名值"不是根本不是RSA签名值,或者是使用与所称签名者证书中的公钥不匹配的私钥生成的签名.

因此,要做的第一件事就是分析

     //CALL WEBSERVICE:
    //signature = WEBSERVICE_CALL_TO_GET_SIGNED_HASH(hash, userId);
 

     //CALL WEBSERVICE:
    //certChain = WEBSERVICE_CALL_TO_GET_SIGNED_CERTIFICATES(userId);
 

隐藏部分代码并修复它们(如果问题出在那里,则修复Web服务),然后才继续将此固定代码集成到PDF签名框中.

PDF签名代码框架的错误

此处的PDF签名框架包含一些错误.上一个问题使用iText进行外部签名PDF(2)[关闭]" 中的代码看起来更正确,所以我会在这里找到正确使用签名Web服务之后,建议在该代码的基础上采用下一种方法.

尽管如此,这里还是对两个错误的解释,这些错误很快引起了我的注意:

 byte[] hash = this.CreatePDFEmtySignature(pdfFilePath, preparedSigPdfFilePath, certificatesChain);

//Get signature from webservice
byte[] signedHash = this.GetSignature(hash, userId);

CreateFinalSignature(preparedSigPdfFilePath, signedPdfFilePath, hash, signedHash, certificatesChain);
 

发送了用于签名到Web服务的错误哈希值

CreatePDFEmtySignature返回的哈希是类MyExternalEmptySignatureContainer试图确定有符号字节范围的哈希的结果.

但是通常在CMS签名容器的上下文中(除了最原始的那种),不是直接为文档字节创建实际的签名字节,而是为属性结构(即所谓的签名属性"或已认证")创建属性");文档字节的哈希只是这些属性之一的值.

因此,CreateFinalSignatureCreateFinalSignature中通过MyExternalSignatureContainer.Sign返回的hashhash签名值signedHash被注入到PKCS#7/CMS签名容器SignerInfo中,其经过身份验证的属性具有完全不同的哈希值. /p>

使用iText PdfPKCS7类生成签名容器时,必须使用与以后的PdfPKCS7.GetEncodedPKCS7调用相对应的参数为PdfPKCS7.GetAuthenticatedAttributeBytes结果的哈希计算签名值字节. /p>

因此,对这样签名的PDF的实际签名字节的验证必须失败.

用DigestInfo包裹的哈希值应在裸露的地方使用

CreatePDFEmtySignature返回的哈希值包装在DigestInfo结构中(通过在MyExternalEmptySignatureContainer.Sign中相应地预先放置一些字节).

通过MyExternalSignatureContainer.Sign中的

Via CreateFinalSignature,稍后将其作为有符号字节的哈希值提供给PdfPKCS7.但是这里期望它是裸露的,没有包裹在DigestInfo结构中.

因此,对于像这样签名的PDF,签名文档字节的哈希值的验证必须失败.

Need to sign PDF by using an external webservice that signs the document hash, the process has to be done in 2 steps, and using a temporary empty signature.

Following Priyanka question and Grazina question and reading the mkl answers on that posts, I currently have invalid signature, even after adding the hash prefix like Grazina did.

iTextSharp version: 5.5.13.1

This program is another aproach to my previous question.Current code (compiles and starts calling SignPDF method):

public class PDFSigner
{
    private const string SIG_FIELD_NAME = "sigField1";

    private void SignPDF(string pdfFilePath, string userId)
    {
        var preparedSigPdfFilePath = $"{pdfFilePath}.tempsig.pdf";
        var signedPdfFilePath = $"{pdfFilePath}.signed.pdf";

        //Get certificates chain from webservice
        var certificatesChain = this.GetUserCertificates(userId);

        byte[] hash = this.CreatePDFEmtySignature(pdfFilePath, preparedSigPdfFilePath, certificatesChain);

        //Get signature from webservice
        byte[] signedHash = this.GetSignature(hash, userId);

        CreateFinalSignature(preparedSigPdfFilePath, signedPdfFilePath, hash, signedHash, certificatesChain);
    }

    private byte[] CreatePDFEmtySignature(string pdfFilePath, string preparedSigPdfFilePath, List<Org.BouncyCastle.X509.X509Certificate> certificatesChain)
    {
        byte[] hash = null;

        using (PdfReader reader = new PdfReader(pdfFilePath))
        {
            using (FileStream baos = File.OpenWrite(preparedSigPdfFilePath))
            {
                PdfStamper pdfStamper = PdfStamper.CreateSignature(reader, baos, '\0', null, true);
                PdfSignatureAppearance sap = pdfStamper.SignatureAppearance;
                sap.SetVisibleSignature(new iTextSharp.text.Rectangle(36, 720, 160, 780), 1, SIG_FIELD_NAME);

                //TODO: check how to select the correct certificate, have 3 items on list, selected leaf after debug (first one)
                sap.Certificate = certificatesChain.First();

                var externalEmptySigContainer = new MyExternalEmptySignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED, preparedSigPdfFilePath);

                MakeSignature.SignExternalContainer(sap, (IExternalSignatureContainer)externalEmptySigContainer, 8192);

                hash = externalEmptySigContainer.PdfHash;
            }
        }
        return hash;
    }

    private void CreateFinalSignature(string preparedSigPdfFilePath, string signedPdfFilePath,
        byte[] hash, byte[] signedHash, List<Org.BouncyCastle.X509.X509Certificate> certificatesChain)
    {
        using (PdfReader reader = new PdfReader(preparedSigPdfFilePath))
        {
            using (FileStream baos = File.OpenWrite(signedPdfFilePath))
            {
                IExternalSignatureContainer externalSigContainer = new MyExternalSignatureContainer(signedPdfFilePath, hash, signedHash, certificatesChain);
                MakeSignature.SignDeferred(reader, SIG_FIELD_NAME, baos, externalSigContainer);
            }
        }
    }

    public class MyExternalEmptySignatureContainer : ExternalBlankSignatureContainer
    {
        public string PdfTempFilePath { get; set; }
        public byte[] PdfHash { get; private set; }

        public MyExternalEmptySignatureContainer(PdfName filter, PdfName subFilter, string pdfTempFilePath) : base(filter, subFilter)
        {
            this.PdfTempFilePath = pdfTempFilePath;
        }

        override public byte[] Sign(Stream data)
        {
            byte[] sigContainer = base.Sign(data);

            //Get the hash
            IDigest messageDigest = DigestUtilities.GetDigest("SHA-256");
            byte[] messageHash = DigestAlgorithms.Digest(data, messageDigest);

            #region Log
            var messageHashFilePath = $"{this.PdfTempFilePath}.messageHash-b64.txt";
            File.WriteAllText(messageHashFilePath, Convert.ToBase64String(messageHash));
            #endregion Log

            //Add hash prefix
            byte[] sha256Prefix = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 };
            byte[] digestInfo = new byte[sha256Prefix.Length + messageHash.Length];
            sha256Prefix.CopyTo(digestInfo, 0);
            messageHash.CopyTo(digestInfo, sha256Prefix.Length);

            #region Log
            var messageHashWithPrefixFilePath = $"{this.PdfTempFilePath}.messageHash-with-prefix-b64.txt";
            File.WriteAllText(messageHashWithPrefixFilePath, Convert.ToBase64String(digestInfo));
            #endregion Log

            this.PdfHash = digestInfo;

            return sigContainer;
        }
    }

    public class MyExternalSignatureContainer : IExternalSignatureContainer
    {
        public byte[] Hash { get; set; }
        public byte[] SignedHash { get; set; }
        public List<Org.BouncyCastle.X509.X509Certificate> CertificatesList { get; set; }

        public MyExternalSignatureContainer(string signedPdfFilePath, byte[] hash, byte[] signedHash, List<Org.BouncyCastle.X509.X509Certificate> certificatesList)
        {
            this.Hash = hash;
            this.SignedHash = signedHash;
            this.CertificatesList = certificatesList;
        }

        public byte[] Sign(Stream data)
        {
            PdfPKCS7 sgn = new PdfPKCS7(null, this.CertificatesList, "SHA256", false);
            sgn.SetExternalDigest(this.SignedHash, null, "RSA");
            return sgn.GetEncodedPKCS7(this.Hash, null, null, null, CryptoStandard.CMS);
        }

        public void ModifySigningDictionary(PdfDictionary signDic)  {   }
    }

    public byte[] GetSignature(byte[] hash, string userId)
    {
        // Request signature for hash value messageHash and return signature bytes
        byte[] signature = null;

        //CALL WEBSERVICE:
        //signature = WEBSERVICE_CALL_TO_GET_SIGNED_HASH(hash, userId);

        return signature;
    }

    private List<Org.BouncyCastle.X509.X509Certificate> GetUserCertificates(string userId)
    {
        List<Org.BouncyCastle.X509.X509Certificate> certChain = null;

        //CALL WEBSERVICE:
        //certChain = WEBSERVICE_CALL_TO_GET_SIGNED_CERTIFICATES(userId);

        return certChain;
    }
}

RESULTS OBTAINED

MESSAGE HASH (BASE 64):

lA2cMByHLkuNdd+aHJRDy3GD2VIeIpVtzlgQGsq3cJw=

MESSAGE HASH WITH PREFIX (BASE 64):

MDEwDQYJYIZIAWUDBAIBBQAEIJQNnDAchy5LjXXfmhyUQ8txg9lSHiKVbc5YEBrKt3Cc

SIGNED HASH (base 64):

LURoF4w3H7uwR3xltjZTBbxBlTCCyD5AqVfseg9F1jn9lfnJ4KAqDL85s2ABSN7iieqjhUd0/U7fReT8gmRV5ZVyjGZcA4BaXr9Lx5E8vLerrHfbE3lsqb4Qm4/3oWX7BjNjfK4ptrBLIaYiDW28sxRKev5mdoo9W2ecIPWAaD8wyrKG/sXj62FQsmetdB0Rzd5rPNbsjVhOeei2V1g1PgF7evJZAz6+1smIWHXPgpxQJ8gZG6KcnHy8N43TGxQ0yV6DKqpl5DGEgqDwiXUY2kGglYNkdaS/5bQy941j7AyEDulni8YXtQ+XH2opuq1OkqVPipLqQnk3DYMPQUzjWqatI1Awfhv4fnceZ2djxgpgtv03tM5PzpHmelXr1gGfcChNDA603SJr+9XVok35mslx13kv+03M4aa2Myp4JKPSNQBuqdeiXKMsXilgv1M13xdbaFL35Omq9ciQbts4kRPpeLj+9PC+kHsyrerRO8pSxHcEjojPqTdYT+pWAmlU

UPDATETested the PDF signature with the mkl test area, obtaining the following results:

Certificates:
Subject: [REMOVED]
Issuer: [REMOVED]
Serial: 7590871326079402939
Subject: [REMOVED]
Issuer: [REMOVED]
Serial: 1738456118788016053
Subject: [REMOVED]
Issuer: [REMOVED]
Serial: 8957244856106358046

Attribute Certificates: none

CRLs: none

SignerInfo: [REMOVED] 8957244856106358046
Certificate: [REMOVED]
Signed attribute 1.2.840.113549.1.9.4 (PKCS 9 - Message Digest)

Digest:
3031300D060960864801650304020105000420940D9C301C872E4B8D75DF9A1
C9443CB7183D9521E22956DCE58101ACAB7709C

Signed attribute 1.2.840.113549.1.9.3 (PKCS 9 - Content Type)

Signed Attributes Hash:
08767823328F202C1C3E5DB543785ED591C6D84D23DAF3DCBB83684B987008CB
Signed Attributes Hash Hash:
1E2D10B23CD772D16987126182E51BD4D827DB58C497BA4129BB533A576E3548
!!! Decrypted RSA signature is not PKCS1 padded: Decryption error
Decrypted signature bytes: [REMOVED]
!!! Decrypted RSA signature does not end with the PSS 0xbc byte either

!!! Signature does not validate with certificate

Going to try to add the padding to the signature, help appreciated.

解决方案

Signature value does not match signer certificate

First and foremost, judging by the result PDF the GetUserCertificates call does not appear to return the signer certificate of the signature returned later by GetSignature in spite of using the same userId value.

This is indicated by the AnalyzeSignatures output pasted into the question:

SignerInfo: [REMOVED] 8957244856106358046
Certificate: [REMOVED]

The SID in the single SignerInfo in the signature container matches a single certificate from the included set of certificates.

!!! Decrypted RSA signature is not PKCS1 padded: Decryption error
Decrypted signature bytes: [REMOVED]
!!! Decrypted RSA signature does not end with the PSS 0xbc byte either

The public key of that certificate is an RSA key and the length of the SignerInfo signature value matches the key length but decrypting the value using that key returns neither something PKCS#1 v1.5 padded nor a PSS structure. Thus, the "signature value" either is not an RSA signature value at all or it is a signature generated using a private key not matching the public key in the alleged signer certificate.

Thus, the first thing to do is analyzing the

    //CALL WEBSERVICE:
    //signature = WEBSERVICE_CALL_TO_GET_SIGNED_HASH(hash, userId);

and

    //CALL WEBSERVICE:
    //certChain = WEBSERVICE_CALL_TO_GET_SIGNED_CERTIFICATES(userId);

hidden parts of the code and fixing them (or the web service if the problem is located there) and only then continuing integrating this fixed code in a PDF signing frame.

Errors of the PDF signing code frame

The PDF signing frame here contains some errors. The code in the previous question "External signing PDF with iText (2) [closed]" looked more correct, so I would propose basing the next approach onto the code there after finding out the correct use of the signing web service here.

Nonetheless, here an explanation of two errors that quickly caught my eyes:

byte[] hash = this.CreatePDFEmtySignature(pdfFilePath, preparedSigPdfFilePath, certificatesChain);

//Get signature from webservice
byte[] signedHash = this.GetSignature(hash, userId);

CreateFinalSignature(preparedSigPdfFilePath, signedPdfFilePath, hash, signedHash, certificatesChain);

Wrong hash sent for signing to the web service

The hash returned by CreatePDFEmtySignature is result of the attempt of the class MyExternalEmptySignatureContainer to determine the hash of the signed byte ranges.

But usually in the context of CMS signature containers (except for the most primitive kind) the actual signature bytes are not created for the document bytes directly but instead for a structure of attributes (the so called "signed attributes" or "authenticated attributes"); the hash of the document bytes is merely the value of one of those attributes.

Thus, the signature value signedHash for hash returned by GetSignature in CreateFinalSignature via MyExternalSignatureContainer.Sign is injected into a PKCS#7 / CMS signature container SignerInfo whose authenticated attributes have a completely different hash.

When using the iText PdfPKCS7 class to generate a signature container, the signature value bytes have to be calculated for the hash of the result of PdfPKCS7.GetAuthenticatedAttributeBytes with the parameters corresponding to those of the later PdfPKCS7.GetEncodedPKCS7 call.

Thus, the validation of the actual signature bytes for PDFs signed like this must fail.

Hash wrapped in DigestInfo used where it should be naked

The hash returned by CreatePDFEmtySignature is wrapped in a DigestInfo structure (by prepending some bytes accordingly in MyExternalEmptySignatureContainer.Sign).

Via CreateFinalSignature in MyExternalSignatureContainer.Sign it later is given to PdfPKCS7 as hash of the signed bytes. But here it is expected naked, not wrapped in a DigestInfo structure.

Thus, the validation of the hash of the signed document bytes for PDFs signed like this must fail.

这篇关于使用iTextsharp进行外部签名PDF(3)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-27 21:51