first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
# `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 "<header>.<payload>." — 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<undefined>` — verify `(input, sig)` returns `Promise<boolean>` (`true` iff `sig.length === 0`); sign `(input, _)` returns `Promise<Uint8Array>` 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 `"<hdr>.<payload>.deadbeef"` with `alg: "none"` is rejected because the signature bytes are non-zero.