jose
Version:
JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes
47 lines (46 loc) • 2.9 kB
JavaScript
import { encode as b64u } from "../util/base64url.js";
import { jwsAlgorithm } from "./jws_algorithms.js";
import { isDisjoint, serializeJoseHeader, validateB64, validateCrit, validateCritDuplicates, JWS_RECOGNIZED } from "./validate.js";
import { JWSInvalid } from "../util/errors.js";
import { concat, encode, encoder } from "./buffer_utils.js";
import { prepareKey, rawKey, checkModulusLength } from "./key.js";
async function createSignature(input, key, rejectUnencoded) {
let [payload, protectedHeader, unprotectedHeader, crit] = input, encodedProtectedHeader = "";
if (protectedHeader !== void 0) {
const normalized = serializeJoseHeader(JWSInvalid, protectedHeader);
protectedHeader = normalized[0], encodedProtectedHeader = b64u(normalized[1]);
}
if (unprotectedHeader !== void 0 && (unprotectedHeader = serializeJoseHeader(JWSInvalid, unprotectedHeader)[0]), !protectedHeader && !unprotectedHeader)
throw new JWSInvalid("either setProtectedHeader or setUnprotectedHeader must be called before #sign()");
if (!isDisjoint(protectedHeader, unprotectedHeader))
throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
const joseHeader = { ...protectedHeader, ...unprotectedHeader };
validateCritDuplicates(JWSInvalid, protectedHeader);
const b64 = validateB64(protectedHeader, validateCrit(JWSInvalid, JWS_RECOGNIZED, crit, protectedHeader, joseHeader));
b64 || rejectUnencoded?.();
const { alg } = joseHeader;
if (typeof alg != "string" || !alg)
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
const entry = jwsAlgorithm(alg);
let encodedPayload = "", signingPayload = payload, signingInput;
if (b64) {
const encodedPayloadCache = input[4];
encodedPayloadCache ? (encodedPayload = encodedPayloadCache[0] ??= b64u(payload), signingPayload = encodedPayloadCache[1] ??= encode(encodedPayload)) : (encodedPayload = b64u(payload), signingInput = encoder.encode(`${encodedProtectedHeader}.${encodedPayload}`));
}
signingInput ??= concat(encode(encodedProtectedHeader), encode("."), signingPayload);
const signingKey = await rawKey(await prepareKey(entry, key, "sign"), entry.subtle, "sign");
entry.minRsaBits && checkModulusLength(entry.alg, signingKey);
const jws = {
signature: b64u(new Uint8Array(await crypto.subtle.sign(entry.signing, signingKey, signingInput))),
payload: encodedPayload
};
return protectedHeader && (jws.protected = encodedProtectedHeader), unprotectedHeader && (jws.header = unprotectedHeader), [jws, b64];
}
async function createCompactSignature(payload, protectedHeader, crit, key, rejectUnencoded) {
const [jws] = await createSignature([payload, protectedHeader, void 0, crit], key, rejectUnencoded);
return `${jws.protected}.${jws.payload}.${jws.signature}`;
}
export {
createCompactSignature,
createSignature
};