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