You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: harden JWS constructors and bump golangci-lint for Go 1.27
Reject key/alg mismatches at NewJWS* construction, document SetAllowedAlgs vs foreign JWS, and move lint to v2.13.1 so CI can target go.mod 1.27.0. Track upstream jwx ECDSA/ML-DSA AlgorithmsForKey gaps for later.
Co-authored-by: Cursor <cursoragent@cursor.com>
@@ -93,7 +93,8 @@ No change to key types or httpsign `SignConfig` / `VerifyConfig` / `Fields` for
93
93
94
94
| Item | Requirement |
95
95
|------|-------------|
96
-
| Go |**1.27.0+** in `go.mod` / CI (today CI is still 1.24) |
96
+
| Go |**1.27.0+** in `go.mod` / CI |
97
+
| golangci-lint |**≥ v2.13** (built with Go 1.27; v2.12.x fails with go.mod `1.27.0`) |
97
98
|`GOEXPERIMENT=jsonv2`| Not required; do not set |
98
99
|`GOEXPERIMENT=nojsonv2`| Avoid in CI |
99
100
@@ -111,12 +112,26 @@ Scoped to httpsign’s use of **jwa** + **jws** only (no JWT/JWE/JWK fetch in li
111
112
-[x] Rewrite imports `jwx/v2|v3` → `jwx/v4`; collapse constructors; update `sign()` / `verify()` dispatch for v4 `jws.Signer` / `jws.Verifier` (renamed from v3 `Signer2` / `Verifier2`; parameter order matches today’s V3 path: key before payload).
112
113
-[x] Confirm factory APIs (`SignerFor` / `VerifierFor`) and `NoSignature` rejection still work.
113
114
-[x] Drop v2↔v3 cross-compat tests; keep round-trip tests on the single v4 path.
114
-
-[x]**PQ:** foreign-JWS round-trip with `crypto/mldsa` + `jwa.MLDSA65()` (and smoke 44/87 if cheap); document in README/release notes.
115
+
-[x]**PQ:** foreign-JWS round-trips with `crypto/mldsa` + `jwa.MLDSA44/65/87()`; document in README/release notes.
115
116
-[ ] Run `jwxmigrate --fix` if helpful; fix remaining compile/test failures by hand. *(done by hand; migrate tool optional)*
116
117
-[x] CI (`test.yml`, `lint.yml`, CodeQL): Go **1.27**; do not set `jsonv2` / `nojsonv2`.
118
+
-[x] Lint: bump **golangci-lint ≥ v2.13** (v2.12.2 is built with go1.26 → fails on go.mod 1.27.0).
117
119
-[x] Docs: README / `CLAUDE.md` / this file — remove dual-version guidance; **`v0.6.0`** release notes with caller steps + PQ; link upstream Changes-v4 if relevant.
120
+
-[x] Hardening: constructor `jws.AlgorithmsForKey` check; reject `NoSignature`; HMAC keys must be `[]byte`; document `SetAllowedAlgs` vs JWS alg.
118
121
-[ ] Tag **`v0.6.0`** and publish. *(after merge)*
119
122
123
+
### Later action: upstream jwx / dsig (found 2026-08-26 while hardening)
124
+
125
+
Not blocking `v0.6.0`. File / track upstream issues; optionally tighten httpsign further if upstream stays loose.
126
+
127
+
| Finding | Severity | Notes |
128
+
|---------|----------|-------|
129
+
|**`jws.AlgorithmsForKey` ignores ECDSA curve** for raw `*ecdsa.{Private,Public}Key`| Correctness | Returns `[ES256, ES384, ES512]` for any EC key. Docs claim curve is inferred from the Go type, but `hasCrv` is never set for stdlib ECDSA; `RegisterAlgorithmForCurve` is only used for Ed25519 in init (no P-256→ES256 etc.). |
130
+
|**ECDSA Sign/Verify do not enforce RFC 7518 curve↔alg**| Spec / footgun |`ES384` effectively means SHA-384 only; a **P-256** key can mint `"alg":"ES384"` and verify with the same P-256 pub (64-byte sig). Will not verify under a real P-384 key. Policy that allows only ES384 expecting P-384 strength can accept weaker P-256+SHA-384 if a P-256 key is registered. dsig examples treat cross-curve as intentional for custom algs. |
131
+
|**`AlgorithmsForKey` lists all ML-DSA algs** for any ML-DSA key | Classifier only | Sign/Verify correctly reject parameter-set mismatch — crypto path is fine; helper is over-broad (same class of bug as ECDSA listing). |
132
+
133
+
**Suggested upstream asks (lestrrat-go/jwx + dsig):** (1) extract curve from raw ECDSA keys in `AlgorithmsForKey` and register P-256/P-384/P-521 → ES256/ES384/ES512; (2) optionally enforce curve↔alg in ECDSA Sign/Verify; (3) refine ML-DSA listing by parameter set. **httpsign follow-up:** if upstream does not tighten ECDSA, consider our own curve check in `validateJWSKeyAlg` (and ML-DSA `Parameters()` vs `jwa.MLDSA*`).
0 commit comments