feat(tsa): let administrators choose the hash algorithm of the timestamp query - #8276
Merged
vitormattos merged 5 commits intoSep 6, 2026
Merged
Conversation
maia-andre
force-pushed
the
feat/8145-tsa-hash-algorithm
branch
from
September 6, 2026 14:39
0b2af67 to
10f18a5
Compare
Contributor
Author
|
Rebased on the updated #8275: the JSignPdf classes moved to |
… class The hash algorithm that signs a document depends on the PDF version, so it is not a valid answer for the other hashes JSignPdf takes: reusing it would send SHA1 to a timestamp authority whenever the document is older than PDF 1.6. Issue LibreSign#8145 asks for each hash to be resolved on its own, which is hard to guarantee while the rules live inside the handler as private methods. Move getHashAlgorithm(), getHashAlgorithmForPdfVersion(), validateHashAlgorithm() and requiresPdfVersionUpgradeForSha256() to HashAlgorithmResolver, where each hash gets its own entry point and can be tested in isolation. The handler keeps reading the PDF version, the only part that is about the document and not about the policy. No behavior change: the same version thresholds, the same fallback to SHA256 and the same supported algorithms. Signed-off-by: André Maia <andrefnkmm@gmail.com> Assisted-by: Claude Code:claude-opus-5
Both the handler and the resolver carry rules that only make sense for
JSignPdf — the PDF version thresholds come from its own HashAlgorithm enum —
so they move to SignEngine/JSignPdf/ and the resolver keeps a name that does
not need to repeat the engine.
Pkcs12Handler used to build the handler class name at runtime from the
configured engine ('...\SignEngine\' . ucfirst($property)), a string no
static analysis, IDE rename or grep could follow: moving the class would
only fail when a document was signed. It now resolves through an explicit
map, so a name that is not an engine answers the same friendly error instead
of reaching the container.
Signed-off-by: André Maia <andrefnkmm@gmail.com>
Assisted-by: Claude Code:claude-opus-5
The hash of the timestamp query was never configurable: JSignPdf decided it alone, and LibreSign#8145 reports authorities rejecting the request because of that choice. It belongs to the TSA settings, next to the URL, the policy OID and the authentication, so every tenant that configures its own authority can also say what that authority expects. SHA256 is the default and keeps what JSignPdf 3.1.0 already does. SHA1 is not offered: it is the algorithm the authorities in the report refuse. Signed-off-by: André Maia <andrefnkmm@gmail.com> Assisted-by: Claude Code:claude-opus-5
…uthority JSignPdf decided the timestamp hash by itself, and the authorities in LibreSign#8145 answer HTTP 400 when that choice is not the one they expect. Send --tsa-hash-algorithm from the TSA policy instead, spelled the way JSignPdf wants it (SHA-256, with the hyphen, unlike --hash-algorithm). The resolver answers this hash on its own, never from the signature one: that one follows the PDF version and would ask for SHA1 on any document older than PDF 1.6, which is the request the authority rejects. The php native engine reads the same policy, so it stops being pinned to SHA-256 and follows what the administrator chose. Signed-off-by: André Maia <andrefnkmm@gmail.com> Assisted-by: Claude Code:claude-opus-5
The algorithm of the timestamp query is now part of the TSA policy, so it belongs next to the URL, the policy OID and the authentication: the administrator who knows which authority is being used is the one who knows what it accepts. The select offers SHA-256, SHA-384 and SHA-512, spelled the way the authorities document them, and defaults to SHA-256. Signed-off-by: André Maia <andrefnkmm@gmail.com> Assisted-by: Claude Code:claude-opus-5
maia-andre
force-pushed
the
feat/8145-tsa-hash-algorithm
branch
from
September 6, 2026 14:46
10f18a5 to
f545682
Compare
|
Codecov Report❌ Patch coverage is
... and 211 files with indirect coverage changes 🚀 New features to boost your workflow:
|
vitormattos
approved these changes
Sep 6, 2026
Member
|
/backport to stable35 |
Merged
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves: #8145
📝 Summary
The last of the three parts of #8145: the hash algorithm of the timestamp query becomes an option of
the TSA policy, next to the URL, the policy OID and the authentication.
Until now nobody could choose it. JSignPdf picked its own default — SHA-1 up to 2.3.0, SHA-256 since
3.1.0 — and the authorities in the report answer
HTTP 400when that choice is not the one theyexpect. The administrator who configures the authority is the one who knows what it accepts, and in
a multi-tenant instance each TSA rule now carries its own answer.
hash_algorithminsidetsa_settings, defaultSHA256.SHA1is not offered: it isthe algorithm the authorities in the report refuse.
--tsa-hash-algorithmis sent with the configured value, spelled the way JSignPdfdocuments it (
SHA-256, with the hyphen, unlike--hash-algorithm).does not silently do nothing when that engine signs.
version and returns SHA1 for documents older than PDF 1.6 — exactly the request TSA timestamping always fails with JSignPdf: --tsa-hash-algorithm is never passed, SHA-1 is used #8145 reports as
rejected.
Existing instances are not affected: the policy value is decoded with
SHA256when the key isabsent, which is what JSignPdf 3.1.0 already does.
🚧 Tasks
commits once it lands). fix(jsignpdf): improve the diagnosis of TSA failures #8274 is independent and can go in any order.
🧪 How to test
vendor/bin/phpunit -c tests/php/phpunit.xml --no-coverage --testsuite unit npm run testIn the interface: Administration settings → LibreSign → Timestamp Authority → Change, turn the
timestamp server on and pick an algorithm.
occ config:app:get libresign tsa_settingsshows thestored value.
Manual verification (Nextcloud 35 devcontainer, LibreSign 16.0.0-dev)
OID and the authentication.
occ config:app:get libresign tsa_settings:{"url":"https://freetsa.org/tsr","policy_oid":"","auth_type":"none","username":"","hash_algorithm":"SHA512"}🎨 UI / Front‑end changes
TSA hash algorithmselect in the TSA rule editor (SHA-256, SHA-384, SHA-512)NcSelectalready used for the authenticationtype, with its own label
⚙️ API / Back‑end changes
TsaPolicyValuegainshash_algorithm(defaultSHA256, validated against SHA256/SHA384/SHA512)HashAlgorithmResolver::forTsa()answers the timestamp hash from the TSA policy, never from the signature oneJSignPdfHandlersends--tsa-hash-algorithm;PhpNativeHandlerpasses the same value to the signer libraryNo API or capability change: the policy value keeps the same shape, with one more key.
✅ Checklist
AEngineHandlerTest::testSetEngineConfiguresIdentifyMethodsForNoneEnginefailures, which come from state left by other test classes (that class passes 26/26 alone)
vue-tsc --noEmitclean🤖 AI (if applicable)