I am using iText7 for performing PDF and signing operations. My scenario is I am computing hash on my local machine and sending this hash to signing server and in response get the signed PKCS1(Raw signature) and then I am embedding this signature into PDF. My code snippet is as follows:
1: Read public cert from smart card device.
2: Initialize PdfReader from original document bytes containing signature field named "Signature1"
3: Initialize PdfSigner and set signature appearance:
PdfSigner pdfSigner = new PdfSigner(pdfReader, outputStream, new StampingProperties().UseAppendMode());
pdfSigner.SetFieldName("Signature1");
pdfSigner.GetDocument().GetCatalog().SetModified();
ImageData imageData = ImageDataFactory.Create(handSignatureBytes);
PdfSignatureAppearance signatureAppearance = pdfSigner.GetSignatureAppearance();
signatureAppearance.SetContact("contactInfo");
signatureAppearance.SetLocation("locationInfo");
signatureAppearance.SetPageNumber(1);
signatureAppearance.SetReason("signingReason");
signatureAppearance.SetSignatureGraphic(imageData);
signatureAppearance.SetRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
signatureAppearance.SetSignatureCreator("Malik");
signatureAppearance.SetCertificate(x509Certificate);
4: I have implemented IExternalSignatureContainer interface to get document hash:
public class PreSigning : IExternalSignatureContainer
{
protected PdfDictionary sigDic;
private byte[] hash;
public PreSigning(PdfName filter, PdfName subFilter)
{
sigDic = new PdfDictionary();
sigDic.Put(PdfName.Filter, filter);
sigDic.Put(PdfName.SubFilter, subFilter);
}
public void ModifySigningDictionary(PdfDictionary signDic)
{
signDic.PutAll(sigDic);
}
public byte[] Sign(Stream data)
{
this.hash = DigestAlgorithms.Digest(data, DigestAlgorithms.GetMessageDigest("SHA256"));
return new byte[0];
}
public byte[] getHash()
{
return hash;
}
public void setHash(byte[] hash)
{
this.hash = hash;
}
}
5: Getting document hash:
PreSigning external = new PreSigning(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached);
pdfSigner.SignExternalContainer(external, estimatedSize);
byte[] documentHash = external.getHash();
6: Initialize PdfPKCS7 class to get Data To Be Signed and getting hash of Data To Be Signed to send to signing server:
PdfPKCS7 pdfPKCS7 = new PdfPKCS7(null, x509CertificatesChain, "SHA256", false);
dataToBeSigned = pdfPKCS7.GetAuthenticatedAttributeBytes(documentHash, PdfSigner.CryptoStandard.CMS, null, null);
byte[] dataToSignHash = DigestAlgorithms.Digest(new MemoryStream(dataToBeSigned), DigestAlgorithms.GetMessageDigest("SHA256"));
7: I have keep the outputStream from PdfSigner for signature embedding phase:
documentStreamBytes = ((MemoryStream)outputStream).ToArray();
8: Send the Data To Be Signed hash to signing server.
9: Get the PKCS1 data from signing server in response:
byte[] PKCS1 = Convert.FromBase64String(preSigningResponse.signedHash);
10: Initialized PdfPKCS7 class for getting PKCS7 from PKCS1:
PdfPKCS7 pdf = new PdfPKCS7(null, x509CertificatesChain, "SHA256", false);
pdf.SetExternalDigest(PKCS1, null, "RSA");
byte[] pkcs7Data = pdf.GetEncodedPKCS7(documentHash, PdfSigner.CryptoStandard.CMS, null, null, null);
11: Get the original document from documentStreamBytes:
Stream pdfReaderStream = new MemoryStream(documentStreamBytes);
PdfReader reader = new PdfReader(pdfReaderStream);
PdfDocument originalDocument = new PdfDocument(reader, new PdfWriter(new MemoryStream()));
12: I have implemented IExternalSignatureContainer for signature embedding using PdfSigner.SignDeferred() method:
public class PostSigning : IExternalSignatureContainer
{
protected byte[] _sig;
public PostSigning (byte[] sign)
{
_sig = sign;
}
public void ModifySigningDictionary(PdfDictionary signDic)
{
}
public byte[] Sign(Stream data)
{
return _sig;
}
}
13: Calling PdfSigner.SignDeferred() method to get the final document:
Stream resultStream = new MemoryStream();
IExternalSignatureContainer externalSignatureContainer = new PostSigning(pkcs7Data);
PdfSigner.SignDeferred(originalDocument, "Signature1", resultStream, externalSignatureContainer);
byte[] finalDoc = ((MemoryStream)resultStream).ToArray();
I am getting the following error: Document has been altered or corrupted since the signature has been applied.
Can anyone help me regarding this scenario using iText7
signerCert
includes a private key? – mkl