var result = new MemoryStream();
using (var document = GemBox.Pdf.PdfDocument.Load(pdf))
{
// Add a visible signature field to the first page of the PDF document.
PdfSignatureField signatureField = document.Form.Fields.AddSignature(document.Pages[pageIndex], left, bottom, width, height);
// Get a digital ID from PKCS#12/PFX file.
var digitalId = new IncertDigitalId(certificat); //new PdfDigitalId(certificat);
// Create a PDF signer that will create PAdES B-LTA level signature.
var signer = new GemBox.Pdf.Forms.PdfSigner(digitalId)
{
ApplicationVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(),
ApplicationName = Assembly.GetEntryAssembly().GetName().Name
};
// PdfSigner should create CAdES-equivalent signature.
signer.SignatureFormat = PdfSignatureFormat.CAdES;
// PdfSigner will embed a timestamp in the signature.
// PdfTimestamper(ConfigurationHelpers.Settings.TimeStampAuthorityURL);
signer.Timestamper = new IncertPdfTimestamper(certificat)
{
ApplicationVersion = signer.ApplicationVersion,
ApplicationName = signer.ApplicationName,
ClientId = digitalId
};
// Make sure that all properties specified on PdfSigner are according to PAdES B-LTA level.
signer.SignatureLevel = PdfSignatureLevel.PAdES_B_LTA;
// Initiate signing of a PDF file with the specified signer.
signatureField.Sign(signer);
// Finish signing of a PDF file.
var tmpMemoryStream = new MemoryStream();
document.Save(tmpMemoryStream);
// Download validation-related information for the signature and the signature's timestamp and embed it in the PDF file.
// This will make the signature "LTV enabled".
document.SecurityStore.AddValidationInfo(signatureField.Value);
// Add an invisible signature field to the PDF document that will hold the document timestamp.
var timestampField = document.Form.Fields.AddSignature();
// Initiate timestamping of a PDF file with the specified timestamper.
((IncertPdfTimestamper)signer.Timestamper).Digest = digitalId.Digest;
timestampField.Timestamp(signer.Timestamper);
// Save any changes done to the PDF file that were done since the last time Save was called and
// finish timestamping of a PDF file.
tmpMemoryStream = new MemoryStream();
document.Save(tmpMemoryStream);
tmpMemoryStream.Seek(0, SeekOrigin.Begin);
tmpMemoryStream.CopyTo(result);
}
I am not sure what exactly you are trying to achieve with your IncertDigitalId and IncertPdfTimestamper implementations, but based on your code snippet, I suspect that you want to retrieve the hash that was passed to your implementation of the IncertDigitalId.SignHash override and pass it to your implementation of IncertPdfTimestamper so that it is used in your implementation of the IncertPdfTimestamper.GetTimestampToken override.
If my suspicion is correct, then this scenario is wrong. PdfTimestamper.GetTimestampToken does not operate on the hash on which PdfDigitalId.SignHash operates.
The hash passed to the PdfDigitalId.SignHash method is either the hash of the PDF file to be signed, excluding the placeholder reserved for the PDF signature content (in CMS format), or the hash calculated as explained in the RFC 5652 - Cryptographic Message Syntax (CMS) , in case of a PAdES signature.
The PdfTimestamper.GetTimestampToken method returns the TimeStampToken that is based on the Stream parameter, and the value of this parameter is explained in the documentation of the PdfTimestamper class (the two bullets in the summary of the class documentation). So, using the hash passed to the PdfDigitalId.SignHash method in the PdfTimestamper.GetTimestampToken method is wrong and won’t work.
There are some other possibly problematic constructs that I noticed in your code snippet:
You use the same certificat parameter in both IncertDigitalId and IncertPdfTimestamper constructor. I do not know what type the certificat parameter is, but using it in both these cases is usually wrong. It implies that the certificat parameter is used for both signing the PDF file and for timestamping and only a special kind of certificates that have an ‘Extended key usage’ extension with a value of ‘TimeStamping‘ can actually be used for timestamping.
You set the digitalId value to the timestamper ClientId property. This is wrong because that property should be set to the digital ID that was issued to you by the Timestamp Authority (TSA), and is the Transport Layer Security protocol if the TSA requires it to identify the TimeStampToken request client.
You pass the hash from the IncertDigitalId.Digest to the IncertPdfTimestamper.Digest before timestamping the document with an additional timestamp signature, but after the timestamp that gets embedded in the initial signature is retrieved. So this hash won’t be picked up when retrieving the timestamp that gets embedded in the initial signature. The only way for it to be picked up there as well is to pass the IncertPdfTimestamper instance to your IncertDigitalId constructor and in your IncertDigitalId.SignHash override, set the hash to the IncertPdfTimestamper.Digest. However, my suspicion from the above still stands; this hash should not be used to retrieve the timestamp.
Lastly, if you want your file to contain only the initial signature with the embedded timestamp, then create PAdES B-T level or PAdES B-LT level signed PDF files, and not PAdES B-LTA level signed files, because the LTA level automatically implies appending timestamp signature(s).
I hope this clarifies your situation. If you have any more questions, do not hesitate to ask!