UNPKG

jose

Version:

JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes

56 lines (55 loc) • 2.74 kB
import { digest, encode } from "../lib/buffer_utils.js"; import { encode as b64u } from "../util/base64url.js"; import { JOSENotSupported, JWKInvalid } from "../util/errors.js"; import { isKeyLike, invalidKeyInput, snapshotJwk } from "../lib/key.js"; import { isObject } from "../lib/validate.js"; import { exportJWK } from "../key/export.js"; const check = (value, description) => { if (typeof value != "string" || !value) throw new JWKInvalid(`${description} missing or invalid`); }; async function calculateJwkThumbprint(key, digestAlgorithm) { let jwk; if (isObject(key)) { if (jwk = snapshotJwk(key), typeof jwk.kty != "string") throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "JSON Web Key")); } else if (isKeyLike(key)) jwk = snapshotJwk(await exportJWK(key)); else throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "JSON Web Key")); if (digestAlgorithm ??= "sha256", digestAlgorithm !== "sha256" && digestAlgorithm !== "sha384" && digestAlgorithm !== "sha512") throw new TypeError('digestAlgorithm must one of "sha256", "sha384", or "sha512"'); let requiredMembers; switch (jwk.kty) { case "AKP": check(jwk.alg, '"alg" (Algorithm) Parameter'), check(jwk.pub, '"pub" (Public key) Parameter'), requiredMembers = { alg: jwk.alg, kty: jwk.kty, pub: jwk.pub }; break; case "EC": check(jwk.crv, '"crv" (Curve) Parameter'), check(jwk.x, '"x" (X Coordinate) Parameter'), check(jwk.y, '"y" (Y Coordinate) Parameter'), requiredMembers = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y }; break; case "OKP": check(jwk.crv, '"crv" (Subtype of Key Pair) Parameter'), check(jwk.x, '"x" (Public Key) Parameter'), requiredMembers = { crv: jwk.crv, kty: jwk.kty, x: jwk.x }; break; case "RSA": check(jwk.e, '"e" (Exponent) Parameter'), check(jwk.n, '"n" (Modulus) Parameter'), requiredMembers = { e: jwk.e, kty: jwk.kty, n: jwk.n }; break; case "oct": if (typeof jwk.k != "string") throw new JWKInvalid('"k" (Key Value) Parameter missing or invalid'); requiredMembers = { k: jwk.k, kty: jwk.kty }; break; default: throw new JOSENotSupported('"kty" (Key Type) Parameter missing or unsupported'); } const thumbprintInput = encode(JSON.stringify(requiredMembers)); return b64u(await digest(digestAlgorithm, thumbprintInput)); } async function calculateJwkThumbprintUri(key, digestAlgorithm) { digestAlgorithm ??= "sha256"; const thumbprint = await calculateJwkThumbprint(key, digestAlgorithm); return `urn:ietf:params:oauth:jwk-thumbprint:sha-${digestAlgorithm.slice(-3)}:${thumbprint}`; } export { calculateJwkThumbprint, calculateJwkThumbprintUri };