Skip to content

Gate PS256 and the rsa dependency behind a default-on ps256 feature - #9

Open
zshenker wants to merge 2 commits into
alg-confusion-fixfrom
ps256-feature
Open

zshenker wants to merge 2 commits into
alg-confusion-fixfrom
ps256-feature

Conversation

@zshenker

@zshenker zshenker commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #6 (base: alg-confusion-fix). It touches the same verify dispatch. Retarget to main once #6 merges.

Problem

PS256 makes rsa a hard dependency. rsa has an unfixed advisory, RUSTSEC-2023-0071 (Marvin, a private-key timing side channel). Every consumer running cargo-deny or cargo-audit is flagged, even when it only verifies ES256 or HMAC tokens. That includes verify-only services such as a MoQ relay validating tokens under #8, which never sign with RSA.

Change

  • New feature. rsa, sha2 and rand_core are now optional, behind a new ps256 feature. It is on by default, so existing PS256 users are unaffected.
  • Opting out. Consumers that don't need PS256 set default-features = false.
  • Variants stay. Algorithm::Ps256 and VerifyingKey::Ps256 remain in every build, so algorithm identifiers still parse and no downstream match changes. Without the feature, PS256 signing and verification return Error::InvalidAlgorithm.
  • Gating.
    • The PS256 tests and the RSA key-size helpers are gated with cfg.
    • The bench and the two asymmetric examples use required-features.
    • A new test_ps256_without_feature_is_rejected covers the no-feature path.
  • Salt length. PS256 signing and verification pass the RFC 8230 §2 salt length (32 bytes) explicitly instead of relying on the rsa default, and the minimum rsa version is 0.9.10. Signatures with any other salt length are refused. This was already the behavior of rsa 0.9.10, and is now explicit and tested.
  • CI. CI also runs cargo test --no-default-features.
  • Docs. README and CHANGELOG are updated.

Verification

  • With default features: fmt and clippy (-D warnings) pass, along with 61 unit tests and 74 doctests.
  • With --no-default-features: clippy passes, along with 54 unit tests and 74 doctests.
  • Salt length test. test_ps256_requires_rfc8230_salt_length covers 0-, 20-, 32- and 64-byte salts; only 32 is accepted.
  • MSRV 1.88: builds in both configurations.
  • All examples run.
  • Consumer check. A throwaway consumer with default-features = false gets a Cargo.lock with no rsa, and cargo audit on it is clean. This repo's own lockfile still lists rsa, because lockfiles always include optional dependencies.

🤖 Generated with Claude Code

rsa has an unfixed private-key timing advisory (RUSTSEC-2023-0071), so
any consumer running cargo-deny/cargo-audit is flagged even if it only
verifies ES256 or HMAC tokens. Make rsa, sha2 and rand_core optional
under a `ps256` feature, enabled by default so existing PS256 users are
unaffected; verify-only consumers can set default-features = false.

Algorithm::Ps256 and VerifyingKey::Ps256 remain in all builds so alg
identifiers still parse; without the feature, PS256 sign/verify return
Error::InvalidAlgorithm. PS256 tests, examples and the bench are gated,
and CI runs the suite with --no-default-features.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RFC 8230 §2 defines PS256 with a salt length equal to the SHA-256
output (32 bytes). rsa 0.9.10's pss keys already default to that and
refuse other lengths, but the behavior was implicit in a library
default and the dependency allowed any 0.9.x. Pass the salt length
explicitly when signing and verifying, require rsa >= 0.9.10, and add a
regression test that signatures with 0-, 20- and 64-byte salts are
refused while 32 is accepted.

Co-Authored-By: Claude Opus 5.5 <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