So I am trying to sign a PDF/A-1A document, the document was generated using ITextSharp. When i Sign the document and try to verify the document i get the following errors,
Validating file "test_pdfA_compliance_signed.pdf" for conformance level pdfa-1a The required XMP property 'pdfaid:part' is missing. The required XMP property 'pdfaid:conformance' is missing. A string is longer than 65535 bytes. The document does not conform to the requested standard. The document doesn't conform to the PDF reference (missing required entries, wrong value types, etc.). The document's meta data is either missing or inconsistent or corrupt. Done.
Document Pre-Signed: https://drive.google.com/file/d/0B9RyqgJoa6W8UDFSeHJSX09QamM/view?usp=sharing
Document Post-Signed: https://drive.google.com/file/d/0B9RyqgJoa6W8Y3lGbFU4a2RsLWc/view?usp=sharing
But the signing process is completed as expected, but what i have realised was that if I test whether the document claims to be PDF/A compliant it fails as if there is not metadata claiming PDF/A,
private bool CreatePdfStamperIsPDFADocument(PdfReader reader)
{
if (reader.Metadata != null && reader.Metadata.Length > 0)
{
IXmpMeta xmpMeta = XmpMetaParser.Parse(reader.Metadata, null);
IXmpProperty pdfaidConformance = xmpMeta.GetProperty(XmpConst.NS_PDFA_ID, "pdfaid:conformance");
IXmpProperty pdfaidPart = xmpMeta.GetProperty(XmpConst.NS_PDFA_ID, "pdfaid:part");
if (pdfaidConformance == null || pdfaidPart == null)
{
return false;
}
}
return true;
}
The code i used to sign the document, the PDF stamper used here is the normal one since the check fails. When i try to use the PDFAStamper it complains saying that only PDF/A documents can be used.
private byte[] SignDocument(Certificate certificate, SigningInformation information, List<SigningBlock> signingBlocks, List<MemberItemSignature> signatureImages, byte[] document, bool certify)
{
for (int i = 0; i < signingBlocks.Count; i++)
{
using (MemoryStream outputStream = new MemoryStream())
{
using (PdfReader reader = new PdfReader(document))
{
using (PdfStamper stamper = CreatePdfStamper(reader, outputStream, true))
{
SigningBlock signingBlock = signingBlocks[i];
PdfSignatureAppearance appearance = CreatePdfAppearance(stamper, information, certify && i == 0);
SignDocumentSigningBlock(certificate, information, signingBlock, appearance, stamper, GetSignatureImage(signatureImages, signingBlock.Name));
}
}
document = outputStream.ToArray();
}
}
return document;
}
So this is the code where i determine which PDF stamper to use, but this is where it fails since the document im using is returning null for both components I use to determine PDF/A claim,
private PdfStamper CreatePdfStamper(PdfReader reader, MemoryStream outputStream, bool isSignature)
{
if (isSignature)
{
if (CreatePdfStamperIsPDFADocument(reader))
{
return PdfAStamper.CreateSignature(reader, outputStream, _pdfVersion, null, true, PdfAConformanceLevel.PDF_A_1A);
}
else
{
return PdfStamper.CreateSignature(reader, outputStream, _pdfVersion, null, true);
}
}
else
{
return new PdfStamper(reader, outputStream, _pdfVersion, true);
}
}
Am I doing something stupid or missing something small? Thank you for any help.
Kind regards
When using the regular PdfStamper
, iTextSharp does not make an attempt to make your output file PDF/A compliant. In particular, it will not add any PDF/A related metadata. So it's expected that your test on the metadata (CreatePdfStamperIsPDFADocument()
) returns false
for the signed document.
When running that code sample on your input file, it returns true
, with pdfaidPart
equal to 1
and pdfaidConformance
equal to A
. This is what the debugger shows while running the code:
To get a PDF/A output file, you have to use PdfAStamper
. You say that PdfAStamper
gives you an error about your input file not being PDF/A. This could be because you are specifying a different PDF/A part and/or conformance level than your input file. PdfAStamper
will not convert a PDF/A input file to a different part or conformance level.
So make sure you create the PdfAStamper
for PDF/A-1a input:
PdfStamper stamper = PdfAStamper.CreateSignature(reader, outputfile,
'\0', PdfAConformanceLevel.PDF_A_1A);