feat: support RSASSA-PSS signature algorithms (closes #624)#625
Merged
Conversation
## Spec reference
- xmldsig-core §6.4.2 — RSASSA-PSS signature method.
- xmldsig-more (W3C Note, 2007-05) — defines `sha256-rsa-MGF1`,
`sha384-rsa-MGF1`, `sha512-rsa-MGF1` URIs.
- saml-sec-consider §6.5 — recommends PSS over PKCS#1 v1.5 and calls for
algorithm agility.
- Audit follow-up F-7 (.skills/audits/2026-04-security-audit.md).
## Why
samlify previously advertised only the PKCS#1 v1.5 RSA-SHA{1,256,512}
URIs, leaving deployments that want RSASSA-PSS — the modern
recommendation per `xmldsig-core §6.4.2` and `saml-sec-consider §6.5` —
without an opt-in. This change closes that algorithm-agility gap while
preserving the pre-existing default (RSA-SHA256, PKCS#1 v1.5) so no
existing caller observes a behaviour change.
## What
- `src/urn.ts`: register the three `xmldsig-more` (2007-05) PSS URIs in
`algorithms.signature` and pair them in `algorithms.digest`. SHA-384's
digest URI (`xmldsig-more#sha384`) is added since no `xmlenc#sha384`
ever existed.
- `src/libsaml.ts`:
- extend `nrsaAliasMapping` with `pss-sha{256,384,512}` for the
redirect-binding detached signature path (`saml-bindings §3.4.4.1`)
via `node-rsa`'s built-in PSS schemes;
- add `RsaSha{256,384,512}Mgf1` plugin classes implementing
xml-crypto's `SignatureAlgorithm` interface, using Node's
`crypto.sign`/`crypto.verify` with `RSA_PKCS1_PSS_PADDING` and
`RSA_PSS_SALTLEN_DIGEST`;
- add a `Sha384Hash` plugin (xml-crypto v6.x ships SHA-1/256/512
only);
- register both on each `SignedXml` instance inside
`constructSAMLSignature` and `verifySignature` via
`registerPssAlgorithms`.
- Default signing algorithm is unchanged (RSA-SHA256, PKCS#1 v1.5).
PSS is opt-in via
`requestSignatureAlgorithm: algorithms.signature.RSA_SHA256_MGF1`.
## Tests
- algorithm-registry coverage: PSS URIs resolve and pair with the
correct digest URIs.
- redirect-binding round-trip (sign + verify) for each of SHA-256,
SHA-384, SHA-512 PSS variants — pins the node-rsa `pss-*` scheme
routing.
- post-binding XML-signature round-trip for each variant — pins the
xml-crypto SignatureAlgorithms / HashAlgorithms registration.
- F-3 regression: unknown signature URIs still throw
`ERR_UNSUPPORTED_SIGNATURE_ALGORITHM` after the registry expansion.
- default-stability pin: signing without an explicit algorithm still
produces a PKCS#1 v1.5 RSA-SHA256 signature (verifiable as such, and
*not* verifiable as PSS) — guards against accidentally moving the
default.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
c884fbc to
0c6ad57
Compare
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.
Summary
Closes #624. Adds RSASSA-PSS signature support — the three
xmldsig-more(W3C Note, 2007-05) URIssha256-rsa-MGF1,sha384-rsa-MGF1,sha512-rsa-MGF1— alongside the existing PKCS#1v1.5 set. Addresses audit follow-up F-7 in
.skills/audits/2026-04-security-audit.md.PSS is opt-in via
requestSignatureAlgorithm: algorithms.signature.RSA_SHA256_MGF1.The default stays RSA-SHA256 (PKCS#1 v1.5) per audit fix F-3 — existing
callers see zero behaviour change.
Spec reference
xmldsig-core §6.4.2— RSASSA-PSS signature method.xmldsig-more(W3C Note, 2007-05) — defines thesha256-rsa-MGF1/sha384-rsa-MGF1/sha512-rsa-MGF1URIs.saml-sec-consider §6.5— recommends PSS over PKCS#1 v1.5 and callsfor algorithm agility so deployments can move off legacy padding
without forking the library.
saml-bindings §3.4.4.1— octet-string construction for theHTTP-Redirect detached signature (PSS path goes through node-rsa's
pss-sha{256,384,512}schemes).saml-bindings §3.5— HTTP-POST envelope for the embedded XMLsignature (PSS path registers plugin classes on the xml-crypto
SignedXmlinstance).What changed
src/urn.tsalgorithms.signatureaddsRSA_SHA256_MGF1,RSA_SHA384_MGF1,RSA_SHA512_MGF1.algorithms.digestpairs each PSS URI with its digest URI.SHA-256 / SHA-512 reuse the existing
xmlencdigest URIs; SHA-384uses
xmldsig-more#sha384since noxmlenc#sha384was everpublished.
src/libsaml.tsnrsaAliasMappingaddspss-sha{256,384,512}for theredirect-binding detached-signature path. node-rsa v1.1.x ships PSS
built-in.
RsaSha{256,384,512}Mgf1plugin classes implementxml-crypto's
SignatureAlgorithminterface (verify againstnode_modules/xml-crypto/lib/types.d.ts). They use Node'scrypto.sign/crypto.verifywithRSA_PKCS1_PSS_PADDINGandRSA_PSS_SALTLEN_DIGEST.Sha384Hashplugin — xml-crypto v6.1.2 shipsSHA-1 / SHA-256 / SHA-512 only.
registerPssAlgorithms(sig)is called insideconstructSAMLSignatureand
verifySignatureto attach the new classes onto eachSignedXmlinstance viasig.SignatureAlgorithms/sig.HashAlgorithms. Confirmed against the installed v6.1.2 source —the API has shifted between major versions, so the registration
pattern was verified rather than assumed.
docs/signed-saml-request.md,docs/signed-saml-response.mdsaml-sec-consider §6.5while clarifying PSS is opt-in..skills/audits/2026-04-security-audit.mdPKCS#1 v1.5 is still pending in v3).
Constraints honoured
per audit F-3. Pinned by an explicit regression test.
pre-existing test suite (316 tests) continues to pass without
modification.
node_modules/xml-crypto/lib/signed-xml.js(v6.1.2) directly ratherthan guessing from version-skewed docs.
Caveats
HashAlgorithmsmap contains onlySHA-1 / SHA-256 / SHA-512. To support
sha384-rsa-MGF1we registera SHA-384 hash plugin alongside the signature plugins. This is
noted in the JSDoc on
Sha384Hash.i.e.
verifySignature(..., { signatureAlgorithm: RSA_SHA256_MGF1 })/
verifyMessageSignature(..., RSA_SHA256_MGF1). This is the samecontract the existing PKCS#1 v1.5 path uses.
Test plan
yarn test— all 325 tests pass (316 pre-existing + 9 new PSStests).
npx tsc --noEmit— clean.yarn coverage— every threshold (≥90% statements / branches /functions / lines) holds. Total: 97.34% stmts, 90.83% branches,
99.2% funcs, 97.34% lines.
signature) for all three PSS hashes.
three PSS hashes.
digest URI).
ERR_UNSUPPORTED_SIGNATURE_ALGORITHM.produces a PKCS#1 v1.5 RSA-SHA256 signature, verifiable as such,
not verifiable as PSS.
🤖 Generated with Claude Code