# `none` algorithm ## Purpose RFC 7518 §3.6 `"none"` algorithm. The `none` value declares "no integrity protection," which is virtually never what a verifier wants but is occasionally needed for non-security-critical contexts (signed-by-policy local development, deliberately-unsigned debugging payloads). This implementation exists only so the registry is complete; the verify pipeline rejects `none` by default and requires BOTH `algorithms: ["none"]` AND `acceptNone: true` to opt in, neutralising the classic "alg: none" downgrade attack. ## Features - `verify` returns `true` if-and-only-if the signature segment is empty (zero bytes after base64url-decode). - `sign` always emits empty signature bytes. - Default rejection: pipeline throws `JWS.ALG_NONE_DISABLED` unless both flags are set. ## Usage: Basic Example ```ts import { compactSign, compactVerify } from "@suaveplan/jws"; const token = await compactSign("hello", undefined, "none"); // token has the form "
.." — empty signature segment. await compactVerify(token, undefined, { algorithms: ["none"], acceptNone: true, }); ``` ## Usage: Advanced Example ```ts import { compactVerify, JwsError } from "@suaveplan/jws"; const noneToken = "eyJhbGciOiJub25lIn0.eyJzdWIiOjF9."; // Default: rejected. try { await compactVerify(noneToken, undefined, { algorithms: ["HS256"] }); } catch (err) { if (err instanceof JwsError && err.code === "JWS.ALG_NONE_DISABLED") { // CVE-class defence in depth. } } // Allowlisted but no acceptNone — also rejected. try { await compactVerify(noneToken, undefined, { algorithms: ["none"] }); } catch (err) { if (err instanceof JwsError && err.code === "JWS.ALG_NONE_DISABLED") { // Two flags required. } } ``` ## API Reference - `none: AlgorithmImpl` — verify `(input, sig)` returns `Promise` (`true` iff `sig.length === 0`); sign `(input, _)` returns `Promise` of length 0. ## Implementation Notes The two-flag opt-in design is a deliberate defence against the historic JWT-CVE class where a caller passes `algorithms: ["HS256"]` AND a public key, then an attacker mints a token with `alg: "none"` and the library accepts it because the allowlist is parsed permissively. Here, even a deliberate `algorithms: ["none"]` requires the second flag `acceptNone: true` — the second flag is intentionally separate so a single typo or merged configuration cannot accidentally accept unsigned tokens. The implementation also requires the signature segment to be empty, not "not present" — a token like `"..deadbeef"` with `alg: "none"` is rejected because the signature bytes are non-zero.