Skip to content

Conversation

@pdizeev
Copy link

@pdizeev pdizeev commented Nov 17, 2025

📌 Summary

This PR introduces a complete revision of the incremental digital signature workflow and several fixes required to preserve PDF/A-1a conformance when signing documents.

The changes address two long-standing problems in PDFsharp:

  1. Previous signatures were marked as non-anchored by ITI (Brazilian ICP-Brasil validator).
    Caused by incomplete incremental update logic, missing object registration, and incorrect byte range / catalog updates.
  2. PDF/A-1a validation errors (transparency + missing required metadata)

Specifically: forbidden /Group transparency entries, missing metadata field F, and inconsistent XMP updates.

This PR ensures:

✔ Existing signatures remain valid after additional signatures
✔ New signatures are embedded incrementally with correct references
✔ PDF/A-1a conformance is preserved after each signature
✔ No transparency or structural violations are introduced
✔ PDFs remain readable in Adobe Reader, browsers, and validators

🧩 Why These Changes Were Necessary

  1. Anchoring of Prior Signatures (Incremental Signing)
    Before this PR, signing an already-signed PDF caused:

    • AcroForm inconsistencies
    • Signature fields not registered in incremental updates
    • Incorrect handling of /SigFlags
    • Objects rewritten instead of appended
    • Inconsistent ByteRangePrevious revisions becoming invalid

    ITI validation reported:

    “Signature not anchored”
    (“Assinatura não ancorada ao documento”)

    This PR updates the incremental signing logic to follow ISO-32000 rules, preserving all previous revisions.

  2. PDF/A-1a Transparency and Metadata Errors
    PDF/A validators (Acrobat Preflight, VeraPDF, ITI) reported:

    • Forbidden transparency (/Group dictionary)
    • Missing metadata field F
    • Unsynchronized or incomplete XMP packets
    • Non-compliant modifications after signing
      Root causes included:
    • Transparency groups being preserved
    • Metadata rewritten inconsistently
    • Missing required PDF/A fields
    • Incremental updates introducing forbidden entries
      This PR ensures:
      ✔ /Group is removed when PDF/A is active
      ✔ XMP metadata stays synchronized
      ✔ Required fields (including F) are present
      ✔ No transparency or forbidden operators are emitted

🛠 Overview of Changes
✔ Incremental Signature Improvements

  • Correct creation and registration of incremental signature fields
  • Ensured entries appear properly in /AcroForm /Fields
  • Added missing /SigFlags
  • Preserved previous revisions instead of overwriting objects
  • Improved ordering and creation of signature dictionaries
  • Fixed deterministic naming (Signature1, Signature2, etc.)
  • Corrected ByteRange and signature placeholder handling

✔ PDF/A-1a Compliance Fixes

  • Removed forbidden /Group entries when IsPdfA is enabled
  • Ensured XMP metadata is synchronized with Info dictionary
  • Added missing PDF/A required metadata fields (including FileName /F)
  • Prevented transparency or other forbidden features
  • Ensured incremental updates preserve PDF/A structure

✔ Structural Stability Fixes

  • Improved Catalog/AcroForm creation when missing
  • Added missing resource entries (/DR, /DA) when needed
  • Ensured only allowed objects are rewritten
  • Prevented emission of non-compliant structures during incremental writes

📜 Business Rules Implemented

This PR enforces the following rules:

  1. Multiple signatures must be allowed without invalidating earlier signatures.
  2. Each new signature is purely incremental unless explicitly disabled.
  3. PDF/A-1a conformance must be preserved after each signature.
  4. All signature fields must be explicitly created and correctly registered.
  5. Metadata and resources must remain consistent with PDF/A and ISO-32000..

🚀 Impact / Benefits

  • Reliable multi-signature support
  • PDF/A-1a documents remain compliant after signing
  • Compatibility improvements for:
    • Adobe Reader
    • Adobe Preflight
    • ICP-Brasil (ITI) validators
    • VeraPDF
    • Browser PDF viewers
  • Eliminates “non-anchored signature” errors
  • Eliminates PDF/A transparency and metadata violations

🧪 Tests Added / Updated

  • Incremental signature tests
  • PDF/A preservation tests
  • Validation of OutputIntents
  • Object structure integrity after incremental writes
  • Prevention of transparency re-introduction

🔄 Backward Compatibility

  • Fully backward compatible
  • Incremental signing is optional (enabled via flag)
  • PDF/A logic remains the same except when correcting invalid states

✔ Final Notes

This PR significantly enhances PDFsharp’s digital signature subsystem, with improvements focused on correctness, compliance, and real-world production reliability—especially in environments that depend on strict digital signature and PDF/A rules.

@dixit-atharva
Copy link

@pdizeev I tried to test the incremental sign but getting below error while opening out the PDF after second sign or AppendSignature has been set true.

System.InvalidOperationException: 'The file is not a valid PDF document.' This exception was originally thrown at this call stack: PdfSharp.Pdf.IO.PdfReader.OpenFromStream(System.IO.Stream, string, PdfSharp.Pdf.IO.PdfDocumentOpenMode, PdfSharp.Pdf.IO.PdfPasswordProvider, PdfSharp.Pdf.IO.PdfReaderOptions) in PdfReader.cs PdfSharp.Pdf.IO.PdfReader.OpenFromFile(string, string, PdfSharp.Pdf.IO.PdfDocumentOpenMode, PdfSharp.Pdf.IO.PdfPasswordProvider) in PdfReader.cs

@alex-vazz
Copy link

alex-vazz commented Nov 26, 2025

@pdizeev I tried to test the incremental sign but getting below error while opening out the PDF after second sign or AppendSignature has been set true.

System.InvalidOperationException: 'The file is not a valid PDF document.' This exception was originally thrown at this call stack: PdfSharp.Pdf.IO.PdfReader.OpenFromStream(System.IO.Stream, string, PdfSharp.Pdf.IO.PdfDocumentOpenMode, PdfSharp.Pdf.IO.PdfPasswordProvider, PdfSharp.Pdf.IO.PdfReaderOptions) in PdfReader.cs PdfSharp.Pdf.IO.PdfReader.OpenFromFile(string, string, PdfSharp.Pdf.IO.PdfDocumentOpenMode, PdfSharp.Pdf.IO.PdfPasswordProvider) in PdfReader.cs

Hi @dixit-atharva ,

It’s difficult to pinpoint the exact cause without knowing how the incremental signing workflow was implemented on your side.
What I can say with confidence is that the logic itself is functional — you can check the incremental signing test added in DefaultSignerTests.cs, which demonstrates the expected behavior.

One common scenario that can produce this exception is saving the second signature into a different output file.
In the test, you’ll notice that the same signedFile is used for both the first and second signatures, ensuring the incremental update chain remains intact.

If this does not match your situation, feel free to share a minimal example of your signing code (without any sensitive data, of course).
I’ll be glad to take a look and help identify what might be happening.

@dixit-atharva
Copy link

dixit-atharva commented Nov 26, 2025

@alex-vazz @pdizeev I did not implemented yet just testing out through the DefaultSignerTests.cs Sign_existing_pdf_incrementally_and_preserve_pdfa method.

@alex-vazz
Copy link

@dixit-atharva
Thanks for clarifying.
Since you're running the exact Sign_existing_pdf_incrementally_and_preserve_pdfa test from DefaultSignerTests.cs, it should normally pass.

Because of that, the most likely cause is an environment-specific factor (framework version, stream behavior, file permissions, PDF compression settings, etc.).
To help narrow this down, could you share:

  • Your .NET runtime / OS environment
  • Whether you’re running the tests from
    • Visual Studio
    • Rider
    • dotnet test
    • CI environment

If possible, the resulting signed PDF after the first signature (before the second one)

These details will make it much easier to reproduce the issue and understand what's causing the difference.

@gboinwink
Copy link

Hi @alex-vazz

I got the exact same issue when running the test.

Your .NET runtime / OS environment : Windows, .NET 8
I'm running the tests under Visual Studio 2026.

Here are the two files, after the first one, then second one.
signed-WIN-CORE-6.0-2B86999FD8_temp_2nd_sign.pdf
signed-WIN-CORE-6.0-C3874CAE91_temp_1st_sign.pdf

I'm managed to be able to open the second file when using a Stream for saving it, but one signature was failing.

Hope it helps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants