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,84 @@
# jwk/thumbprint
## Purpose
Compute the JWK Thumbprint of an RSA public key per RFC 7638 §3.2. The
thumbprint is a deterministic hash over the canonical JSON form of the
public-key members (`e`, `kty`, `n` in alphabetical order with no
whitespace), giving every RSA key a stable identifier independent of
its wire format. Used downstream for `kid` derivation, key rotation
diffing, and key-pinning protocols.
## Features
- RFC 7638 §3.2 conformant — RSA member ordering `e`, `kty`, `n`
- Default SHA-256 hash; SHA-1 / SHA-384 / SHA-512 supported via `hash` option
- Accepts both canonical `RsaPublicKey` and `RsaJwk` shapes
- Hand-built canonical JSON byte string (does NOT use `JSON.stringify` —
member order is implementation-defined for that API)
- Worked-example matched against the RFC 7638 §3.1 reference value
`"NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"`
- `jwkThumbprintBase64Url` convenience returns the URL-safe base64 encoding directly
- All thrown errors are `CryptoRsaError` with `INVALID_KEY` /
`UNSUPPORTED_HASH`
## Usage: Basic Example
```ts
import { jwkThumbprint } from "@suaveplan/crypto-rsa/jwk";
const fingerprint = jwkThumbprint(publicKey);
// 32 bytes (SHA-256 default)
```
## Usage: Advanced Example
The `kid` JWK member is conventionally set to the base64url-encoded
SHA-256 thumbprint. Combine `jwkThumbprintBase64Url` with
`serializeRsaPublicKeyJwk` to populate it on emit:
```ts
import {
jwkThumbprintBase64Url,
serializeRsaPublicKeyJwk,
} from "@suaveplan/crypto-rsa";
const baseJwk = serializeRsaPublicKeyJwk(publicKey);
const jwkWithKid = {
...baseJwk,
kid: jwkThumbprintBase64Url(publicKey),
};
```
## API Reference
### `jwkThumbprint(key, options?)`
- `key: RsaPublicKey | RsaJwk` — public key or JWK
- `options.hash?: RsaHashAlgorithm` — defaults to `"SHA-256"`
- **returns** `Uint8Array` — digest bytes
- **throws** `CryptoRsaError(CRYPTO_RSA.UNSUPPORTED_HASH)` on bad hash;
`CRYPTO_RSA.INVALID_KEY` on missing `e` or `n`
### `jwkThumbprintBase64Url(key, options?)`
Convenience: returns `toBase64Url(jwkThumbprint(key, options))`.
### `JwkThumbprintOptions`
- `hash?: RsaHashAlgorithm`
## Implementation Notes
- The canonical JSON byte string is `'{"e":"<b64u(e)>","kty":"RSA","n":"<b64u(n)>"}'`.
Members are alphabetically ordered per RFC 7638 §3.2; only the three
required members participate in the digest.
- `JSON.stringify` is NOT used because member-order in object iteration
is implementation-defined for non-integer keys; constructing the byte
string by hand is the only correctness-stable approach.
- When the input is a `RsaPublicKey` (canonical bigint form), the
implementation routes through `serializeRsaPublicKeyJwk` to obtain
the base64url members, then concatenates the canonical JSON shape.
- Hash algorithm validation runs BEFORE member-validity checks so
consumers see `UNSUPPORTED_HASH` on bad hashes regardless of key
validity — useful for fail-fast configuration validators.