Skip to content

Size DSS /Contents dynamically with a retry fallback (#430)#431

Merged
kwart merged 2 commits into
masterfrom
fix/430/configurable-size
Jun 25, 2026
Merged

Size DSS /Contents dynamically with a retry fallback (#430)#431
kwart merged 2 commits into
masterfrom
fix/430/configurable-size

Conversation

@kwart

@kwart kwart commented Jun 25, 2026

Copy link
Copy Markdown
Member

Problem

The new EU DSS (PAdES) engine reserved DSS's fixed default of 9472 bytes for the CMS signature /Contents. That is too small for large certificate chains (eID / qualified certs) combined with an embedded signature timestamp, so signing consistently failed with:

The signature size [9472] is too small for the signature value with a length [14380].

Fixes #430.

Approach

The reservation must be fixed before the byte ranges are digested, so it cannot be derived from the produced signature. Instead:

  1. Estimate up front from the actual certificate chain (Σ cert.getEncoded().length) + overhead for the signer info / signed attributes / signature value / ASN.1 framing, plus a fixed TSA allowance when a timestamp is embedded. This covers the eID+TSA case in a single pass.
  2. Grow-and-resign as a safety net: if DSS still reports the reservation too small, parse the exact required length, grow by a margin and re-sign (capped, with a no-progress guard). For timestamped levels each retry refetches the TSA token, hence the cap.

Both behaviours are configurable via EngineConfig:

Key Default Meaning
engine.dss.contentSize 0 Explicit reserved /Contents size in bytes; 0 = auto-estimate
engine.dss.retryOnUndersize true Grow the reservation and re-sign if DSS reports it too small

Tradeoffs

  • Common eID+TSA case now signs in one pass — no double TSA call, no PKCS#11 PIN re-prompt.
  • The retry path repeats signing (and refetches a TSA token), so it is capped; the generous up-front estimate keeps it off the hot path.
  • The only residual fragility is parsing the required size out of DSS's exception message text (DSS exposes no typed getter); that path is a fallback and degrades gracefully to doubling.

Tests

Added 3 tests (14 total, all green):

  • undersize recovers via retry
  • undersize fails when retry disabled
  • generous explicit content size signs in one pass

🤖 Generated with Claude Code

kwart and others added 2 commits June 25, 2026 16:54
The DSS engine reserved DSS's fixed default of 9472 bytes for the CMS
/Contents, which is too small for large certificate chains (eID /
qualified certs) combined with an embedded signature timestamp. Signing
then failed with "The signature size [9472] is too small ...".

Estimate the reservation from the actual certificate chain plus a fixed
timestamp allowance so the common eID+TSA case signs in a single pass,
and grow-and-resign when DSS still reports it too small. Both behaviours
are configurable:

- engine.dss.contentSize: explicit reserved size (0 = auto-estimate)
- engine.dss.retryOnUndersize: grow and re-sign on undersize (default on)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When an undersized /Contents cannot be recovered (retry disabled, or
exhausted) the only feedback was DSS's raw exception naming
setContentSize(...), a DSS API call rather than a JSignPdf setting. Log
an actionable message that names the two knobs and a concrete value:
enable engine.dss.retryOnUndersize, or raise engine.dss.contentSize.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kwart kwart merged commit 2816f19 into master Jun 25, 2026
1 check passed
@kwart kwart deleted the fix/430/configurable-size branch June 25, 2026 20:58
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.

PAdES doesn't work in JSignPdf_3_1_0-RC-1

1 participant