I have a signed PDF file from my client, which contains 2 signatures and is totally valid when opened with Adobe Acrobat Reader and Foxit Reader. But I'm using iText7 (C#) to verify those signatures and get false while verifying the second signature.
Below is my code:
public static async Task VefifySignaturePDFFile(Stream mStream)
{
try
{
using (iText.Kernel.Pdf.PdfReader pdfReader = new iText.Kernel.Pdf.PdfReader(mStream, new iText.Kernel.Pdf.ReaderProperties()))
{
using (var oStream = new MemoryStream())
{
using (iText.Kernel.Pdf.PdfDocument pdfDocument = new iText.Kernel.Pdf.PdfDocument(pdfReader))
{
iText.Signatures.SignatureUtil signatureUtil = new iText.Signatures.SignatureUtil(pdfDocument);
iText.Forms.PdfAcroForm acroForm = iText.Forms.PdfAcroForm.GetAcroForm(pdfDocument, false);
if (signatureUtil.GetSignatureNames().Count > 0)
{
foreach (String name in signatureUtil.GetSignatureNames())
{
#region Kiểm tra chữ ký trong file
iText.Signatures.PdfPKCS7 pkcs7 = null;
var sig = signatureUtil.GetSignature(name);
var cover = signatureUtil.SignatureCoversWholeDocument(name);
var llX = float.Parse(acroForm.GetFormFields()[name].GetWidgets().First().GetRectangle().Get(0).ToString());
var llY = float.Parse(acroForm.GetFormFields()[name].GetWidgets().First().GetRectangle().Get(1).ToString());
var urX = float.Parse(acroForm.GetFormFields()[name].GetWidgets().First().GetRectangle().Get(2).ToString()) - llX;
var urY = float.Parse(acroForm.GetFormFields()[name].GetWidgets().First().GetRectangle().Get(3).ToString()) - llY;
var page = pdfDocument.GetPageNumber(acroForm.GetFormFields()[name].GetWidgets().First().GetPage());
var reason = sig.GetReason();
try
{
pkcs7 = signatureUtil.ReadSignatureData(name); // Chữ ký bị lỗi thì sẽ nhẩy vào ex
}
catch (Exception ex)
{
continue;
}
var verify = pkcs7.VerifySignatureIntegrityAndAuthenticity(); // Tài liệu bị thay đổi sẽ ra false
#endregion
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
Does anyone know what I am doing wrong here?
There is an issue in the second signature: Its embedded CMS signature container has this EncapsulatedContentInfo
entry:
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.2.840.113549.1.7.1 data (PKCS #7)
[0] (1 elem)
OCTET STRING (0 byte)
In particular this entry has an eContent
value, the 0-tagged OCTET STRING (0 byte)
, i.e. a byte array of length zero.
According to RFC 3852 and RFC 5652 (which the PDF specifications ISO 32000-1 and ISO 32000-2 respectively reference as CMS specification), eContent
- if present - contains the signed data. Only if eContent
is not present, the signed data is outside the CMS container.
Thus, your second signature strictly said claims that it signs an empty byte array and not the PDF document it is embedded in.
You mention that Adobe Acrobat and Foxit validate the signature. Apparently these validators disregard the misleading eContent
entry, maybe because the contained byte array is empty. iText and eSig DSS, on the other hand, strictly follow the RFCs, consider the eContent
entry in their validation routine and consequentially run into a validation failure.