I am using iText for PDF manipulation. In my scenario I am getting the Certify Policy applied on the specific document but iText always returns 0 in any document case.
I am using the following code snippet:
PdfSigner pdfSigner = new PdfSigner(_pdfReader, outputStream, new StampingProperties().UseAppendMode());
int certificationLevel = pdfSigner.GetCertificationLevel();
The document is attached on the following link for reference:
https://1drv.ms/b/s!AvIgyv7xAxxoig9eXND6b14wJGtK?e=A3eM1c
PdfSigner.GetCertificationLevel() does not return the certification level implied by existing signatures as you assume.
Instead it returns the certification level of the signature this PdfSigner will create.
As you have not yet called PdfSigner.SetCertificationLevel(), the default level 0 (NOT_CERTIFIED, a mere approval signature) is returned.
Related
The goal is to implement a PDF signing process in which the server provides the hash to be signed to the client on request. The client then signs the given hash using a private key obtained from a smart card through a PKCS#11 interface. The signature is then sent back to the server for attaching into the PDF file using iTextSharp 5.5.4.
On reviewing the signature in Acrobat Reader, it gives me the error "The document has been altered or corrupted since the signature was applied".
Here is the method i used to calculate hash on the server.
public byte[] GetHashToSign(byte[] unsignedPdfBytes, out string signatureFieldName, out byte[] tempFile)
{
byte[] result = null;
using (PdfReader reader = new PdfReader(unsignedPdfBytes))
{
using (MemoryStream stream = new MemoryStream())
{
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ETSI_CADES_DETACHED);
PdfStamper stamper = PdfStamper.CreateSignature(reader, stream, '\0');
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
signatureFieldName = appearance.FieldName;
MakeSignature.SignExternalContainer(appearance, external, 30000);
result = SHA256Managed.Create().ComputeHash(appearance.GetRangeStream());
tempFile = stream.ToArray();
}
return result;
}
}
After the client signs the given hash, i embed signed hash to pdf on the server. Here is the method i used to embed signed hash.
public void EmbedSignature(byte[] tempPdfBytes, string signatureFieldName, byte[] signedBytes, string signedPdfPath)
{
using (PdfReader pdfReader = new PdfReader(tempPdfBytes))
{
using (FileStream os = File.OpenWrite(signedPdfPath))
{
IExternalSignatureContainer external = new MyExternalSignatureContainer(signedBytes);
MakeSignature.SignDeferred(pdfReader, signatureFieldName, os, external);
}
}
}
On the other hand, when i use the SHA-1, i did not get any error. Acrobat Reader verifies the signature as follows. But i have to use SHA256.
Here is the method i used to calculate hash with SHA-1 on the server.
public byte[] GetHashToSign(byte[] unsignedPdfBytes, out string signatureFieldName, out byte[] tempFile)
{
byte[] result = null;
using (PdfReader reader = new PdfReader(unsignedPdfBytes))
{
using (MemoryStream stream = new MemoryStream())
{
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_SHA1);
PdfStamper stamper = PdfStamper.CreateSignature(reader, stream, '\0');
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
signatureFieldName = appearance.FieldName;
MakeSignature.SignExternalContainer(appearance, external, 30000);
result = SHA1Managed.Create().ComputeHash(appearance.GetRangeStream());
tempFile = stream.ToArray();
}
return result;
}
}
EDIT: Signed PDF - Invalid signature with SHA256
Signed PDF - valid signature with SHA1
I research all related entries but I did not get any result to handle this problem.
What am I missing or doing wrong?
In Short
There are different sub-types of PDF signatures which have different requirements on the signature to embed. In your switch away from SHA1 usage you change the type and, therefore, not only have to replace SHA1 by SHA256 everywhere, you also have to generate your signature containers differently.
In Detail
You used to generate PDF signatures of subtype adbe.pkcs7.sha1:
external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_SHA1);
This subtype is defined as:
The SHA1 digest of the document’s byte range shall be encapsulated in the CMS SignedData field with ContentInfo of type Data. The digest of that SignedData shall be incorporated as the normal CMS digest. The value adbe.pkcs7.sha1 for the SubFilter key has been deprecated with PDF 2.0. To support backward compatibility, PDF readers should process this value for this key, but PDF writers shall not use this value.
(ISO 32000-2 section 12.8.3.3 "CMS (PKCS #7) signatures")
As SHA1 in this subtype is used without alternative, you must use a different subtype when replacing SHA1 by SHA256. Furthermore, this subtype is deprecated, so there is even more cause to switch.
You chose to switch to the subtype ETSI.CAdES.detached:
external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ETSI_CADES_DETACHED);
This subtype is specified as:
12.8.3.4.2 Signature dictionary for PAdES signatures
When the SubFilter value is ETSI.CAdES.detached, the value of Contents shall be a DER-encoded CMS SignedData binary data object containing the signature. The signature dictionary shall follow the specification given in 12.7.5.5, "Signature fields" with the following additional restrictions/constraints:
The ByteRange shall cover the entire file, including the signature dictionary but excluding the Contents entry.
The signature dictionary shall not contain a Cert entry.
Either the time of signing may be indicated by the value of the M entry in the signature dictionary or the signing-time attribute may be used, but not both.
12.8.3.4.3 Attributes for PAdES signatures
The attributes in the SignedData object used as the value of the signature dictionary Contents key shall obey the following rules:
a) content-type: shall be present and shall always have the value "id-data".
b) Signature timestamp: A timestamp from a trusted timestamp server should be present as a unsigned attribute. The timestamp should be applied on the digital signature immediately after the signature is created so the timestamp specifies a time as close as possible to the time at which the document was signed. The rules from clause 5.3 in ETSI EN 319 122-1 shall apply.
c) content timestamp: may be present. If the content timestamp attribute is present, it shall be used in the same way as defined in clause 5.2.8 in ETSI EN 319 122-1.
d) exactly one single SignerInfo attribute shall be present.
e) message-digest: shall be present and shall be used as defined in CMS (Internet RFC 5652).
f) signing-certificate or signing-certificate-v2: shall be used as a signed attribute as described in the ESS signing-certificate attribute or as described in the ESS signing-certificate-v2 attribute as defined in clause 5.2.2 in ETSI EN 319 122-1. The details of the signing certificate attribute can be found in Internet RFC 5035.
g) signing-time: may be present. If present, it contains a UTC time. If the signing-time attribute is present, the time of signing shall not be indicated by the value of the M entry in the signature dictionary.
h) signer-location, as defined in clause 5.2.5 in ETSI EN 319 122-1, may be present. In such a case, the Location entry in the signature dictionary shall not be present.
i) these attributes shall not be used: counter-signature, content-reference, content-identifier, and content-hints.
j) signer-attributes-v2: may be used and shall follow the definition given in clause 5.2.6.1 of ETSI EN 319 122-1.
k) Unsigned signature attributes not explicitly noted here may be ignored.
(ISO 32000-2 section 12.8.3.4 "CAdES signatures as used in PDF")
As you see, the ETSI.CAdES.detached subtype has far more specific requirements than the deprecated adbe.pkcs7.sha1 subtype. The main difference is, though,
that in adbe.pkcs7.sha1 the SHA1 digest of the signed byte ranges is the message signed by the signature container, and this message is encapsulated therein
while in ETSI.CAdES.detached the signed byte ranges themselves are signed directly by the signature container but are not encapsulated therein.
Thus, you do not merely have to switch the hashing algorithm in your client side code but you also have to use the hash value returned from your GetHashToSign method differently, not anymore as abstract data message to sign but instead already as the hash of the data to sign.
In your example "invalid signature with SHA256.pdf" the hash of the signed byte ranges still is used as abstract message to sign which is why it's invalid.
I am using the below c# code (IText7 library) to set the appearance object to show the digital signature on my pdf.
string destPdf = "D:\\UnsignedPDF.pdf";
string srcPdf = "D:\\SignedPDF.pdf";
PdfReader reader = new PdfReader(srcPdf);
PdfSigner signer = new PdfSigner(reader,
new FileStream(destPdf, FileMode.Create),
new StampingProperties());
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance.SetReason("My reson to sign...")
.SetLocation("India")
.SetPageRect(new Rectangle(36, 648, 200, 100))
.SetPageNumber(1);
signer.SetFieldName("MyFieldName");
A digital signature is printed on my pdf but not as what I expected, it should show a validity unknown symbol or signature valid symbol but it is not getting printed. I am getting it printed like below image.
but my expectation is to print it like below images:
A digital signature is printed on my pdf but not as what I expected, it should show a validity unknown symbol or signature valid symbol but it is not getting printed.
No, it shouldn't.
What you describe is a behavior that has been deprecated in 2003 when Adobe Acrobat 6 has been published. In particular that behavior has never been specified in the ISO PDF specification ISO 32000; on the contrary it has been forbidden in the update ISO 32000-2. For references read this answer.
With respect to iText:
iText(Sharp) 5.x, having inherited its signing API implementation base from iText 2.x/4.x, still offered a backward switch (PdfSignatureAppearance.Acro6Layers) which set to false allowed the creation of signature appearances supporting those in-document validation status marks.
iText 7.x, being a product started in the 2010s, got rid of this burden.
If you happen to work in a context which technologically got stuck in the early 2000s, and if you indeed are required to enable such (nowadays invalid) behavior, you may consider re-integrating the code for generating those pre-Acrobat6 layers in the current iText 7 sign module. If you compare the PdfSignatureAppearance.GetAppearance() source iText 5 and iText 7, you find quickly where with Acro6Layers == false additional layers where added.
I am using iText 7 to sign pdf documents.
This works without problems, and the signature is shown as valid.
In addition to the digital signature, i want to show a visual representation on the pdf. This is described in the digital signature book chapter 2.4 Creating different signature appearances.
The produced pdf shows this appearance if i open it using adobe reader.
The first image is a pdf created using word and the save as pdf functionality.
The second image is a demo pdf i just downloaded random.
If i open the first pdf in chrome, the signature appearance text is not shown, but if i open the pdf which was initially created using word, the signature apperance is missing.
Any ideas on whats wrong with the pdf which doesn't show the signature appearance in chrome?
edit: Links to the documents
Pdf which shows signature in chrome
https://1drv.ms/b/s!AkROTDoCWFJnkd5VOFjUHZfpQXzJWQ?e=MeyZje
Pdf which doesn't show signature in chrome
https://1drv.ms/b/s!AkROTDoCWFJnkd5W5P3MCbb8fwLASA?e=zsmks0
edit 2: Code sample
The following code sample will sign a pdf document using a local certificate and place some text into the SignatureAppearance which is not shown in chrome.
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Signatures;
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace PdfSigning.Lib.Helpers
{
public class SignPdfTest
{
public static byte[] SingPdfUsingCertificate(X509Certificate2 cert2, byte[] pdfToSign)
{
var apk = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(cert2.PrivateKey).Private;
IExternalSignature pks = new PrivateKeySignature(apk, DigestAlgorithms.SHA512);
var cp = new Org.BouncyCastle.X509.X509CertificateParser();
var chain = new[] { cp.ReadCertificate(cert2.RawData) };
using (PdfReader reader = new PdfReader(new MemoryStream(pdfToSign)))
{
using (MemoryStream fout = new MemoryStream())
{
StampingProperties sp = new StampingProperties();
sp.UseAppendMode();
PdfSigner signer = new PdfSigner(reader, fout, sp);
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance.SetPageNumber(1);
appearance.SetLayer2Text("Hello world");
appearance.SetLayer2FontSize(8);
Rectangle pr = new Rectangle(10, 10, 200, 100);
appearance.SetPageRect(pr);
appearance.SetRenderingMode(PdfSignatureAppearance.RenderingMode.DESCRIPTION);
appearance.SetPageRect(pr);
signer.SignDetached(pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
return fout.ToArray();
}
}
}
}
}
private static void SignDocumentUsingCertificateConfiguration()
{
try
{
var certificateSignatureConfiguration = new CertificateSignatureConfiguration();
var cert2 = new X509Certificate2(#"C:\temp\MyCertificate.pfx", "mypassword", X509KeyStorageFlags.Exportable);
CertificatePdfSigner certPdfSigner = new CertificatePdfSigner(certificateSignatureConfiguration);
byte[] signedPdf = PdfSigning.Lib.Helpers.SignPdfTest.SingPdfUsingCertificate(cert2, File.ReadAllBytes(#"C:\temp\WordSaveAsPdf.pdf"));
File.WriteAllBytes(#"C:\temp\WordSaveAsPdf_Signed.pdf", signedPdf);
Console.WriteLine("Done");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
In short
Chrome appears to not read object streams of hybrid reference PDFs, in particular not in the incremental update added during signature creation.
iText, on the other hand, puts nearly all its changes during signing into an object stream.
Thus, Chrome is not aware of the added signature and its appearance.
One can resolve the situation by forcing iText not to create an object stream here.
What is special about the Word generated source PDF?
PDF files contain object cross reference information which map object numbers to offsets of the respective starts of these objects in the file. These information can be stored in two ways, as cross reference table and (since PDF 1.5) also as cross reference stream. Also since PDF 1.5 the format allows to put non-stream objects into so called object streams which allows superior compression as only stream contents can be compressed.
As most PDF viewers at the time PDF 1.5 has been introduced did not support cross reference and object streams, a mixed, hybrid reference style was also introduced then. In this style the basic objects in a PDF which are strictly necessary to display it, are added normally (not in object streams) and are referenced from cross reference tables. Extra information which is not strictly necessary is then added in object streams and referenced from cross reference streams.
MS Word creates PDFs in this hybrid style and is virtually the only software to do so.
What is special about the iText signed result PDF?
iText put nearly all the changes into an object stream in a new incremental update.
Apparently, though, Chrome does not fully support object and cross reference streams, in particular not if combined with further incremental updates.
Thus, Chrome is not aware of the added signature and its visualization.
How to resolve the problem?
What we need to do, therefore, is convince iText that it shall not add important data in an object stream during signing. Due to member variable visibilities this is not as easy as one would like; I used reflection here for that.
In your code simply use the following PdfSignerNoObjectStream instead of PdfSigner:
public class PdfSignerNoObjectStream : PdfSigner
{
public PdfSignerNoObjectStream(PdfReader reader, Stream outputStream, StampingProperties properties) : base(reader, outputStream, properties)
{
}
protected override PdfDocument InitDocument(PdfReader reader, PdfWriter writer, StampingProperties properties)
{
try
{
return base.InitDocument(reader, writer, properties);
}
finally
{
FieldInfo propertiesField = typeof(PdfWriter).GetField("properties", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
WriterProperties writerProperties = (WriterProperties) propertiesField.GetValue(writer);
writerProperties.SetFullCompressionMode(false);
}
}
}
Beware, though, tweaking iText functionality like this is not guaranteed to work across versions. I tested it for a recent iText-7.1.7-SNAPSHOT development state; I expect it to also work for the previous 7.1.x versions.
Is this a Chrome bug? Or an iText bug? Or what?
Most likely it's kind of both.
On one hand the Chrome PDF viewer appears to have issues with hybrid reference PDFs. Considering how long they have been part of the PDF format, that is somewhat disappointing.
And on the other hand the PDF specification requires in the context of hybrid reference documents:
In general, the objects that may be hidden are optional objects specified by indirect references. [...]
Items that shall be visible include the entire page tree, fonts, font descriptors, and width tables. Objects that may be hidden in a hybrid-reference file include the structure tree, the outline tree, article threads, annotations, destinations, Web Capture information, and page labels.
(ISO 32000-1, section 7.5.8.4 Compatibility with Applications That Do Not Support Compressed Reference Streams)
In the case at hand an (updated) page object is in the object stream, i.e. hidden from viewers not supporting cross reference and object streams.
Currently iText 7 PdfDocument attempts to enforce FullCompression on PdfWriters if the underlying PdfReader has any cross reference stream (HasXrefStm):
writer.properties.isFullCompression = reader.HasXrefStm();
(PdfDocument method Open)
Probably it shouldn't enforce that if the PdfReader also is identified as hybrid reference stream (HasHybridXref).
This might be simply caused by the chrome build-in PDF reader. As far as I understood his case, the person who requested help from Chrome devs in this question has received some answers and was redirected to another part of the forum where he could get help. I can try to recreate the problem with itext-sharp 5 (I used that in a previous project) and see if that signature is not shown in Chrome but the odds won't be good.
This sounds an awful lot like a case of the "Needs Appearances" flag not being set. Back in my day (wheeze) iText form fields were generated with as little graphical data as possible, and would set the \NeedsAppearances flag to true, letting the PDF viewer in question (Acrobat Reader was about it back then) that it needed to generate the form fields' appearances before trying to draw them to screen.
And visible PDF Signatures are held in form fields.
So its at least theoretically possible that you can fix this programmatically by telling iText to (re?)generate the form field appearances.
I am attempting to digitally sign a pdf document while still allowing for the modification of annotations and allowing the adding and removing of pages using itextsharp, Version=4.1.6.0. Below is my current code:
var signatureStamper = PdfStamper.CreateSignature(pdfReader, memoryStream, '\0', null);
signatureStamper.SetEncryption(null, Encoding.UTF8.GetBytes(certificationBundle.Password), PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_MODIFY_ANNOTATIONS | PdfWriter.AllowAssembly, PdfWriter.STANDARD_ENCRYPTION_128);
With this configuration however, I am still unable to add and remove pages. Am I Using PdfWriter.AllowAssembly incorrectly?
I am attempting to digitally sign a pdf document while still allowing for the modification of annotations and allowing the adding and removing of pages
Addition or removal of pages is never allowed for signed documents, cf. this stack overflow answer. At most you are allowed to do the following:
Adding signature fields
Adding or editing annotations
Supplying form field values
Digitally signing
I'm using iText 5.5.3 to sign PDF documents. I need these documents to be timestamped and LTV-enabled. I followed the instructions and used the addLtv method (code sample 5.9, page 137 in the Lowagie's white paper). I get a PDF with 2 signatures, which is normal: the first is my own signature, the second is the document-level timestamp.
However, Acrobat tells me my signature is LTV enabled, but the timestamp signature is not :
Image from Acrobat Pro XI http://img15.hostingpics.net/pics/727285so2.jpg
This is because the revocation info of the timestamp certificate is not embedded in the document :
Missing revocation info 1 http://img15.hostingpics.net/pics/491507so2a.jpg
Missing revocation info 2 http://img15.hostingpics.net/pics/312720so2b.jpg
From my understanding, the addLtv method should get all revocation information needed and embed it in the document. Is that correct, or do I have to "manually" get and embed these informations ?
This is the sample code this question is about:
public void addLtv(String src, String dest, OcspClient ocsp, CrlClient crl, TSAClient tsa) throws IOException, DocumentException, GeneralSecurityException
{
PdfReader r = new PdfReader(src);
FileOutputStream fos = new FileOutputStream(dest);
PdfStamper stp = PdfStamper.createSignature(r, fos, '\0', null, true);
LtvVerification v = stp.getLtvVerification();
AcroFields fields = stp.getAcroFields();
List<String> names = fields.getSignatureNames();
String sigName = names.get(names.size() - 1);
PdfPKCS7 pkcs7 = fields.verifySignature(sigName);
if (pkcs7.isTsp())
{
v.addVerification(sigName, ocsp, crl,
LtvVerification.CertificateOption.SIGNING_CERTIFICATE,
LtvVerification.Level.OCSP_CRL,
LtvVerification.CertificateInclusion.NO);
}
else
{
for (String name : names)
{
v.addVerification(name, ocsp, crl,
LtvVerification.CertificateOption.WHOLE_CHAIN,
LtvVerification.Level.OCSP_CRL,
LtvVerification.CertificateInclusion.NO);
}
}
PdfSignatureAppearance sap = stp.getSignatureAppearance();
LtvTimestamp.timestamp(sap, tsa, null);
}
This code identifies the most recently filled signature field of the PDF and checks whether it is a document time stamp or an usual signature.
If it is a document time stamp, the code adds validation information only for this document timestamp. Otherwise the code adds validation information for all signatures.
(The assumed work flow behind this is that the document is signed (for certification and/or approval) a number of times first, and then the document enters LTV cycles adding validation information and document time stamps but no usual signatures anymore. Your work flow may vary and, therefore, your program logic, too.)
Only after all this is done, a new document time stamp is added.
For this finally added time stamp no validation information are explicitly added to the PDF (if document time stamps from the same TSA have been applied in short succession, validation information included for a prior time stamp may be applicable). And this is why Adobe Reader/Acrobat usually does not consider this document time stamp LTV enabled.
If you need validation information for this final document time stamp, too, simply apply this method (the same as the method above, merely not adding a document time stamp) to the file with the document time stamp:
public void addLtvNoTS(String src, String dest, OcspClient ocsp, CrlClient crl) throws IOException, DocumentException, GeneralSecurityException
{
PdfReader r = new PdfReader(src);
FileOutputStream fos = new FileOutputStream(dest);
PdfStamper stp = new PdfStamper(r, fos, '\0', true);
LtvVerification v = stp.getLtvVerification();
AcroFields fields = stp.getAcroFields();
List<String> names = fields.getSignatureNames();
String sigName = names.get(names.size() - 1);
PdfPKCS7 pkcs7 = fields.verifySignature(sigName);
if (pkcs7.isTsp())
{
v.addVerification(sigName, ocsp, crl,
LtvVerification.CertificateOption.SIGNING_CERTIFICATE,
LtvVerification.Level.OCSP_CRL,
LtvVerification.CertificateInclusion.NO);
}
else
{
for (String name : names)
{
v.addVerification(name, ocsp, crl,
LtvVerification.CertificateOption.WHOLE_CHAIN,
LtvVerification.Level.OCSP_CRL,
LtvVerification.CertificateInclusion.NO);
}
}
stp.close();
}
Background
The reason why the iText addLtv example does not (necessarily) create LTV-enabled PDFs is that it is nearer to the best practices for LTV as proposed by ETSI in the PAdES specification than to Adobe's best practices for LTV.
According to ETSI TS 102 778-4 V1.1.2 (2009-12) the structure of a PDF document to which LTV is applied is illustrated in figure 2.
The life-time of the protection can be further extended beyond the life-of the last document Time-stamp applied by adding further DSS information to validate the previous last document Time-stamp along with a new document Time-stamp. This is illustrated in figure 3.
On the other hand, according to Adobe (as written by their PDF evangelist Leonard Rosenthol on the iText mailing list in January 2013),
LTV enabled means that all information necessary to validate the file
(minus root certs) is contained within. So this statement of yours would
be true.
the PDF is signed correctly and contains all necessary certificates,
a valid CRL or OSCP response for every certificate
But since the only way for that statement to be true is for the presence
of DSS, you must have DSS for LTV-enabled to appear. No timestamp
(regular or document level) is required.
Due to this divergence PDF documents with LTV according to ETSI usually are presented by Adobe software to have one not LTV-enabled document time stamp.
See also
enable LTV in iText
LTV enabled signature in PDF
Digital signature with timestamp in Java
What I did was to embed the LTV data for the timestamp before timestamping the document by requesting two timestamps (using the first one to extract LTV data and update DSS and the second one to actually timestamp the document):
Request a dummy timestamp token from the TSA
Extract and validate the trust-chain of this token
Add OSCP replies and CRLs for the certificates in the chain to the document DSS
Now request second timestamp for the document (including the updated DSS) and use it to timestamp the PDF
Verify that the two timestamps were signed by the same certificate (for the unlikely case that the TSA used different certificates)
Extracting the signing certificate from the tsa token:
IDigest messageDigest = tsaClient.GetMessageDigest();
byte[] tsImprint = new byte[messageDigest.GetDigestSize()];
messageDigest.DoFinal(tsImprint, 0);
byte[] tsToken;
try {
tsToken = tsaClient.GetTimeStampToken(tsImprint);
} catch(Exception e) {
throw new GeneralSecurityException(e.Message);
}
Asn1Sequence asn1Seq = Asn1Sequence.GetInstance(tsToken);
ContentInfo sigData = ContentInfo.GetInstance(asn1Seq);
TimeStampToken token = new TimeStampToken(sigData);
IX509Store tokenCerts = token.GetCertificates("COLLECTION");
List<X509Certificate> signingCerts = new List<X509Certificate>();
foreach(X509Certificate cert in tokenCerts.GetMatches(token.SignerID)) {
signingCerts.Add(cert);
}
// now perform LTV steps for signingCerts[0] ...