Skip to content

sign: write /Perms /DocMDP for a certification signature - #165

Open
uinoushi wants to merge 1 commit into
digitorus:mainfrom
DJSNGroup:fix/certification-signature-perms-docmdp
Open

uinoushi wants to merge 1 commit into
digitorus:mainfrom
DJSNGroup:fix/certification-signature-perms-docmdp

Conversation

@uinoushi

Copy link
Copy Markdown

The problem

CertType: CertificationSignature writes the DocMDP transform into the signature dictionary:

/Reference [ << /Type /SigRef /TransformMethod /DocMDP
               /TransformParams << /Type /TransformParams /P 1 /V /1.2 >> >> ]

but the document catalog never gains the matching /Perms entry. ISO 32000-1 §12.8.2.2:

A document can contain only one signature field that contains a DocMDP transform method; it shall be the first signed field in the document. The Perms entry in the document catalog dictionary shall contain a DocMDP entry whose value is the signature dictionary of that signature field.

Both halves are required. The /P value states the permission level; /Perms is what makes a conforming reader apply it.

Without /Perms, the output is an ordinary approval signature. The failure is quiet: the file verifies, and tools that report the signature type still find the DocMDP transform in /Reference — but Acrobat shows no "Certified by" bar and the /P restriction is not enforced. Comparing a pdfsign-certified file against an Adobe Acrobat Sign-certified one, /Perms<</DocMDP N 0 R>> in the catalog is the only structural difference.

createCatalog already carries the comment // Set SigFlags and Permissions based on Signature Type over a switch that only ever writes /SigFlags, so this looks like an intent that was never finished rather than a deliberate omission.

The fix

Six lines in createCatalog. SignData.objectId holds the signature dictionary's object number and is populated by addSignatureObject, which SignPDF runs before addCatalog — so the reference is available exactly where it is needed, and no ordering change is required.

There is no caller-side workaround: PreSignCallback runs before the signature object exists, UpdateObject is overwritten by the catalog addCatalog writes afterwards, and a second incremental update would invalidate the signature it is trying to describe.

Tests

TestCertificationSignatureSetsPermsDocMDP signs testfiles/testfile20.pdf as both a certification and an approval signature and asserts that:

  • a certification signature's /Perms /DocMDP resolves to the /Type /Sig object, whose /Reference carries /TransformMethod /DocMDP and /TransformParams /P 1;
  • an approval signature writes no /Perms at all.

It fails on the unpatched tree with "certification signature has no catalog /Perms". The two CertificationSignature golden catalogs in TestCreateCatalog gain the entry, with the signature object number pinned so the expectation stays deterministic.

go build ./... && go vet ./... && go test ./... is green.


Found while evaluating pdfsign for a PAdES certification seal over documents composed with pdfcpu. Happy to adjust the shape — e.g. gating it on DocMDPPerm != 0, or emitting /Perms for other cert types — if you'd prefer something different.

A CertificationSignature produced a signature dictionary with the DocMDP
transform — /Reference -> /TransformMethod /DocMDP -> /TransformParams /P —
but the document catalog never gained the matching /Perms entry.

ISO 32000-1 12.8.2.2 requires both: "The Perms entry in the document catalog
dictionary shall contain a DocMDP entry whose value is the signature
dictionary of that signature field." The /P value states the permission
level; /Perms is what makes a conforming reader apply it.

Without it the output is an ordinary approval signature. That failure is
silent — the file still verifies, and tooling that reports the signature type
still reports the DocMDP transform from the /Reference array — but Acrobat
shows no "Certified by" bar and the /P restriction is not enforced.

createCatalog already had the comment "Set SigFlags and Permissions based on
Signature Type" over a switch that only ever wrote /SigFlags.
SignData.objectId holds the signature dictionary's object number and is
populated by addSignatureObject, which SignPDF runs before addCatalog, so the
reference is available at the point the catalog is built.

The new test signs testfile20.pdf both ways and asserts that a certification
signature's /Perms /DocMDP resolves to the /Type /Sig object carrying /P 1,
and that an approval signature writes no /Perms at all. It fails on the
unpatched tree. The two CertificationSignature golden catalogs in
TestCreateCatalog gain the entry, with the signature object number pinned so
the expectation stays deterministic.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant