问题描述
需要通过使用外部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签名容器的上下文中(除了最原始的那种),不是直接为文档字节创建实际的签名字节,而是为属性结构(即所谓的签名属性"或已认证")创建属性");文档字节的哈希只是这些属性之一的值.
因此,CreateFinalSignature
在CreateFinalSignature
中通过MyExternalSignatureContainer.Sign
返回的hash
的hash
签名值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)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!