UNPKG

@gaonengwww/jose

Version:

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

204 lines (197 loc) 6.03 kB
// src/util/errors.ts var JOSEError = class extends Error { /** * A unique error code for the particular error subclass. * * @ignore */ static code = "ERR_JOSE_GENERIC"; /** A unique error code for {@link JOSEError}. */ code = "ERR_JOSE_GENERIC"; /** @ignore */ constructor(message2, options) { super(message2, options); this.name = this.constructor.name; Error.captureStackTrace?.(this, this.constructor); } }; var JOSENotSupported = class extends JOSEError { /** @ignore */ static code = "ERR_JOSE_NOT_SUPPORTED"; /** A unique error code for {@link JOSENotSupported}. */ code = "ERR_JOSE_NOT_SUPPORTED"; }; // src/lib/subtle_dsa.ts var subtle_dsa_default = (alg, algorithm) => { const hash = `SHA-${alg.slice(-3)}`; switch (alg) { case "HS256": case "HS384": case "HS512": return { hash, name: "HMAC" }; case "PS256": case "PS384": case "PS512": return { hash, name: "RSA-PSS", saltLength: parseInt(alg.slice(-3), 10) >> 3 }; case "RS256": case "RS384": case "RS512": return { hash, name: "RSASSA-PKCS1-v1_5" }; case "ES256": case "ES384": case "ES512": return { hash, name: "ECDSA", namedCurve: algorithm.namedCurve }; case "Ed25519": // Fall through case "EdDSA": return { name: "Ed25519" }; default: throw new JOSENotSupported( `alg ${alg} is not supported either by JOSE or your javascript runtime` ); } }; // src/lib/check_key_length.ts var check_key_length_default = (alg, key) => { if (alg.startsWith("RS") || alg.startsWith("PS")) { const { modulusLength } = key.algorithm; if (typeof modulusLength !== "number" || modulusLength < 2048) { throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`); } } }; // src/lib/crypto_key.ts function unusable(name, prop = "algorithm.name") { return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`); } function isAlgorithm(algorithm, name) { return algorithm.name === name; } function getHashLength(hash) { return parseInt(hash.name.slice(4), 10); } function getNamedCurve(alg) { switch (alg) { case "ES256": return "P-256"; case "ES384": return "P-384"; case "ES512": return "P-521"; default: throw new Error("unreachable"); } } function checkUsage(key, usage) { if (usage && !key.usages.includes(usage)) { throw new TypeError( `CryptoKey does not support this operation, its usages must include ${usage}.` ); } } function checkSigCryptoKey(key, alg, usage) { switch (alg) { case "HS256": case "HS384": case "HS512": { if (!isAlgorithm(key.algorithm, "HMAC")) throw unusable("HMAC"); const expected = parseInt(alg.slice(2), 10); const actual = getHashLength(key.algorithm.hash); if (actual !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash"); break; } case "RS256": case "RS384": case "RS512": { if (!isAlgorithm(key.algorithm, "RSASSA-PKCS1-v1_5")) throw unusable("RSASSA-PKCS1-v1_5"); const expected = parseInt(alg.slice(2), 10); const actual = getHashLength(key.algorithm.hash); if (actual !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash"); break; } case "PS256": case "PS384": case "PS512": { if (!isAlgorithm(key.algorithm, "RSA-PSS")) throw unusable("RSA-PSS"); const expected = parseInt(alg.slice(2), 10); const actual = getHashLength(key.algorithm.hash); if (actual !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash"); break; } case "Ed25519": // Fall through case "EdDSA": { if (!isAlgorithm(key.algorithm, "Ed25519")) throw unusable("Ed25519"); break; } case "ES256": case "ES384": case "ES512": { if (!isAlgorithm(key.algorithm, "ECDSA")) throw unusable("ECDSA"); const expected = getNamedCurve(alg); const actual = key.algorithm.namedCurve; if (actual !== expected) throw unusable(expected, "algorithm.namedCurve"); break; } default: throw new TypeError("CryptoKey does not support this operation"); } checkUsage(key, usage); } // src/lib/invalid_key_input.ts function message(msg, actual, ...types) { types = types.filter(Boolean); if (types.length > 2) { const last = types.pop(); msg += `one of type ${types.join(", ")}, or ${last}.`; } else if (types.length === 2) { msg += `one of type ${types[0]} or ${types[1]}.`; } else { msg += `of type ${types[0]}.`; } if (actual == null) { msg += ` Received ${actual}`; } else if (typeof actual === "function" && actual.name) { msg += ` Received function ${actual.name}`; } else if (typeof actual === "object" && actual != null) { if (actual.constructor?.name) { msg += ` Received an instance of ${actual.constructor.name}`; } } return msg; } var invalid_key_input_default = (actual, ...types) => { return message("Key must be ", actual, ...types); }; // src/lib/get_sign_verify_key.ts var get_sign_verify_key_default = async (alg, key, usage) => { if (key instanceof Uint8Array) { if (!alg.startsWith("HS")) { throw new TypeError(invalid_key_input_default(key, "CryptoKey", "KeyObject", "JSON Web Key")); } return crypto.subtle.importKey( "raw", key, { hash: `SHA-${alg.slice(-3)}`, name: "HMAC" }, false, [usage] ); } checkSigCryptoKey(key, alg, usage); return key; }; // src/lib/verify.ts var verify_default = async (alg, key, signature, data) => { const cryptoKey = await get_sign_verify_key_default(alg, key, "verify"); check_key_length_default(alg, cryptoKey); const algorithm = subtle_dsa_default(alg, cryptoKey.algorithm); try { return await crypto.subtle.verify(algorithm, cryptoKey, signature, data); } catch { return false; } }; export { verify_default as default };