Skip to content

jws: Verify rejects b64=false without "b64" listed in "crit" - #2102

Merged
lestrrat merged 1 commit into
develop/v3from
fix-v3-verify-b64-false-requires-crit
Apr 29, 2026
Merged

lestrrat merged 1 commit into
develop/v3from
fix-v3-verify-b64-false-requires-crit

Conversation

@lestrrat

Copy link
Copy Markdown
Collaborator

v3 backport of #2101.

RFC 7797 §3 requires producers that set b64=false to also list b64 in crit; §6 ties this to RFC 7515's critical-header-parameter rule. VerifyCompactFast rejects any b64-bearing message outright; jws.Verify silently accepted the non-conformant shape (b64=false with no crit, or crit missing b64).

Adds validateB64InCritIfFalse called from both VerifyMessage and verifyStreaming inside the existing critValidation block. v3 critValidation defaults to false, so the new check is opt-in here (jws.WithCritValidation(true)); behavior on v3 default config is unchanged. v4's default is true, so the v4 PR rejects the non-conformant shape by default.

Regression test mirrors TestVerifyCompactFastRefusesB64False on the slow path. Also extracts the duplicated {"alg":"HS256","b64":false} literal into a shared package const.

v3 backport of #2101.

RFC 7797 §3 requires producers that set "b64":false in the protected
header to also include "b64" in the "crit" array; §6 ties this to RFC
7515's critical-header-parameter rule. VerifyCompactFast already rejects
any b64-bearing message outright (jws.ErrB64Present), but jws.Verify
silently accepted the non-conformant shape — b64=false on the wire with
no crit, or with a crit that doesn't list "b64". A strictly conformant
verifier would compute a different signing input on the same bytes,
exactly the cross-implementation disagreement §6 was designed to prevent.

Adds validateB64InCritIfFalse in verify_context.go, called from both
VerifyMessage and verifyStreaming inside the existing critValidation
block. v3 critValidation defaults to false so the new check is opt-in
on this branch (use jws.WithCritValidation(true)); v4 critValidation
defaults to true so the v4 PR rejects the non-conformant shape by
default. Behavior on v3 default config is unchanged.

Includes a regression test that mirrors TestVerifyCompactFastRefusesB64False
on the slow path. Also extracts the duplicated `{"alg":"HS256","b64":false}`
literal into a shared package const to head off the goconst lint warning.
@lestrrat
lestrrat merged commit e02536b into develop/v3 Apr 29, 2026
14 checks passed
@lestrrat
lestrrat deleted the fix-v3-verify-b64-false-requires-crit branch April 29, 2026 22:49
lestrrat added a commit that referenced this pull request Apr 29, 2026
v3 backport of #2103.

RFC 7797 §3 requires producers that set "b64":false to also list "b64"
in "crit". Callers who set b64=false typically forget the crit
declaration; the resulting JWS is non-conformant and fails to interop
with strict verifiers.

Auto-add "b64" to the protected header's crit array inside Sign whenever
b64=false is set. Idempotent: pre-existing crit with b64 unchanged;
crit with other extensions gets "b64" appended; absent crit is created
with just "b64".

This pairs with the v3 Verify-side change in #2102, which makes
jws.Verify (under WithCritValidation(true)) refuse non-conformant
b64=false streams. Together they close the producer/verifier gap on v3.
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