PDFBox not recognising pdf to be non printable - pdf

I am using PDFBox for validating a pdf document and one of the validation states that whether the pdf document is printable or not.
I use the following code to perform this operation:
PDDocument document = PDDocument.load("<path_to_pdf_file>");
System.out.println(document.getCurrentAccessPermission().canPrint());
but this is returning me true though when the pdf is opened, it shows the print icon disabled.

Access permissions are integrated into a document by means of encryption.
Even PDF documents which don't ask for a password when opened in Acrobat Reader may be encrypted, they essentially are encrypted using a default password. This is the case in your PDF.
PDFBox determines the permissions of an encrypted PDF only while decrypting it, not already when loading a PDDocument. Thus, you have to try and decrypt the document before inspecting its properties if it is encrypted.
In your case:
PDDocument document = PDDocument.load("<path_to_pdf_file>");
if (document.isEncrypted())
{
document.decrypt("");
}
System.out.println(document.getCurrentAccessPermission().canPrint());
The empty string "" represents the default password. If the file is encrypted using a different password, you'll get an exception here. Thus, catch accordingly.
PS: If you do not know all the passwords in question, you may still use PDFBox to check the permissions, but you have to work more low-level:
PDDocument document = PDDocument.load("<path_to_pdf_file>");
if (document.isEncrypted())
{
final int PRINT_BIT = 3;
PDEncryptionDictionary encryptionDictionary = document.getEncryptionDictionary();
int perms = encryptionDictionary.getPermissions();
boolean printAllowed = (perms & (1 << (PRINT_BIT-1))) != 0;
System.out.println("Document encrypted; printing allowed?" + printAllowed);
}
else
{
System.out.println("Document not encrypted; printing allowed? true");
}

Related

Pdf signature invalidates existing signature in Acrobat Reader

I'm using iText 7.1.15 and SignDeferred to apply signatures to pdf documents.
SignDeferred is required since the signature is created PKCS11 hardware token (usb key).
When i sign a "regular" pdf, e.g. created via word, i can apply multiple signatures and all signatures are shown as valid in the adobe acrobat reader.
If the pdf was created by combining multiple pdf documents with adobe DC, the first signature is valid but becomes invalid as soon as the seconds signature is applied.
Document in Adobe reader after the first signature is applied:
Document in Adobe reader after the second signature is applied:
The signatures of the same document are shown as valid in foxit reader.
I've found a similar issue on stackoverflow (multiple signatures invalidate first signature in iTextSharp pdf signing), but it was using iText 5 and i'm not sure it is the same problem.
Question: What can i do in order to keep both signatures valid in the Acrobat Reader?
Unsigned Pdf document on which the first signature becomes invalid:
https://github.com/suntsu42/iTextDemoInvalidSecondSignature/blob/master/test.pdf
Twice signed document which is invalid:
https://github.com/suntsu42/iTextDemoInvalidSecondSignature/blob/master/InvalidDocumentSignedTwice.pdf
Code used for signing
//Step #1 >> prepare pdf for signing (Allocate space for the signature and calculate hash)
using (MemoryStream input = new MemoryStream(pdfToSign))
{
using (var reader = new PdfReader(input))
{
StampingProperties sp = new StampingProperties();
sp.UseAppendMode();
using (MemoryStream baos = new MemoryStream())
{
var signer = new PdfSigner(reader, baos, sp);
//Has to be NOT_CERTIFIED since otherwiese a pdf cannot be signed multiple times
signer.SetCertificationLevel(PdfSigner.NOT_CERTIFIED);
if (visualRepresentation != null)
{
try
{
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
base.SetPdfSignatureAppearance(appearance, visualRepresentation);
}
catch (Exception ex)
{
throw new Exception("Unable to set provided signature image", ex);
}
}
//Make the SignatureAttributeName unique
SignatureAttributeName = $"SignatureAttributeName_{DateTime.Now:yyyyMMddTHHmmss}";
signer.SetFieldName(SignatureAttributeName);
DigestCalcBlankSigner external = new DigestCalcBlankSigner(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached);
signer.SignExternalContainer(external, EstimateSize);
hash = external.GetDocBytesHash();
tmpPdf = baos.ToArray();
}
}
//Step #2 >> Create the signature based on the document hash
// This is the part which accesses the HSM via PCKS11
byte[] signature = null;
if (LocalSigningCertificate == null)
{
signature = CreatePKCS7SignatureViaPKCS11(hash, pin);
}
else
{
signature = CreatePKCS7SignatureViaX509Certificate(hash);
}
//Step #3 >> Apply the signature to the document
ReadySignatureSigner extSigContainer = new ReadySignatureSigner(signature);
using (MemoryStream preparedPdfStream = new MemoryStream(tmpPdf))
{
using (var pdfReader = new PdfReader(preparedPdfStream))
{
using (PdfDocument docToSign = new PdfDocument(pdfReader))
{
using (MemoryStream outStream = new MemoryStream())
{
PdfSigner.SignDeferred(docToSign, SignatureAttributeName, outStream, extSigContainer);
return outStream.ToArray();
}
}
}
}
}
Sample project
I've created a working sample project which uses a local certificate for signing. I also did update iText to version 7.2 but with the same result.
It also contains the document which cannot be signed twice (test.pdf)
https://github.com/suntsu42/iTextDemoInvalidSecondSignature/tree/master
Edit
I've applied the solution provided by MKL to the sample project on github.
As a second note, It is also possible to use PdfSigner but in this case, the bookmarks of the original document must be removed.
As already mentioned in a comment, the example document "InvalidDocumentSignedTwice.pdf" has the signature not applied in an incremental update, so here it is obvious that former signatures will break. But this is not the issue of the OP's example project. Thus, the issue is processed with an eye on the actual outputs of the example project.
Analyzing the Issue
When validating signed PDFs Adobe Acrobat executes two types of checks:
It checks the signature itself and whether the revision of the PDF it covers is untouched.
(If there are additions to the PDF after the revision covered by the signature:) It checks whether changes applied in incremental updates only consist of allowed changes.
The former check is pretty stable and standard but the second one is very whimsical and prone to incorrect negative validation results. Like in your case...
In case of your example document one can simply determine that the first check must positively validate the first signature: The file with only one (valid!) signature constitutes a byte-wise starting piece of the file with two signatures, so nothing can have been broken here.
Thus, the second type of check, the fickle type, must go wrong in the case at hand.
To find out what change one has to analyze the changes done during signing. A helpful fact is that doing the same using iText 5 does not produce the issue; thus, the change that triggered the check must be in what iText 7 does differently than iText 5 here. And the main difference in this context is that iText 7 has a more thorough tagging support than iText 5 and, therefore, also adds a reference to the new signature field to the document structure tree.
This by itself does not yet trigger the whimsical check, though, it only does so here because one outline element refers to the parent structure tree element of the change as its structure element (SE). Apparently Adobe Acrobat considers the change in the associated structure element as a change of the outline link and, therefore, as a (disallowed) change of the behavior of the document revision signed by the first signature.
So is this an iText error (adding entries to the structure tree) or an Adobe Acrobat error (complaining about the additions)? Well, in a tagged PDF (and your PDF has the corresponding Marked entry set to true) the content including annotations and form fields is expected to be tagged. Thus, addition of structure tree entries for the newly added signature field and its appearance not only should be allowed but actually recommended or even required! So this appears to be an error of Adobe Acrobat.
A Work-Around
Knowing that this appears to be an Adobe Acrobat bug is all well and good, but at the end of the day one might need a way now to sign such documents multiple times without current Adobe Acrobat calling that invalid.
It is possible to make iText believe there is no structure tree and no need to update a structure tree. This can be done by making the initialization of the document tag structure fail. For this we override the PdfDocument method TryInitTagStructure. As the iText PdfSigner creates its document object internally, we do this in an override of the PdfSigner method InitDocument.
I.e. instead of PdfSigner we use the class MySigner defined like this:
public class MySigner : PdfSigner
{
public MySigner(PdfReader reader, Stream outputStream, StampingProperties properties) : base(reader, outputStream, properties)
{
}
override protected PdfDocument InitDocument(PdfReader reader, PdfWriter writer, StampingProperties properties)
{
return new MyDocument(reader, writer, properties);
}
}
public class MyDocument : PdfDocument
{
public MyDocument(PdfReader reader, PdfWriter writer, StampingProperties properties) : base(reader, writer, properties)
{
}
override protected void TryInitTagStructure(PdfDictionary str)
{
structTreeRoot = null;
structParentIndex = -1;
}
}
Using MySigner for signing documents iText won't add tagging anymore and so won't make Adobe Acrobat complain about new entries in the structure tree.
The Same Work-Around in Java
As I feel more comfortable working in Java, I analyzed this and tested the work-around in Java.
Here this can be put into a more closed form (maybe it also can for C#, I don't know), instead of initializing the signer like this
PdfSigner pdfSigner = new PdfSigner(pdfReader, os, new StampingProperties().useAppendMode());
we do it like this:
PdfSigner pdfSigner = new PdfSigner(pdfReader, os, new StampingProperties().useAppendMode()) {
#Override
protected PdfDocument initDocument(PdfReader reader, PdfWriter writer, StampingProperties properties) {
return new PdfDocument(reader, writer, properties) {
#Override
protected void tryInitTagStructure(PdfDictionary str) {
structTreeRoot = null;
structParentIndex = -1;
}
};
}
};
(MultipleSignaturesAndTagging test testSignTestManuelTwiceNoTag)
TL;DR
iText 7 adds a structure element for the new signature field to the document structure tree during signing. If the parent node of this new node is referenced as associated structure element of an outline element, though, Adobe Acrobat incorrectly considers this a disallowed change. As a work-around one can tweak iText signing to not add structure elements.
I've got a similar problem with signatures after last update of Adobe Reader. I wrote a post on their community, but they still didn't answer me.
Take a look:
https://community.adobe.com/t5/acrobat-reader-discussions/invalid-signatures-after-adobe-reader-update-2022-001-20085/td-p/12892048
I am using a iText v.5.5.5 to generate pdf. I sign and certify pdf document in single method. Moreover, foxit reader shows that signatures are valid. I believe that this is an Adobe bug and it will be fixed soon :) Key are an log.

Does not comply with PDF/A when signing a document through Itext 5.5.5

I am working on converting a PDF to PDF/A.
I already did this conversion through a paid PDFTools library, the result of the conversion I place it on this page that is responsible for validating whether it complies with the PDA/A standard https://www.pdf-online.com/osa/validate.aspx
Validating indicates that it meets the standard.
Once converted, the PDF will be signed with the Itext 5.5.5 library, however, if I used the validator again the PDF/A standard is no longer valid. The errors shown on the validator are the following:
The name object must be UTF-8 encoded.
A device-specific color space (DeviceGray) without an appropriate output intent is used.
The font Helvetica must be embedded.
The document does not conform to the requested standard.
When signing, information about the digital signature (such as a stamp) is added to the document; it is for this reason that it no longer meets the standard.
Started by eliminating each of these errors, I have already eliminated the Helvetica font error with the following code:
String path = Sign.class.getResource("helvetica.ttf").toExternalForm();
FontFactory.register(path);
BaseFont base = BaseFont.createFont(path, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
Font font = new Font(base);
appearance.setLayer2Font(font);
However, I have not eliminated these two errors:
The name object must be UTF-8 encoded.
A device-specific color space (DeviceGray) without an appropriate output intent is used.
The document does not conform to the requested standard.
The error of the color space, I tried to eliminate it with the following code, but didn't help at all
because it keeps getting the error when I do the validation again.
path = Sign.class.getResource("sRGBColorSpaceProfile.icm").toExternalForm();
ICC_Profile icc = ICC_Profile.getInstance(new FileInputStream(path));
stamper.getWriter().setOutputIntents("Custom", "", "http://www.color.org", "sRGB IEC61966-2.1", icc);
I hope you can help me see how to eliminate the errors so that it complies with the PDF/A standard, or if there is another alternative that allows me to convert to PDF/A and then sign it with the Itext 5.5.5 library.
I appreciate the help you can give me.Thank you
UPDATE
This the code that I use to sign documents with the Itext 5.5.5 library.
String pkcs11Config = "name=NAME" + "\n" + "library=PATH";
ByteArrayInputStream configStream = new ByteArrayInputStream(pkcs11Config.getBytes());
Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(configStream);
Security.addProvider(pkcs11Provider);
KeyStore ks = KeyStore.getInstance("PKCS11");
ks.load(null, password);
PdfReader reader = new PdfReader(pdfInput);
FileOutputStream os = new FileOutputStream(pdfOutputTemp);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true);
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
String path = Sign.class.getResource("helvetica.ttf").toExternalForm();
FontFactory.register(path);
BaseFont base = BaseFont.createFont(path, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
Font font = new Font(base);
appearance.setLayer2Font(font);
path = Sign.class.getResource("sRGBColorSpaceProfile.icm").toExternalForm();
ICC_Profile icc = ICC_Profile.getInstance(new FileInputStream(path));
stamper.getWriter().setOutputIntents("Custom", "", "http://www.color.org", "sRGB IEC61966-2.1", icc);
...
PrivateKey key = (PrivateKey) ks.getKey(alias, pass);
ExternalSignature es = new PrivateKeySignature(key, DigestAlgorithms.SHA256, null);
ExternalDigest digest = new BouncyCastleDigest();
MakeSignature.signDetached(appearance, digest, es, chain, crlList, null, tsc, 0, CryptoStandard.CADES);
UPDATE 2
I tried changing the PdfStamper to PdfAStamper, but when I try to sign a document it returns the following error:
com.itextpdf.text.pdf.PdfAConformanceException: Annotation of type /Widget should have Contents key.
at com.itextpdf.text.pdf.internal.PdfA2Checker.checkAnnotation(PdfA2Checker.java:707)
at com.itextpdf.text.pdf.internal.PdfAChecker.checkPdfAConformance(PdfAChecker.java:219)
at com.itextpdf.text.pdf.internal.PdfAConformanceImp.checkPdfIsoConformance(PdfAConformanceImp.java:71)
at com.itextpdf.text.pdf.PdfWriter.checkPdfIsoConformance(PdfWriter.java:3480)
at com.itextpdf.text.pdf.PdfWriter.checkPdfIsoConformance(PdfWriter.java:3476)
at com.itextpdf.text.pdf.PdfAnnotation.toPdf(PdfAnnotation.java:989)
at com.itextpdf.text.pdf.PdfWriter$PdfBody.addToObjStm(PdfWriter.java:292)
at com.itextpdf.text.pdf.PdfWriter$PdfBody.add(PdfWriter.java:382)
at com.itextpdf.text.pdf.PdfWriter$PdfBody.add(PdfWriter.java:373)
at com.itextpdf.text.pdf.PdfWriter$PdfBody.add(PdfWriter.java:369)
at com.itextpdf.text.pdf.PdfWriter.addToBody(PdfWriter.java:843)
at com.itextpdf.text.pdf.PdfStamperImp.addAnnotation(PdfStamperImp.java:1395)
at com.itextpdf.text.pdf.PdfStamperImp.addAnnotation(PdfStamperImp.java:1408)
at com.itextpdf.text.pdf.PdfSignatureAppearance.preClose(PdfSignatureAppearance.java:1285)
at com.itextpdf.text.pdf.security.MakeSignature.signDetached(MakeSignature.java:243)
UPDATE 3
I updated the itext library from 5.5.5 to 5.5.13.1, and it worked better.
If I use the PdfStamper, I can sign the document but when I use the PDF/A validator, it returns the following errors:
Validating file "DOCUMENT.pdf" for conformance level pdfa-2a
A device-specific color space (DeviceGray) without an appropriate output intent is used.
The document does not conform to the requested standard.
The document contains device-specific color spaces.
The document does not conform to the PDF/A-2a standard.
Done.
The error that said: "The name object must be UTF-8 encoded." doesn't appear anymore.
Also, I tried to use the PdfStamper. When I try to sign a document it returns a different exception than before. This is the new exeption:
com.itextpdf.text.pdf.PdfAConformanceException: DeviceGray shall only be used if a device independent DefaultGray colour space has been set when the DeviceGray colour space is used, or if a PDF/A OutputIntent is present.
at com.itextpdf.text.pdf.internal.PdfA2Checker.close(PdfA2Checker.java:829)
at com.itextpdf.text.pdf.PdfAStamperImp.close(PdfAStamperImp.java:227)
at com.itextpdf.text.pdf.PdfSignatureAppearance.preClose(PdfSignatureAppearance.java:1348)
at com.itextpdf.text.pdf.security.MakeSignature.signDetached(MakeSignature.java:244)

PDF String Extract a checkbox being checked or not

We have a method to check if a checkbox in a PDF (No forms) is checked or not and it works great on one company's PDF. But on another, there is no way to tell if the checkbox is checked or not.
Here is the code that works on one company's PDF
protected static final String[] HOLLOW_CHECKBOX = {"\uF06F", "\u0086"};
protected static final String[] FILLED_CHECKBOX = {"\uF06E", "\u0084"};
protected boolean isBoxChecked(String boxLabel, String content) {
content = content.trim();
for (String checkCharacter : FILLED_CHECKBOX) {
String option = String.format("%s %s", checkCharacter, boxLabel);
String option2 = String.format("%s%s", checkCharacter, boxLabel);
if (content.contains(option) || content.contains("\u0084 ") || content.contains(option2)) {
return true;
}
}
return false;
}
However, when I do the same for another company's PDF there is nothing in the extracted text near the checkbox to tell us if it is checked or not.
The big issue is we have no XML Schema, no Metadata, and no forms on these PDFs, it is just raw String, so you can see a checkbox is difficult to have in a String, but that is all we have. Here is code example of pulling the String in the PDF from a page to some other page, all the text in between
protected String getTextFromPages(int startPage, int endPage, PDDocument document) throws IOException {
PDFTextStripper stripper = new PDFTextStripper();
stripper.setStartPage(startPage);
stripper.setEndPage(endPage);
return stripper.getText(document);
}
I wish the pdfs had an easier way to extract the text/data, but these vendors that make the PDFs decided it was better to keep that out of them.
No we cannot have the vendor's/ other companies change anything, we receive these PDFs from the courts system that have been submitted by lawyers that we don't know and that the lawyers bought the PDF software that generates these files.
We also cannot do it the even longer way of trying to figure out the object model that PDFBox creates of the document with things like
o.apache.pdfbox.util.PDFStreamEngine - processing substream token: PDFOperator{Tf}
because these are 80-100 page PDFs and would take us years just to code to parse one vendor's format.

How to open a password protected PDF using VB6/VB.NET?

I want to open and view a password protected PDF file in VB6/VB.NET program. I have tried using the Acrobat PDF Library but could not do it.
The reason I want to create a password protected PDF file is because I dont want the PDF file to be opened without the password externally i.e outside the program.
To open a password protected PDF you will need to develop at least a PDF parser, decryptor and generator. I wouldn't recommend to do that, though. It's nowhere near an easy task to accomplish.
With help of a PDF library everything is much simpler. You might want to try Docotic.Pdf library for the task.
Here is a sample for you task:
public static void unprotectPdf(string input, string output)
{
bool passwordProtected = PdfDocument.IsPasswordProtected(input);
if (passwordProtected)
{
string password = null; // retrieve the password somehow
using (PdfDocument doc = new PdfDocument(input, password))
{
// clear both passwords in order
// to produce unprotected document
doc.OwnerPassword = "";
doc.UserPassword = "";
doc.Save(output);
}
}
else
{
// no decryption is required
File.Copy(input, output, true);
}
}
Docotic.Pdf can also extract text (formatted or not) from PDFs. It might be useful for indexing (I guess it's what you are up to because you mentioned Adobe IFilter)
you can convert code to vb over the internet

How to enable LTV for a timestamp signature?

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] ...