Skip to content

SignatureAppearance.Page is documented but ignored — visible signature always attaches to the first page #69

Description

@DiegoFSFlor

Summary

SignatureAppearance.Page is documented as "Page number (1-based) where the signature
annotation is placed", but the value is never read by the signing pipeline. Regardless
of what Page is set to, the visible signature widget annotation is always attached to
the first page of the document.

Root cause

In SimpleSign.PAdES/Signing/PdfSignatureWriter.cs, the page used to anchor the
signature widget annotation is always resolved via:

var (pageObjNum, pageObjDictStart, pageObjDictEnd) = PdfStructureParser.FindFirstPageObject(inputMem.Span);

options.Appearance.Page is never read anywhere in this file to select a different
page — it's not used to pick which page object to resolve.

Looking at SimpleSign.Pdf/PdfStructureParser.cs, there is currently no method to
locate the Nth page — only:

public static (int ObjNum, int DictStart, int DictEnd) FindFirstPageObject(ReadOnlySpan<byte> data)

So there's no way, even internally, to resolve any page other than the first for the
signature annotation.

Repro

var appearance = new SignatureAppearance
{
    Page = 3,          // PDF has 4+ pages
    X = 50,
    Y = 50,
    AutoPosition = false
};

var signed = await SimpleSigner
    .Document(pdfBytes)
    .WithCertificate(cert)
    .WithAppearance(appearance)
    .SignAsync();

Expected: signature widget appears on page 3.
Actual: signature widget appears on page 1, every time, regardless of the Page value.

Environment

  • Package: SimpleSign.Brasil (and SimpleSign core)
  • Version: 0.7.0
  • Target framework: .NET 8

Suggested fix

Add a page-resolution method to PdfStructureParser that walks the /Pages/Kids
tree to the Nth page (reusing the same traversal/ObjStm-fallback logic already present
in FindFirstPageObjNumFromCatalog), e.g.:

public static (int ObjNum, int DictStart, int DictEnd) FindNthPageObject(ReadOnlySpan<byte> data, int pageNumber)

And in PdfSignatureWriter.cs, branch on options.Appearance?.Page:

var (pageObjNum, pageObjDictStart, pageObjDictEnd) =
    (options.Appearance?.Page ?? 1) > 1
        ? PdfStructureParser.FindNthPageObject(inputMem.Span, options.Appearance.Page)
        : PdfStructureParser.FindFirstPageObject(inputMem.Span);

Happy to help test against real-world PDFs (including PDFs with pages in compressed
ObjStm) if useful — this is a blocker for us for any multi-page document where the
signature isn't meant to go on page 1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions