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
JavaScript
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
};