| import { JOSENotSupported } from '../util/errors.js'; | ||
| import { table } from './key_descriptor.js'; | ||
| const wrap = { | ||
| public: ['encrypt', 'wrapKey'], | ||
| private: ['decrypt', 'unwrapKey'], | ||
| }; | ||
| const derive = { public: [], private: ['deriveBits'] }; | ||
| const none = { public: [], private: [] }; | ||
| function rsaes(bits) { | ||
| return { | ||
| kty: ['RSA'], | ||
| subtle: { name: 'RSA-OAEP', hash: `SHA-${bits}` }, | ||
| usages: wrap, | ||
| minModulusLength: 2048, | ||
| keyOps: { encrypt: 'wrapKey', decrypt: 'unwrapKey' }, | ||
| }; | ||
| } | ||
| function ecdh(kwBits) { | ||
| return { | ||
| kty: ['EC', 'OKP'], | ||
| subtle: { name: 'ECDH' }, | ||
| subtleFor: ({ kty, crv, asymmetricKeyType }) => { | ||
| if (crv === 'X25519' || asymmetricKeyType === 'x25519') { | ||
| return { name: 'X25519' }; | ||
| } | ||
| if (kty === 'OKP') { | ||
| throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value'); | ||
| } | ||
| return { name: 'ECDH', namedCurve: crv }; | ||
| }, | ||
| usages: derive, | ||
| kwBits, | ||
| keyOps: { decrypt: 'deriveBits' }, | ||
| }; | ||
| } | ||
| function aeskw(bits) { | ||
| return { | ||
| kty: ['oct'], | ||
| symmetric: true, | ||
| subtle: { name: 'AES-KW', length: bits }, | ||
| usages: none, | ||
| keyOps: { encrypt: 'wrapKey', decrypt: 'unwrapKey' }, | ||
| }; | ||
| } | ||
| function aesgcmkw(bits) { | ||
| return { | ||
| kty: ['oct'], | ||
| symmetric: true, | ||
| subtle: { name: 'AES-GCM', length: bits }, | ||
| usages: none, | ||
| gcmkw: `A${bits}GCM`, | ||
| keyOps: { encrypt: 'encrypt', decrypt: 'decrypt' }, | ||
| }; | ||
| } | ||
| function pbes2(bits, kwBits) { | ||
| return { | ||
| kty: ['oct'], | ||
| symmetric: true, | ||
| subtle: { name: 'PBKDF2' }, | ||
| usages: none, | ||
| pbes2Hash: `SHA-${bits}`, | ||
| kwBits, | ||
| keyOps: { encrypt: 'deriveBits', decrypt: 'deriveBits' }, | ||
| }; | ||
| } | ||
| const JWE = table({ | ||
| dir: { | ||
| kty: ['oct'], | ||
| symmetric: true, | ||
| subtle: { name: 'AES-GCM' }, | ||
| usages: none, | ||
| keyOps: { encrypt: 'encrypt', decrypt: 'decrypt' }, | ||
| }, | ||
| 'RSA-OAEP': rsaes(1), | ||
| 'RSA-OAEP-256': rsaes(256), | ||
| 'RSA-OAEP-384': rsaes(384), | ||
| 'RSA-OAEP-512': rsaes(512), | ||
| 'ECDH-ES': ecdh(), | ||
| 'ECDH-ES+A128KW': ecdh(128), | ||
| 'ECDH-ES+A192KW': ecdh(192), | ||
| 'ECDH-ES+A256KW': ecdh(256), | ||
| A128KW: aeskw(128), | ||
| A192KW: aeskw(192), | ||
| A256KW: aeskw(256), | ||
| A128GCMKW: aesgcmkw(128), | ||
| A192GCMKW: aesgcmkw(192), | ||
| A256GCMKW: aesgcmkw(256), | ||
| 'PBES2-HS256+A128KW': pbes2(256, 128), | ||
| 'PBES2-HS384+A192KW': pbes2(384, 192), | ||
| 'PBES2-HS512+A256KW': pbes2(512, 256), | ||
| }); | ||
| const content = { public: [], private: [] }; | ||
| const contentOps = { encrypt: 'encrypt', decrypt: 'decrypt' }; | ||
| function gcm(bits) { | ||
| return { | ||
| kty: ['oct'], | ||
| symmetric: true, | ||
| subtle: { name: 'AES-GCM', length: bits }, | ||
| usages: content, | ||
| keyOps: contentOps, | ||
| cekBits: bits, | ||
| ivBits: 96, | ||
| cbc: false, | ||
| }; | ||
| } | ||
| function cbc(bits) { | ||
| return { | ||
| kty: ['oct'], | ||
| symmetric: true, | ||
| subtle: { name: 'AES-CBC', length: bits }, | ||
| usages: content, | ||
| keyOps: contentOps, | ||
| cekBits: bits, | ||
| ivBits: 128, | ||
| cbc: true, | ||
| }; | ||
| } | ||
| const ENC = table({ | ||
| A128GCM: gcm(128), | ||
| A192GCM: gcm(192), | ||
| A256GCM: gcm(256), | ||
| 'A128CBC-HS256': cbc(256), | ||
| 'A192CBC-HS384': cbc(384), | ||
| 'A256CBC-HS512': cbc(512), | ||
| }); | ||
| const unsupportedAlgHeader = 'Invalid or unsupported "alg" (JWE Algorithm) header value'; | ||
| export function jweAlgorithm(alg) { | ||
| const entry = JWE[alg]; | ||
| if (!entry) { | ||
| throw new JOSENotSupported(unsupportedAlgHeader); | ||
| } | ||
| return entry; | ||
| } | ||
| export function maybeJWEAlgorithm(alg) { | ||
| return JWE[alg]; | ||
| } | ||
| export function jweEncryption(enc) { | ||
| const entry = ENC[enc]; | ||
| if (!entry) { | ||
| throw new JOSENotSupported(`Unsupported JWE Algorithm: ${enc}`); | ||
| } | ||
| return entry; | ||
| } |
| import { decrypt, generateCek } from './content_encryption.js'; | ||
| import { decodeBase64url, encodeBase64url, parseJoseHeader } from './helpers.js'; | ||
| import { JOSEAlgNotAllowed, JOSENotSupported, JWEInvalid } from '../util/errors.js'; | ||
| import { isDisjoint, isObject } from './type_checks.js'; | ||
| import { decryptKeyManagement } from './key_management.js'; | ||
| import { concat, decoder, encode } from './buffer_utils.js'; | ||
| import { validateCrit, validateAlgorithms, JWE_RECOGNIZED } from './options.js'; | ||
| import { prepareKey } from './key.js'; | ||
| import { jweAlgorithm, jweEncryption } from './jwe_algorithms.js'; | ||
| import { decompress } from './deflate.js'; | ||
| export function checkShared(jwe) { | ||
| if (jwe.iv !== undefined && typeof jwe.iv !== 'string') { | ||
| throw new JWEInvalid('JWE Initialization Vector incorrect type'); | ||
| } | ||
| if (typeof jwe.ciphertext !== 'string') { | ||
| throw new JWEInvalid('JWE Ciphertext missing or incorrect type'); | ||
| } | ||
| if (jwe.tag !== undefined && typeof jwe.tag !== 'string') { | ||
| throw new JWEInvalid('JWE Authentication Tag incorrect type'); | ||
| } | ||
| if (jwe.protected !== undefined && typeof jwe.protected !== 'string') { | ||
| throw new JWEInvalid('JWE Protected Header incorrect type'); | ||
| } | ||
| if (jwe.aad !== undefined && typeof jwe.aad !== 'string') { | ||
| throw new JWEInvalid('JWE AAD incorrect type'); | ||
| } | ||
| if (jwe.unprotected !== undefined && !isObject(jwe.unprotected)) { | ||
| throw new JWEInvalid('JWE Shared Unprotected Header incorrect type'); | ||
| } | ||
| } | ||
| export function checkRecipient(jwe) { | ||
| if (jwe.encrypted_key !== undefined && typeof jwe.encrypted_key !== 'string') { | ||
| throw new JWEInvalid('JWE Encrypted Key incorrect type'); | ||
| } | ||
| if (jwe.header !== undefined && !isObject(jwe.header)) { | ||
| throw new JWEInvalid('JWE Per-Recipient Unprotected Header incorrect type'); | ||
| } | ||
| if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) { | ||
| throw new JWEInvalid('JOSE Header missing'); | ||
| } | ||
| } | ||
| export function shareJWE(jwe) { | ||
| let parsedProt; | ||
| if (jwe.protected) { | ||
| parsedProt = parseJoseHeader(jwe.protected, JWEInvalid, 'JWE Protected Header is invalid'); | ||
| } | ||
| const protectedHeader = jwe.protected !== undefined ? encode(jwe.protected) : new Uint8Array(); | ||
| return { | ||
| parsedProt, | ||
| ciphertext: decodeBase64url(jwe.ciphertext, 'ciphertext', JWEInvalid), | ||
| iv: jwe.iv !== undefined ? decodeBase64url(jwe.iv, 'iv', JWEInvalid) : undefined, | ||
| tag: jwe.tag !== undefined ? decodeBase64url(jwe.tag, 'tag', JWEInvalid) : undefined, | ||
| additionalData: jwe.aad !== undefined | ||
| ? concat(protectedHeader, encode('.'), encodeBase64url(jwe.aad, 'aad', JWEInvalid)) | ||
| : protectedHeader, | ||
| }; | ||
| } | ||
| export function decryptResult(jwe, decrypted) { | ||
| const result = { plaintext: decrypted.plaintext }; | ||
| if (jwe.protected !== undefined) { | ||
| result.protectedHeader = decrypted.parsedProt; | ||
| } | ||
| if (jwe.aad !== undefined) { | ||
| result.additionalAuthenticatedData = decodeBase64url(jwe.aad, 'aad', JWEInvalid); | ||
| } | ||
| if (jwe.unprotected !== undefined) { | ||
| result.sharedUnprotectedHeader = jwe.unprotected; | ||
| } | ||
| if (jwe.header !== undefined) { | ||
| result.unprotectedHeader = jwe.header; | ||
| } | ||
| if (decrypted.resolvedKey) { | ||
| return { ...result, key: decrypted.key }; | ||
| } | ||
| return result; | ||
| } | ||
| export function prepareDecrypt(options) { | ||
| return { | ||
| keyManagementAlgorithms: options && validateAlgorithms('keyManagementAlgorithms', options.keyManagementAlgorithms), | ||
| contentEncryptionAlgorithms: options && | ||
| validateAlgorithms('contentEncryptionAlgorithms', options.contentEncryptionAlgorithms), | ||
| options, | ||
| }; | ||
| } | ||
| export async function decryptRecipient(jwe, token, shared, key) { | ||
| const { options } = shared; | ||
| const { parsedProt } = token; | ||
| let joseHeader; | ||
| if (jwe.header !== undefined || jwe.unprotected !== undefined) { | ||
| if (!isDisjoint(parsedProt, jwe.header, jwe.unprotected)) { | ||
| throw new JWEInvalid('JWE Protected, JWE Unprotected Header, and JWE Per-Recipient Unprotected Header Parameter names must be disjoint'); | ||
| } | ||
| joseHeader = { ...parsedProt, ...jwe.header, ...jwe.unprotected }; | ||
| } | ||
| else { | ||
| joseHeader = parsedProt ?? {}; | ||
| } | ||
| validateCrit(JWEInvalid, JWE_RECOGNIZED, options?.crit, parsedProt, joseHeader); | ||
| if (joseHeader.zip !== undefined && joseHeader.zip !== 'DEF') { | ||
| throw new JOSENotSupported('Unsupported JWE "zip" (Compression Algorithm) Header Parameter value.'); | ||
| } | ||
| if (joseHeader.zip !== undefined && !parsedProt?.zip) { | ||
| throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header Parameter MUST be in a protected header.'); | ||
| } | ||
| const { alg, enc } = joseHeader; | ||
| if (typeof alg !== 'string' || !alg) { | ||
| throw new JWEInvalid('missing JWE Algorithm (alg) in JWE Header'); | ||
| } | ||
| if (typeof enc !== 'string' || !enc) { | ||
| throw new JWEInvalid('missing JWE Encryption Algorithm (enc) in JWE Header'); | ||
| } | ||
| const { keyManagementAlgorithms, contentEncryptionAlgorithms } = shared; | ||
| if ((keyManagementAlgorithms && !keyManagementAlgorithms.has(alg)) || | ||
| (!keyManagementAlgorithms && alg.startsWith('PBES2'))) { | ||
| throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed'); | ||
| } | ||
| if (contentEncryptionAlgorithms && !contentEncryptionAlgorithms.has(enc)) { | ||
| throw new JOSEAlgNotAllowed('"enc" (Encryption Algorithm) Header Parameter value not allowed'); | ||
| } | ||
| const encEntry = jweEncryption(enc); | ||
| let encryptedKey; | ||
| if (jwe.encrypted_key !== undefined) { | ||
| encryptedKey = decodeBase64url(jwe.encrypted_key, 'encrypted_key', JWEInvalid); | ||
| } | ||
| let resolvedKey = false; | ||
| if (typeof key === 'function') { | ||
| key = await key(parsedProt, jwe); | ||
| resolvedKey = true; | ||
| } | ||
| const algEntry = jweAlgorithm(alg); | ||
| const k = await prepareKey(alg === 'dir' ? encEntry : algEntry, key, 'decrypt'); | ||
| let cek; | ||
| try { | ||
| cek = await decryptKeyManagement(alg, encEntry, k, encryptedKey, joseHeader, options); | ||
| } | ||
| catch (err) { | ||
| if (err instanceof TypeError || err instanceof JWEInvalid || err instanceof JOSENotSupported) { | ||
| throw err; | ||
| } | ||
| cek = generateCek(encEntry); | ||
| } | ||
| let plaintext = await decrypt(encEntry, cek, token.ciphertext, token.iv, token.tag, token.additionalData); | ||
| if (joseHeader.zip === 'DEF') { | ||
| const maxDecompressedLength = options?.maxDecompressedLength ?? 250_000; | ||
| if (maxDecompressedLength === 0) { | ||
| throw new JOSENotSupported('JWE "zip" (Compression Algorithm) Header Parameter is not supported.'); | ||
| } | ||
| if (maxDecompressedLength !== Infinity && | ||
| (!Number.isSafeInteger(maxDecompressedLength) || maxDecompressedLength < 1)) { | ||
| throw new TypeError('maxDecompressedLength must be 0, a positive safe integer, or Infinity'); | ||
| } | ||
| plaintext = await decompress(plaintext, maxDecompressedLength).catch((cause) => { | ||
| if (cause instanceof JWEInvalid) | ||
| throw cause; | ||
| throw new JWEInvalid('Failed to decompress plaintext', { cause }); | ||
| }); | ||
| } | ||
| return { plaintext, parsedProt, key: k, resolvedKey }; | ||
| } | ||
| export async function decryptJWE(jwe, shared, key) { | ||
| return decryptRecipient(jwe, shareJWE(jwe), shared, key); | ||
| } | ||
| export async function decryptCompact(jwe, shared, key) { | ||
| if (jwe instanceof Uint8Array) { | ||
| jwe = decoder.decode(jwe); | ||
| } | ||
| if (typeof jwe !== 'string') { | ||
| throw new JWEInvalid('Compact JWE must be a string or Uint8Array'); | ||
| } | ||
| const { 0: protectedHeader, 1: encryptedKey, 2: iv, 3: ciphertext, 4: tag, length, } = jwe.split('.'); | ||
| if (length !== 5) { | ||
| throw new JWEInvalid('Invalid Compact JWE'); | ||
| } | ||
| return decryptJWE({ | ||
| ciphertext, | ||
| iv: iv || undefined, | ||
| protected: protectedHeader, | ||
| tag: tag || undefined, | ||
| encrypted_key: encryptedKey || undefined, | ||
| }, shared, key); | ||
| } |
| import { encode as b64u } from '../util/base64url.js'; | ||
| import { encrypt } from './content_encryption.js'; | ||
| import { encryptKeyManagement } from './key_management.js'; | ||
| import { JOSENotSupported, JWEInvalid } from '../util/errors.js'; | ||
| import { isDisjoint } from './type_checks.js'; | ||
| import { concat, encode } from './buffer_utils.js'; | ||
| import { validateCrit, JWE_RECOGNIZED } from './options.js'; | ||
| import { prepareKey } from './key.js'; | ||
| import { jweAlgorithm, jweEncryption } from './jwe_algorithms.js'; | ||
| import { compress } from './deflate.js'; | ||
| export function checkEncryptHeaders(input) { | ||
| const { protectedHeader, unprotectedHeader, sharedUnprotectedHeader } = input; | ||
| if (!isDisjoint(protectedHeader, unprotectedHeader, sharedUnprotectedHeader)) { | ||
| throw new JWEInvalid('JWE Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint'); | ||
| } | ||
| const joseHeader = { | ||
| ...protectedHeader, | ||
| ...unprotectedHeader, | ||
| ...sharedUnprotectedHeader, | ||
| }; | ||
| validateCrit(JWEInvalid, JWE_RECOGNIZED, input.crit, protectedHeader, joseHeader); | ||
| if (joseHeader.zip !== undefined && joseHeader.zip !== 'DEF') { | ||
| throw new JOSENotSupported('Unsupported JWE "zip" (Compression Algorithm) Header Parameter value.'); | ||
| } | ||
| if (joseHeader.zip !== undefined && !protectedHeader?.zip) { | ||
| throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header Parameter MUST be in a protected header.'); | ||
| } | ||
| const { alg, enc } = joseHeader; | ||
| if (typeof alg !== 'string' || !alg) { | ||
| throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid'); | ||
| } | ||
| if (typeof enc !== 'string' || !enc) { | ||
| throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid'); | ||
| } | ||
| return { joseHeader, alg, enc, encEntry: jweEncryption(enc) }; | ||
| } | ||
| export async function encryptJWE(input, checked, key) { | ||
| const { joseHeader, alg, encEntry } = checked; | ||
| let { protectedHeader, unprotectedHeader } = input; | ||
| const { sharedUnprotectedHeader } = input; | ||
| if (input.cek && (alg === 'dir' || alg === 'ECDH-ES')) { | ||
| throw new TypeError(`setContentEncryptionKey cannot be called with JWE "alg" (Algorithm) Header ${alg}`); | ||
| } | ||
| const algEntry = jweAlgorithm(alg); | ||
| const k = await prepareKey(alg === 'dir' ? encEntry : algEntry, key, 'encrypt'); | ||
| const { cek, encryptedKey, parameters } = await encryptKeyManagement(alg, encEntry, k, input.cek, input.keyManagementParameters); | ||
| if (parameters) { | ||
| if (input.unprotectedParameters) { | ||
| unprotectedHeader = unprotectedHeader ? { ...unprotectedHeader, ...parameters } : parameters; | ||
| } | ||
| else { | ||
| protectedHeader = protectedHeader ? { ...protectedHeader, ...parameters } : parameters; | ||
| } | ||
| } | ||
| let protectedHeaderS; | ||
| let protectedHeaderB; | ||
| if (protectedHeader) { | ||
| protectedHeaderS = b64u(JSON.stringify(protectedHeader)); | ||
| protectedHeaderB = encode(protectedHeaderS); | ||
| } | ||
| else { | ||
| protectedHeaderS = ''; | ||
| protectedHeaderB = new Uint8Array(); | ||
| } | ||
| let additionalData; | ||
| let aadMember; | ||
| if (input.aad?.byteLength) { | ||
| aadMember = b64u(input.aad); | ||
| additionalData = concat(protectedHeaderB, encode('.'), encode(aadMember)); | ||
| } | ||
| else { | ||
| additionalData = protectedHeaderB; | ||
| } | ||
| let plaintext = input.plaintext; | ||
| if (joseHeader.zip === 'DEF') { | ||
| plaintext = await compress(plaintext).catch((cause) => { | ||
| throw new JWEInvalid('Failed to compress plaintext', { cause }); | ||
| }); | ||
| } | ||
| const { ciphertext, tag, iv } = await encrypt(encEntry, plaintext, cek, input.iv, additionalData); | ||
| const jwe = { | ||
| ciphertext: b64u(ciphertext), | ||
| }; | ||
| if (iv) { | ||
| jwe.iv = b64u(iv); | ||
| } | ||
| if (tag) { | ||
| jwe.tag = b64u(tag); | ||
| } | ||
| if (encryptedKey) { | ||
| jwe.encrypted_key = b64u(encryptedKey); | ||
| } | ||
| if (aadMember) { | ||
| jwe.aad = aadMember; | ||
| } | ||
| if (protectedHeader) { | ||
| jwe.protected = protectedHeaderS; | ||
| } | ||
| if (sharedUnprotectedHeader) { | ||
| jwe.unprotected = sharedUnprotectedHeader; | ||
| } | ||
| if (unprotectedHeader) { | ||
| jwe.header = unprotectedHeader; | ||
| } | ||
| return jwe; | ||
| } | ||
| export async function createJWE(input, key) { | ||
| return encryptJWE(input, checkEncryptHeaders(input), key); | ||
| } |
| import { JOSENotSupported } from '../util/errors.js'; | ||
| import { table } from './key_descriptor.js'; | ||
| const sig = { public: ['verify'], private: ['sign'] }; | ||
| function hmac(bits) { | ||
| const subtle = { name: 'HMAC', hash: `SHA-${bits}` }; | ||
| return { kty: ['oct'], symmetric: true, subtle, operation: subtle, usages: sig }; | ||
| } | ||
| function rsa(name, bits, saltLength) { | ||
| const subtle = { name, hash: `SHA-${bits}` }; | ||
| return { | ||
| kty: ['RSA'], | ||
| subtle, | ||
| operation: saltLength ? { ...subtle, saltLength } : subtle, | ||
| usages: sig, | ||
| minModulusLength: 2048, | ||
| }; | ||
| } | ||
| function ecdsa(crv, bits) { | ||
| return { | ||
| kty: ['EC'], | ||
| crv, | ||
| subtle: { name: 'ECDSA', namedCurve: crv }, | ||
| operation: { name: 'ECDSA', hash: `SHA-${bits}` }, | ||
| usages: sig, | ||
| }; | ||
| } | ||
| function eddsa() { | ||
| const subtle = { name: 'Ed25519' }; | ||
| return { | ||
| kty: ['OKP'], | ||
| crv: 'Ed25519', | ||
| subtle, | ||
| operation: subtle, | ||
| usages: sig, | ||
| }; | ||
| } | ||
| function mldsa(name) { | ||
| const subtle = { name }; | ||
| return { | ||
| kty: ['AKP'], | ||
| subtle, | ||
| operation: subtle, | ||
| usages: sig, | ||
| }; | ||
| } | ||
| const JWS = table({ | ||
| HS256: hmac(256), | ||
| HS384: hmac(384), | ||
| HS512: hmac(512), | ||
| RS256: rsa('RSASSA-PKCS1-v1_5', 256), | ||
| RS384: rsa('RSASSA-PKCS1-v1_5', 384), | ||
| RS512: rsa('RSASSA-PKCS1-v1_5', 512), | ||
| PS256: rsa('RSA-PSS', 256, 32), | ||
| PS384: rsa('RSA-PSS', 384, 48), | ||
| PS512: rsa('RSA-PSS', 512, 64), | ||
| ES256: ecdsa('P-256', 256), | ||
| ES384: ecdsa('P-384', 384), | ||
| ES512: ecdsa('P-521', 512), | ||
| EdDSA: eddsa(), | ||
| Ed25519: eddsa(), | ||
| 'ML-DSA-44': mldsa('ML-DSA-44'), | ||
| 'ML-DSA-65': mldsa('ML-DSA-65'), | ||
| 'ML-DSA-87': mldsa('ML-DSA-87'), | ||
| }); | ||
| export function jwsAlgorithm(alg) { | ||
| const entry = JWS[alg]; | ||
| if (!entry) { | ||
| throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); | ||
| } | ||
| return entry; | ||
| } | ||
| export function maybeJWSAlgorithm(alg) { | ||
| return JWS[alg]; | ||
| } |
| import { encode as b64u } from '../util/base64url.js'; | ||
| import { sign } from './signing.js'; | ||
| import { jwsAlgorithm } from './jws_algorithms.js'; | ||
| import { isDisjoint } from './type_checks.js'; | ||
| import { JWSInvalid } from '../util/errors.js'; | ||
| import { concat, encode } from './buffer_utils.js'; | ||
| import { validateCrit, validateCritDuplicates, JWS_RECOGNIZED } from './options.js'; | ||
| import { prepareKey } from './key.js'; | ||
| export function unencodedPayload(protectedHeader) { | ||
| return (protectedHeader?.b64 === false && | ||
| Array.isArray(protectedHeader.crit) && | ||
| protectedHeader.crit.includes('b64')); | ||
| } | ||
| export async function createSignature(input, key) { | ||
| const { protectedHeader, unprotectedHeader } = input; | ||
| 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 extensions = validateCrit(JWSInvalid, JWS_RECOGNIZED, input.crit, protectedHeader, joseHeader); | ||
| let b64 = true; | ||
| if (extensions.has('b64')) { | ||
| b64 = protectedHeader.b64; | ||
| if (typeof b64 !== 'boolean') { | ||
| throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean'); | ||
| } | ||
| } | ||
| const { alg } = joseHeader; | ||
| if (typeof alg !== 'string' || !alg) { | ||
| throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); | ||
| } | ||
| const entry = jwsAlgorithm(alg); | ||
| let payloadS; | ||
| let payloadB; | ||
| if (b64) { | ||
| const encoded = (input.encoded ??= {}); | ||
| encoded.b64 ??= b64u(input.payload); | ||
| encoded.raw ??= encode(encoded.b64); | ||
| payloadS = encoded.b64; | ||
| payloadB = encoded.raw; | ||
| } | ||
| else { | ||
| payloadB = input.payload; | ||
| payloadS = ''; | ||
| } | ||
| let protectedHeaderString; | ||
| let protectedHeaderBytes; | ||
| if (protectedHeader) { | ||
| protectedHeaderString = b64u(JSON.stringify(protectedHeader)); | ||
| protectedHeaderBytes = encode(protectedHeaderString); | ||
| } | ||
| else { | ||
| protectedHeaderString = ''; | ||
| protectedHeaderBytes = new Uint8Array(); | ||
| } | ||
| const data = concat(protectedHeaderBytes, encode('.'), payloadB); | ||
| const k = await prepareKey(entry, key, 'sign'); | ||
| const signature = await sign(entry, k, data); | ||
| const jws = { | ||
| signature: b64u(signature), | ||
| payload: payloadS, | ||
| }; | ||
| if (protectedHeader) { | ||
| jws.protected = protectedHeaderString; | ||
| } | ||
| return jws; | ||
| } |
| import { verify } from './signing.js'; | ||
| import { jwsAlgorithm } from './jws_algorithms.js'; | ||
| import { JOSEAlgNotAllowed, JWSInvalid, JWSSignatureVerificationFailed } from '../util/errors.js'; | ||
| import { concat, decoder, encoder, encode } from './buffer_utils.js'; | ||
| import { decodeBase64url, encodeBase64url, parseJoseHeader } from './helpers.js'; | ||
| import { isDisjoint } from './type_checks.js'; | ||
| import { validateCrit, validateAlgorithms, JWS_RECOGNIZED } from './options.js'; | ||
| import { prepareKey } from './key.js'; | ||
| export function verifyResult(jws, verified) { | ||
| const result = { payload: verified.payload }; | ||
| if (jws.protected !== undefined) { | ||
| result.protectedHeader = verified.parsedProt; | ||
| } | ||
| if (jws.header !== undefined) { | ||
| result.unprotectedHeader = jws.header; | ||
| } | ||
| if (verified.resolvedKey) { | ||
| return { ...result, key: verified.key }; | ||
| } | ||
| return result; | ||
| } | ||
| export function prepareVerify(options) { | ||
| return { | ||
| algorithms: options && validateAlgorithms('algorithms', options.algorithms), | ||
| crit: options?.crit, | ||
| }; | ||
| } | ||
| export async function verifySignature(jws, shared, key) { | ||
| let parsedProt = {}; | ||
| if (jws.protected) { | ||
| parsedProt = parseJoseHeader(jws.protected, JWSInvalid, 'JWS Protected Header is invalid'); | ||
| } | ||
| let joseHeader; | ||
| if (jws.header !== undefined) { | ||
| if (!isDisjoint(parsedProt, jws.header)) { | ||
| throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint'); | ||
| } | ||
| joseHeader = { ...parsedProt, ...jws.header }; | ||
| } | ||
| else { | ||
| joseHeader = parsedProt; | ||
| } | ||
| const extensions = validateCrit(JWSInvalid, JWS_RECOGNIZED, shared.crit, parsedProt, joseHeader); | ||
| let b64 = true; | ||
| if (extensions.has('b64')) { | ||
| b64 = parsedProt.b64; | ||
| if (typeof b64 !== 'boolean') { | ||
| throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean'); | ||
| } | ||
| } | ||
| const { alg } = joseHeader; | ||
| if (typeof alg !== 'string' || !alg) { | ||
| throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); | ||
| } | ||
| if (shared.algorithms && !shared.algorithms.has(alg)) { | ||
| throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed'); | ||
| } | ||
| if (b64) { | ||
| if (typeof jws.payload !== 'string') { | ||
| throw new JWSInvalid('JWS Payload must be a string'); | ||
| } | ||
| } | ||
| else if (typeof jws.payload !== 'string' && !(jws.payload instanceof Uint8Array)) { | ||
| throw new JWSInvalid('JWS Payload must be a string or an Uint8Array instance'); | ||
| } | ||
| let resolvedKey = false; | ||
| if (typeof key === 'function') { | ||
| key = await key(parsedProt, jws); | ||
| resolvedKey = true; | ||
| } | ||
| const entry = jwsAlgorithm(alg); | ||
| const data = concat(jws.protected !== undefined ? encode(jws.protected) : new Uint8Array(), encode('.'), typeof jws.payload === 'string' | ||
| ? b64 | ||
| ? | ||
| (shared.b64p ??= encodeBase64url(jws.payload, 'payload', JWSInvalid)) | ||
| : encoder.encode(jws.payload) | ||
| : jws.payload); | ||
| const signature = decodeBase64url(jws.signature, 'signature', JWSInvalid); | ||
| const k = await prepareKey(entry, key, 'verify'); | ||
| const verified = await verify(entry, k, signature, data); | ||
| if (!verified) { | ||
| throw new JWSSignatureVerificationFailed(); | ||
| } | ||
| let payload; | ||
| if (b64) { | ||
| payload = decodeBase64url(jws.payload, 'payload', JWSInvalid); | ||
| } | ||
| else if (typeof jws.payload === 'string') { | ||
| payload = encoder.encode(jws.payload); | ||
| } | ||
| else { | ||
| payload = jws.payload; | ||
| } | ||
| return { payload, parsedProt, b64, key: k, resolvedKey }; | ||
| } | ||
| export async function verifyCompact(jws, shared, key) { | ||
| if (jws instanceof Uint8Array) { | ||
| jws = decoder.decode(jws); | ||
| } | ||
| if (typeof jws !== 'string') { | ||
| throw new JWSInvalid('Compact JWS must be a string or Uint8Array'); | ||
| } | ||
| const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.'); | ||
| if (length !== 3) { | ||
| throw new JWSInvalid('Invalid Compact JWS'); | ||
| } | ||
| return verifySignature({ payload, protected: protectedHeader, signature }, shared, key); | ||
| } |
| import { JOSENotSupported } from '../util/errors.js'; | ||
| import { maybeJWSAlgorithm } from './jws_algorithms.js'; | ||
| import { maybeJWEAlgorithm } from './jwe_algorithms.js'; | ||
| function unsupportedAlgorithm() { | ||
| return new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value'); | ||
| } | ||
| export function keyAlgorithm(alg) { | ||
| if (typeof alg !== 'string') { | ||
| throw unsupportedAlgorithm(); | ||
| } | ||
| const entry = maybeJWSAlgorithm(alg) ?? maybeJWEAlgorithm(alg); | ||
| if (!entry) { | ||
| throw unsupportedAlgorithm(); | ||
| } | ||
| return entry; | ||
| } |
| export function table(entries) { | ||
| const out = { __proto__: null }; | ||
| for (const alg of Object.keys(entries)) { | ||
| out[alg] = { ...entries[alg], alg }; | ||
| } | ||
| return out; | ||
| } |
| import { withAlg as invalidKeyInput } from './invalid_key_input.js'; | ||
| import { isKeyLike, isCryptoKey } from './is_key_like.js'; | ||
| import * as jwk from './type_checks.js'; | ||
| import { decode } from '../util/base64url.js'; | ||
| import { jwkToKey } from './jwk_to_key.js'; | ||
| const tag = (key) => key[Symbol.toStringTag]; | ||
| const jwkMatchesOp = (entry, key, usage) => { | ||
| const { alg } = entry; | ||
| if (key.use !== undefined) { | ||
| let expected; | ||
| switch (usage) { | ||
| case 'sign': | ||
| case 'verify': | ||
| expected = 'sig'; | ||
| break; | ||
| case 'encrypt': | ||
| case 'decrypt': | ||
| expected = 'enc'; | ||
| break; | ||
| } | ||
| if (key.use !== expected) { | ||
| throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`); | ||
| } | ||
| } | ||
| if (key.alg !== undefined && key.alg !== alg) { | ||
| throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`); | ||
| } | ||
| if (Array.isArray(key.key_ops)) { | ||
| const expectedKeyOp = usage === 'encrypt' || usage === 'decrypt' ? entry.keyOps?.[usage] : usage; | ||
| if (expectedKeyOp && key.key_ops?.includes?.(expectedKeyOp) === false) { | ||
| throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`); | ||
| } | ||
| } | ||
| return true; | ||
| }; | ||
| const symmetricTypeCheck = (entry, key, usage) => { | ||
| const { alg } = entry; | ||
| if (key instanceof Uint8Array) | ||
| return { kind: BYTES, key }; | ||
| if (jwk.isJWK(key)) { | ||
| if (jwk.isSecretJWK(key) && jwkMatchesOp(entry, key, usage)) | ||
| return { kind: JWK, key }; | ||
| throw new TypeError(`JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`); | ||
| } | ||
| if (!isKeyLike(key)) { | ||
| throw new TypeError(invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key', 'Uint8Array')); | ||
| } | ||
| if (key.type !== 'secret') { | ||
| throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`); | ||
| } | ||
| return isCryptoKey(key) ? { kind: CRYPTO, key } : { kind: KEYOBJECT, key }; | ||
| }; | ||
| const asymmetricTypeCheck = (entry, key, usage) => { | ||
| const { alg } = entry; | ||
| if (jwk.isJWK(key)) { | ||
| switch (usage) { | ||
| case 'decrypt': | ||
| case 'sign': | ||
| if (jwk.isPrivateJWK(key) && jwkMatchesOp(entry, key, usage)) | ||
| return { kind: JWK, key }; | ||
| throw new TypeError(`JSON Web Key for this operation must be a private JWK`); | ||
| case 'encrypt': | ||
| case 'verify': | ||
| if (jwk.isPublicJWK(key) && jwkMatchesOp(entry, key, usage)) | ||
| return { kind: JWK, key }; | ||
| throw new TypeError(`JSON Web Key for this operation must be a public JWK`); | ||
| } | ||
| } | ||
| if (!isKeyLike(key)) { | ||
| throw new TypeError(invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key')); | ||
| } | ||
| if (key.type === 'secret') { | ||
| throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`); | ||
| } | ||
| if (key.type === 'public') { | ||
| switch (usage) { | ||
| case 'sign': | ||
| throw new TypeError(`${tag(key)} instances for asymmetric algorithm signing must be of type "private"`); | ||
| case 'decrypt': | ||
| throw new TypeError(`${tag(key)} instances for asymmetric algorithm decryption must be of type "private"`); | ||
| } | ||
| } | ||
| if (key.type === 'private') { | ||
| switch (usage) { | ||
| case 'verify': | ||
| throw new TypeError(`${tag(key)} instances for asymmetric algorithm verifying must be of type "public"`); | ||
| case 'encrypt': | ||
| throw new TypeError(`${tag(key)} instances for asymmetric algorithm encryption must be of type "public"`); | ||
| } | ||
| } | ||
| return isCryptoKey(key) ? { kind: CRYPTO, key } : { kind: KEYOBJECT, key }; | ||
| }; | ||
| const BYTES = Symbol(); | ||
| const CRYPTO = Symbol(); | ||
| const KEYOBJECT = Symbol(); | ||
| const JWK = Symbol(); | ||
| export function checkKeyType(entry, key, usage) { | ||
| return entry.symmetric | ||
| ? symmetricTypeCheck(entry, key, usage) | ||
| : asymmetricTypeCheck(entry, key, usage); | ||
| } | ||
| let cache; | ||
| const nist = { | ||
| __proto__: null, | ||
| prime256v1: 'P-256', | ||
| secp384r1: 'P-384', | ||
| secp521r1: 'P-521', | ||
| }; | ||
| function cached(key, alg) { | ||
| cache ||= new WeakMap(); | ||
| return cache.get(key)?.[alg]; | ||
| } | ||
| function store(key, alg, cryptoKey) { | ||
| const entry = cache.get(key); | ||
| if (entry) { | ||
| entry[alg] = cryptoKey; | ||
| } | ||
| else { | ||
| cache.set(key, { [alg]: cryptoKey }); | ||
| } | ||
| return cryptoKey; | ||
| } | ||
| const handleJWK = async (key, jwk, entry) => { | ||
| const hit = cached(key, entry.alg); | ||
| if (hit) | ||
| return hit; | ||
| const cryptoKey = await jwkToKey(entry, { ...jwk, alg: entry.alg }); | ||
| return store(key, entry.alg, cryptoKey); | ||
| }; | ||
| const handleKeyObject = (keyObject, entry) => { | ||
| const hit = cached(keyObject, entry.alg); | ||
| if (hit) | ||
| return hit; | ||
| const isPublic = keyObject.type === 'public'; | ||
| const usages = isPublic ? entry.usages.public : entry.usages.private; | ||
| const { asymmetricKeyType } = keyObject; | ||
| const crv = nist[keyObject.asymmetricKeyDetails?.namedCurve]; | ||
| const params = entry.subtleFor?.({ crv, asymmetricKeyType }) ?? entry.subtle; | ||
| return store(keyObject, entry.alg, keyObject.toCryptoKey(params, isPublic, usages)); | ||
| }; | ||
| export async function prepareKey(entry, key, usage) { | ||
| const tagged = checkKeyType(entry, key, usage); | ||
| switch (tagged.kind) { | ||
| case BYTES: | ||
| case CRYPTO: | ||
| return tagged.key; | ||
| case JWK: { | ||
| if (tagged.key.k) { | ||
| return decode(tagged.key.k); | ||
| } | ||
| if (!Object.isFrozen(tagged.key)) { | ||
| const { key_ops } = tagged.key; | ||
| if (Array.isArray(key_ops)) | ||
| Object.freeze(key_ops); | ||
| Object.freeze(tagged.key); | ||
| } | ||
| return handleJWK(tagged.key, tagged.key, entry); | ||
| } | ||
| case KEYOBJECT: { | ||
| const keyObject = tagged.key; | ||
| if (keyObject.type === 'secret') { | ||
| return keyObject.export(); | ||
| } | ||
| if ('toCryptoKey' in keyObject && typeof keyObject.toCryptoKey === 'function') { | ||
| return handleKeyObject(keyObject, entry); | ||
| } | ||
| return handleJWK(keyObject, keyObject.export({ format: 'jwk' }), entry); | ||
| } | ||
| } | ||
| } |
| import { JOSENotSupported, JWEInvalid, JWSInvalid } from '../util/errors.js'; | ||
| export const JWS_RECOGNIZED = new Map([['b64', true]]); | ||
| export const JWE_RECOGNIZED = new Map(); | ||
| export function validateAlgorithms(option, algorithms) { | ||
| if (algorithms !== undefined && | ||
| (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== 'string'))) { | ||
| throw new TypeError(`"${option}" option must be an array of strings`); | ||
| } | ||
| if (!algorithms) { | ||
| return undefined; | ||
| } | ||
| return new Set(algorithms); | ||
| } | ||
| export function validateCritDuplicates(Err, protectedHeader) { | ||
| const { crit } = protectedHeader ?? {}; | ||
| if (Array.isArray(crit) && new Set(crit).size !== crit.length) { | ||
| throw new Err('"crit" (Critical) Header Parameter MUST NOT contain duplicate values'); | ||
| } | ||
| } | ||
| export function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) { | ||
| if (joseHeader.crit !== undefined && protectedHeader?.crit === undefined) { | ||
| throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected'); | ||
| } | ||
| if (!protectedHeader || protectedHeader.crit === undefined) { | ||
| return new Set(); | ||
| } | ||
| if (!Array.isArray(protectedHeader.crit) || | ||
| protectedHeader.crit.length === 0 || | ||
| protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) { | ||
| throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present'); | ||
| } | ||
| let recognized; | ||
| if (recognizedOption !== undefined) { | ||
| recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]); | ||
| } | ||
| else { | ||
| recognized = recognizedDefault; | ||
| } | ||
| for (const parameter of protectedHeader.crit) { | ||
| if (!recognized.has(parameter)) { | ||
| throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`); | ||
| } | ||
| if (joseHeader[parameter] === undefined) { | ||
| throw new Err(`Extension Header Parameter "${parameter}" is missing`); | ||
| } | ||
| if (recognized.get(parameter) && protectedHeader[parameter] === undefined) { | ||
| throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`); | ||
| } | ||
| } | ||
| return new Set(protectedHeader.crit); | ||
| } |
@@ -30,4 +30,5 @@ export { compactDecrypt } from './jwe/compact/decrypt.js'; | ||
| export { createLocalJWKSet } from './jwks/local.js'; | ||
| export type { LocalJWKSet } from './jwks/local.js'; | ||
| export { createRemoteJWKSet, jwksCache, customFetch } from './jwks/remote.js'; | ||
| export type { RemoteJWKSetOptions, JWKSCacheInput, ExportedJWKSCache, FetchImplementation, } from './jwks/remote.js'; | ||
| export type { RemoteJWKSet, RemoteJWKSetOptions, JWKSCacheInput, ExportedJWKSCache, FetchImplementation, } from './jwks/remote.js'; | ||
| export { UnsecuredJWT } from './jwt/unsecured.js'; | ||
@@ -44,8 +45,8 @@ export type { UnsecuredResult } from './jwt/unsecured.js'; | ||
| export { generateKeyPair } from './key/generate_key_pair.js'; | ||
| export type { GenerateKeyPairResult, GenerateKeyPairOptions } from './key/generate_key_pair.js'; | ||
| export type { GenerateKeyPairAlgorithm, GenerateKeyPairResult, GenerateKeyPairOptions, } from './key/generate_key_pair.js'; | ||
| export { generateSecret } from './key/generate_secret.js'; | ||
| export type { GenerateSecretOptions } from './key/generate_secret.js'; | ||
| export type { GenerateSecretAlgorithm, GenerateSecretOptions } from './key/generate_secret.js'; | ||
| import * as base64url from './util/base64url.js'; | ||
| export { base64url }; | ||
| export type { CompactDecryptResult, CompactJWEHeaderParameters, CompactJWSHeaderParameters, CompactVerifyResult, CritOption, CryptoKey, DecryptOptions, EncryptOptions, FlattenedDecryptResult, FlattenedJWE, FlattenedJWS, FlattenedJWSInput, FlattenedVerifyResult, GeneralDecryptResult, GeneralJWE, GeneralJWS, GeneralJWSInput, GeneralVerifyResult, GetKeyFunction, JoseHeaderParameters, JSONWebKeySet, JWEHeaderParameters, JWEKeyManagementHeaderParameters, JWK_EC_Private, JWK_EC_Public, JWK_oct, JWK_OKP_Private, JWK_OKP_Public, JWK_RSA_Private, JWK_RSA_Public, JWK, JWKParameters, JWSHeaderParameters, JWTClaimVerificationOptions, JWTDecryptResult, JWTHeaderParameters, JWTPayload, JWTVerifyResult, KeyObject, ProduceJWT, ResolvedKey, SignOptions, VerifyOptions, } from './types.d.ts'; | ||
| export type { AnyJWK, CompactDecryptResult, CompactJWEHeaderParameters, CompactJWSHeaderParameters, CompactVerifyResult, CritOption, CryptoKey, DecryptOptions, EncryptOptions, FlattenedDecryptResult, FlattenedJWE, FlattenedJWS, FlattenedJWSInput, FlattenedVerifyResult, GeneralDecryptResult, GeneralJWE, GeneralJWS, GeneralJWSInput, GeneralVerifyResult, GetKeyFunction, JoseHeaderParameters, JSONWebKeySet, JWEContentEncryptionAlgorithm, JWEHeaderParameters, JWEKeyManagementAlgorithm, JWEKeyManagementHeaderParameters, JWK_AKP_Private, JWK_AKP_Public, JWK_EC_Private, JWK_EC_Public, JWK_oct, JWK_OKP_Private, JWK_OKP_Public, JWK_RSA_Private, JWK_RSA_Public, JWK, JWKKeyType, JWKParameters, JWSAlgorithm, JWSHeaderParameters, JWTClaimVerificationOptions, JWTDecryptResult, JWTHeaderParameters, JWTPayload, JWTVerifyResult, KeyInput, KeyObject, ProduceJWT, ResolvedKey, SignOptions, VerifyOptions, } from './types.d.ts'; | ||
| /** | ||
@@ -55,4 +56,4 @@ * In prior releases this indicated whether a Node.js-specific build was loaded, this is now fixed | ||
| * | ||
| * @deprecated | ||
| * @deprecated Remove any runtime branching on this value; it is always `"WebCryptoAPI"`. | ||
| */ | ||
| export declare const cryptoRuntime = "WebCryptoAPI"; |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * Decrypting JSON Web Encryption (JWE) in Compact Serialization | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../../types.d.ts'; | ||
@@ -11,3 +6,3 @@ /** | ||
| */ | ||
| export interface CompactDecryptGetKey extends types.GetKeyFunction<types.CompactJWEHeaderParameters, types.FlattenedJWE> { | ||
| export interface CompactDecryptGetKey<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array> extends types.GetKeyFunction<types.CompactJWEHeaderParameters, types.FlattenedJWE, KeyType | types.KeyObject | types.JWK> { | ||
| } | ||
@@ -17,5 +12,2 @@ /** | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jwe/compact/decrypt'`. | ||
| * | ||
| * @param jwe Compact JWE. | ||
@@ -26,4 +18,7 @@ * @param key Private Key or Secret to decrypt the JWE with. See | ||
| */ | ||
| export declare function compactDecrypt(jwe: string | Uint8Array, key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.DecryptOptions): Promise<types.CompactDecryptResult>; | ||
| export declare function compactDecrypt(jwe: string | Uint8Array, key: types.KeyInput, options?: types.DecryptOptions): Promise<types.CompactDecryptResult>; | ||
| /** | ||
| * Decrypts a Compact JWE, resolving the key dynamically. The result additionally carries the | ||
| * {@link types.ResolvedKey.key resolved key}. | ||
| * | ||
| * @param jwe Compact JWE. | ||
@@ -34,2 +29,13 @@ * @param getKey Function resolving Private Key or Secret to decrypt the JWE with. See | ||
| */ | ||
| export declare function compactDecrypt(jwe: string | Uint8Array, getKey: CompactDecryptGetKey, options?: types.DecryptOptions): Promise<types.CompactDecryptResult & types.ResolvedKey>; | ||
| export declare function compactDecrypt<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array>(jwe: string | Uint8Array, getKey: CompactDecryptGetKey<KeyType>, options?: types.DecryptOptions): Promise<types.CompactDecryptResult & types.ResolvedKey<KeyType>>; | ||
| /** | ||
| * Accepts either form of the `key` argument. Use this overload when forwarding a value that may be | ||
| * either a key or a key resolution function; `key` is present on the result only when a resolution | ||
| * function was used. | ||
| * | ||
| * @param jwe Compact JWE. | ||
| * @param key Private Key or Secret, or a function resolving one, to decrypt the JWE with. See | ||
| * {@link https://github.com/panva/jose/issues/210#jwe-alg Algorithm Key Requirements}. | ||
| * @param options JWE Decryption options. | ||
| */ | ||
| export declare function compactDecrypt(jwe: string | Uint8Array, key: types.KeyInput | CompactDecryptGetKey, options?: types.DecryptOptions): Promise<types.CompactDecryptResult & Partial<types.ResolvedKey>>; |
@@ -1,14 +0,3 @@ | ||
| /** | ||
| * Encrypting JSON Web Encryption (JWE) in Compact Serialization | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../../types.d.ts'; | ||
| /** | ||
| * The CompactEncrypt class is used to build and encrypt Compact JWE strings. | ||
| * | ||
| * This class is exported (as a named export) from the main `'jose'` module entry point as well as | ||
| * from its subpath export `'jose/jwe/compact/encrypt'`. | ||
| * | ||
| */ | ||
| /** The CompactEncrypt class is used to build and encrypt Compact JWE strings. */ | ||
| export declare class CompactEncrypt { | ||
@@ -24,3 +13,3 @@ #private; | ||
| * Sets a content encryption key to use, by default a random suitable one is generated for the JWE | ||
| * enc" (Encryption Algorithm) Header Parameter. | ||
| * "enc" (Encryption Algorithm) Header Parameter. | ||
| * | ||
@@ -35,3 +24,3 @@ * @deprecated You should not use this method. It is only really intended for test and vector | ||
| * Sets the JWE Initialization Vector to use for content encryption, by default a random suitable | ||
| * one is generated for the JWE enc" (Encryption Algorithm) Header Parameter. | ||
| * one is generated for the JWE "enc" (Encryption Algorithm) Header Parameter. | ||
| * | ||
@@ -51,7 +40,6 @@ * @deprecated You should not use this method. It is only really intended for test and vector | ||
| /** | ||
| * Sets the JWE Key Management parameters to be used when encrypting. | ||
| * Sets the JWE Key Management parameters to be used when encrypting. For ECDH based algorithms, | ||
| * use this method to set the "apu" (Agreement PartyUInfo) or "apv" (Agreement PartyVInfo) | ||
| * parameters. | ||
| * | ||
| * (ECDH-ES) Use of this method is needed for ECDH based algorithms to set the "apu" (Agreement | ||
| * PartyUInfo) or "apv" (Agreement PartyVInfo) parameters. | ||
| * | ||
| * @param parameters JWE Key Management parameters. | ||
@@ -67,3 +55,3 @@ */ | ||
| */ | ||
| encrypt(key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.EncryptOptions): Promise<string>; | ||
| encrypt(key: types.KeyInput, options?: types.EncryptOptions): Promise<string>; | ||
| } |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * Decrypting JSON Web Encryption (JWE) in Flattened JSON Serialization | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../../types.d.ts'; | ||
@@ -11,3 +6,3 @@ /** | ||
| */ | ||
| export interface FlattenedDecryptGetKey extends types.GetKeyFunction<types.JWEHeaderParameters | undefined, types.FlattenedJWE> { | ||
| export interface FlattenedDecryptGetKey<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array> extends types.GetKeyFunction<types.JWEHeaderParameters | undefined, types.FlattenedJWE, KeyType | types.KeyObject | types.JWK> { | ||
| } | ||
@@ -17,5 +12,2 @@ /** | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jwe/flattened/decrypt'`. | ||
| * | ||
| * @param jwe Flattened JWE. | ||
@@ -26,4 +18,7 @@ * @param key Private Key or Secret to decrypt the JWE with. See | ||
| */ | ||
| export declare function flattenedDecrypt(jwe: types.FlattenedJWE, key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.DecryptOptions): Promise<types.FlattenedDecryptResult>; | ||
| export declare function flattenedDecrypt(jwe: types.FlattenedJWE, key: types.KeyInput, options?: types.DecryptOptions): Promise<types.FlattenedDecryptResult>; | ||
| /** | ||
| * Decrypts a Flattened JWE, resolving the key dynamically. The result additionally carries the | ||
| * {@link types.ResolvedKey.key resolved key}. | ||
| * | ||
| * @param jwe Flattened JWE. | ||
@@ -34,2 +29,13 @@ * @param getKey Function resolving Private Key or Secret to decrypt the JWE with. See | ||
| */ | ||
| export declare function flattenedDecrypt(jwe: types.FlattenedJWE, getKey: FlattenedDecryptGetKey, options?: types.DecryptOptions): Promise<types.FlattenedDecryptResult & types.ResolvedKey>; | ||
| export declare function flattenedDecrypt<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array>(jwe: types.FlattenedJWE, getKey: FlattenedDecryptGetKey<KeyType>, options?: types.DecryptOptions): Promise<types.FlattenedDecryptResult & types.ResolvedKey<KeyType>>; | ||
| /** | ||
| * Accepts either form of the `key` argument. Use this overload when forwarding a value that may be | ||
| * either a key or a key resolution function; `key` is present on the result only when a resolution | ||
| * function was used. | ||
| * | ||
| * @param jwe Flattened JWE. | ||
| * @param key Private Key or Secret, or a function resolving one, to decrypt the JWE with. See | ||
| * {@link https://github.com/panva/jose/issues/210#jwe-alg Algorithm Key Requirements}. | ||
| * @param options JWE Decryption options. | ||
| */ | ||
| export declare function flattenedDecrypt(jwe: types.FlattenedJWE, key: types.KeyInput | FlattenedDecryptGetKey, options?: types.DecryptOptions): Promise<types.FlattenedDecryptResult & Partial<types.ResolvedKey>>; |
@@ -1,14 +0,3 @@ | ||
| /** | ||
| * Encrypting JSON Web Encryption (JWE) in Flattened JSON Serialization | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../../types.d.ts'; | ||
| /** | ||
| * The FlattenedEncrypt class is used to build and encrypt Flattened JWE objects. | ||
| * | ||
| * This class is exported (as a named export) from the main `'jose'` module entry point as well as | ||
| * from its subpath export `'jose/jwe/flattened/encrypt'`. | ||
| * | ||
| */ | ||
| /** The FlattenedEncrypt class is used to build and encrypt Flattened JWE objects. */ | ||
| export declare class FlattenedEncrypt { | ||
@@ -23,7 +12,6 @@ #private; | ||
| /** | ||
| * Sets the JWE Key Management parameters to be used when encrypting. | ||
| * Sets the JWE Key Management parameters to be used when encrypting. For ECDH based algorithms, | ||
| * use this method to set the "apu" (Agreement PartyUInfo) or "apv" (Agreement PartyVInfo) | ||
| * parameters. | ||
| * | ||
| * (ECDH-ES) Use of this method is needed for ECDH based algorithms to set the "apu" (Agreement | ||
| * PartyUInfo) or "apv" (Agreement PartyVInfo) parameters. | ||
| * | ||
| * @param parameters JWE Key Management parameters. | ||
@@ -58,3 +46,3 @@ */ | ||
| * Sets a content encryption key to use, by default a random suitable one is generated for the JWE | ||
| * enc" (Encryption Algorithm) Header Parameter. | ||
| * "enc" (Encryption Algorithm) Header Parameter. | ||
| * | ||
@@ -69,3 +57,3 @@ * @deprecated You should not use this method. It is only really intended for test and vector | ||
| * Sets the JWE Initialization Vector to use for content encryption, by default a random suitable | ||
| * one is generated for the JWE enc" (Encryption Algorithm) Header Parameter. | ||
| * one is generated for the JWE "enc" (Encryption Algorithm) Header Parameter. | ||
| * | ||
@@ -85,3 +73,3 @@ * @deprecated You should not use this method. It is only really intended for test and vector | ||
| */ | ||
| encrypt(key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.EncryptOptions): Promise<types.FlattenedJWE>; | ||
| encrypt(key: types.KeyInput, options?: types.EncryptOptions): Promise<types.FlattenedJWE>; | ||
| } |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * Decrypting JSON Web Encryption (JWE) in General JSON Serialization | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../../types.d.ts'; | ||
@@ -11,3 +6,3 @@ /** | ||
| */ | ||
| export interface GeneralDecryptGetKey extends types.GetKeyFunction<types.JWEHeaderParameters, types.FlattenedJWE> { | ||
| export interface GeneralDecryptGetKey<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array> extends types.GetKeyFunction<types.JWEHeaderParameters | undefined, types.FlattenedJWE, KeyType | types.KeyObject | types.JWK> { | ||
| } | ||
@@ -17,7 +12,3 @@ /** | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jwe/general/decrypt'`. | ||
| * | ||
| * > [!NOTE]\ | ||
| * > The function iterates over the `recipients` array in the General JWE and returns the decryption | ||
| * > Note: The function iterates over the `recipients` array in the General JWE and returns the decryption | ||
| * > result of the first recipient entry that can be successfully decrypted. The result only contains | ||
@@ -33,4 +24,7 @@ * > the plaintext and headers of that successfully decrypted recipient entry. Other recipient entries | ||
| */ | ||
| export declare function generalDecrypt(jwe: types.GeneralJWE, key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.DecryptOptions): Promise<types.GeneralDecryptResult>; | ||
| export declare function generalDecrypt(jwe: types.GeneralJWE, key: types.KeyInput, options?: types.DecryptOptions): Promise<types.GeneralDecryptResult>; | ||
| /** | ||
| * Decrypts a General JWE, resolving the key dynamically. The result additionally carries the | ||
| * {@link types.ResolvedKey.key resolved key}. | ||
| * | ||
| * @param jwe General JWE. | ||
@@ -41,2 +35,13 @@ * @param getKey Function resolving Private Key or Secret to decrypt the JWE with. See | ||
| */ | ||
| export declare function generalDecrypt(jwe: types.GeneralJWE, getKey: GeneralDecryptGetKey, options?: types.DecryptOptions): Promise<types.GeneralDecryptResult & types.ResolvedKey>; | ||
| export declare function generalDecrypt<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array>(jwe: types.GeneralJWE, getKey: GeneralDecryptGetKey<KeyType>, options?: types.DecryptOptions): Promise<types.GeneralDecryptResult & types.ResolvedKey<KeyType>>; | ||
| /** | ||
| * Accepts either form of the `key` argument. Use this overload when forwarding a value that may be | ||
| * either a key or a key resolution function; `key` is present on the result only when a resolution | ||
| * function was used. | ||
| * | ||
| * @param jwe General JWE. | ||
| * @param key Private Key or Secret, or a function resolving one, to decrypt the JWE with. See | ||
| * {@link https://github.com/panva/jose/issues/210#jwe-alg Algorithm Key Requirements}. | ||
| * @param options JWE Decryption options. | ||
| */ | ||
| export declare function generalDecrypt(jwe: types.GeneralJWE, key: types.KeyInput | GeneralDecryptGetKey, options?: types.DecryptOptions): Promise<types.GeneralDecryptResult & Partial<types.ResolvedKey>>; |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * Encrypting JSON Web Encryption (JWE) in General JSON Serialization | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../../types.d.ts'; | ||
@@ -16,24 +11,28 @@ /** Used to build General JWE object's individual recipients. */ | ||
| /** | ||
| * Sets the JWE Key Management parameters to be used when encrypting. | ||
| * Sets the JWE Key Management parameters to be used when encrypting. For ECDH based algorithms, | ||
| * use this method to set the "apu" (Agreement PartyUInfo) or "apv" (Agreement PartyVInfo) | ||
| * parameters. | ||
| * | ||
| * (ECDH-ES) Use of this method is needed for ECDH based algorithms to set the "apu" (Agreement | ||
| * PartyUInfo) or "apv" (Agreement PartyVInfo) parameters. | ||
| * | ||
| * @param parameters JWE Key Management parameters. | ||
| */ | ||
| setKeyManagementParameters(parameters: types.JWEKeyManagementHeaderParameters): Recipient; | ||
| /** A shorthand for calling addRecipient() on the enclosing {@link GeneralEncrypt} instance */ | ||
| addRecipient(...args: Parameters<GeneralEncrypt['addRecipient']>): Recipient; | ||
| /** A shorthand for calling encrypt() on the enclosing {@link GeneralEncrypt} instance */ | ||
| encrypt(...args: Parameters<GeneralEncrypt['encrypt']>): Promise<types.GeneralJWE>; | ||
| /** | ||
| * A shorthand for calling {@link GeneralEncrypt.addRecipient addRecipient()} on the enclosing | ||
| * {@link GeneralEncrypt} instance. | ||
| * | ||
| * @param key Public Key or Secret to encrypt the Content Encryption Key for the recipient with. | ||
| * See {@link https://github.com/panva/jose/issues/210#jwe-alg Algorithm Key Requirements}. | ||
| * @param options JWE Encryption options. | ||
| */ | ||
| addRecipient(key: types.KeyInput, options?: types.CritOption): Recipient; | ||
| /** | ||
| * A shorthand for calling {@link GeneralEncrypt.encrypt encrypt()} on the enclosing | ||
| * {@link GeneralEncrypt} instance. Takes no arguments — each recipient's key is supplied to | ||
| * {@link addRecipient}. | ||
| */ | ||
| encrypt(): Promise<types.GeneralJWE>; | ||
| /** Returns the enclosing {@link GeneralEncrypt} instance */ | ||
| done(): GeneralEncrypt; | ||
| } | ||
| /** | ||
| * The GeneralEncrypt class is used to build and encrypt General JWE objects. | ||
| * | ||
| * This class is exported (as a named export) from the main `'jose'` module entry point as well as | ||
| * from its subpath export `'jose/jwe/general/encrypt'`. | ||
| * | ||
| */ | ||
| /** The GeneralEncrypt class is used to build and encrypt General JWE objects. */ | ||
| export declare class GeneralEncrypt { | ||
@@ -54,3 +53,3 @@ #private; | ||
| */ | ||
| addRecipient(key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.CritOption): Recipient; | ||
| addRecipient(key: types.KeyInput, options?: types.CritOption): Recipient; | ||
| /** | ||
@@ -57,0 +56,0 @@ * Sets the JWE Protected Header on the GeneralEncrypt object. |
@@ -1,17 +0,13 @@ | ||
| /** | ||
| * Verification using a JWK Embedded in a JWS Header | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
| /** | ||
| * EmbeddedJWK is an implementation of a GetKeyFunction intended to be used with the JWS/JWT verify | ||
| * operations whenever you need to opt-in to verify signatures with a public key embedded in the | ||
| * token's "jwk" (JSON Web Key) Header Parameter. It is recommended to combine this with the verify | ||
| * function's `algorithms` option to define accepted JWS "alg" (Algorithm) Header Parameter values. | ||
| * EmbeddedJWK is an implementation of a {@link types.GetKeyFunction GetKeyFunction} intended to be | ||
| * used with the JWS/JWT verify operations whenever you need to opt-in to verify signatures with a | ||
| * public key embedded in the token's "jwk" (JSON Web Key) Header Parameter. It is recommended to | ||
| * combine this with the verify function's `algorithms` option to define accepted JWS "alg" | ||
| * (Algorithm) Header Parameter values. | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jwk/embedded'`. | ||
| * | ||
| * @param protectedHeader JWS Protected Header. | ||
| * @param token The consumed JWS token. | ||
| * @returns The public key from the JWS "jwk" (JSON Web Key) Header Parameter. | ||
| */ | ||
| export declare function EmbeddedJWK(protectedHeader?: types.JWSHeaderParameters, token?: types.FlattenedJWSInput): Promise<types.CryptoKey>; |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * JSON Web Key Thumbprint and JSON Web Key Thumbprint URI | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
@@ -10,10 +5,5 @@ /** | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jwk/thumbprint'`. | ||
| * | ||
| * @param key Key to calculate the thumbprint for. | ||
| * @param digestAlgorithm Digest Algorithm to use for calculating the thumbprint. Default is | ||
| * "sha256". | ||
| * | ||
| * @see {@link https://www.rfc-editor.org/rfc/rfc7638 RFC7638} | ||
| */ | ||
@@ -24,11 +14,6 @@ export declare function calculateJwkThumbprint(key: types.JWK | types.CryptoKey | types.KeyObject, digestAlgorithm?: 'sha256' | 'sha384' | 'sha512'): Promise<string>; | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jwk/thumbprint'`. | ||
| * | ||
| * @param key Key to calculate the thumbprint for. | ||
| * @param digestAlgorithm Digest Algorithm to use for calculating the thumbprint. Default is | ||
| * "sha256". | ||
| * | ||
| * @see {@link https://www.rfc-editor.org/rfc/rfc9278 RFC9278} | ||
| */ | ||
| export declare function calculateJwkThumbprintUri(key: types.CryptoKey | types.KeyObject | types.JWK, digestAlgorithm?: 'sha256' | 'sha384' | 'sha512'): Promise<string>; |
@@ -1,29 +0,20 @@ | ||
| /** | ||
| * Verification using a JSON Web Key Set (JWKS) available locally | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
| /** The key resolution function returned by {@link createLocalJWKSet}. */ | ||
| export interface LocalJWKSet { | ||
| (protectedHeader?: types.JWSHeaderParameters, token?: types.FlattenedJWSInput): Promise<types.CryptoKey>; | ||
| /** Returns a structured clone of the JSON Web Key Set this resolver was created with. */ | ||
| jwks: () => types.JSONWebKeySet; | ||
| } | ||
| /** | ||
| * Returns a function that resolves a JWS JOSE Header to a public key object from a locally stored, | ||
| * or otherwise available, JSON Web Key Set. | ||
| * or otherwise available, JSON Web Key Set. Selection respects the header's "alg" (Algorithm) and | ||
| * "kid" (Key ID) as well as the JWK's "use" (Public Key Use) and "key_ops" (Key Operations). | ||
| * Exactly one key must match; if multiple keys match, the thrown `JWKSMultipleMatchingKeys` can be | ||
| * iterated. | ||
| * | ||
| * It uses the "alg" (JWS Algorithm) Header Parameter to determine the right JWK "kty" (Key Type), | ||
| * then proceeds to match the JWK "kid" (Key ID) with one found in the JWS Header Parameters (if | ||
| * there is one) while also respecting the JWK "use" (Public Key Use) and JWK "key_ops" (Key | ||
| * Operations) Parameters (if they are present on the JWK). | ||
| * | ||
| * Only a single public key must match the selection process. As shown in the example below when | ||
| * multiple keys get matched it is possible to opt-in to iterate over the matched keys and attempt | ||
| * verification in an iterative manner. | ||
| * | ||
| * > [!NOTE]\ | ||
| * > The function's purpose is to resolve public keys used for verifying signatures and will not work | ||
| * > Note: The function's purpose is to resolve public keys used for verifying signatures and will not work | ||
| * > for public encryption keys. | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jwks/local'`. | ||
| * | ||
| * @param jwks JSON Web Key Set formatted object. | ||
| */ | ||
| export declare function createLocalJWKSet(jwks: types.JSONWebKeySet): (protectedHeader?: types.JWSHeaderParameters, token?: types.FlattenedJWSInput) => Promise<types.CryptoKey>; | ||
| export declare function createLocalJWKSet(jwks: types.JSONWebKeySet): LocalJWKSet; |
+34
-165
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * Verification using a JSON Web Key Set (JWKS) available on an HTTP(S) URL | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
@@ -11,90 +6,4 @@ /** | ||
| * | ||
| * > [!NOTE]\ | ||
| * > Known caveat: Expect Type-related issues when passing the inputs through to fetch-like modules, | ||
| * > Note: Known caveat: Expect Type-related issues when passing the inputs through to fetch-like modules, | ||
| * > they hardly ever get their typings inline with actual fetch, you should `@ts-expect-error` them. | ||
| * | ||
| * import ky from 'ky' | ||
| * | ||
| * let logRequest!: (request: Request) => void | ||
| * let logResponse!: (request: Request, response: Response) => void | ||
| * let logRetry!: (request: Request, error: Error, retryCount: number) => void | ||
| * | ||
| * const JWKS = jose.createRemoteJWKSet(url, { | ||
| * [jose.customFetch]: (...args) => | ||
| * ky(args[0], { | ||
| * ...args[1], | ||
| * hooks: { | ||
| * beforeRequest: [ | ||
| * (request) => { | ||
| * logRequest(request) | ||
| * }, | ||
| * ], | ||
| * beforeRetry: [ | ||
| * ({ request, error, retryCount }) => { | ||
| * logRetry(request, error, retryCount) | ||
| * }, | ||
| * ], | ||
| * afterResponse: [ | ||
| * (request, _, response) => { | ||
| * logResponse(request, response) | ||
| * }, | ||
| * ], | ||
| * }, | ||
| * }), | ||
| * }) | ||
| * ``` | ||
| * | ||
| * import * as undici from 'undici' | ||
| * | ||
| * // see https://undici.nodejs.org/api/EnvHttpProxyAgent | ||
| * let envHttpProxyAgent = new undici.EnvHttpProxyAgent() | ||
| * | ||
| * // @ts-ignore | ||
| * const JWKS = jose.createRemoteJWKSet(url, { | ||
| * [jose.customFetch]: (...args) => { | ||
| * // @ts-ignore | ||
| * return undici.fetch(args[0], { ...args[1], dispatcher: envHttpProxyAgent }) // prettier-ignore | ||
| * }, | ||
| * }) | ||
| * ``` | ||
| * | ||
| * import * as undici from 'undici' | ||
| * | ||
| * // see https://undici.nodejs.org/api/RetryAgent | ||
| * let retryAgent = new undici.RetryAgent(new undici.Agent(), { | ||
| * statusCodes: [], | ||
| * errorCodes: [ | ||
| * 'ECONNRESET', | ||
| * 'ECONNREFUSED', | ||
| * 'ENOTFOUND', | ||
| * 'ENETDOWN', | ||
| * 'ENETUNREACH', | ||
| * 'EHOSTDOWN', | ||
| * 'UND_ERR_SOCKET', | ||
| * ], | ||
| * }) | ||
| * | ||
| * // @ts-ignore | ||
| * const JWKS = jose.createRemoteJWKSet(url, { | ||
| * [jose.customFetch]: (...args) => { | ||
| * // @ts-ignore | ||
| * return undici.fetch(args[0], { ...args[1], dispatcher: retryAgent }) // prettier-ignore | ||
| * }, | ||
| * }) | ||
| * ``` | ||
| * | ||
| * import * as undici from 'undici' | ||
| * | ||
| * // see https://undici.nodejs.org/api/MockAgent | ||
| * let mockAgent = new undici.MockAgent() | ||
| * mockAgent.disableNetConnect() | ||
| * | ||
| * // @ts-ignore | ||
| * const JWKS = jose.createRemoteJWKSet(url, { | ||
| * [jose.customFetch]: (...args) => { | ||
| * // @ts-ignore | ||
| * return undici.fetch(args[0], { ...args[1], dispatcher: mockAgent }) // prettier-ignore | ||
| * }, | ||
| * }) | ||
| * ``` | ||
| */ | ||
@@ -117,4 +26,3 @@ export declare const customFetch: unique symbol; | ||
| /** | ||
| * > [!WARNING]\ | ||
| * > This option has security implications that must be understood, assessed for applicability, and | ||
| * > Warning: This option has security implications that must be understood, assessed for applicability, and | ||
| * > accepted before use. It is critical that the JSON Web Key Set cache only be writable by your own | ||
@@ -124,45 +32,5 @@ * > code. | ||
| * This option is intended for cloud computing runtimes that cannot keep an in memory cache between | ||
| * their code's invocations. Use in runtimes where an in memory cache between requests is available | ||
| * is not desirable. | ||
| * | ||
| * When passed to {@link jwks/remote.createRemoteJWKSet createRemoteJWKSet} this allows the passed in | ||
| * object to: | ||
| * | ||
| * - Serve as an initial value for the JSON Web Key Set that the module would otherwise need to | ||
| * trigger an HTTP request for | ||
| * - Have the JSON Web Key Set the function optionally ended up triggering an HTTP request for | ||
| * assigned to it as properties | ||
| * | ||
| * The intended use pattern is: | ||
| * | ||
| * - Before verifying with {@link jwks/remote.createRemoteJWKSet createRemoteJWKSet} you pull the | ||
| * previously cached object from a low-latency key-value store offered by the cloud computing | ||
| * runtime it is executed on; | ||
| * - Default to an empty object `{}` instead when there's no previously cached value; | ||
| * - Pass it in as {@link RemoteJWKSetOptions[jwksCache]}; | ||
| * - Afterwards, update the key-value storage if the {@link ExportedJWKSCache.uat `uat`} property of | ||
| * the object has changed. | ||
| * | ||
| * // Prerequisites | ||
| * let url!: URL | ||
| * let jwt!: string | ||
| * let getPreviouslyCachedJWKS!: () => Promise<jose.ExportedJWKSCache> | ||
| * let storeNewJWKScache!: (cache: jose.ExportedJWKSCache) => Promise<void> | ||
| * | ||
| * // Load JSON Web Key Set cache | ||
| * const jwksCache: jose.JWKSCacheInput = (await getPreviouslyCachedJWKS()) || {} | ||
| * const { uat } = jwksCache | ||
| * | ||
| * const JWKS = jose.createRemoteJWKSet(url, { | ||
| * [jose.jwksCache]: jwksCache, | ||
| * }) | ||
| * | ||
| * // Use JSON Web Key Set cache | ||
| * await jose.jwtVerify(jwt, JWKS) | ||
| * | ||
| * if (uat !== jwksCache.uat) { | ||
| * // Update JSON Web Key Set cache | ||
| * await storeNewJWKScache(jwksCache) | ||
| * } | ||
| * ``` | ||
| * their code's invocations. The supplied writable object seeds the resolver's cache and is updated | ||
| * with `jwks` and `uat` after a successful fetch; persist it whenever `uat` changes. Using this in | ||
| * runtimes that can keep an in-memory cache between requests is not desirable. | ||
| */ | ||
@@ -203,2 +71,25 @@ export declare const jwksCache: unique symbol; | ||
| export type JWKSCacheInput = ExportedJWKSCache | Record<string, never>; | ||
| /** The key resolution function returned by {@link createRemoteJWKSet}. */ | ||
| export interface RemoteJWKSet { | ||
| (protectedHeader?: types.JWSHeaderParameters, token?: types.FlattenedJWSInput): Promise<types.CryptoKey>; | ||
| /** Whether the cooldown window following the last successful fetch is still in effect. */ | ||
| readonly coolingDown: boolean; | ||
| /** | ||
| * Whether the currently cached JSON Web Key Set is within its | ||
| * {@link RemoteJWKSetOptions.cacheMaxAge}. | ||
| */ | ||
| readonly fresh: boolean; | ||
| /** Whether a JSON Web Key Set fetch is currently in flight. */ | ||
| readonly reloading: boolean; | ||
| /** | ||
| * Triggers a JSON Web Key Set fetch, bypassing | ||
| * {@link RemoteJWKSetOptions.cooldownDuration the cooldown}. | ||
| */ | ||
| reload: () => Promise<void>; | ||
| /** | ||
| * The currently cached JSON Web Key Set, or `undefined` when none has been fetched or seeded via | ||
| * {@link jwksCache} yet. | ||
| */ | ||
| jwks: () => types.JSONWebKeySet | undefined; | ||
| } | ||
| /** | ||
@@ -208,35 +99,13 @@ * Returns a function that resolves a JWS JOSE Header to a public key object downloaded from a | ||
| * jwks_uri. The JSON Web Key Set is fetched when no key matches the selection process but only as | ||
| * frequently as the `cooldownDuration` option allows to prevent abuse. | ||
| * frequently as the `cooldownDuration` option allows to prevent abuse. Selection respects the | ||
| * header's "alg" (Algorithm) and "kid" (Key ID) as well as the JWK's "use" (Public Key Use) and | ||
| * "key_ops" (Key Operations). Exactly one key must match; if multiple keys match, the thrown | ||
| * `JWKSMultipleMatchingKeys` can be iterated. | ||
| * | ||
| * It uses the "alg" (JWS Algorithm) Header Parameter to determine the right JWK "kty" (Key Type), | ||
| * then proceeds to match the JWK "kid" (Key ID) with one found in the JWS Header Parameters (if | ||
| * there is one) while also respecting the JWK "use" (Public Key Use) and JWK "key_ops" (Key | ||
| * Operations) Parameters (if they are present on the JWK). | ||
| * | ||
| * Only a single public key must match the selection process. As shown in the example below when | ||
| * multiple keys get matched it is possible to opt-in to iterate over the matched keys and attempt | ||
| * verification in an iterative manner. | ||
| * | ||
| * > [!NOTE]\ | ||
| * > The function's purpose is to resolve public keys used for verifying signatures and will not work | ||
| * > Note: The function's purpose is to resolve public keys used for verifying signatures and will not work | ||
| * > for public encryption keys. | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jwks/remote'`. | ||
| * | ||
| * @param url URL to fetch the JSON Web Key Set from. | ||
| * @param options Options for the remote JSON Web Key Set. | ||
| */ | ||
| export declare function createRemoteJWKSet(url: URL, options?: RemoteJWKSetOptions): { | ||
| (protectedHeader?: types.JWSHeaderParameters, token?: types.FlattenedJWSInput): Promise<types.CryptoKey>; | ||
| /** @ignore */ | ||
| coolingDown: boolean; | ||
| /** @ignore */ | ||
| fresh: boolean; | ||
| /** @ignore */ | ||
| reloading: boolean; | ||
| /** @ignore */ | ||
| reload: () => Promise<void>; | ||
| /** @ignore */ | ||
| jwks: () => types.JSONWebKeySet | undefined; | ||
| }; | ||
| export declare function createRemoteJWKSet(url: URL, options?: RemoteJWKSetOptions): RemoteJWKSet; |
@@ -1,14 +0,3 @@ | ||
| /** | ||
| * Signing JSON Web Signature (JWS) in Compact Serialization | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../../types.d.ts'; | ||
| /** | ||
| * The CompactSign class is used to build and sign Compact JWS strings. | ||
| * | ||
| * This class is exported (as a named export) from the main `'jose'` module entry point as well as | ||
| * from its subpath export `'jose/jws/compact/sign'`. | ||
| * | ||
| */ | ||
| /** The CompactSign class is used to build and sign Compact JWS strings. */ | ||
| export declare class CompactSign { | ||
@@ -35,3 +24,3 @@ #private; | ||
| */ | ||
| sign(key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.SignOptions): Promise<string>; | ||
| sign(key: types.KeyInput, options?: types.SignOptions): Promise<string>; | ||
| } |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * Verifying JSON Web Signature (JWS) in Compact Serialization | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../../types.d.ts'; | ||
@@ -10,6 +5,4 @@ /** | ||
| * verified at the time of this function call. | ||
| * | ||
| * @see {@link jwks/remote.createRemoteJWKSet createRemoteJWKSet} to verify using a remote JSON Web Key Set. | ||
| */ | ||
| export interface CompactVerifyGetKey extends types.GenericGetKeyFunction<types.CompactJWSHeaderParameters, types.FlattenedJWSInput, types.CryptoKey | types.KeyObject | types.JWK | Uint8Array> { | ||
| export interface CompactVerifyGetKey<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array> extends types.GetKeyFunction<types.CompactJWSHeaderParameters, types.FlattenedJWSInput, KeyType | types.KeyObject | types.JWK> { | ||
| } | ||
@@ -19,5 +12,2 @@ /** | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jws/compact/verify'`. | ||
| * | ||
| * @param jws Compact JWS. | ||
@@ -28,4 +18,7 @@ * @param key Key to verify the JWS with. See | ||
| */ | ||
| export declare function compactVerify(jws: string | Uint8Array, key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.VerifyOptions): Promise<types.CompactVerifyResult>; | ||
| export declare function compactVerify(jws: string | Uint8Array, key: types.KeyInput, options?: types.VerifyOptions): Promise<types.CompactVerifyResult>; | ||
| /** | ||
| * Verifies the signature and format of and afterwards decodes the Compact JWS, resolving the key | ||
| * dynamically. The result additionally carries the {@link types.ResolvedKey.key resolved key}. | ||
| * | ||
| * @param jws Compact JWS. | ||
@@ -36,2 +29,13 @@ * @param getKey Function resolving a key to verify the JWS with. See | ||
| */ | ||
| export declare function compactVerify(jws: string | Uint8Array, getKey: CompactVerifyGetKey, options?: types.VerifyOptions): Promise<types.CompactVerifyResult & types.ResolvedKey>; | ||
| export declare function compactVerify<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array>(jws: string | Uint8Array, getKey: CompactVerifyGetKey<KeyType>, options?: types.VerifyOptions): Promise<types.CompactVerifyResult & types.ResolvedKey<KeyType>>; | ||
| /** | ||
| * Accepts either form of the `key` argument. Use this overload when forwarding a value that may be | ||
| * either a key or a key resolution function; `key` is present on the result only when a resolution | ||
| * function was used. | ||
| * | ||
| * @param jws Compact JWS. | ||
| * @param key Key, or function resolving a key, to verify the JWS with. See | ||
| * {@link https://github.com/panva/jose/issues/210#jws-alg Algorithm Key Requirements}. | ||
| * @param options JWS Verify options. | ||
| */ | ||
| export declare function compactVerify(jws: string | Uint8Array, key: types.KeyInput | CompactVerifyGetKey, options?: types.VerifyOptions): Promise<types.CompactVerifyResult & Partial<types.ResolvedKey>>; |
@@ -1,14 +0,3 @@ | ||
| /** | ||
| * Signing JSON Web Signature (JWS) in Flattened JSON Serialization | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../../types.d.ts'; | ||
| /** | ||
| * The FlattenedSign class is used to build and sign Flattened JWS objects. | ||
| * | ||
| * This class is exported (as a named export) from the main `'jose'` module entry point as well as | ||
| * from its subpath export `'jose/jws/flattened/sign'`. | ||
| * | ||
| */ | ||
| /** The FlattenedSign class is used to build and sign Flattened JWS objects. */ | ||
| export declare class FlattenedSign { | ||
@@ -41,3 +30,3 @@ #private; | ||
| */ | ||
| sign(key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.SignOptions): Promise<types.FlattenedJWS>; | ||
| sign(key: types.KeyInput, options?: types.SignOptions): Promise<types.FlattenedJWS>; | ||
| } |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * Verifying JSON Web Signature (JWS) in Flattened JSON Serialization | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../../types.d.ts'; | ||
@@ -10,6 +5,4 @@ /** | ||
| * verified at the time of this function call. | ||
| * | ||
| * @see {@link jwks/remote.createRemoteJWKSet createRemoteJWKSet} to verify using a remote JSON Web Key Set. | ||
| */ | ||
| export interface FlattenedVerifyGetKey extends types.GenericGetKeyFunction<types.JWSHeaderParameters | undefined, types.FlattenedJWSInput, types.CryptoKey | types.KeyObject | types.JWK | Uint8Array> { | ||
| export interface FlattenedVerifyGetKey<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array> extends types.GetKeyFunction<types.JWSHeaderParameters, types.FlattenedJWSInput, KeyType | types.KeyObject | types.JWK> { | ||
| } | ||
@@ -19,5 +12,2 @@ /** | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jws/flattened/verify'`. | ||
| * | ||
| * @param jws Flattened JWS. | ||
@@ -28,4 +18,7 @@ * @param key Key to verify the JWS with. See | ||
| */ | ||
| export declare function flattenedVerify(jws: types.FlattenedJWSInput, key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.VerifyOptions): Promise<types.FlattenedVerifyResult>; | ||
| export declare function flattenedVerify(jws: types.FlattenedJWSInput, key: types.KeyInput, options?: types.VerifyOptions): Promise<types.FlattenedVerifyResult>; | ||
| /** | ||
| * Verifies the signature and format of and afterwards decodes the Flattened JWS, resolving the key | ||
| * dynamically. The result additionally carries the {@link types.ResolvedKey.key resolved key}. | ||
| * | ||
| * @param jws Flattened JWS. | ||
@@ -36,2 +29,13 @@ * @param getKey Function resolving a key to verify the JWS with. See | ||
| */ | ||
| export declare function flattenedVerify(jws: types.FlattenedJWSInput, getKey: FlattenedVerifyGetKey, options?: types.VerifyOptions): Promise<types.FlattenedVerifyResult & types.ResolvedKey>; | ||
| export declare function flattenedVerify<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array>(jws: types.FlattenedJWSInput, getKey: FlattenedVerifyGetKey<KeyType>, options?: types.VerifyOptions): Promise<types.FlattenedVerifyResult & types.ResolvedKey<KeyType>>; | ||
| /** | ||
| * Accepts either form of the `key` argument. Use this overload when forwarding a value that may be | ||
| * either a key or a key resolution function; `key` is present on the result only when a resolution | ||
| * function was used. | ||
| * | ||
| * @param jws Flattened JWS. | ||
| * @param key Key, or function resolving a key, to verify the JWS with. See | ||
| * {@link https://github.com/panva/jose/issues/210#jws-alg Algorithm Key Requirements}. | ||
| * @param options JWS Verify options. | ||
| */ | ||
| export declare function flattenedVerify(jws: types.FlattenedJWSInput, key: types.KeyInput | FlattenedVerifyGetKey, options?: types.VerifyOptions): Promise<types.FlattenedVerifyResult & Partial<types.ResolvedKey>>; |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * Signing JSON Web Signature (JWS) in General JSON Serialization | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../../types.d.ts'; | ||
@@ -21,16 +16,20 @@ /** Used to build General JWS object's individual signatures. */ | ||
| setUnprotectedHeader(unprotectedHeader: types.JWSHeaderParameters): Signature; | ||
| /** A shorthand for calling addSignature() on the enclosing {@link GeneralSign} instance */ | ||
| addSignature(...args: Parameters<GeneralSign['addSignature']>): Signature; | ||
| /** A shorthand for calling encrypt() on the enclosing {@link GeneralSign} instance */ | ||
| sign(...args: Parameters<GeneralSign['sign']>): Promise<types.GeneralJWS>; | ||
| /** | ||
| * A shorthand for calling {@link GeneralSign.addSignature addSignature()} on the enclosing | ||
| * {@link GeneralSign} instance. | ||
| * | ||
| * @param key Private Key or Secret to sign the individual JWS signature with. See | ||
| * {@link https://github.com/panva/jose/issues/210#jws-alg Algorithm Key Requirements}. | ||
| * @param options JWS Sign options. | ||
| */ | ||
| addSignature(key: types.KeyInput, options?: types.SignOptions): Signature; | ||
| /** | ||
| * A shorthand for calling {@link GeneralSign.sign sign()} on the enclosing {@link GeneralSign} | ||
| * instance. Takes no arguments — each signature's key is supplied to {@link addSignature}. | ||
| */ | ||
| sign(): Promise<types.GeneralJWS>; | ||
| /** Returns the enclosing {@link GeneralSign} instance */ | ||
| done(): GeneralSign; | ||
| } | ||
| /** | ||
| * The GeneralSign class is used to build and sign General JWS objects. | ||
| * | ||
| * This class is exported (as a named export) from the main `'jose'` module entry point as well as | ||
| * from its subpath export `'jose/jws/general/sign'`. | ||
| * | ||
| */ | ||
| /** The GeneralSign class is used to build and sign General JWS objects. */ | ||
| export declare class GeneralSign { | ||
@@ -51,5 +50,5 @@ #private; | ||
| */ | ||
| addSignature(key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.SignOptions): Signature; | ||
| addSignature(key: types.KeyInput, options?: types.SignOptions): Signature; | ||
| /** Signs and resolves the value of the General JWS object. */ | ||
| sign(): Promise<types.GeneralJWS>; | ||
| } |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * Verifying JSON Web Signature (JWS) in General JSON Serialization | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../../types.d.ts'; | ||
@@ -10,6 +5,4 @@ /** | ||
| * verified at the time of this function call. | ||
| * | ||
| * @see {@link jwks/remote.createRemoteJWKSet createRemoteJWKSet} to verify using a remote JSON Web Key Set. | ||
| */ | ||
| export interface GeneralVerifyGetKey extends types.GenericGetKeyFunction<types.JWSHeaderParameters, types.FlattenedJWSInput, types.CryptoKey | types.KeyObject | types.JWK | Uint8Array> { | ||
| export interface GeneralVerifyGetKey<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array> extends types.GetKeyFunction<types.JWSHeaderParameters, types.FlattenedJWSInput, KeyType | types.KeyObject | types.JWK> { | ||
| } | ||
@@ -19,7 +12,3 @@ /** | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jws/general/verify'`. | ||
| * | ||
| * > [!NOTE]\ | ||
| * > The function iterates over the `signatures` array in the General JWS and returns the verification | ||
| * > Note: The function iterates over the `signatures` array in the General JWS and returns the verification | ||
| * > result of the first signature entry that can be successfully verified. The result only contains | ||
@@ -36,4 +25,7 @@ * > the payload, protected header, and unprotected header of that successfully verified signature | ||
| */ | ||
| export declare function generalVerify(jws: types.GeneralJWSInput, key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.VerifyOptions): Promise<types.GeneralVerifyResult>; | ||
| export declare function generalVerify(jws: types.GeneralJWSInput, key: types.KeyInput, options?: types.VerifyOptions): Promise<types.GeneralVerifyResult>; | ||
| /** | ||
| * Verifies the signature and format of and afterwards decodes the General JWS, resolving the key | ||
| * dynamically. The result additionally carries the {@link types.ResolvedKey.key resolved key}. | ||
| * | ||
| * @param jws General JWS. | ||
@@ -44,2 +36,13 @@ * @param getKey Function resolving a key to verify the JWS with. See | ||
| */ | ||
| export declare function generalVerify(jws: types.GeneralJWSInput, getKey: GeneralVerifyGetKey, options?: types.VerifyOptions): Promise<types.GeneralVerifyResult & types.ResolvedKey>; | ||
| export declare function generalVerify<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array>(jws: types.GeneralJWSInput, getKey: GeneralVerifyGetKey<KeyType>, options?: types.VerifyOptions): Promise<types.GeneralVerifyResult & types.ResolvedKey<KeyType>>; | ||
| /** | ||
| * Accepts either form of the `key` argument. Use this overload when forwarding a value that may be | ||
| * either a key or a key resolution function; `key` is present on the result only when a resolution | ||
| * function was used. | ||
| * | ||
| * @param jws General JWS. | ||
| * @param key Key, or function resolving a key, to verify the JWS with. See | ||
| * {@link https://github.com/panva/jose/issues/210#jws-alg Algorithm Key Requirements}. | ||
| * @param options JWS Verify options. | ||
| */ | ||
| export declare function generalVerify(jws: types.GeneralJWSInput, key: types.KeyInput | GeneralVerifyGetKey, options?: types.VerifyOptions): Promise<types.GeneralVerifyResult & Partial<types.ResolvedKey>>; |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * JSON Web Token (JWT) Decryption (JWT is in JWE format) | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
@@ -14,3 +9,3 @@ /** Combination of JWE Decryption options and JWT Claims Set verification options. */ | ||
| */ | ||
| export interface JWTDecryptGetKey extends types.GetKeyFunction<types.CompactJWEHeaderParameters, types.FlattenedJWE> { | ||
| export interface JWTDecryptGetKey<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array> extends types.GetKeyFunction<types.CompactJWEHeaderParameters, types.FlattenedJWE, KeyType | types.KeyObject | types.JWK> { | ||
| } | ||
@@ -21,5 +16,2 @@ /** | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jwt/decrypt'`. | ||
| * | ||
| * @param jwt JSON Web Token value (encoded as JWE). | ||
@@ -30,4 +22,7 @@ * @param key Private Key or Secret to decrypt and verify the JWT with. See | ||
| */ | ||
| export declare function jwtDecrypt<PayloadType = types.JWTPayload>(jwt: string | Uint8Array, key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: JWTDecryptOptions): Promise<types.JWTDecryptResult<PayloadType>>; | ||
| export declare function jwtDecrypt<PayloadType = types.JWTPayload>(jwt: string | Uint8Array, key: types.KeyInput, options?: JWTDecryptOptions): Promise<types.JWTDecryptResult<PayloadType>>; | ||
| /** | ||
| * Decrypts a JWT and validates its JWT Claims Set, resolving the key dynamically. The result | ||
| * additionally carries the {@link types.ResolvedKey.key resolved key}. | ||
| * | ||
| * @param jwt JSON Web Token value (encoded as JWE). | ||
@@ -38,2 +33,13 @@ * @param getKey Function resolving Private Key or Secret to decrypt and verify the JWT with. See | ||
| */ | ||
| export declare function jwtDecrypt<PayloadType = types.JWTPayload>(jwt: string | Uint8Array, getKey: JWTDecryptGetKey, options?: JWTDecryptOptions): Promise<types.JWTDecryptResult<PayloadType> & types.ResolvedKey>; | ||
| export declare function jwtDecrypt<PayloadType = types.JWTPayload, KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array>(jwt: string | Uint8Array, getKey: JWTDecryptGetKey<KeyType>, options?: JWTDecryptOptions): Promise<types.JWTDecryptResult<PayloadType> & types.ResolvedKey<KeyType>>; | ||
| /** | ||
| * Accepts either form of the `key` argument. Use this overload when forwarding a value that may be | ||
| * either a key or a key resolution function; `key` is present on the result only when a resolution | ||
| * function was used. | ||
| * | ||
| * @param jwt JSON Web Token value (encoded as JWE). | ||
| * @param key Private Key or Secret, or a function resolving one, to decrypt and verify the JWT | ||
| * with. See {@link https://github.com/panva/jose/issues/210#jwe-alg Algorithm Key Requirements}. | ||
| * @param options JWT Decryption and JWT Claims Set validation options. | ||
| */ | ||
| export declare function jwtDecrypt<PayloadType = types.JWTPayload>(jwt: string | Uint8Array, key: types.KeyInput | JWTDecryptGetKey, options?: JWTDecryptOptions): Promise<types.JWTDecryptResult<PayloadType> & Partial<types.ResolvedKey>>; |
@@ -1,14 +0,3 @@ | ||
| /** | ||
| * JSON Web Token (JWT) Encryption (JWT is in JWE format) | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
| /** | ||
| * The EncryptJWT class is used to build and encrypt Compact JWE formatted JSON Web Tokens. | ||
| * | ||
| * This class is exported (as a named export) from the main `'jose'` module entry point as well as | ||
| * from its subpath export `'jose/jwt/encrypt'`. | ||
| * | ||
| */ | ||
| /** The EncryptJWT class is used to build and encrypt Compact JWE formatted JSON Web Tokens. */ | ||
| export declare class EncryptJWT implements types.ProduceJWT { | ||
@@ -37,7 +26,6 @@ #private; | ||
| /** | ||
| * Sets the JWE Key Management parameters to be used when encrypting. | ||
| * Sets the JWE Key Management parameters to be used when encrypting. For ECDH based algorithms, | ||
| * use this method to set the "apu" (Agreement PartyUInfo) or "apv" (Agreement PartyVInfo) | ||
| * parameters. | ||
| * | ||
| * (ECDH-ES) Use of this method is needed for ECDH based algorithms to set the "apu" (Agreement | ||
| * PartyUInfo) or "apv" (Agreement PartyVInfo) parameters. | ||
| * | ||
| * @param parameters JWE Key Management parameters. | ||
@@ -48,3 +36,3 @@ */ | ||
| * Sets a content encryption key to use, by default a random suitable one is generated for the JWE | ||
| * enc" (Encryption Algorithm) Header Parameter. | ||
| * "enc" (Encryption Algorithm) Header Parameter. | ||
| * | ||
@@ -59,3 +47,3 @@ * @deprecated You should not use this method. It is only really intended for test and vector | ||
| * Sets the JWE Initialization Vector to use for content encryption, by default a random suitable | ||
| * one is generated for the JWE enc" (Encryption Algorithm) Header Parameter. | ||
| * one is generated for the JWE "enc" (Encryption Algorithm) Header Parameter. | ||
| * | ||
@@ -68,19 +56,7 @@ * @deprecated You should not use this method. It is only really intended for test and vector | ||
| setInitializationVector(iv: Uint8Array): this; | ||
| /** | ||
| * Replicates the "iss" (Issuer) Claim as a JWE Protected Header Parameter. | ||
| * | ||
| * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-5.3 RFC7519#section-5.3} | ||
| */ | ||
| /** Replicates the "iss" (Issuer) Claim as a JWE Protected Header Parameter. */ | ||
| replicateIssuerAsHeader(): this; | ||
| /** | ||
| * Replicates the "sub" (Subject) Claim as a JWE Protected Header Parameter. | ||
| * | ||
| * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-5.3 RFC7519#section-5.3} | ||
| */ | ||
| /** Replicates the "sub" (Subject) Claim as a JWE Protected Header Parameter. */ | ||
| replicateSubjectAsHeader(): this; | ||
| /** | ||
| * Replicates the "aud" (Audience) Claim as a JWE Protected Header Parameter. | ||
| * | ||
| * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-5.3 RFC7519#section-5.3} | ||
| */ | ||
| /** Replicates the "aud" (Audience) Claim as a JWE Protected Header Parameter. */ | ||
| replicateAudienceAsHeader(): this; | ||
@@ -94,3 +70,3 @@ /** | ||
| */ | ||
| encrypt(key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.EncryptOptions): Promise<string>; | ||
| encrypt(key: types.KeyInput, options?: types.EncryptOptions): Promise<string>; | ||
| } |
@@ -1,14 +0,3 @@ | ||
| /** | ||
| * JSON Web Token (JWT) Signing (JWT is in JWS format) | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
| /** | ||
| * The SignJWT class is used to build and sign Compact JWS formatted JSON Web Tokens. | ||
| * | ||
| * This class is exported (as a named export) from the main `'jose'` module entry point as well as | ||
| * from its subpath export `'jose/jwt/sign'`. | ||
| * | ||
| */ | ||
| /** The SignJWT class is used to build and sign Compact JWS formatted JSON Web Tokens. */ | ||
| export declare class SignJWT implements types.ProduceJWT { | ||
@@ -42,3 +31,3 @@ #private; | ||
| */ | ||
| sign(key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: types.SignOptions): Promise<string>; | ||
| sign(key: types.KeyInput, options?: types.SignOptions): Promise<string>; | ||
| } |
@@ -1,19 +0,10 @@ | ||
| /** | ||
| * Unsecured (unsigned & unencrypted) JSON Web Tokens (JWT) | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
| /** Result of decoding an Unsecured JWT. */ | ||
| export interface UnsecuredResult<PayloadType = types.JWTPayload> { | ||
| payload: PayloadType & types.JWTPayload; | ||
| /** JWT Claims Set. */ | ||
| payload: PayloadType & types.JWTPayload & ([PayloadType] extends [object] ? unknown : unknown extends PayloadType ? unknown : never); | ||
| /** The decoded JOSE Header; always `{ "alg": "none" }` for an Unsecured JWT. */ | ||
| header: types.JWSHeaderParameters; | ||
| } | ||
| /** | ||
| * The UnsecuredJWT class is a utility for dealing with `{ "alg": "none" }` Unsecured JWTs. | ||
| * | ||
| * This class is exported (as a named export) from the main `'jose'` module entry point as well as | ||
| * from its subpath export `'jose/jwt/unsecured'`. | ||
| * | ||
| */ | ||
| /** The UnsecuredJWT class is a utility for dealing with `{ "alg": "none" }` Unsecured JWTs. */ | ||
| export declare class UnsecuredJWT implements types.ProduceJWT { | ||
@@ -20,0 +11,0 @@ #private; |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * JSON Web Token (JWT) Verification (JWT is in JWS format) | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
@@ -13,6 +8,4 @@ /** Combination of JWS Verification options and JWT Claims Set verification options. */ | ||
| * the time of this function call. | ||
| * | ||
| * @see {@link jwks/remote.createRemoteJWKSet createRemoteJWKSet} to verify using a remote JSON Web Key Set. | ||
| */ | ||
| export interface JWTVerifyGetKey extends types.GenericGetKeyFunction<types.JWTHeaderParameters, types.FlattenedJWSInput, types.CryptoKey | types.KeyObject | types.JWK | Uint8Array> { | ||
| export interface JWTVerifyGetKey<KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array> extends types.GetKeyFunction<types.CompactJWSHeaderParameters, types.FlattenedJWSInput, KeyType | types.KeyObject | types.JWK> { | ||
| } | ||
@@ -23,5 +16,2 @@ /** | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jwt/verify'`. | ||
| * | ||
| * @param jwt JSON Web Token value (encoded as JWS). | ||
@@ -32,3 +22,3 @@ * @param key Key to verify the JWT with. See | ||
| */ | ||
| export declare function jwtVerify<PayloadType = types.JWTPayload>(jwt: string | Uint8Array, key: types.CryptoKey | types.KeyObject | types.JWK | Uint8Array, options?: JWTVerifyOptions): Promise<types.JWTVerifyResult<PayloadType>>; | ||
| export declare function jwtVerify<PayloadType = types.JWTPayload>(jwt: string | Uint8Array, key: types.KeyInput, options?: JWTVerifyOptions): Promise<types.JWTVerifyResult<PayloadType>>; | ||
| /** | ||
@@ -40,2 +30,13 @@ * @param jwt JSON Web Token value (encoded as JWS). | ||
| */ | ||
| export declare function jwtVerify<PayloadType = types.JWTPayload>(jwt: string | Uint8Array, getKey: JWTVerifyGetKey, options?: JWTVerifyOptions): Promise<types.JWTVerifyResult<PayloadType> & types.ResolvedKey>; | ||
| export declare function jwtVerify<PayloadType = types.JWTPayload, KeyType extends types.CryptoKey | Uint8Array = types.CryptoKey | Uint8Array>(jwt: string | Uint8Array, getKey: JWTVerifyGetKey<KeyType>, options?: JWTVerifyOptions): Promise<types.JWTVerifyResult<PayloadType> & types.ResolvedKey<KeyType>>; | ||
| /** | ||
| * Accepts either form of the `key` argument. Use this overload when forwarding a value that may be | ||
| * either a key or a key resolution function; `key` is present on the result only when a resolution | ||
| * function was used. | ||
| * | ||
| * @param jwt JSON Web Token value (encoded as JWS). | ||
| * @param key Key, or function resolving a key, to verify the JWT with. See | ||
| * {@link https://github.com/panva/jose/issues/210#jws-alg Algorithm Key Requirements}. | ||
| * @param options JWT Decryption and JWT Claims Set validation options. | ||
| */ | ||
| export declare function jwtVerify<PayloadType = types.JWTPayload>(jwt: string | Uint8Array, key: types.KeyInput | JWTVerifyGetKey, options?: JWTVerifyOptions): Promise<types.JWTVerifyResult<PayloadType> & Partial<types.ResolvedKey>>; |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * Cryptographic key export functions | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
@@ -10,5 +5,2 @@ /** | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/key/export'`. | ||
| * | ||
| * @param key Key to export to a PEM-encoded SPKI string format. | ||
@@ -20,5 +12,2 @@ */ | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/key/export'`. | ||
| * | ||
| * @param key Key to export to a PEM-encoded PKCS8 string format. | ||
@@ -30,7 +19,4 @@ */ | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/key/export'`. | ||
| * | ||
| * @param key Key to export as JWK. | ||
| */ | ||
| export declare function exportJWK(key: types.CryptoKey | types.KeyObject | Uint8Array): Promise<types.JWK>; |
@@ -0,7 +1,7 @@ | ||
| import type * as types from '../types.d.ts'; | ||
| /** | ||
| * Asymmetric key generation | ||
| * | ||
| * @module | ||
| * JWA Algorithm Identifiers that {@link generateKeyPair} is able to generate a key pair for, subject | ||
| * to runtime support. | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
| export type GenerateKeyPairAlgorithm = 'PS256' | 'PS384' | 'PS512' | 'RS256' | 'RS384' | 'RS512' | 'RSA-OAEP' | 'RSA-OAEP-256' | 'RSA-OAEP-384' | 'RSA-OAEP-512' | 'ES256' | 'ES384' | 'ES512' | 'Ed25519' | 'EdDSA' | 'ML-DSA-44' | 'ML-DSA-65' | 'ML-DSA-87' | 'ECDH-ES' | 'ECDH-ES+A128KW' | 'ECDH-ES+A192KW' | 'ECDH-ES+A256KW' | (string & {}); | ||
| /** Asymmetric key pair generation function result. */ | ||
@@ -26,6 +26,3 @@ export interface GenerateKeyPairResult { | ||
| modulusLength?: number; | ||
| /** | ||
| * The value to use as {@link !SubtleCrypto.generateKey} `extractable` argument. Default is false. | ||
| * | ||
| */ | ||
| /** The value to use as {@link !SubtleCrypto.generateKey} `extractable` argument. Default is false. */ | ||
| extractable?: boolean; | ||
@@ -37,9 +34,5 @@ } | ||
| * | ||
| * > [!NOTE]\ | ||
| * > The `privateKey` is generated with `extractable` set to `false` by default. See | ||
| * > Note: The `privateKey` is generated with `extractable` set to `false` by default. See | ||
| * > {@link GenerateKeyPairOptions.extractable} to generate an extractable `privateKey`. | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/generate/keypair'`. | ||
| * | ||
| * @param alg JWA Algorithm Identifier to be used with the generated key pair. See | ||
@@ -49,2 +42,2 @@ * {@link https://github.com/panva/jose/issues/210 Algorithm Key Requirements}. | ||
| */ | ||
| export declare function generateKeyPair(alg: string, options?: GenerateKeyPairOptions): Promise<GenerateKeyPairResult>; | ||
| export declare function generateKeyPair(alg: GenerateKeyPairAlgorithm, options?: GenerateKeyPairOptions): Promise<GenerateKeyPairResult>; |
@@ -0,7 +1,15 @@ | ||
| import type * as types from '../types.d.ts'; | ||
| /** | ||
| * Symmetric key generation | ||
| * | ||
| * @module | ||
| * JWA Algorithm Identifiers that {@link generateSecret} is able to generate a secret for, subject to | ||
| * runtime support. | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
| export type GenerateSecretAlgorithm = 'HS256' | 'HS384' | 'HS512' | 'A128CBC-HS256' | 'A192CBC-HS384' | 'A256CBC-HS512' | 'A128KW' | 'A192KW' | 'A256KW' | 'A128GCMKW' | 'A192GCMKW' | 'A256GCMKW' | 'A128GCM' | 'A192GCM' | 'A256GCM' | (string & {}); | ||
| /** | ||
| * Resolves what {@link generateSecret} returns for a given JWA Algorithm Identifier. The | ||
| * AES_CBC_HMAC_SHA2 content encryption algorithms have no {@link !CryptoKey} representation, so they | ||
| * yield a {@link !Uint8Array}; every other supported identifier yields a | ||
| * {@link types.CryptoKey CryptoKey}. When the identifier is not statically known this resolves to | ||
| * their union. | ||
| */ | ||
| export type GeneratedSecret<Alg extends string> = Alg extends 'A128CBC-HS256' | 'A192CBC-HS384' | 'A256CBC-HS512' ? Uint8Array : string extends Alg ? types.CryptoKey | Uint8Array : types.CryptoKey; | ||
| /** Secret generation function options. */ | ||
@@ -12,4 +20,3 @@ export interface GenerateSecretOptions { | ||
| * | ||
| * > [!NOTE]\ | ||
| * > Because A128CBC-HS256, A192CBC-HS384, and A256CBC-HS512 secrets cannot be represented as | ||
| * > Note: Because A128CBC-HS256, A192CBC-HS384, and A256CBC-HS512 secrets cannot be represented as | ||
| * > {@link !CryptoKey} this option has no effect for them. | ||
@@ -22,12 +29,7 @@ */ | ||
| * | ||
| * > [!NOTE]\ | ||
| * > The secret key is generated with `extractable` set to `false` by default. | ||
| * > Note: The secret key is generated with `extractable` set to `false` by default. | ||
| * | ||
| * > [!NOTE]\ | ||
| * > Because A128CBC-HS256, A192CBC-HS384, and A256CBC-HS512 secrets cannot be represented as | ||
| * > Note: Because A128CBC-HS256, A192CBC-HS384, and A256CBC-HS512 secrets cannot be represented as | ||
| * > {@link !CryptoKey} this method yields a {@link !Uint8Array} for them instead. | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/generate/secret'`. | ||
| * | ||
| * @param alg JWA Algorithm Identifier to be used with the generated secret. See | ||
@@ -37,2 +39,2 @@ * {@link https://github.com/panva/jose/issues/210 Algorithm Key Requirements}. | ||
| */ | ||
| export declare function generateSecret(alg: string, options?: GenerateSecretOptions): Promise<types.CryptoKey | Uint8Array>; | ||
| export declare function generateSecret<Alg extends GenerateSecretAlgorithm>(alg: Alg, options?: GenerateSecretOptions): Promise<GeneratedSecret<Alg>>; |
@@ -0,7 +1,14 @@ | ||
| import type * as types from '../types.d.ts'; | ||
| /** | ||
| * Cryptographic key import functions | ||
| * | ||
| * @module | ||
| * Resolves what {@link importJWK} returns for a given JWK type. The "kty" (Key Type) Parameter fully | ||
| * determines the outcome at runtime: `"oct"` yields a {@link !Uint8Array} secret, every other | ||
| * supported key type yields a {@link types.CryptoKey CryptoKey}. When "kty" is not statically known | ||
| * — the usual case for a JWK parsed from JSON, or for a value typed as {@link types.JWK JWK} — this | ||
| * resolves to their union. | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
| export type ImportedJWK<JWKType extends types.JWK> = JWKType extends { | ||
| kty: 'oct'; | ||
| } ? Uint8Array : JWKType extends { | ||
| kty: 'AKP' | 'EC' | 'OKP' | 'RSA'; | ||
| } ? types.CryptoKey : types.CryptoKey | Uint8Array; | ||
| /** Key Import Function options. */ | ||
@@ -18,10 +25,6 @@ export interface KeyImportOptions { | ||
| * | ||
| * > [!NOTE]\ | ||
| * > The OID id-RSASSA-PSS (1.2.840.113549.1.1.10) is not supported in | ||
| * > Note: The OID id-RSASSA-PSS (1.2.840.113549.1.1.10) is not supported in | ||
| * > {@link https://w3c.github.io/webcrypto/ Web Cryptography API}, use the OID rsaEncryption | ||
| * > (1.2.840.113549.1.1.1) instead for all RSA algorithms. | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/key/import'`. | ||
| * | ||
| * @param spki PEM-encoded SPKI string | ||
@@ -35,10 +38,6 @@ * @param alg JSON Web Algorithm identifier to be used with the imported key. See | ||
| * | ||
| * > [!NOTE]\ | ||
| * > The OID id-RSASSA-PSS (1.2.840.113549.1.1.10) is not supported in | ||
| * > Note: The OID id-RSASSA-PSS (1.2.840.113549.1.1.10) is not supported in | ||
| * > {@link https://w3c.github.io/webcrypto/ Web Cryptography API}, use the OID rsaEncryption | ||
| * > (1.2.840.113549.1.1.1) instead for all RSA algorithms. | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/key/import'`. | ||
| * | ||
| * @param x509 X.509 certificate string | ||
@@ -52,10 +51,6 @@ * @param alg JSON Web Algorithm identifier to be used with the imported key. See | ||
| * | ||
| * > [!NOTE]\ | ||
| * > The OID id-RSASSA-PSS (1.2.840.113549.1.1.10) is not supported in | ||
| * > Note: The OID id-RSASSA-PSS (1.2.840.113549.1.1.10) is not supported in | ||
| * > {@link https://w3c.github.io/webcrypto/ Web Cryptography API}, use the OID rsaEncryption | ||
| * > (1.2.840.113549.1.1.1) instead for all RSA algorithms. | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/key/import'`. | ||
| * | ||
| * @param pkcs8 PEM-encoded PKCS#8 string | ||
@@ -70,13 +65,8 @@ * @param alg JSON Web Algorithm identifier to be used with the imported key. See | ||
| * | ||
| * > [!NOTE]\ | ||
| * > The JSON Web Key parameters "use", "key_ops", and "ext" are also used in the {@link !CryptoKey} | ||
| * > import process. | ||
| * > Note: The JSON Web Key parameters "key_ops" and "ext" are also used in the {@link !CryptoKey} import | ||
| * > process. | ||
| * | ||
| * > [!NOTE]\ | ||
| * > Symmetric JSON Web Keys (i.e. `kty: "oct"`) yield back an {@link !Uint8Array} instead of a | ||
| * > Note: Symmetric JSON Web Keys (i.e. `kty: "oct"`) yield back an {@link !Uint8Array} instead of a | ||
| * > {@link !CryptoKey}. | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/key/import'`. | ||
| * | ||
| * @param jwk JSON Web Key. | ||
@@ -87,2 +77,2 @@ * @param alg JSON Web Algorithm identifier to be used with the imported key. Default is the "alg" | ||
| */ | ||
| export declare function importJWK(jwk: types.JWK, alg?: string, options?: KeyImportOptions): Promise<types.CryptoKey | Uint8Array>; | ||
| export declare function importJWK<JWKType extends types.JWK>(jwk: JWKType, alg?: string, options?: KeyImportOptions): Promise<ImportedJWK<JWKType>>; |
+242
-223
@@ -1,11 +0,77 @@ | ||
| /** Generic JSON Web Key Parameters. */ | ||
| export interface JWKParameters { | ||
| /** | ||
| * JWS "alg" (Algorithm) Header Parameter values supported by this module. Availability of a given | ||
| * identifier additionally depends on the runtime. | ||
| */ | ||
| export type JWSAlgorithm = | ||
| | 'HS256' | ||
| | 'HS384' | ||
| | 'HS512' | ||
| | 'RS256' | ||
| | 'RS384' | ||
| | 'RS512' | ||
| | 'PS256' | ||
| | 'PS384' | ||
| | 'PS512' | ||
| | 'ES256' | ||
| | 'ES384' | ||
| | 'ES512' | ||
| | 'EdDSA' | ||
| | 'Ed25519' | ||
| | 'ML-DSA-44' | ||
| | 'ML-DSA-65' | ||
| | 'ML-DSA-87' | ||
| | (string & {}) | ||
| /** | ||
| * JWE "alg" (Algorithm) Header Parameter values supported by this module. Availability of a given | ||
| * identifier additionally depends on the runtime. | ||
| */ | ||
| export type JWEKeyManagementAlgorithm = | ||
| | 'dir' | ||
| | 'A128KW' | ||
| | 'A192KW' | ||
| | 'A256KW' | ||
| | 'A128GCMKW' | ||
| | 'A192GCMKW' | ||
| | 'A256GCMKW' | ||
| | 'ECDH-ES' | ||
| | 'ECDH-ES+A128KW' | ||
| | 'ECDH-ES+A192KW' | ||
| | 'ECDH-ES+A256KW' | ||
| | 'RSA-OAEP' | ||
| | 'RSA-OAEP-256' | ||
| | 'RSA-OAEP-384' | ||
| | 'RSA-OAEP-512' | ||
| | 'PBES2-HS256+A128KW' | ||
| | 'PBES2-HS384+A192KW' | ||
| | 'PBES2-HS512+A256KW' | ||
| | (string & {}) | ||
| /** | ||
| * JWE "enc" (Encryption Algorithm) Header Parameter values supported by this module. Availability | ||
| * of a given identifier additionally depends on the runtime. | ||
| */ | ||
| export type JWEContentEncryptionAlgorithm = | ||
| | 'A128CBC-HS256' | ||
| | 'A192CBC-HS384' | ||
| | 'A256CBC-HS512' | ||
| | 'A128GCM' | ||
| | 'A192GCM' | ||
| | 'A256GCM' | ||
| | (string & {}) | ||
| /** JWK "kty" (Key Type) Parameter values supported by this module. */ | ||
| export type JWKKeyType = 'EC' | 'RSA' | 'OKP' | 'AKP' | 'oct' | (string & {}) | ||
| /** | ||
| * Generic JSON Web Key Parameters. | ||
| * | ||
| * > Note: This is declared as a type alias rather than an interface so that it satisfies the implicit index | ||
| * > signature of the `JsonWebKey` types shipped by `@types/node` and `lib.dom`. | ||
| */ | ||
| export type JWKParameters = { | ||
| /** JWK "kty" (Key Type) Parameter */ | ||
| kty?: string | ||
| /** | ||
| * JWK "alg" (Algorithm) Parameter | ||
| * | ||
| * @see {@link https://github.com/panva/jose/issues/210 Algorithm Key Requirements} | ||
| */ | ||
| alg?: string | ||
| kty?: JWKKeyType | ||
| /** JWK "alg" (Algorithm) Parameter */ | ||
| alg?: JWSAlgorithm | JWEKeyManagementAlgorithm | JWEContentEncryptionAlgorithm | ||
| /** JWK "key_ops" (Key Operations) Parameter */ | ||
@@ -16,3 +82,3 @@ key_ops?: string[] | ||
| /** JWK "use" (Public Key Use) Parameter */ | ||
| use?: string | ||
| use?: 'sig' | 'enc' | (string & {}) | ||
| /** JWK "x5c" (X.509 Certificate Chain) Parameter */ | ||
@@ -105,16 +171,31 @@ x5c?: string[] | ||
| /** | ||
| * JSON Web Key ({@link https://www.rfc-editor.org/rfc/rfc7517 JWK}). "RSA", "EC", "OKP", "AKP", and | ||
| * "oct" key types are supported. | ||
| * JSON Web Key ({@link https://www.rfc-editor.org/info/rfc7517/ JWK}). "RSA", "EC", "OKP", "AKP", | ||
| * and "oct" key types are supported. | ||
| * | ||
| * @see {@link JWK_AKP_Public} | ||
| * @see {@link JWK_AKP_Private} | ||
| * @see {@link JWK_OKP_Public} | ||
| * @see {@link JWK_OKP_Private} | ||
| * @see {@link JWK_EC_Public} | ||
| * @see {@link JWK_EC_Private} | ||
| * @see {@link JWK_RSA_Public} | ||
| * @see {@link JWK_RSA_Private} | ||
| * @see {@link JWK_oct} | ||
| * > Note: This is declared as a type alias rather than an interface so that it satisfies the implicit index | ||
| * > signature of the `JsonWebKey` types shipped by `@types/node` and `lib.dom`. It spells out the | ||
| * > {@link JWKParameters} members rather than intersecting them so that every JWK member is documented | ||
| * > in one place. | ||
| */ | ||
| export interface JWK extends JWKParameters { | ||
| export type JWK = { | ||
| /** JWK "kty" (Key Type) Parameter */ | ||
| kty?: JWKKeyType | ||
| /** JWK "alg" (Algorithm) Parameter */ | ||
| alg?: JWSAlgorithm | JWEKeyManagementAlgorithm | JWEContentEncryptionAlgorithm | ||
| /** JWK "key_ops" (Key Operations) Parameter */ | ||
| key_ops?: string[] | ||
| /** JWK "ext" (Extractable) Parameter */ | ||
| ext?: boolean | ||
| /** JWK "use" (Public Key Use) Parameter */ | ||
| use?: 'sig' | 'enc' | (string & {}) | ||
| /** JWK "x5c" (X.509 Certificate Chain) Parameter */ | ||
| x5c?: string[] | ||
| /** JWK "x5t" (X.509 Certificate SHA-1 Thumbprint) Parameter */ | ||
| x5t?: string | ||
| /** JWK "x5t#S256" (X.509 Certificate SHA-256 Thumbprint) Parameter */ | ||
| 'x5t#S256'?: string | ||
| /** JWK "x5u" (X.509 URL) Parameter */ | ||
| x5u?: string | ||
| /** JWK "kid" (Key ID) Parameter */ | ||
| kid?: string | ||
| /** | ||
@@ -158,16 +239,44 @@ * - EC JWK "crv" (Curve) Parameter | ||
| priv?: string | ||
| /** | ||
| * RSA JWK "oth" (Other Primes Info) Parameter | ||
| * | ||
| * > Note: Multi-prime RSA keys are not supported; importing a JWK with this parameter present throws. | ||
| */ | ||
| oth?: Array<{ | ||
| /** The Factor CRT Exponent */ | ||
| d?: string | ||
| /** The Prime Factor */ | ||
| r?: string | ||
| /** The Factor CRT Coefficient */ | ||
| t?: string | ||
| }> | ||
| } | ||
| /** | ||
| * @private | ||
| * | ||
| * @internal | ||
| * Discriminated union of the JSON Web Key shapes supported by this module. Unlike {@link JWK}, each | ||
| * member requires and fixes the "kty" (Key Type) Parameter to its key type so that the union can be | ||
| * narrowed on it. | ||
| */ | ||
| // The "kty" is intersected into each arm one at a time rather than distributed over a parenthesised | ||
| // union - `X & (A | B)` means the same thing, but typedoc renders it without the parentheses, which | ||
| // reads as though the second arm carried no "kty" at all. | ||
| export type AnyJWK = | ||
| | (JWK_EC_Private & { kty: 'EC' }) | ||
| | (JWK_EC_Public & { kty: 'EC' }) | ||
| | (JWK_RSA_Private & { kty: 'RSA' }) | ||
| | (JWK_RSA_Public & { kty: 'RSA' }) | ||
| | (JWK_OKP_Private & { kty: 'OKP' }) | ||
| | (JWK_OKP_Public & { kty: 'OKP' }) | ||
| | (JWK_AKP_Private & { kty: 'AKP' }) | ||
| | (JWK_AKP_Public & { kty: 'AKP' }) | ||
| | (JWK_oct & { kty: 'oct' }) | ||
| /** Key or secret input accepted by all sign, verify, encrypt, and decrypt operations. */ | ||
| export type KeyInput = CryptoKey | KeyObject | JWK | Uint8Array | ||
| export interface GenericGetKeyFunction<IProtectedHeader, IToken, ReturnKeyTypes> { | ||
| /** | ||
| * Dynamic key resolution function. No token components have been verified at the time of this | ||
| * function call. | ||
| * function call. If a suitable key for the token cannot be matched, throw an error instead. | ||
| * | ||
| * If a suitable key for the token cannot be matched, throw an error instead. | ||
| * | ||
| * @param protectedHeader JWE or JWS Protected Header. | ||
@@ -179,13 +288,8 @@ * @param token The consumed JWE or JWS token. | ||
| /** | ||
| * Generic Interface for consuming operations dynamic key resolution. | ||
| * | ||
| * @param IProtectedHeader Type definition of the JWE or JWS Protected Header. | ||
| * @param IToken Type definition of the consumed JWE or JWS token. | ||
| */ | ||
| export interface GetKeyFunction<IProtectedHeader, IToken> extends GenericGetKeyFunction< | ||
| /** Interface for consuming operations dynamic key resolution. */ | ||
| export interface GetKeyFunction< | ||
| IProtectedHeader, | ||
| IToken, | ||
| CryptoKey | KeyObject | JWK | Uint8Array | ||
| > {} | ||
| KeyTypes extends KeyInput = KeyInput, | ||
| > extends GenericGetKeyFunction<IProtectedHeader, IToken, KeyTypes> {} | ||
@@ -229,3 +333,3 @@ /** | ||
| * The "payload" member MUST be present and contain the value BASE64URL(JWS Payload). When when | ||
| * JWS Unencoded Payload ({@link https://www.rfc-editor.org/rfc/rfc7797 RFC7797}) "b64": false is | ||
| * JWS Unencoded Payload ({@link https://www.rfc-editor.org/info/rfc7797/ RFC7797}) "b64": false is | ||
| * used the value passed may also be a {@link !Uint8Array}. | ||
@@ -244,3 +348,3 @@ */ | ||
| * Flattened JWS JSON Serialization Syntax token. Payload is returned as an empty string when JWS | ||
| * Unencoded Payload ({@link https://www.rfc-editor.org/rfc/rfc7797 RFC7797}) is used. | ||
| * Unencoded Payload ({@link https://www.rfc-editor.org/info/rfc7797/ RFC7797}) is used. | ||
| */ | ||
@@ -254,3 +358,3 @@ export interface FlattenedJWS extends Partial<FlattenedJWSInput> { | ||
| * General JWS JSON Serialization Syntax token. Payload is returned as an empty string when JWS | ||
| * Unencoded Payload ({@link https://www.rfc-editor.org/rfc/rfc7797 RFC7797}) is used. | ||
| * Unencoded Payload ({@link https://www.rfc-editor.org/info/rfc7797/ RFC7797}) is used. | ||
| */ | ||
@@ -279,4 +383,7 @@ export interface GeneralJWS { | ||
| /** "jwk" (JSON Web Key) Header Parameter */ | ||
| jwk?: Pick<JWK, 'kty' | 'crv' | 'x' | 'y' | 'e' | 'n' | 'alg' | 'pub'> | ||
| /** | ||
| * "jwk" (JSON Web Key) Header Parameter. This must be a public JSON Web Key; private and | ||
| * symmetric key parameters are not permitted. | ||
| */ | ||
| jwk?: Omit<JWK, 'd' | 'dp' | 'dq' | 'k' | 'p' | 'q' | 'qi' | 'priv' | 'oth'> | ||
@@ -292,12 +399,8 @@ /** "typ" (Type) Header Parameter */ | ||
| export interface JWSHeaderParameters extends JoseHeaderParameters { | ||
| /** | ||
| * JWS "alg" (Algorithm) Header Parameter | ||
| * | ||
| * @see {@link https://github.com/panva/jose/issues/210#jws-alg Algorithm Key Requirements} | ||
| */ | ||
| alg?: string | ||
| /** JWS "alg" (Algorithm) Header Parameter */ | ||
| alg?: JWSAlgorithm | ||
| /** | ||
| * This JWS Extension Header Parameter modifies the JWS Payload representation and the JWS Signing | ||
| * Input computation as per {@link https://www.rfc-editor.org/rfc/rfc7797 RFC7797}. | ||
| * Input computation as per {@link https://www.rfc-editor.org/info/rfc7797/ RFC7797}. | ||
| */ | ||
@@ -409,15 +512,7 @@ b64?: boolean | ||
| export interface JWEHeaderParameters extends JoseHeaderParameters { | ||
| /** | ||
| * JWE "alg" (Algorithm) Header Parameter | ||
| * | ||
| * @see {@link https://github.com/panva/jose/issues/210#jwe-alg Algorithm Key Requirements} | ||
| */ | ||
| alg?: string | ||
| /** JWE "alg" (Algorithm) Header Parameter */ | ||
| alg?: JWEKeyManagementAlgorithm | ||
| /** | ||
| * JWE "enc" (Encryption Algorithm) Header Parameter | ||
| * | ||
| * @see {@link https://github.com/panva/jose/issues/210#jwe-alg Algorithm Key Requirements} | ||
| */ | ||
| enc?: string | ||
| /** JWE "enc" (Encryption Algorithm) Header Parameter */ | ||
| enc?: JWEContentEncryptionAlgorithm | ||
@@ -428,10 +523,7 @@ /** JWE "crit" (Critical) Header Parameter */ | ||
| /** | ||
| * JWE "zip" (Compression Algorithm) Header Parameter. | ||
| * | ||
| * The only supported value is `"DEF"` (DEFLATE). Requires the `CompressionStream` / | ||
| * `DecompressionStream` APIs to be available in the runtime. | ||
| * | ||
| * @see {@link https://www.rfc-editor.org/rfc/rfc7516#section-4.1.3 JWE "zip" Header Parameter} | ||
| * JWE "zip" (Compression Algorithm) Header Parameter. The only supported value is `"DEF"` | ||
| * (DEFLATE), and it requires the `CompressionStream` / `DecompressionStream` APIs to be available | ||
| * in the runtime. | ||
| */ | ||
| zip?: string | ||
| zip?: 'DEF' | (string & {}) | ||
@@ -447,16 +539,10 @@ /** Any other JWE Header member. */ | ||
| * for those is either `true` or `false`. `true` when the Header Parameter MUST be integrity | ||
| * protected, `false` when it's irrelevant. | ||
| * protected, `false` when it's irrelevant. The JWS extension Header Parameter `b64` is always | ||
| * recognized and processed properly; no other registered Header Parameters currently receive this | ||
| * built-in treatment. | ||
| * | ||
| * This makes the "Extension Header Parameter "..." is not recognized" error go away. | ||
| * | ||
| * Use this when a given JWS/JWT/JWE profile requires the use of proprietary non-registered "crit" | ||
| * (Critical) Header Parameters. This will only make sure the Header Parameter is syntactically | ||
| * correct when provided and that it is optionally integrity protected. It will not process the | ||
| * Header Parameter in any way or reject the operation if it is missing. You MUST still verify the | ||
| * Header Parameter was present and process it according to the profile's validation steps after | ||
| * the operation succeeds. | ||
| * | ||
| * The JWS extension Header Parameter `b64` is always recognized and processed properly. No other | ||
| * registered Header Parameters that need this kind of default built-in treatment are currently | ||
| * available. | ||
| * > Warning: This only checks that the Header Parameter is syntactically correct when provided and, | ||
| * > optionally, integrity protected. It does not process the Header Parameter or reject the | ||
| * > operation when it is missing. You MUST still verify its presence and process it according to | ||
| * > the profile's validation steps after the operation succeeds. | ||
| */ | ||
@@ -475,3 +561,3 @@ crit?: { | ||
| */ | ||
| keyManagementAlgorithms?: string[] | ||
| keyManagementAlgorithms?: JWEKeyManagementAlgorithm[] | ||
@@ -482,3 +568,3 @@ /** | ||
| */ | ||
| contentEncryptionAlgorithms?: string[] | ||
| contentEncryptionAlgorithms?: JWEContentEncryptionAlgorithm[] | ||
@@ -495,7 +581,4 @@ /** | ||
| * Algorithm) Header Parameter is present. By default this value is set to 250000 (250 KB). The | ||
| * value must be `0`, a positive safe integer, or `Infinity`. | ||
| * | ||
| * Set to `0` to reject all compressed JWEs during decryption. | ||
| * | ||
| * Set to `Infinity` to disable the decompressed size limit. | ||
| * value must be `0`, a positive safe integer, or `Infinity`. Set it to `0` to reject all | ||
| * compressed JWEs during decryption or to `Infinity` to disable the decompressed size limit. | ||
| */ | ||
@@ -511,5 +594,4 @@ maxDecompressedLength?: number | ||
| /** | ||
| * Expected JWT "aud" (Audience) Claim value(s). | ||
| * | ||
| * This option makes the JWT "aud" (Audience) Claim presence required. | ||
| * Expected JWT "aud" (Audience) Claim value(s). This option makes the JWT "aud" (Audience) Claim | ||
| * presence required. | ||
| */ | ||
@@ -519,9 +601,6 @@ audience?: string | string[] | ||
| /** | ||
| * Clock skew tolerance | ||
| * | ||
| * - In seconds when number (e.g. 5) | ||
| * - Resolved into a number of seconds when a string (e.g. "5 seconds", "10 minutes", "2 hours"). | ||
| * | ||
| * Used when validating the JWT "nbf" (Not Before) and "exp" (Expiration Time) claims, and when | ||
| * validating the "iat" (Issued At) claim if the {@link maxTokenAge `maxTokenAge` option} is set. | ||
| * Clock skew tolerance in seconds when a number (e.g. 5), or resolved into seconds when a string | ||
| * (e.g. "5 seconds", "10 minutes", "2 hours"). Used when validating the JWT "nbf" (Not Before) | ||
| * and "exp" (Expiration Time) claims, and when validating the "iat" (Issued At) claim if the | ||
| * {@link maxTokenAge `maxTokenAge` option} is set. | ||
| */ | ||
@@ -531,5 +610,4 @@ clockTolerance?: string | number | ||
| /** | ||
| * Expected JWT "iss" (Issuer) Claim value(s). | ||
| * | ||
| * This option makes the JWT "iss" (Issuer) Claim presence required. | ||
| * Expected JWT "iss" (Issuer) Claim value(s). This option makes the JWT "iss" (Issuer) Claim | ||
| * presence required. | ||
| */ | ||
@@ -539,8 +617,5 @@ issuer?: string | string[] | ||
| /** | ||
| * Maximum time elapsed (in seconds) from the JWT "iat" (Issued At) Claim value. | ||
| * | ||
| * - In seconds when number (e.g. 5) | ||
| * - Resolved into a number of seconds when a string (e.g. "5 seconds", "10 minutes", "2 hours"). | ||
| * | ||
| * This option makes the JWT "iat" (Issued At) Claim presence required. | ||
| * Maximum time elapsed from the JWT "iat" (Issued At) Claim value, in seconds when a number (e.g. | ||
| * 5), or resolved into seconds when a string (e.g. "5 seconds", "10 minutes", "2 hours"). This | ||
| * option makes the JWT "iat" (Issued At) Claim presence required. | ||
| */ | ||
@@ -550,5 +625,4 @@ maxTokenAge?: string | number | ||
| /** | ||
| * Expected JWT "sub" (Subject) Claim value. | ||
| * | ||
| * This option makes the JWT "sub" (Subject) Claim presence required. | ||
| * Expected JWT "sub" (Subject) Claim value. This option makes the JWT "sub" (Subject) Claim | ||
| * presence required. | ||
| */ | ||
@@ -558,5 +632,4 @@ subject?: string | ||
| /** | ||
| * Expected JWT "typ" (Type) Header Parameter value. | ||
| * | ||
| * This option makes the JWT "typ" (Type) Header Parameter presence required. | ||
| * Expected JWT "typ" (Type) Header Parameter value. This option makes the JWT "typ" (Type) Header | ||
| * Parameter presence required. | ||
| */ | ||
@@ -585,6 +658,5 @@ typ?: string | ||
| * | ||
| * > [!NOTE]\ | ||
| * > Unsecured JWTs (`{ "alg": "none" }`) are never accepted by this API. | ||
| * > Note: Unsecured JWTs (`{ "alg": "none" }`) are never accepted by this API. | ||
| */ | ||
| algorithms?: string[] | ||
| algorithms?: JWSAlgorithm[] | ||
| } | ||
@@ -597,49 +669,21 @@ | ||
| export interface JWTPayload { | ||
| /** | ||
| * JWT Issuer | ||
| * | ||
| * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.1 RFC7519#section-4.1.1} | ||
| */ | ||
| /** JWT Issuer */ | ||
| iss?: string | ||
| /** | ||
| * JWT Subject | ||
| * | ||
| * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.2 RFC7519#section-4.1.2} | ||
| */ | ||
| /** JWT Subject */ | ||
| sub?: string | ||
| /** | ||
| * JWT Audience | ||
| * | ||
| * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3 RFC7519#section-4.1.3} | ||
| */ | ||
| /** JWT Audience */ | ||
| aud?: string | string[] | ||
| /** | ||
| * JWT ID | ||
| * | ||
| * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.7 RFC7519#section-4.1.7} | ||
| */ | ||
| /** JWT ID */ | ||
| jti?: string | ||
| /** | ||
| * JWT Not Before | ||
| * | ||
| * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.5 RFC7519#section-4.1.5} | ||
| */ | ||
| /** JWT Not Before */ | ||
| nbf?: number | ||
| /** | ||
| * JWT Expiration Time | ||
| * | ||
| * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4 RFC7519#section-4.1.4} | ||
| */ | ||
| /** JWT Expiration Time */ | ||
| exp?: number | ||
| /** | ||
| * JWT Issued At | ||
| * | ||
| * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6 RFC7519#section-4.1.6} | ||
| */ | ||
| /** JWT Issued At */ | ||
| iat?: number | ||
@@ -708,3 +752,5 @@ | ||
| /** JWT Claims Set. */ | ||
| payload: PayloadType & JWTPayload | ||
| payload: PayloadType & | ||
| JWTPayload & | ||
| ([PayloadType] extends [object] ? unknown : unknown extends PayloadType ? unknown : never) | ||
@@ -718,3 +764,5 @@ /** JWS Protected Header. */ | ||
| /** JWT Claims Set. */ | ||
| payload: PayloadType & JWTPayload | ||
| payload: PayloadType & | ||
| JWTPayload & | ||
| ([PayloadType] extends [object] ? unknown : unknown extends PayloadType ? unknown : never) | ||
@@ -726,5 +774,5 @@ /** JWE Protected Header. */ | ||
| /** When key resolver functions are used this becomes part of successful resolves */ | ||
| export interface ResolvedKey { | ||
| export interface ResolvedKey<KeyType extends CryptoKey | Uint8Array = CryptoKey | Uint8Array> { | ||
| /** Key resolved from the key resolver function. */ | ||
| key: CryptoKey | Uint8Array | ||
| key: KeyType | ||
| } | ||
@@ -734,3 +782,3 @@ | ||
| export interface CompactJWSHeaderParameters extends JWSHeaderParameters { | ||
| alg: string | ||
| alg: JWSAlgorithm | ||
| } | ||
@@ -740,3 +788,3 @@ | ||
| export interface JWTHeaderParameters extends CompactJWSHeaderParameters { | ||
| b64?: true | ||
| b64?: boolean | ||
| } | ||
@@ -746,4 +794,4 @@ | ||
| export interface CompactJWEHeaderParameters extends JWEHeaderParameters { | ||
| alg: string | ||
| enc: string | ||
| alg: JWEKeyManagementAlgorithm | ||
| enc: JWEContentEncryptionAlgorithm | ||
| } | ||
@@ -762,3 +810,3 @@ | ||
| export interface KeyObject { | ||
| type: string | ||
| type: 'private' | 'public' | 'secret' | ||
| } | ||
@@ -772,7 +820,23 @@ | ||
| */ | ||
| export type CryptoKey = Extract< | ||
| Awaited<ReturnType<typeof crypto.subtle.generateKey>>, | ||
| { type: string } | ||
| > | ||
| export type CryptoKey = typeof globalThis extends { | ||
| crypto: { subtle: { generateKey(...args: any[]): Promise<infer R> } } | ||
| } | ||
| ? Extract<R, { type: string }> | ||
| : CryptoKeyStructuralFallback | ||
| /** | ||
| * Used as {@link CryptoKey} only when the host runtime's `crypto` global is not typed at all, e.g. a | ||
| * consumer compiling with neither the DOM lib nor `@types/node`. Whenever a `CryptoKey` type is | ||
| * available it is aliased instead, deliberately, so that this module never introduces a competing | ||
| * nominal `CryptoKey` and values flow freely to and from {@link !SubtleCrypto} APIs. | ||
| */ | ||
| export interface CryptoKeyStructuralFallback { | ||
| readonly algorithm: { name: string } | ||
| readonly extractable: boolean | ||
| readonly type: 'private' | 'public' | 'secret' | ||
| readonly usages: ( | ||
| 'decrypt' | 'deriveBits' | 'deriveKey' | 'encrypt' | 'sign' | 'unwrapKey' | 'verify' | 'wrapKey' | ||
| )[] | ||
| } | ||
| /** Generic interface for JWT producing classes. */ | ||
@@ -809,22 +873,7 @@ export interface ProduceJWT { | ||
| /** | ||
| * Set the "nbf" (Not Before) Claim. | ||
| * Set the "nbf" (Not Before) Claim. A `number` is used directly, a `Date` is converted to a Unix | ||
| * timestamp, and a `string` is parsed as a time span relative to the current Unix timestamp. | ||
| * String units may be seconds, minutes, hours, days, weeks, or years; months are unsupported and | ||
| * a year is 365.25 days. A leading `-` or trailing `"ago"` subtracts the time span. | ||
| * | ||
| * - If a `number` is passed as an argument it is used as the claim directly. | ||
| * - If a `Date` instance is passed as an argument it is converted to unix timestamp and used as the | ||
| * claim. | ||
| * - If a `string` is passed as an argument it is resolved to a time span, and then added to the | ||
| * current unix timestamp and used as the claim. | ||
| * | ||
| * Format used for time span should be a number followed by a unit, such as "5 minutes" or "1 | ||
| * day". | ||
| * | ||
| * Valid units are: "sec", "secs", "second", "seconds", "s", "minute", "minutes", "min", "mins", | ||
| * "m", "hour", "hours", "hr", "hrs", "h", "day", "days", "d", "week", "weeks", "w", "year", | ||
| * "years", "yr", "yrs", and "y". It is not possible to specify months. 365.25 days is used as an | ||
| * alias for a year. | ||
| * | ||
| * If the string is suffixed with "ago", or prefixed with a "-", the resulting time span gets | ||
| * subtracted from the current unix timestamp. A "from now" suffix can also be used for | ||
| * readability when adding to the current unix timestamp. | ||
| * | ||
| * @param input "nbf" (Not Before) Claim value to set on the JWT Claims Set. | ||
@@ -835,22 +884,7 @@ */ | ||
| /** | ||
| * Set the "exp" (Expiration Time) Claim. | ||
| * Set the "exp" (Expiration Time) Claim. A `number` is used directly, a `Date` is converted to a | ||
| * Unix timestamp, and a `string` is parsed as a time span relative to the current Unix timestamp. | ||
| * String units may be seconds, minutes, hours, days, weeks, or years; months are unsupported and | ||
| * a year is 365.25 days. A leading `-` or trailing `"ago"` subtracts the time span. | ||
| * | ||
| * - If a `number` is passed as an argument it is used as the claim directly. | ||
| * - If a `Date` instance is passed as an argument it is converted to unix timestamp and used as the | ||
| * claim. | ||
| * - If a `string` is passed as an argument it is resolved to a time span, and then added to the | ||
| * current unix timestamp and used as the claim. | ||
| * | ||
| * Format used for time span should be a number followed by a unit, such as "5 minutes" or "1 | ||
| * day". | ||
| * | ||
| * Valid units are: "sec", "secs", "second", "seconds", "s", "minute", "minutes", "min", "mins", | ||
| * "m", "hour", "hours", "hr", "hrs", "h", "day", "days", "d", "week", "weeks", "w", "year", | ||
| * "years", "yr", "yrs", and "y". It is not possible to specify months. 365.25 days is used as an | ||
| * alias for a year. | ||
| * | ||
| * If the string is suffixed with "ago", or prefixed with a "-", the resulting time span gets | ||
| * subtracted from the current unix timestamp. A "from now" suffix can also be used for | ||
| * readability when adding to the current unix timestamp. | ||
| * | ||
| * @param input "exp" (Expiration Time) Claim value to set on the JWT Claims Set. | ||
@@ -861,26 +895,11 @@ */ | ||
| /** | ||
| * Set the "iat" (Issued At) Claim. | ||
| * Set the "iat" (Issued At) Claim. With no argument the current Unix timestamp is used. A | ||
| * `number` is used directly, a `Date` is converted to a Unix timestamp, and a `string` is parsed | ||
| * as a time span relative to the current Unix timestamp. String units may be seconds, minutes, | ||
| * hours, days, weeks, or years; months are unsupported and a year is 365.25 days. A leading `-` | ||
| * or trailing `"ago"` subtracts the time span. | ||
| * | ||
| * - If no argument is used the current unix timestamp is used as the claim. | ||
| * - If a `number` is passed as an argument it is used as the claim directly. | ||
| * - If a `Date` instance is passed as an argument it is converted to unix timestamp and used as the | ||
| * claim. | ||
| * - If a `string` is passed as an argument it is resolved to a time span, and then added to the | ||
| * current unix timestamp and used as the claim. | ||
| * | ||
| * Format used for time span should be a number followed by a unit, such as "5 minutes" or "1 | ||
| * day". | ||
| * | ||
| * Valid units are: "sec", "secs", "second", "seconds", "s", "minute", "minutes", "min", "mins", | ||
| * "m", "hour", "hours", "hr", "hrs", "h", "day", "days", "d", "week", "weeks", "w", "year", | ||
| * "years", "yr", "yrs", and "y". It is not possible to specify months. 365.25 days is used as an | ||
| * alias for a year. | ||
| * | ||
| * If the string is suffixed with "ago", or prefixed with a "-", the resulting time span gets | ||
| * subtracted from the current unix timestamp. A "from now" suffix can also be used for | ||
| * readability when adding to the current unix timestamp. | ||
| * | ||
| * @param input "iat" (Expiration Time) Claim value to set on the JWT Claims Set. | ||
| * @param input "iat" (Issued At) Claim value to set on the JWT Claims Set. | ||
| */ | ||
| setIssuedAt(input?: number | string | Date): this | ||
| } |
| /** | ||
| * Base64URL encoding and decoding utilities | ||
| * Decodes a Base64URL encoded input. | ||
| * | ||
| * @module | ||
| * @param input Base64URL encoded input, as a string or its UTF-8 bytes. | ||
| * @returns The decoded bytes. | ||
| * @throws {!TypeError} When the input is not correctly Base64URL encoded. Standard Base64 input | ||
| * (i.e. containing `+` or `/`) is rejected. | ||
| */ | ||
| /** Decodes a Base64URL encoded input. */ | ||
| export declare function decode(input: Uint8Array | string): Uint8Array; | ||
| /** Encodes an input using Base64URL with no padding. */ | ||
| /** | ||
| * Encodes an input using Base64URL with no padding. | ||
| * | ||
| * @param input Input to encode, as a string or as bytes. Strings are encoded as UTF-8 first. | ||
| * @returns The Base64URL encoded, unpadded, representation of the input. | ||
| */ | ||
| export declare function encode(input: Uint8Array | string): string; |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * JSON Web Token (JWT) Claims Set Decoding (no validation, no signature checking) | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
@@ -13,7 +8,4 @@ /** | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/jwt/decode'`. | ||
| * | ||
| * @param jwt JWT token in compact JWS serialization. | ||
| */ | ||
| export declare function decodeJwt<PayloadType = types.JWTPayload>(jwt: string): PayloadType & types.JWTPayload; | ||
| export declare function decodeJwt<PayloadType = types.JWTPayload>(jwt: string): PayloadType & types.JWTPayload & ([PayloadType] extends [object] ? unknown : unknown extends PayloadType ? unknown : never); |
@@ -1,6 +0,1 @@ | ||
| /** | ||
| * JOSE Protected Header Decoding (JWE, JWS, all serialization syntaxes) | ||
| * | ||
| * @module | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
@@ -12,7 +7,4 @@ /** JWE and JWS Header Parameters */ | ||
| * | ||
| * This function is exported (as a named export) from the main `'jose'` module entry point as well | ||
| * as from its subpath export `'jose/decode/protected_header'`. | ||
| * | ||
| * @param token JWE/JWS/JWT token in any JOSE serialization. | ||
| */ | ||
| export declare function decodeProtectedHeader(token: string | object): ProtectedHeaderParameters; |
+128
-121
@@ -0,21 +1,33 @@ | ||
| import type * as types from '../types.d.ts'; | ||
| /** | ||
| * JOSE module errors and error codes | ||
| * | ||
| * @module | ||
| * Every stable error code used by this module. {@link AnyJOSEError} pairs each subclass with the one | ||
| * it is thrown with, making that union a discriminated one. | ||
| */ | ||
| import type * as types from '../types.d.ts'; | ||
| export type JOSEErrorCode = 'ERR_JOSE_ALG_NOT_ALLOWED' | 'ERR_JOSE_GENERIC' | 'ERR_JOSE_NOT_SUPPORTED' | 'ERR_JWE_DECRYPTION_FAILED' | 'ERR_JWE_INVALID' | 'ERR_JWK_INVALID' | 'ERR_JWKS_INVALID' | 'ERR_JWKS_MULTIPLE_MATCHING_KEYS' | 'ERR_JWKS_NO_MATCHING_KEY' | 'ERR_JWKS_TIMEOUT' | 'ERR_JWS_INVALID' | 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED' | 'ERR_JWT_CLAIM_VALIDATION_FAILED' | 'ERR_JWT_EXPIRED' | 'ERR_JWT_INVALID'; | ||
| /** | ||
| * A generic Error that all other JOSE specific Error subclasses extend. | ||
| * The shape shared by the two errors thrown during JWT Claims Set validation. | ||
| * | ||
| * > Note: {@link JWTExpired} does not extend {@link JWTClaimValidationFailed}, so `instanceof | ||
| * > JWTClaimValidationFailed` is `false` for an expired JWT. Use {@link JWTClaimValidationError} or | ||
| * > the {@link JOSEError.code code} discriminant to handle both. | ||
| */ | ||
| export interface JWTClaimValidationFailure { | ||
| /** The Claim for which the validation failed. */ | ||
| claim: string; | ||
| /** Reason code for the validation failure. */ | ||
| reason: JWTClaimValidationReason; | ||
| /** The parsed JWT Claims Set (aka payload). */ | ||
| payload: types.JWTPayload; | ||
| } | ||
| /** Reason codes produced by JWT Claims Set validation. */ | ||
| export type JWTClaimValidationReason = 'check_failed' | 'invalid' | 'mismatch' | 'missing' | 'unspecified' | (string & {}); | ||
| /** A generic Error that all other JOSE specific Error subclasses extend. */ | ||
| export declare class JOSEError extends Error { | ||
| /** A unique error code for the particular error subclass. */ | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** | ||
| * A unique error code for the particular error subclass. | ||
| * | ||
| * @ignore | ||
| * A unique error code for {@link JOSEError}. Each subclass sets its own; see {@link AnyJOSEError} | ||
| * to switch over them as a discriminated union. | ||
| */ | ||
| static code: string; | ||
| /** A unique error code for {@link JOSEError}. */ | ||
| code: string; | ||
| /** @ignore */ | ||
| code: JOSEErrorCode | (string & {}); | ||
| constructor(message?: string, options?: { | ||
@@ -25,15 +37,13 @@ cause?: unknown; | ||
| } | ||
| /** | ||
| * An error subclass thrown when a JWT Claim Set member validation fails. | ||
| * | ||
| */ | ||
| export declare class JWTClaimValidationFailed extends JOSEError { | ||
| /** @ignore */ | ||
| static code: string; | ||
| /** An error subclass thrown when a JWT Claim Set member validation fails. */ | ||
| export declare class JWTClaimValidationFailed extends JOSEError implements JWTClaimValidationFailure { | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JWTClaimValidationFailed}. */ | ||
| code: string; | ||
| code: JOSEErrorCode | (string & {}); | ||
| /** The {@link JWTClaimValidationFailure} carried by every instance of this error. */ | ||
| cause: JWTClaimValidationFailure; | ||
| /** The Claim for which the validation failed. */ | ||
| claim: string; | ||
| /** Reason code for the validation failure. */ | ||
| reason: string; | ||
| reason: JWTClaimValidationReason; | ||
| /** | ||
@@ -46,18 +56,15 @@ * The parsed JWT Claims Set (aka payload). Other JWT claims may or may not have been verified at | ||
| payload: types.JWTPayload; | ||
| /** @ignore */ | ||
| constructor(message: string, payload: types.JWTPayload, claim?: string, reason?: string); | ||
| constructor(message: string, payload: types.JWTPayload, claim?: string, reason?: JWTClaimValidationReason); | ||
| } | ||
| /** | ||
| * An error subclass thrown when a JWT is expired. | ||
| * | ||
| */ | ||
| export declare class JWTExpired extends JOSEError implements JWTClaimValidationFailed { | ||
| /** @ignore */ | ||
| static code: string; | ||
| /** An error subclass thrown when a JWT is expired. */ | ||
| export declare class JWTExpired extends JOSEError implements JWTClaimValidationFailure { | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JWTExpired}. */ | ||
| code: string; | ||
| code: JOSEErrorCode | (string & {}); | ||
| /** The {@link JWTClaimValidationFailure} carried by every instance of this error. */ | ||
| cause: JWTClaimValidationFailure; | ||
| /** The Claim for which the validation failed. */ | ||
| claim: string; | ||
| /** Reason code for the validation failure. */ | ||
| reason: string; | ||
| reason: JWTClaimValidationReason; | ||
| /** | ||
@@ -70,14 +77,9 @@ * The parsed JWT Claims Set (aka payload). Other JWT claims may or may not have been verified at | ||
| payload: types.JWTPayload; | ||
| /** @ignore */ | ||
| constructor(message: string, payload: types.JWTPayload, claim?: string, reason?: string); | ||
| constructor(message: string, payload: types.JWTPayload, claim?: string, reason?: JWTClaimValidationReason); | ||
| } | ||
| /** | ||
| * An error subclass thrown when a JOSE Algorithm is not allowed per developer preference. | ||
| * | ||
| */ | ||
| /** An error subclass thrown when a JOSE Algorithm is not allowed per developer preference. */ | ||
| export declare class JOSEAlgNotAllowed extends JOSEError { | ||
| /** @ignore */ | ||
| static code: string; | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JOSEAlgNotAllowed}. */ | ||
| code: string; | ||
| code: JOSEErrorCode | (string & {}); | ||
| } | ||
@@ -87,20 +89,13 @@ /** | ||
| * implementation or JOSE in general. | ||
| * | ||
| */ | ||
| export declare class JOSENotSupported extends JOSEError { | ||
| /** @ignore */ | ||
| static code: string; | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JOSENotSupported}. */ | ||
| code: string; | ||
| code: JOSEErrorCode | (string & {}); | ||
| } | ||
| /** | ||
| * An error subclass thrown when a JWE ciphertext decryption fails. | ||
| * | ||
| */ | ||
| /** An error subclass thrown when a JWE ciphertext decryption fails. */ | ||
| export declare class JWEDecryptionFailed extends JOSEError { | ||
| /** @ignore */ | ||
| static code: string; | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JWEDecryptionFailed}. */ | ||
| code: string; | ||
| /** @ignore */ | ||
| code: JOSEErrorCode | (string & {}); | ||
| constructor(message?: string, options?: { | ||
@@ -110,62 +105,37 @@ cause?: unknown; | ||
| } | ||
| /** | ||
| * An error subclass thrown when a JWE is invalid. | ||
| * | ||
| */ | ||
| /** An error subclass thrown when a JWE is invalid. */ | ||
| export declare class JWEInvalid extends JOSEError { | ||
| /** @ignore */ | ||
| static code: string; | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JWEInvalid}. */ | ||
| code: string; | ||
| code: JOSEErrorCode | (string & {}); | ||
| } | ||
| /** | ||
| * An error subclass thrown when a JWS is invalid. | ||
| * | ||
| */ | ||
| /** An error subclass thrown when a JWS is invalid. */ | ||
| export declare class JWSInvalid extends JOSEError { | ||
| /** @ignore */ | ||
| static code: string; | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JWSInvalid}. */ | ||
| code: string; | ||
| code: JOSEErrorCode | (string & {}); | ||
| } | ||
| /** | ||
| * An error subclass thrown when a JWT is invalid. | ||
| * | ||
| */ | ||
| /** An error subclass thrown when a JWT is invalid. */ | ||
| export declare class JWTInvalid extends JOSEError { | ||
| /** @ignore */ | ||
| static code: string; | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JWTInvalid}. */ | ||
| code: string; | ||
| code: JOSEErrorCode | (string & {}); | ||
| } | ||
| /** | ||
| * An error subclass thrown when a JWK is invalid. | ||
| * | ||
| */ | ||
| /** An error subclass thrown when a JWK is invalid. */ | ||
| export declare class JWKInvalid extends JOSEError { | ||
| /** @ignore */ | ||
| static code: string; | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JWKInvalid}. */ | ||
| code: string; | ||
| code: JOSEErrorCode | (string & {}); | ||
| } | ||
| /** | ||
| * An error subclass thrown when a JWKS is invalid. | ||
| * | ||
| */ | ||
| /** An error subclass thrown when a JWKS is invalid. */ | ||
| export declare class JWKSInvalid extends JOSEError { | ||
| /** @ignore */ | ||
| static code: string; | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JWKSInvalid}. */ | ||
| code: string; | ||
| code: JOSEErrorCode | (string & {}); | ||
| } | ||
| /** | ||
| * An error subclass thrown when no keys match from a JWKS. | ||
| * | ||
| */ | ||
| /** An error subclass thrown when no keys match from a JWKS. */ | ||
| export declare class JWKSNoMatchingKey extends JOSEError { | ||
| /** @ignore */ | ||
| static code: string; | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JWKSNoMatchingKey}. */ | ||
| code: string; | ||
| /** @ignore */ | ||
| code: JOSEErrorCode | (string & {}); | ||
| constructor(message?: string, options?: { | ||
@@ -175,14 +145,15 @@ cause?: unknown; | ||
| } | ||
| /** | ||
| * An error subclass thrown when multiple keys match from a JWKS. | ||
| * | ||
| */ | ||
| /** An error subclass thrown when multiple keys match from a JWKS. */ | ||
| export declare class JWKSMultipleMatchingKeys extends JOSEError { | ||
| /** @ignore */ | ||
| /** | ||
| * Iterates the public keys that matched the JWS JOSE Header, so that verification can be | ||
| * attempted with each in turn. See the {@link jwks/remote.createRemoteJWKSet createRemoteJWKSet} | ||
| * and {@link jwks/local.createLocalJWKSet createLocalJWKSet} examples. Instances thrown by this | ||
| * module always iterate the matched keys; an instance constructed by other code iterates | ||
| * nothing. | ||
| */ | ||
| [Symbol.asyncIterator]: () => AsyncIterableIterator<types.CryptoKey>; | ||
| /** @ignore */ | ||
| static code: string; | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JWKSMultipleMatchingKeys}. */ | ||
| code: string; | ||
| /** @ignore */ | ||
| code: JOSEErrorCode | (string & {}); | ||
| constructor(message?: string, options?: { | ||
@@ -192,12 +163,7 @@ cause?: unknown; | ||
| } | ||
| /** | ||
| * Timeout was reached when retrieving the JWKS response. | ||
| * | ||
| */ | ||
| /** Timeout was reached when retrieving the JWKS response. */ | ||
| export declare class JWKSTimeout extends JOSEError { | ||
| /** @ignore */ | ||
| static code: string; | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JWKSTimeout}. */ | ||
| code: string; | ||
| /** @ignore */ | ||
| code: JOSEErrorCode | (string & {}); | ||
| constructor(message?: string, options?: { | ||
@@ -207,12 +173,7 @@ cause?: unknown; | ||
| } | ||
| /** | ||
| * An error subclass thrown when JWS signature verification fails. | ||
| * | ||
| */ | ||
| /** An error subclass thrown when JWS signature verification fails. */ | ||
| export declare class JWSSignatureVerificationFailed extends JOSEError { | ||
| /** @ignore */ | ||
| static code: string; | ||
| static code: JOSEErrorCode | (string & {}); | ||
| /** A unique error code for {@link JWSSignatureVerificationFailed}. */ | ||
| code: string; | ||
| /** @ignore */ | ||
| code: JOSEErrorCode | (string & {}); | ||
| constructor(message?: string, options?: { | ||
@@ -222,1 +183,47 @@ cause?: unknown; | ||
| } | ||
| /** | ||
| * Union of the errors thrown during JWT Claims Set validation. {@link JWTExpired} does not extend | ||
| * {@link JWTClaimValidationFailed}, so a single `instanceof` check cannot cover both. Use this type | ||
| * — together with the {@link JOSEError.code code} discriminant — when handling either. | ||
| */ | ||
| export type JWTClaimValidationError = JWTClaimValidationFailed | JWTExpired; | ||
| /** | ||
| * Union of every {@link JOSEError} subclass this module throws, each paired with the single | ||
| * {@link JOSEErrorCode} it is thrown with. That pairing lives here rather than on the classes, so | ||
| * that `code` stays assignable, writable, and overridable on them exactly as before, while a value | ||
| * of this type can still be switched over as a discriminated union. | ||
| * | ||
| * > Note: The base {@link JOSEError} is deliberately not a member — its `code` spans every value, which | ||
| * > would defeat the discriminant. A small number of JSON Web Key Set HTTP failures are thrown as the | ||
| * > base class itself, so `instanceof JOSEError` remains the catch-all; this union is for handling a | ||
| * > value already known to be one of the specific errors. | ||
| */ | ||
| export type AnyJOSEError = (JOSEAlgNotAllowed & { | ||
| code: 'ERR_JOSE_ALG_NOT_ALLOWED'; | ||
| }) | (JOSENotSupported & { | ||
| code: 'ERR_JOSE_NOT_SUPPORTED'; | ||
| }) | (JWEDecryptionFailed & { | ||
| code: 'ERR_JWE_DECRYPTION_FAILED'; | ||
| }) | (JWEInvalid & { | ||
| code: 'ERR_JWE_INVALID'; | ||
| }) | (JWKInvalid & { | ||
| code: 'ERR_JWK_INVALID'; | ||
| }) | (JWKSInvalid & { | ||
| code: 'ERR_JWKS_INVALID'; | ||
| }) | (JWKSMultipleMatchingKeys & { | ||
| code: 'ERR_JWKS_MULTIPLE_MATCHING_KEYS'; | ||
| }) | (JWKSNoMatchingKey & { | ||
| code: 'ERR_JWKS_NO_MATCHING_KEY'; | ||
| }) | (JWKSTimeout & { | ||
| code: 'ERR_JWKS_TIMEOUT'; | ||
| }) | (JWSInvalid & { | ||
| code: 'ERR_JWS_INVALID'; | ||
| }) | (JWSSignatureVerificationFailed & { | ||
| code: 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED'; | ||
| }) | (JWTClaimValidationFailed & { | ||
| code: 'ERR_JWT_CLAIM_VALIDATION_FAILED'; | ||
| }) | (JWTExpired & { | ||
| code: 'ERR_JWT_EXPIRED'; | ||
| }) | (JWTInvalid & { | ||
| code: 'ERR_JWT_INVALID'; | ||
| }); |
@@ -1,23 +0,5 @@ | ||
| import { flattenedDecrypt } from '../flattened/decrypt.js'; | ||
| import { JWEInvalid } from '../../util/errors.js'; | ||
| import { decoder } from '../../lib/buffer_utils.js'; | ||
| import { prepareDecrypt, decryptCompact } from '../../lib/jwe_decrypt.js'; | ||
| export async function compactDecrypt(jwe, key, options) { | ||
| if (jwe instanceof Uint8Array) { | ||
| jwe = decoder.decode(jwe); | ||
| } | ||
| if (typeof jwe !== 'string') { | ||
| throw new JWEInvalid('Compact JWE must be a string or Uint8Array'); | ||
| } | ||
| const { 0: protectedHeader, 1: encryptedKey, 2: iv, 3: ciphertext, 4: tag, length, } = jwe.split('.'); | ||
| if (length !== 5) { | ||
| throw new JWEInvalid('Invalid Compact JWE'); | ||
| } | ||
| const decrypted = await flattenedDecrypt({ | ||
| ciphertext, | ||
| iv: iv || undefined, | ||
| protected: protectedHeader, | ||
| tag: tag || undefined, | ||
| encrypted_key: encryptedKey || undefined, | ||
| }, key, options); | ||
| const result = { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader }; | ||
| const decrypted = await decryptCompact(jwe, prepareDecrypt(options), key); | ||
| const result = { plaintext: decrypted.plaintext, protectedHeader: decrypted.parsedProt }; | ||
| if (typeof key === 'function') { | ||
@@ -24,0 +6,0 @@ return { ...result, key: decrypted.key }; |
@@ -1,15 +0,4 @@ | ||
| import { decode as b64u } from '../../util/base64url.js'; | ||
| import { decrypt } from '../../lib/content_encryption.js'; | ||
| import { decodeBase64url } from '../../lib/helpers.js'; | ||
| import { JOSEAlgNotAllowed, JOSENotSupported, JWEInvalid } from '../../util/errors.js'; | ||
| import { isDisjoint } from '../../lib/type_checks.js'; | ||
| import { JWEInvalid } from '../../util/errors.js'; | ||
| import { isObject } from '../../lib/type_checks.js'; | ||
| import { decryptKeyManagement } from '../../lib/key_management.js'; | ||
| import { decoder, concat, encode } from '../../lib/buffer_utils.js'; | ||
| import { generateCek } from '../../lib/content_encryption.js'; | ||
| import { validateCrit } from '../../lib/validate_crit.js'; | ||
| import { validateAlgorithms } from '../../lib/validate_algorithms.js'; | ||
| import { normalizeKey } from '../../lib/normalize_key.js'; | ||
| import { checkKeyType } from '../../lib/check_key_type.js'; | ||
| import { decompress } from '../../lib/deflate.js'; | ||
| import { prepareDecrypt, decryptJWE, decryptResult, checkShared, checkRecipient, } from '../../lib/jwe_decrypt.js'; | ||
| export async function flattenedDecrypt(jwe, key, options) { | ||
@@ -19,142 +8,5 @@ if (!isObject(jwe)) { | ||
| } | ||
| if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) { | ||
| throw new JWEInvalid('JOSE Header missing'); | ||
| } | ||
| if (jwe.iv !== undefined && typeof jwe.iv !== 'string') { | ||
| throw new JWEInvalid('JWE Initialization Vector incorrect type'); | ||
| } | ||
| if (typeof jwe.ciphertext !== 'string') { | ||
| throw new JWEInvalid('JWE Ciphertext missing or incorrect type'); | ||
| } | ||
| if (jwe.tag !== undefined && typeof jwe.tag !== 'string') { | ||
| throw new JWEInvalid('JWE Authentication Tag incorrect type'); | ||
| } | ||
| if (jwe.protected !== undefined && typeof jwe.protected !== 'string') { | ||
| throw new JWEInvalid('JWE Protected Header incorrect type'); | ||
| } | ||
| if (jwe.encrypted_key !== undefined && typeof jwe.encrypted_key !== 'string') { | ||
| throw new JWEInvalid('JWE Encrypted Key incorrect type'); | ||
| } | ||
| if (jwe.aad !== undefined && typeof jwe.aad !== 'string') { | ||
| throw new JWEInvalid('JWE AAD incorrect type'); | ||
| } | ||
| if (jwe.header !== undefined && !isObject(jwe.header)) { | ||
| throw new JWEInvalid('JWE Shared Unprotected Header incorrect type'); | ||
| } | ||
| if (jwe.unprotected !== undefined && !isObject(jwe.unprotected)) { | ||
| throw new JWEInvalid('JWE Per-Recipient Unprotected Header incorrect type'); | ||
| } | ||
| let parsedProt; | ||
| if (jwe.protected) { | ||
| try { | ||
| const protectedHeader = b64u(jwe.protected); | ||
| parsedProt = JSON.parse(decoder.decode(protectedHeader)); | ||
| } | ||
| catch { | ||
| throw new JWEInvalid('JWE Protected Header is invalid'); | ||
| } | ||
| } | ||
| if (!isDisjoint(parsedProt, jwe.header, jwe.unprotected)) { | ||
| throw new JWEInvalid('JWE Protected, JWE Unprotected Header, and JWE Per-Recipient Unprotected Header Parameter names must be disjoint'); | ||
| } | ||
| const joseHeader = { | ||
| ...parsedProt, | ||
| ...jwe.header, | ||
| ...jwe.unprotected, | ||
| }; | ||
| validateCrit(JWEInvalid, new Map(), options?.crit, parsedProt, joseHeader); | ||
| if (joseHeader.zip !== undefined && joseHeader.zip !== 'DEF') { | ||
| throw new JOSENotSupported('Unsupported JWE "zip" (Compression Algorithm) Header Parameter value.'); | ||
| } | ||
| if (joseHeader.zip !== undefined && !parsedProt?.zip) { | ||
| throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header Parameter MUST be in a protected header.'); | ||
| } | ||
| const { alg, enc } = joseHeader; | ||
| if (typeof alg !== 'string' || !alg) { | ||
| throw new JWEInvalid('missing JWE Algorithm (alg) in JWE Header'); | ||
| } | ||
| if (typeof enc !== 'string' || !enc) { | ||
| throw new JWEInvalid('missing JWE Encryption Algorithm (enc) in JWE Header'); | ||
| } | ||
| const keyManagementAlgorithms = options && validateAlgorithms('keyManagementAlgorithms', options.keyManagementAlgorithms); | ||
| const contentEncryptionAlgorithms = options && | ||
| validateAlgorithms('contentEncryptionAlgorithms', options.contentEncryptionAlgorithms); | ||
| if ((keyManagementAlgorithms && !keyManagementAlgorithms.has(alg)) || | ||
| (!keyManagementAlgorithms && alg.startsWith('PBES2'))) { | ||
| throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed'); | ||
| } | ||
| if (contentEncryptionAlgorithms && !contentEncryptionAlgorithms.has(enc)) { | ||
| throw new JOSEAlgNotAllowed('"enc" (Encryption Algorithm) Header Parameter value not allowed'); | ||
| } | ||
| let encryptedKey; | ||
| if (jwe.encrypted_key !== undefined) { | ||
| encryptedKey = decodeBase64url(jwe.encrypted_key, 'encrypted_key', JWEInvalid); | ||
| } | ||
| let resolvedKey = false; | ||
| if (typeof key === 'function') { | ||
| key = await key(parsedProt, jwe); | ||
| resolvedKey = true; | ||
| } | ||
| checkKeyType(alg === 'dir' ? enc : alg, key, 'decrypt'); | ||
| const k = await normalizeKey(key, alg); | ||
| let cek; | ||
| try { | ||
| cek = await decryptKeyManagement(alg, k, encryptedKey, joseHeader, options); | ||
| } | ||
| catch (err) { | ||
| if (err instanceof TypeError || err instanceof JWEInvalid || err instanceof JOSENotSupported) { | ||
| throw err; | ||
| } | ||
| cek = generateCek(enc); | ||
| } | ||
| let iv; | ||
| let tag; | ||
| if (jwe.iv !== undefined) { | ||
| iv = decodeBase64url(jwe.iv, 'iv', JWEInvalid); | ||
| } | ||
| if (jwe.tag !== undefined) { | ||
| tag = decodeBase64url(jwe.tag, 'tag', JWEInvalid); | ||
| } | ||
| const protectedHeader = jwe.protected !== undefined ? encode(jwe.protected) : new Uint8Array(); | ||
| let additionalData; | ||
| if (jwe.aad !== undefined) { | ||
| additionalData = concat(protectedHeader, encode('.'), encode(jwe.aad)); | ||
| } | ||
| else { | ||
| additionalData = protectedHeader; | ||
| } | ||
| const ciphertext = decodeBase64url(jwe.ciphertext, 'ciphertext', JWEInvalid); | ||
| const plaintext = await decrypt(enc, cek, ciphertext, iv, tag, additionalData); | ||
| const result = { plaintext }; | ||
| if (joseHeader.zip === 'DEF') { | ||
| const maxDecompressedLength = options?.maxDecompressedLength ?? 250_000; | ||
| if (maxDecompressedLength === 0) { | ||
| throw new JOSENotSupported('JWE "zip" (Compression Algorithm) Header Parameter is not supported.'); | ||
| } | ||
| if (maxDecompressedLength !== Infinity && | ||
| (!Number.isSafeInteger(maxDecompressedLength) || maxDecompressedLength < 1)) { | ||
| throw new TypeError('maxDecompressedLength must be 0, a positive safe integer, or Infinity'); | ||
| } | ||
| result.plaintext = await decompress(plaintext, maxDecompressedLength).catch((cause) => { | ||
| if (cause instanceof JWEInvalid) | ||
| throw cause; | ||
| throw new JWEInvalid('Failed to decompress plaintext', { cause }); | ||
| }); | ||
| } | ||
| if (jwe.protected !== undefined) { | ||
| result.protectedHeader = parsedProt; | ||
| } | ||
| if (jwe.aad !== undefined) { | ||
| result.additionalAuthenticatedData = decodeBase64url(jwe.aad, 'aad', JWEInvalid); | ||
| } | ||
| if (jwe.unprotected !== undefined) { | ||
| result.sharedUnprotectedHeader = jwe.unprotected; | ||
| } | ||
| if (jwe.header !== undefined) { | ||
| result.unprotectedHeader = jwe.header; | ||
| } | ||
| if (resolvedKey) { | ||
| return { ...result, key: k }; | ||
| } | ||
| return result; | ||
| checkShared(jwe); | ||
| checkRecipient(jwe); | ||
| return decryptResult(jwe, await decryptJWE(jwe, prepareDecrypt(options), key)); | ||
| } |
@@ -1,12 +0,5 @@ | ||
| import { encode as b64u } from '../../util/base64url.js'; | ||
| import { unprotected, assertNotSet } from '../../lib/helpers.js'; | ||
| import { encrypt } from '../../lib/content_encryption.js'; | ||
| import { encryptKeyManagement } from '../../lib/key_management.js'; | ||
| import { JOSENotSupported, JWEInvalid } from '../../util/errors.js'; | ||
| import { isDisjoint } from '../../lib/type_checks.js'; | ||
| import { concat, encode } from '../../lib/buffer_utils.js'; | ||
| import { validateCrit } from '../../lib/validate_crit.js'; | ||
| import { normalizeKey } from '../../lib/normalize_key.js'; | ||
| import { checkKeyType } from '../../lib/check_key_type.js'; | ||
| import { compress } from '../../lib/deflate.js'; | ||
| import { JWEInvalid } from '../../util/errors.js'; | ||
| import { createJWE } from '../../lib/jwe_encrypt.js'; | ||
| import { validateCritDuplicates } from '../../lib/options.js'; | ||
| export class FlattenedEncrypt { | ||
@@ -65,104 +58,16 @@ #plaintext; | ||
| } | ||
| if (!isDisjoint(this.#protectedHeader, this.#unprotectedHeader, this.#sharedUnprotectedHeader)) { | ||
| throw new JWEInvalid('JWE Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint'); | ||
| } | ||
| const joseHeader = { | ||
| ...this.#protectedHeader, | ||
| ...this.#unprotectedHeader, | ||
| ...this.#sharedUnprotectedHeader, | ||
| }; | ||
| validateCrit(JWEInvalid, new Map(), options?.crit, this.#protectedHeader, joseHeader); | ||
| if (joseHeader.zip !== undefined && joseHeader.zip !== 'DEF') { | ||
| throw new JOSENotSupported('Unsupported JWE "zip" (Compression Algorithm) Header Parameter value.'); | ||
| } | ||
| if (joseHeader.zip !== undefined && !this.#protectedHeader?.zip) { | ||
| throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header Parameter MUST be in a protected header.'); | ||
| } | ||
| const { alg, enc } = joseHeader; | ||
| if (typeof alg !== 'string' || !alg) { | ||
| throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid'); | ||
| } | ||
| if (typeof enc !== 'string' || !enc) { | ||
| throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid'); | ||
| } | ||
| let encryptedKey; | ||
| if (this.#cek && (alg === 'dir' || alg === 'ECDH-ES')) { | ||
| throw new TypeError(`setContentEncryptionKey cannot be called with JWE "alg" (Algorithm) Header ${alg}`); | ||
| } | ||
| checkKeyType(alg === 'dir' ? enc : alg, key, 'encrypt'); | ||
| let cek; | ||
| { | ||
| let parameters; | ||
| const k = await normalizeKey(key, alg); | ||
| ({ cek, encryptedKey, parameters } = await encryptKeyManagement(alg, enc, k, this.#cek, this.#keyManagementParameters)); | ||
| if (parameters) { | ||
| if (options && unprotected in options) { | ||
| if (!this.#unprotectedHeader) { | ||
| this.setUnprotectedHeader(parameters); | ||
| } | ||
| else { | ||
| this.#unprotectedHeader = { ...this.#unprotectedHeader, ...parameters }; | ||
| } | ||
| } | ||
| else if (!this.#protectedHeader) { | ||
| this.setProtectedHeader(parameters); | ||
| } | ||
| else { | ||
| this.#protectedHeader = { ...this.#protectedHeader, ...parameters }; | ||
| } | ||
| } | ||
| } | ||
| let additionalData; | ||
| let protectedHeaderS; | ||
| let protectedHeaderB; | ||
| let aadMember; | ||
| if (this.#protectedHeader) { | ||
| protectedHeaderS = b64u(JSON.stringify(this.#protectedHeader)); | ||
| protectedHeaderB = encode(protectedHeaderS); | ||
| } | ||
| else { | ||
| protectedHeaderS = ''; | ||
| protectedHeaderB = new Uint8Array(); | ||
| } | ||
| if (this.#aad) { | ||
| aadMember = b64u(this.#aad); | ||
| const aadMemberBytes = encode(aadMember); | ||
| additionalData = concat(protectedHeaderB, encode('.'), aadMemberBytes); | ||
| } | ||
| else { | ||
| additionalData = protectedHeaderB; | ||
| } | ||
| let plaintext = this.#plaintext; | ||
| if (joseHeader.zip === 'DEF') { | ||
| plaintext = await compress(plaintext).catch((cause) => { | ||
| throw new JWEInvalid('Failed to compress plaintext', { cause }); | ||
| }); | ||
| } | ||
| const { ciphertext, tag, iv } = await encrypt(enc, plaintext, cek, this.#iv, additionalData); | ||
| const jwe = { | ||
| ciphertext: b64u(ciphertext), | ||
| }; | ||
| if (iv) { | ||
| jwe.iv = b64u(iv); | ||
| } | ||
| if (tag) { | ||
| jwe.tag = b64u(tag); | ||
| } | ||
| if (encryptedKey) { | ||
| jwe.encrypted_key = b64u(encryptedKey); | ||
| } | ||
| if (aadMember) { | ||
| jwe.aad = aadMember; | ||
| } | ||
| if (this.#protectedHeader) { | ||
| jwe.protected = protectedHeaderS; | ||
| } | ||
| if (this.#sharedUnprotectedHeader) { | ||
| jwe.unprotected = this.#sharedUnprotectedHeader; | ||
| } | ||
| if (this.#unprotectedHeader) { | ||
| jwe.header = this.#unprotectedHeader; | ||
| } | ||
| return jwe; | ||
| validateCritDuplicates(JWEInvalid, this.#protectedHeader); | ||
| return createJWE({ | ||
| plaintext: this.#plaintext, | ||
| protectedHeader: this.#protectedHeader, | ||
| unprotectedHeader: this.#unprotectedHeader, | ||
| sharedUnprotectedHeader: this.#sharedUnprotectedHeader, | ||
| aad: this.#aad, | ||
| cek: this.#cek, | ||
| iv: this.#iv, | ||
| keyManagementParameters: this.#keyManagementParameters, | ||
| crit: options?.crit, | ||
| unprotectedParameters: options ? unprotected in options : false, | ||
| }, key); | ||
| } | ||
| } |
@@ -1,2 +0,2 @@ | ||
| import { flattenedDecrypt } from '../flattened/decrypt.js'; | ||
| import { prepareDecrypt, shareJWE, decryptRecipient, decryptResult, checkShared, checkRecipient, } from '../../lib/jwe_decrypt.js'; | ||
| import { JWEDecryptionFailed, JWEInvalid } from '../../util/errors.js'; | ||
@@ -14,5 +14,15 @@ import { isObject } from '../../lib/type_checks.js'; | ||
| } | ||
| let shared; | ||
| let token; | ||
| try { | ||
| checkShared(jwe); | ||
| shared = prepareDecrypt(options); | ||
| token = shareJWE(jwe); | ||
| } | ||
| catch { | ||
| throw new JWEDecryptionFailed(); | ||
| } | ||
| for (const recipient of jwe.recipients) { | ||
| try { | ||
| return await flattenedDecrypt({ | ||
| const flattened = { | ||
| aad: jwe.aad, | ||
@@ -26,3 +36,5 @@ ciphertext: jwe.ciphertext, | ||
| unprotected: jwe.unprotected, | ||
| }, key, options); | ||
| }; | ||
| checkRecipient(flattened); | ||
| return decryptResult(flattened, await decryptRecipient(flattened, token, shared, key)); | ||
| } | ||
@@ -29,0 +41,0 @@ catch { |
| import { FlattenedEncrypt } from '../flattened/encrypt.js'; | ||
| import { unprotected, assertNotSet } from '../../lib/helpers.js'; | ||
| import { JOSENotSupported, JWEInvalid } from '../../util/errors.js'; | ||
| import { assertNotSet } from '../../lib/helpers.js'; | ||
| import { JWEInvalid } from '../../util/errors.js'; | ||
| import { generateCek } from '../../lib/content_encryption.js'; | ||
| import { isDisjoint } from '../../lib/type_checks.js'; | ||
| import { encryptKeyManagement } from '../../lib/key_management.js'; | ||
| import { encode as b64u } from '../../util/base64url.js'; | ||
| import { validateCrit } from '../../lib/validate_crit.js'; | ||
| import { normalizeKey } from '../../lib/normalize_key.js'; | ||
| import { checkKeyType } from '../../lib/check_key_type.js'; | ||
| import { validateCritDuplicates } from '../../lib/options.js'; | ||
| import { checkEncryptHeaders, encryptJWE } from '../../lib/jwe_encrypt.js'; | ||
| import { prepareKey } from '../../lib/key.js'; | ||
| import { jweAlgorithm } from '../../lib/jwe_algorithms.js'; | ||
| class IndividualRecipient { | ||
@@ -74,2 +74,5 @@ #parent; | ||
| } | ||
| if (!(this.#plaintext instanceof Uint8Array)) { | ||
| throw new TypeError('plaintext must be an instance of Uint8Array'); | ||
| } | ||
| if (this.#recipients.length === 1) { | ||
@@ -82,2 +85,3 @@ const [recipient] = this.#recipients; | ||
| .setUnprotectedHeader(recipient.unprotectedHeader) | ||
| .setKeyManagementParameters(recipient.keyManagementParameters) | ||
| .encrypt(recipient.key, { ...recipient.options }); | ||
@@ -102,38 +106,32 @@ const jwe = { | ||
| } | ||
| validateCritDuplicates(JWEInvalid, this.#protectedHeader); | ||
| let enc; | ||
| const inputs = []; | ||
| const checked = []; | ||
| for (let i = 0; i < this.#recipients.length; i++) { | ||
| const recipient = this.#recipients[i]; | ||
| if (!isDisjoint(this.#protectedHeader, this.#unprotectedHeader, recipient.unprotectedHeader)) { | ||
| throw new JWEInvalid('JWE Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint'); | ||
| } | ||
| const joseHeader = { | ||
| ...this.#protectedHeader, | ||
| ...this.#unprotectedHeader, | ||
| ...recipient.unprotectedHeader, | ||
| const input = { | ||
| plaintext: this.#plaintext, | ||
| protectedHeader: this.#protectedHeader, | ||
| unprotectedHeader: recipient.unprotectedHeader, | ||
| sharedUnprotectedHeader: this.#unprotectedHeader, | ||
| aad: this.#aad, | ||
| keyManagementParameters: recipient.keyManagementParameters, | ||
| crit: recipient.options.crit, | ||
| unprotectedParameters: true, | ||
| }; | ||
| const { alg } = joseHeader; | ||
| if (typeof alg !== 'string' || !alg) { | ||
| throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid'); | ||
| } | ||
| if (alg === 'dir' || alg === 'ECDH-ES') { | ||
| const headers = checkEncryptHeaders(input); | ||
| inputs.push(input); | ||
| checked.push(headers); | ||
| if (headers.alg === 'dir' || headers.alg === 'ECDH-ES') { | ||
| throw new JWEInvalid('"dir" and "ECDH-ES" alg may only be used with a single recipient'); | ||
| } | ||
| if (typeof joseHeader.enc !== 'string' || !joseHeader.enc) { | ||
| throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid'); | ||
| } | ||
| if (!enc) { | ||
| enc = joseHeader.enc; | ||
| enc = headers.enc; | ||
| } | ||
| else if (enc !== joseHeader.enc) { | ||
| else if (enc !== headers.enc) { | ||
| throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter must be the same for all recipients'); | ||
| } | ||
| validateCrit(JWEInvalid, new Map(), recipient.options.crit, this.#protectedHeader, joseHeader); | ||
| if (joseHeader.zip !== undefined && joseHeader.zip !== 'DEF') { | ||
| throw new JOSENotSupported('Unsupported JWE "zip" (Compression Algorithm) Header Parameter value.'); | ||
| } | ||
| if (joseHeader.zip !== undefined && !this.#protectedHeader?.zip) { | ||
| throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header Parameter MUST be in a protected header.'); | ||
| } | ||
| } | ||
| const cek = generateCek(enc); | ||
| const cek = generateCek(checked[0].encEntry); | ||
| const jwe = { | ||
@@ -148,13 +146,3 @@ ciphertext: '', | ||
| if (i === 0) { | ||
| const flattened = await new FlattenedEncrypt(this.#plaintext) | ||
| .setAdditionalAuthenticatedData(this.#aad) | ||
| .setContentEncryptionKey(cek) | ||
| .setProtectedHeader(this.#protectedHeader) | ||
| .setSharedUnprotectedHeader(this.#unprotectedHeader) | ||
| .setUnprotectedHeader(recipient.unprotectedHeader) | ||
| .setKeyManagementParameters(recipient.keyManagementParameters) | ||
| .encrypt(recipient.key, { | ||
| ...recipient.options, | ||
| [unprotected]: true, | ||
| }); | ||
| const flattened = await encryptJWE({ ...inputs[0], cek }, checked[0], recipient.key); | ||
| jwe.ciphertext = flattened.ciphertext; | ||
@@ -174,8 +162,5 @@ jwe.iv = flattened.iv; | ||
| } | ||
| const alg = recipient.unprotectedHeader?.alg || | ||
| this.#protectedHeader?.alg || | ||
| this.#unprotectedHeader?.alg; | ||
| checkKeyType(alg === 'dir' ? enc : alg, recipient.key, 'encrypt'); | ||
| const k = await normalizeKey(recipient.key, alg); | ||
| const { encryptedKey, parameters } = await encryptKeyManagement(alg, enc, k, cek, recipient.keyManagementParameters); | ||
| const { alg } = checked[i]; | ||
| const k = await prepareKey(jweAlgorithm(alg), recipient.key, 'encrypt'); | ||
| const { encryptedKey, parameters } = await encryptKeyManagement(alg, checked[i].encEntry, k, cek, recipient.keyManagementParameters); | ||
| target.encrypted_key = b64u(encryptedKey); | ||
@@ -182,0 +167,0 @@ if (recipient.unprotectedHeader || parameters) |
@@ -1,2 +0,3 @@ | ||
| import { importJWK } from '../key/import.js'; | ||
| import { jwkToKey } from '../lib/jwk_to_key.js'; | ||
| import { jwsAlgorithm } from '../lib/jws_algorithms.js'; | ||
| import { isObject } from '../lib/type_checks.js'; | ||
@@ -12,4 +13,5 @@ import { JWSInvalid } from '../util/errors.js'; | ||
| } | ||
| const key = await importJWK({ ...joseHeader.jwk, ext: true }, joseHeader.alg); | ||
| if (key instanceof Uint8Array || key.type !== 'public') { | ||
| const entry = jwsAlgorithm(joseHeader.alg); | ||
| const key = await jwkToKey(entry, { ...joseHeader.jwk, ext: true }); | ||
| if (key.type !== 'public') { | ||
| throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key'); | ||
@@ -16,0 +18,0 @@ } |
@@ -1,24 +0,18 @@ | ||
| import { importJWK } from '../key/import.js'; | ||
| import { jwkToKey } from '../lib/jwk_to_key.js'; | ||
| import { maybeJWSAlgorithm } from '../lib/jws_algorithms.js'; | ||
| import { JWKSInvalid, JOSENotSupported, JWKSNoMatchingKey, JWKSMultipleMatchingKeys, } from '../util/errors.js'; | ||
| import { isObject } from '../lib/type_checks.js'; | ||
| function getKtyFromAlg(alg) { | ||
| switch (typeof alg === 'string' && alg.slice(0, 2)) { | ||
| case 'RS': | ||
| case 'PS': | ||
| return 'RSA'; | ||
| case 'ES': | ||
| return 'EC'; | ||
| case 'Ed': | ||
| return 'OKP'; | ||
| case 'ML': | ||
| return 'AKP'; | ||
| default: | ||
| throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set'); | ||
| function signatureAlgorithm(alg) { | ||
| const entry = typeof alg === 'string' ? maybeJWSAlgorithm(alg) : undefined; | ||
| if (!entry || entry.symmetric) { | ||
| throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set'); | ||
| } | ||
| return entry; | ||
| } | ||
| function isJWKSLike(jwks) { | ||
| return (jwks && | ||
| typeof jwks === 'object' && | ||
| Array.isArray(jwks.keys) && | ||
| jwks.keys.every(isJWKLike)); | ||
| if (!jwks || typeof jwks !== 'object') { | ||
| return false; | ||
| } | ||
| const { keys } = jwks; | ||
| return Array.isArray(keys) && keys.every(isJWKLike); | ||
| } | ||
@@ -28,3 +22,3 @@ function isJWKLike(key) { | ||
| } | ||
| class LocalJWKSet { | ||
| class LocalJWKSetImpl { | ||
| #jwks; | ||
@@ -43,9 +37,9 @@ #cached = new WeakMap(); | ||
| const { alg, kid } = { ...protectedHeader, ...token?.header }; | ||
| const kty = getKtyFromAlg(alg); | ||
| const entry = signatureAlgorithm(alg); | ||
| const candidates = this.#jwks.keys.filter((jwk) => { | ||
| let candidate = kty === jwk.kty; | ||
| let candidate = entry.kty.includes(jwk.kty); | ||
| if (candidate && typeof kid === 'string') { | ||
| candidate = kid === jwk.kid; | ||
| } | ||
| if (candidate && (typeof jwk.alg === 'string' || kty === 'AKP')) { | ||
| if (candidate && (typeof jwk.alg === 'string' || jwk.kty === 'AKP')) { | ||
| candidate = alg === jwk.alg; | ||
@@ -59,18 +53,4 @@ } | ||
| } | ||
| if (candidate) { | ||
| switch (alg) { | ||
| case 'ES256': | ||
| candidate = jwk.crv === 'P-256'; | ||
| break; | ||
| case 'ES384': | ||
| candidate = jwk.crv === 'P-384'; | ||
| break; | ||
| case 'ES512': | ||
| candidate = jwk.crv === 'P-521'; | ||
| break; | ||
| case 'Ed25519': | ||
| case 'EdDSA': | ||
| candidate = jwk.crv === 'Ed25519'; | ||
| break; | ||
| } | ||
| if (candidate && entry.crv) { | ||
| candidate = jwk.crv === entry.crv; | ||
| } | ||
@@ -89,3 +69,3 @@ return candidate; | ||
| try { | ||
| yield await importWithAlgCache(_cached, jwk, alg); | ||
| yield await importWithAlgCache(_cached, jwk, entry); | ||
| } | ||
@@ -97,18 +77,18 @@ catch { } | ||
| } | ||
| return importWithAlgCache(this.#cached, jwk, alg); | ||
| return importWithAlgCache(this.#cached, jwk, entry); | ||
| } | ||
| } | ||
| async function importWithAlgCache(cache, jwk, alg) { | ||
| async function importWithAlgCache(cache, jwk, entry) { | ||
| const cached = cache.get(jwk) || cache.set(jwk, {}).get(jwk); | ||
| if (cached[alg] === undefined) { | ||
| const key = await importJWK({ ...jwk, ext: true }, alg); | ||
| if (key instanceof Uint8Array || key.type !== 'public') { | ||
| if (cached[entry.alg] === undefined) { | ||
| const key = await jwkToKey(entry, { ...jwk, alg: entry.alg, ext: true }); | ||
| if (key.type !== 'public') { | ||
| throw new JWKSInvalid('JSON Web Key Set members must be public keys'); | ||
| } | ||
| cached[alg] = key; | ||
| cached[entry.alg] = key; | ||
| } | ||
| return cached[alg]; | ||
| return cached[entry.alg]; | ||
| } | ||
| export function createLocalJWKSet(jwks) { | ||
| const set = new LocalJWKSet(jwks); | ||
| const set = new LocalJWKSetImpl(jwks); | ||
| const localJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token); | ||
@@ -115,0 +95,0 @@ Object.defineProperties(localJWKSet, { |
@@ -12,3 +12,3 @@ import { JOSEError, JWKSNoMatchingKey, JWKSTimeout } from '../util/errors.js'; | ||
| const NAME = 'jose'; | ||
| const VERSION = 'v6.2.4'; | ||
| const VERSION = 'v6.2.5'; | ||
| USER_AGENT = `${NAME}/${VERSION}`; | ||
@@ -55,3 +55,3 @@ } | ||
| } | ||
| class RemoteJWKSet { | ||
| class RemoteJWKSetImpl { | ||
| #url; | ||
@@ -149,3 +149,3 @@ #timeoutDuration; | ||
| export function createRemoteJWKSet(url, options) { | ||
| const set = new RemoteJWKSet(url, options); | ||
| const set = new RemoteJWKSetImpl(url, options); | ||
| const remoteJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token); | ||
@@ -152,0 +152,0 @@ Object.defineProperties(remoteJWKSet, { |
| import { FlattenedSign } from '../flattened/sign.js'; | ||
| import { unencodedPayload } from '../../lib/jws_sign.js'; | ||
| export class CompactSign { | ||
| #flattened; | ||
| #protectedHeader; | ||
| constructor(payload) { | ||
@@ -9,11 +11,12 @@ this.#flattened = new FlattenedSign(payload); | ||
| this.#flattened.setProtectedHeader(protectedHeader); | ||
| this.#protectedHeader = protectedHeader; | ||
| return this; | ||
| } | ||
| async sign(key, options) { | ||
| const jws = await this.#flattened.sign(key, options); | ||
| if (jws.payload === undefined) { | ||
| if (unencodedPayload(this.#protectedHeader)) { | ||
| throw new TypeError('use the flattened module for creating JWS with b64: false'); | ||
| } | ||
| const jws = await this.#flattened.sign(key, options); | ||
| return `${jws.protected}.${jws.payload}.${jws.signature}`; | ||
| } | ||
| } |
@@ -1,17 +0,5 @@ | ||
| import { flattenedVerify } from '../flattened/verify.js'; | ||
| import { JWSInvalid } from '../../util/errors.js'; | ||
| import { decoder } from '../../lib/buffer_utils.js'; | ||
| import { prepareVerify, verifyCompact } from '../../lib/jws_verify.js'; | ||
| export async function compactVerify(jws, key, options) { | ||
| if (jws instanceof Uint8Array) { | ||
| jws = decoder.decode(jws); | ||
| } | ||
| if (typeof jws !== 'string') { | ||
| throw new JWSInvalid('Compact JWS must be a string or Uint8Array'); | ||
| } | ||
| const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.'); | ||
| if (length !== 3) { | ||
| throw new JWSInvalid('Invalid Compact JWS'); | ||
| } | ||
| const verified = await flattenedVerify({ payload, protected: protectedHeader, signature }, key, options); | ||
| const result = { payload: verified.payload, protectedHeader: verified.protectedHeader }; | ||
| const verified = await verifyCompact(jws, prepareVerify(options), key); | ||
| const result = { payload: verified.payload, protectedHeader: verified.parsedProt }; | ||
| if (typeof key === 'function') { | ||
@@ -18,0 +6,0 @@ return { ...result, key: verified.key }; |
@@ -1,9 +0,3 @@ | ||
| import { encode as b64u } from '../../util/base64url.js'; | ||
| import { sign } from '../../lib/signing.js'; | ||
| import { isDisjoint } from '../../lib/type_checks.js'; | ||
| import { JWSInvalid } from '../../util/errors.js'; | ||
| import { concat, encode } from '../../lib/buffer_utils.js'; | ||
| import { checkKeyType } from '../../lib/check_key_type.js'; | ||
| import { validateCrit } from '../../lib/validate_crit.js'; | ||
| import { normalizeKey } from '../../lib/normalize_key.js'; | ||
| import { createSignature } from '../../lib/jws_sign.js'; | ||
| import { assertNotSet } from '../../lib/helpers.js'; | ||
@@ -34,57 +28,13 @@ export class FlattenedSign { | ||
| } | ||
| if (!isDisjoint(this.#protectedHeader, this.#unprotectedHeader)) { | ||
| throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint'); | ||
| } | ||
| const joseHeader = { | ||
| ...this.#protectedHeader, | ||
| ...this.#unprotectedHeader, | ||
| }; | ||
| const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options?.crit, this.#protectedHeader, joseHeader); | ||
| let b64 = true; | ||
| if (extensions.has('b64')) { | ||
| b64 = this.#protectedHeader.b64; | ||
| if (typeof b64 !== 'boolean') { | ||
| throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean'); | ||
| } | ||
| } | ||
| const { alg } = joseHeader; | ||
| if (typeof alg !== 'string' || !alg) { | ||
| throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); | ||
| } | ||
| checkKeyType(alg, key, 'sign'); | ||
| let payloadS; | ||
| let payloadB; | ||
| if (b64) { | ||
| payloadS = b64u(this.#payload); | ||
| payloadB = encode(payloadS); | ||
| } | ||
| else { | ||
| payloadB = this.#payload; | ||
| payloadS = ''; | ||
| } | ||
| let protectedHeaderString; | ||
| let protectedHeaderBytes; | ||
| if (this.#protectedHeader) { | ||
| protectedHeaderString = b64u(JSON.stringify(this.#protectedHeader)); | ||
| protectedHeaderBytes = encode(protectedHeaderString); | ||
| } | ||
| else { | ||
| protectedHeaderString = ''; | ||
| protectedHeaderBytes = new Uint8Array(); | ||
| } | ||
| const data = concat(protectedHeaderBytes, encode('.'), payloadB); | ||
| const k = await normalizeKey(key, alg); | ||
| const signature = await sign(alg, k, data); | ||
| const jws = { | ||
| signature: b64u(signature), | ||
| payload: payloadS, | ||
| }; | ||
| const jws = await createSignature({ | ||
| payload: this.#payload, | ||
| protectedHeader: this.#protectedHeader, | ||
| unprotectedHeader: this.#unprotectedHeader, | ||
| crit: options?.crit, | ||
| }, key); | ||
| if (this.#unprotectedHeader) { | ||
| jws.header = this.#unprotectedHeader; | ||
| } | ||
| if (this.#protectedHeader) { | ||
| jws.protected = protectedHeaderString; | ||
| } | ||
| return jws; | ||
| } | ||
| } |
@@ -1,12 +0,4 @@ | ||
| import { decode as b64u } from '../../util/base64url.js'; | ||
| import { verify } from '../../lib/signing.js'; | ||
| import { JOSEAlgNotAllowed, JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.js'; | ||
| import { concat, encoder, decoder, encode } from '../../lib/buffer_utils.js'; | ||
| import { decodeBase64url } from '../../lib/helpers.js'; | ||
| import { isDisjoint } from '../../lib/type_checks.js'; | ||
| import { JWSInvalid } from '../../util/errors.js'; | ||
| import { isObject } from '../../lib/type_checks.js'; | ||
| import { checkKeyType } from '../../lib/check_key_type.js'; | ||
| import { validateCrit } from '../../lib/validate_crit.js'; | ||
| import { validateAlgorithms } from '../../lib/validate_algorithms.js'; | ||
| import { normalizeKey } from '../../lib/normalize_key.js'; | ||
| import { prepareVerify, verifySignature, verifyResult } from '../../lib/jws_verify.js'; | ||
| export async function flattenedVerify(jws, key, options) { | ||
@@ -31,81 +23,3 @@ if (!isObject(jws)) { | ||
| } | ||
| let parsedProt = {}; | ||
| if (jws.protected) { | ||
| try { | ||
| const protectedHeader = b64u(jws.protected); | ||
| parsedProt = JSON.parse(decoder.decode(protectedHeader)); | ||
| } | ||
| catch { | ||
| throw new JWSInvalid('JWS Protected Header is invalid'); | ||
| } | ||
| } | ||
| if (!isDisjoint(parsedProt, jws.header)) { | ||
| throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint'); | ||
| } | ||
| const joseHeader = { | ||
| ...parsedProt, | ||
| ...jws.header, | ||
| }; | ||
| const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options?.crit, parsedProt, joseHeader); | ||
| let b64 = true; | ||
| if (extensions.has('b64')) { | ||
| b64 = parsedProt.b64; | ||
| if (typeof b64 !== 'boolean') { | ||
| throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean'); | ||
| } | ||
| } | ||
| const { alg } = joseHeader; | ||
| if (typeof alg !== 'string' || !alg) { | ||
| throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); | ||
| } | ||
| const algorithms = options && validateAlgorithms('algorithms', options.algorithms); | ||
| if (algorithms && !algorithms.has(alg)) { | ||
| throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed'); | ||
| } | ||
| if (b64) { | ||
| if (typeof jws.payload !== 'string') { | ||
| throw new JWSInvalid('JWS Payload must be a string'); | ||
| } | ||
| } | ||
| else if (typeof jws.payload !== 'string' && !(jws.payload instanceof Uint8Array)) { | ||
| throw new JWSInvalid('JWS Payload must be a string or an Uint8Array instance'); | ||
| } | ||
| let resolvedKey = false; | ||
| if (typeof key === 'function') { | ||
| key = await key(parsedProt, jws); | ||
| resolvedKey = true; | ||
| } | ||
| checkKeyType(alg, key, 'verify'); | ||
| const data = concat(jws.protected !== undefined ? encode(jws.protected) : new Uint8Array(), encode('.'), typeof jws.payload === 'string' | ||
| ? b64 | ||
| ? encode(jws.payload) | ||
| : encoder.encode(jws.payload) | ||
| : jws.payload); | ||
| const signature = decodeBase64url(jws.signature, 'signature', JWSInvalid); | ||
| const k = await normalizeKey(key, alg); | ||
| const verified = await verify(alg, k, signature, data); | ||
| if (!verified) { | ||
| throw new JWSSignatureVerificationFailed(); | ||
| } | ||
| let payload; | ||
| if (b64) { | ||
| payload = decodeBase64url(jws.payload, 'payload', JWSInvalid); | ||
| } | ||
| else if (typeof jws.payload === 'string') { | ||
| payload = encoder.encode(jws.payload); | ||
| } | ||
| else { | ||
| payload = jws.payload; | ||
| } | ||
| const result = { payload }; | ||
| if (jws.protected !== undefined) { | ||
| result.protectedHeader = parsedProt; | ||
| } | ||
| if (jws.header !== undefined) { | ||
| result.unprotectedHeader = jws.header; | ||
| } | ||
| if (resolvedKey) { | ||
| return { ...result, key: k }; | ||
| } | ||
| return result; | ||
| return verifyResult(jws, await verifySignature(jws, prepareVerify(options), key)); | ||
| } |
@@ -1,2 +0,2 @@ | ||
| import { FlattenedSign } from '../flattened/sign.js'; | ||
| import { createSignature } from '../../lib/jws_sign.js'; | ||
| import { JWSInvalid } from '../../util/errors.js'; | ||
@@ -50,2 +50,5 @@ import { assertNotSet } from '../../lib/helpers.js'; | ||
| } | ||
| if (!(this.#payload instanceof Uint8Array)) { | ||
| throw new TypeError('payload must be an instance of Uint8Array'); | ||
| } | ||
| const jws = { | ||
@@ -55,8 +58,18 @@ signatures: [], | ||
| }; | ||
| const encoded = {}; | ||
| for (let i = 0; i < this.#signatures.length; i++) { | ||
| const signature = this.#signatures[i]; | ||
| const flattened = new FlattenedSign(this.#payload); | ||
| flattened.setProtectedHeader(signature.protectedHeader); | ||
| flattened.setUnprotectedHeader(signature.unprotectedHeader); | ||
| const { payload, ...rest } = await flattened.sign(signature.key, signature.options); | ||
| if (!signature.protectedHeader && !signature.unprotectedHeader) { | ||
| throw new JWSInvalid('either setProtectedHeader or setUnprotectedHeader must be called before #sign()'); | ||
| } | ||
| const { payload, ...rest } = await createSignature({ | ||
| payload: this.#payload, | ||
| protectedHeader: signature.protectedHeader, | ||
| unprotectedHeader: signature.unprotectedHeader, | ||
| crit: signature.options?.crit, | ||
| encoded, | ||
| }, signature.key); | ||
| if (signature.unprotectedHeader) { | ||
| rest.header = signature.unprotectedHeader; | ||
| } | ||
| if (i === 0) { | ||
@@ -63,0 +76,0 @@ jws.payload = payload; |
@@ -1,2 +0,2 @@ | ||
| import { flattenedVerify } from '../flattened/verify.js'; | ||
| import { prepareVerify, verifySignature, verifyResult } from '../../lib/jws_verify.js'; | ||
| import { JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.js'; | ||
@@ -11,5 +11,23 @@ import { isObject } from '../../lib/type_checks.js'; | ||
| } | ||
| let shared; | ||
| try { | ||
| if (jws.payload === undefined) | ||
| throw new Error(); | ||
| shared = prepareVerify(options); | ||
| } | ||
| catch { | ||
| throw new JWSSignatureVerificationFailed(); | ||
| } | ||
| for (const signature of jws.signatures) { | ||
| try { | ||
| return await flattenedVerify({ | ||
| if (signature.protected === undefined && signature.header === undefined) | ||
| throw new Error(); | ||
| if (signature.protected !== undefined && typeof signature.protected !== 'string') { | ||
| throw new Error(); | ||
| } | ||
| if (typeof signature.signature !== 'string') | ||
| throw new Error(); | ||
| if (signature.header !== undefined && !isObject(signature.header)) | ||
| throw new Error(); | ||
| return verifyResult(signature, await verifySignature({ | ||
| header: signature.header, | ||
@@ -19,3 +37,3 @@ payload: jws.payload, | ||
| signature: signature.signature, | ||
| }, key, options); | ||
| }, shared, key)); | ||
| } | ||
@@ -22,0 +40,0 @@ catch { |
@@ -1,8 +0,8 @@ | ||
| import { compactDecrypt } from '../jwe/compact/decrypt.js'; | ||
| import { prepareDecrypt, decryptCompact } from '../lib/jwe_decrypt.js'; | ||
| import { validateClaimsSet } from '../lib/jwt_claims_set.js'; | ||
| import { JWTClaimValidationFailed } from '../util/errors.js'; | ||
| export async function jwtDecrypt(jwt, key, options) { | ||
| const decrypted = await compactDecrypt(jwt, key, options); | ||
| const payload = validateClaimsSet(decrypted.protectedHeader, decrypted.plaintext, options); | ||
| const { protectedHeader } = decrypted; | ||
| const decrypted = await decryptCompact(jwt, prepareDecrypt(options), key); | ||
| const protectedHeader = decrypted.parsedProt; | ||
| const payload = validateClaimsSet(protectedHeader, decrypted.plaintext, options); | ||
| if (protectedHeader.iss !== undefined && protectedHeader.iss !== payload.iss) { | ||
@@ -9,0 +9,0 @@ throw new JWTClaimValidationFailed('replicated "iss" claim header parameter mismatch', payload, 'iss', 'mismatch'); |
| import { CompactSign } from '../jws/compact/sign.js'; | ||
| import { unencodedPayload } from '../lib/jws_sign.js'; | ||
| import { JWTInvalid } from '../util/errors.js'; | ||
@@ -45,5 +46,3 @@ import { JWTClaimsBuilder } from '../lib/jwt_claims_set.js'; | ||
| sig.setProtectedHeader(this.#protectedHeader); | ||
| if (Array.isArray(this.#protectedHeader?.crit) && | ||
| this.#protectedHeader.crit.includes('b64') && | ||
| this.#protectedHeader.b64 === false) { | ||
| if (unencodedPayload(this.#protectedHeader)) { | ||
| throw new JWTInvalid('JWTs MUST NOT use unencoded payload'); | ||
@@ -50,0 +49,0 @@ } |
| import * as b64u from '../util/base64url.js'; | ||
| import { decoder } from '../lib/buffer_utils.js'; | ||
| import { strictDecoder } from '../lib/buffer_utils.js'; | ||
| import { decodeBase64url } from '../lib/helpers.js'; | ||
| import { JWTInvalid } from '../util/errors.js'; | ||
@@ -53,3 +54,3 @@ import { validateClaimsSet, JWTClaimsBuilder } from '../lib/jwt_claims_set.js'; | ||
| try { | ||
| header = JSON.parse(decoder.decode(b64u.decode(encodedHeader))); | ||
| header = JSON.parse(strictDecoder.decode(b64u.decode(encodedHeader))); | ||
| if (header.alg !== 'none') | ||
@@ -61,5 +62,5 @@ throw new Error(); | ||
| } | ||
| const payload = validateClaimsSet(header, b64u.decode(encodedPayload), options); | ||
| const payload = validateClaimsSet(header, decodeBase64url(encodedPayload, 'payload', JWTInvalid), options); | ||
| return { payload, header }; | ||
| } | ||
| } |
@@ -1,11 +0,11 @@ | ||
| import { compactVerify } from '../jws/compact/verify.js'; | ||
| import { prepareVerify, verifyCompact } from '../lib/jws_verify.js'; | ||
| import { validateClaimsSet } from '../lib/jwt_claims_set.js'; | ||
| import { JWTInvalid } from '../util/errors.js'; | ||
| export async function jwtVerify(jwt, key, options) { | ||
| const verified = await compactVerify(jwt, key, options); | ||
| if (verified.protectedHeader.crit?.includes('b64') && verified.protectedHeader.b64 === false) { | ||
| const verified = await verifyCompact(jwt, prepareVerify(options), key); | ||
| if (!verified.b64) { | ||
| throw new JWTInvalid('JWTs MUST NOT use unencoded payload'); | ||
| } | ||
| const payload = validateClaimsSet(verified.protectedHeader, verified.payload, options); | ||
| const result = { payload, protectedHeader: verified.protectedHeader }; | ||
| const payload = validateClaimsSet(verified.parsedProt, verified.payload, options); | ||
| const result = { payload, protectedHeader: verified.parsedProt }; | ||
| if (typeof key === 'function') { | ||
@@ -12,0 +12,0 @@ return { ...result, key: verified.key }; |
| import { toSPKI as exportPublic, toPKCS8 as exportPrivate } from '../lib/asn1.js'; | ||
| import { keyToJWK } from '../lib/key_to_jwk.js'; | ||
| import { invalidKeyInput } from '../lib/invalid_key_input.js'; | ||
| import { encode as b64u } from '../util/base64url.js'; | ||
| import { isCryptoKey, isKeyObject } from '../lib/is_key_like.js'; | ||
| function omitUndefinedProperties(jwk) { | ||
| return Object.fromEntries(Object.entries(jwk).filter(([, value]) => value !== undefined)); | ||
| } | ||
| async function keyToJWK(key) { | ||
| if (isKeyObject(key)) { | ||
| if (key.type === 'secret') { | ||
| key = key.export(); | ||
| } | ||
| else { | ||
| return key.export({ format: 'jwk' }); | ||
| } | ||
| } | ||
| if (key instanceof Uint8Array) { | ||
| return { | ||
| kty: 'oct', | ||
| k: b64u(key), | ||
| }; | ||
| } | ||
| if (!isCryptoKey(key)) { | ||
| throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'KeyObject', 'Uint8Array')); | ||
| } | ||
| if (!key.extractable) { | ||
| throw new TypeError('non-extractable CryptoKey cannot be exported as a JWK'); | ||
| } | ||
| const { ext, key_ops, alg, use, ...jwk } = omitUndefinedProperties(await crypto.subtle.exportKey('jwk', key)); | ||
| if (jwk.kty === 'AKP') { | ||
| ; | ||
| jwk.alg = alg; | ||
| } | ||
| return jwk; | ||
| } | ||
| export async function exportSPKI(key) { | ||
@@ -4,0 +37,0 @@ return exportPublic(key); |
| import { JOSENotSupported } from '../util/errors.js'; | ||
| import { keyAlgorithm } from '../lib/key_algorithm.js'; | ||
| function getModulusLengthOption(options) { | ||
@@ -10,89 +11,38 @@ const modulusLength = options?.modulusLength ?? 2048; | ||
| export async function generateKeyPair(alg, options) { | ||
| const entry = keyAlgorithm(alg); | ||
| if (entry.symmetric) { | ||
| throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value'); | ||
| } | ||
| let algorithm; | ||
| let keyUsages; | ||
| switch (alg) { | ||
| case 'PS256': | ||
| case 'PS384': | ||
| case 'PS512': | ||
| algorithm = { | ||
| name: 'RSA-PSS', | ||
| hash: `SHA-${alg.slice(-3)}`, | ||
| publicExponent: Uint8Array.of(0x01, 0x00, 0x01), | ||
| modulusLength: getModulusLengthOption(options), | ||
| }; | ||
| keyUsages = ['sign', 'verify']; | ||
| break; | ||
| case 'RS256': | ||
| case 'RS384': | ||
| case 'RS512': | ||
| algorithm = { | ||
| name: 'RSASSA-PKCS1-v1_5', | ||
| hash: `SHA-${alg.slice(-3)}`, | ||
| publicExponent: Uint8Array.of(0x01, 0x00, 0x01), | ||
| modulusLength: getModulusLengthOption(options), | ||
| }; | ||
| keyUsages = ['sign', 'verify']; | ||
| break; | ||
| case 'RSA-OAEP': | ||
| case 'RSA-OAEP-256': | ||
| case 'RSA-OAEP-384': | ||
| case 'RSA-OAEP-512': | ||
| algorithm = { | ||
| name: 'RSA-OAEP', | ||
| hash: `SHA-${parseInt(alg.slice(-3), 10) || 1}`, | ||
| publicExponent: Uint8Array.of(0x01, 0x00, 0x01), | ||
| modulusLength: getModulusLengthOption(options), | ||
| }; | ||
| keyUsages = ['decrypt', 'unwrapKey', 'encrypt', 'wrapKey']; | ||
| break; | ||
| case 'ES256': | ||
| algorithm = { name: 'ECDSA', namedCurve: 'P-256' }; | ||
| keyUsages = ['sign', 'verify']; | ||
| break; | ||
| case 'ES384': | ||
| algorithm = { name: 'ECDSA', namedCurve: 'P-384' }; | ||
| keyUsages = ['sign', 'verify']; | ||
| break; | ||
| case 'ES512': | ||
| algorithm = { name: 'ECDSA', namedCurve: 'P-521' }; | ||
| keyUsages = ['sign', 'verify']; | ||
| break; | ||
| case 'Ed25519': | ||
| case 'EdDSA': { | ||
| keyUsages = ['sign', 'verify']; | ||
| algorithm = { name: 'Ed25519' }; | ||
| break; | ||
| if (entry.subtleFor) { | ||
| switch (options?.crv ?? 'P-256') { | ||
| case 'P-256': | ||
| case 'P-384': | ||
| case 'P-521': | ||
| algorithm = { name: 'ECDH', namedCurve: options?.crv ?? 'P-256' }; | ||
| break; | ||
| case 'X25519': | ||
| algorithm = { name: 'X25519' }; | ||
| break; | ||
| default: | ||
| throw new JOSENotSupported('Invalid or unsupported crv option provided, supported values are P-256, P-384, P-521, and X25519'); | ||
| } | ||
| case 'ML-DSA-44': | ||
| case 'ML-DSA-65': | ||
| case 'ML-DSA-87': { | ||
| keyUsages = ['sign', 'verify']; | ||
| algorithm = { name: alg }; | ||
| break; | ||
| } | ||
| else { | ||
| if (entry.crv !== undefined && options?.crv !== undefined && options.crv !== entry.crv) { | ||
| throw new JOSENotSupported(`Invalid or unsupported crv option provided, the only supported value for ${alg} is ${entry.crv}`); | ||
| } | ||
| case 'ECDH-ES': | ||
| case 'ECDH-ES+A128KW': | ||
| case 'ECDH-ES+A192KW': | ||
| case 'ECDH-ES+A256KW': { | ||
| keyUsages = ['deriveBits']; | ||
| const crv = options?.crv ?? 'P-256'; | ||
| switch (crv) { | ||
| case 'P-256': | ||
| case 'P-384': | ||
| case 'P-521': { | ||
| algorithm = { name: 'ECDH', namedCurve: crv }; | ||
| break; | ||
| algorithm = | ||
| entry.kty[0] === 'RSA' | ||
| ? { | ||
| ...entry.subtle, | ||
| publicExponent: Uint8Array.of(0x01, 0x00, 0x01), | ||
| modulusLength: getModulusLengthOption(options), | ||
| } | ||
| case 'X25519': | ||
| algorithm = { name: 'X25519' }; | ||
| break; | ||
| default: | ||
| throw new JOSENotSupported('Invalid or unsupported crv option provided, supported values are P-256, P-384, P-521, and X25519'); | ||
| } | ||
| break; | ||
| } | ||
| default: | ||
| throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value'); | ||
| : entry.subtle; | ||
| } | ||
| return crypto.subtle.generateKey(algorithm, options?.extractable ?? false, keyUsages); | ||
| return crypto.subtle.generateKey(algorithm, options?.extractable ?? false, [ | ||
| ...entry.usages.private, | ||
| ...entry.usages.public, | ||
| ]); | ||
| } |
| import { decode as decodeBase64URL } from '../util/base64url.js'; | ||
| import { fromSPKI, fromPKCS8, fromX509 } from '../lib/asn1.js'; | ||
| import { jwkToKey } from '../lib/jwk_to_key.js'; | ||
| import { keyAlgorithm } from '../lib/key_algorithm.js'; | ||
| import { JOSENotSupported } from '../util/errors.js'; | ||
@@ -28,5 +29,7 @@ import { isObject } from '../lib/type_checks.js'; | ||
| } | ||
| let ext; | ||
| alg ??= jwk.alg; | ||
| ext ??= options?.extractable ?? jwk.ext; | ||
| const ext = options?.extractable ?? jwk.ext; | ||
| if (jwk.kty !== 'oct' && !alg) { | ||
| throw new TypeError('"alg" argument is required when "jwk.alg" is not present'); | ||
| } | ||
| switch (jwk.kty) { | ||
@@ -39,6 +42,3 @@ case 'oct': | ||
| case 'RSA': | ||
| if ('oth' in jwk && jwk.oth !== undefined) { | ||
| throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported'); | ||
| } | ||
| return jwkToKey({ ...jwk, alg, ext }); | ||
| return jwkToKey(keyAlgorithm(alg), { ...jwk, alg, ext }); | ||
| case 'AKP': { | ||
@@ -51,7 +51,7 @@ if (typeof jwk.alg !== 'string' || !jwk.alg) { | ||
| } | ||
| return jwkToKey({ ...jwk, ext }); | ||
| return jwkToKey(keyAlgorithm(jwk.alg), { ...jwk, ext }); | ||
| } | ||
| case 'EC': | ||
| case 'OKP': | ||
| return jwkToKey({ ...jwk, alg, ext }); | ||
| return jwkToKey(keyAlgorithm(alg), { ...jwk, alg, ext }); | ||
| default: | ||
@@ -58,0 +58,0 @@ throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value'); |
+28
-64
| import { invalidKeyInput } from './invalid_key_input.js'; | ||
| import { encodeBase64, decodeBase64 } from '../lib/base64.js'; | ||
| import { JOSENotSupported } from '../util/errors.js'; | ||
| import { keyAlgorithm } from './key_algorithm.js'; | ||
| import { isCryptoKey, isKeyObject } from './is_key_like.js'; | ||
@@ -39,4 +40,11 @@ const formatPEM = (b64, descriptor) => { | ||
| const createASN1State = (data) => ({ data, pos: 0 }); | ||
| const readByte = (state) => { | ||
| const byte = state.data[state.pos++]; | ||
| if (byte === undefined) { | ||
| throw new Error('Unexpected end of ASN.1 input'); | ||
| } | ||
| return byte; | ||
| }; | ||
| const parseLength = (state) => { | ||
| const first = state.data[state.pos++]; | ||
| const first = readByte(state); | ||
| if (first & 0x80) { | ||
@@ -46,3 +54,3 @@ const lengthOfLen = first & 0x7f; | ||
| for (let i = 0; i < lengthOfLen; i++) { | ||
| length = (length << 8) | state.data[state.pos++]; | ||
| length = (length << 8) | readByte(state); | ||
| } | ||
@@ -64,3 +72,3 @@ return length; | ||
| const expectTag = (state, expectedTag, errorMessage) => { | ||
| if (state.data[state.pos++] !== expectedTag) { | ||
| if (readByte(state) !== expectedTag) { | ||
| throw new Error(errorMessage); | ||
@@ -70,2 +78,5 @@ } | ||
| const getSubarray = (state, length) => { | ||
| if (length < 0 || state.pos + length > state.data.length) { | ||
| throw new Error('Unexpected end of ASN.1 input'); | ||
| } | ||
| const result = state.data.subarray(state.pos, state.pos + length); | ||
@@ -122,67 +133,20 @@ state.pos += length; | ||
| const genericImport = async (keyFormat, keyData, alg, options) => { | ||
| const entry = keyAlgorithm(alg); | ||
| if (entry.symmetric) { | ||
| throw new JOSENotSupported('Invalid or unsupported "alg" (Algorithm) value'); | ||
| } | ||
| const isPublic = keyFormat === 'spki'; | ||
| let algorithm; | ||
| let keyUsages; | ||
| const isPublic = keyFormat === 'spki'; | ||
| const getSigUsages = () => (isPublic ? ['verify'] : ['sign']); | ||
| const getEncUsages = () => isPublic ? ['encrypt', 'wrapKey'] : ['decrypt', 'unwrapKey']; | ||
| switch (alg) { | ||
| case 'PS256': | ||
| case 'PS384': | ||
| case 'PS512': | ||
| algorithm = { name: 'RSA-PSS', hash: `SHA-${alg.slice(-3)}` }; | ||
| keyUsages = getSigUsages(); | ||
| break; | ||
| case 'RS256': | ||
| case 'RS384': | ||
| case 'RS512': | ||
| algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: `SHA-${alg.slice(-3)}` }; | ||
| keyUsages = getSigUsages(); | ||
| break; | ||
| case 'RSA-OAEP': | ||
| case 'RSA-OAEP-256': | ||
| case 'RSA-OAEP-384': | ||
| case 'RSA-OAEP-512': | ||
| algorithm = { | ||
| name: 'RSA-OAEP', | ||
| hash: `SHA-${parseInt(alg.slice(-3), 10) || 1}`, | ||
| }; | ||
| keyUsages = getEncUsages(); | ||
| break; | ||
| case 'ES256': | ||
| case 'ES384': | ||
| case 'ES512': { | ||
| const curveMap = { ES256: 'P-256', ES384: 'P-384', ES512: 'P-521' }; | ||
| algorithm = { name: 'ECDSA', namedCurve: curveMap[alg] }; | ||
| keyUsages = getSigUsages(); | ||
| break; | ||
| if (entry.subtleFor) { | ||
| try { | ||
| algorithm = entry.subtleFor({ crv: options.getNamedCurve(keyData) }); | ||
| } | ||
| case 'ECDH-ES': | ||
| case 'ECDH-ES+A128KW': | ||
| case 'ECDH-ES+A192KW': | ||
| case 'ECDH-ES+A256KW': { | ||
| try { | ||
| const namedCurve = options.getNamedCurve(keyData); | ||
| algorithm = namedCurve === 'X25519' ? { name: 'X25519' } : { name: 'ECDH', namedCurve }; | ||
| } | ||
| catch (cause) { | ||
| throw new JOSENotSupported('Invalid or unsupported key format'); | ||
| } | ||
| keyUsages = isPublic ? [] : ['deriveBits']; | ||
| break; | ||
| catch (cause) { | ||
| throw new JOSENotSupported('Invalid or unsupported key format'); | ||
| } | ||
| case 'Ed25519': | ||
| case 'EdDSA': | ||
| algorithm = { name: 'Ed25519' }; | ||
| keyUsages = getSigUsages(); | ||
| break; | ||
| case 'ML-DSA-44': | ||
| case 'ML-DSA-65': | ||
| case 'ML-DSA-87': | ||
| algorithm = { name: alg }; | ||
| keyUsages = getSigUsages(); | ||
| break; | ||
| default: | ||
| throw new JOSENotSupported('Invalid or unsupported "alg" (Algorithm) value'); | ||
| } | ||
| return crypto.subtle.importKey(keyFormat, keyData, algorithm, options?.extractable ?? (isPublic ? true : false), keyUsages); | ||
| else { | ||
| algorithm = entry.subtle; | ||
| } | ||
| return crypto.subtle.importKey(keyFormat, keyData, algorithm, options?.extractable ?? (isPublic ? true : false), isPublic ? entry.usages.public : entry.usages.private); | ||
| }; | ||
@@ -189,0 +153,0 @@ const processPEMData = (pem, pattern) => { |
| export const encoder = new TextEncoder(); | ||
| export const decoder = new TextDecoder(); | ||
| export const strictDecoder = new TextDecoder('utf-8', { fatal: true }); | ||
| const MAX_INT32 = 2 ** 32; | ||
@@ -4,0 +5,0 @@ export function concat(...buffers) { |
| import { concat, uint64be } from './buffer_utils.js'; | ||
| import { checkEncCryptoKey } from './crypto_key.js'; | ||
| import { checkCryptoKey } from './crypto_key.js'; | ||
| import { invalidKeyInput } from './invalid_key_input.js'; | ||
| import { JOSENotSupported, JWEDecryptionFailed, JWEInvalid } from '../util/errors.js'; | ||
| import { JWEDecryptionFailed, JWEInvalid } from '../util/errors.js'; | ||
| import { isCryptoKey } from './is_key_like.js'; | ||
| export function cekLength(alg) { | ||
| switch (alg) { | ||
| case 'A128GCM': | ||
| return 128; | ||
| case 'A192GCM': | ||
| return 192; | ||
| case 'A256GCM': | ||
| case 'A128CBC-HS256': | ||
| return 256; | ||
| case 'A192CBC-HS384': | ||
| return 384; | ||
| case 'A256CBC-HS512': | ||
| return 512; | ||
| default: | ||
| throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`); | ||
| } | ||
| } | ||
| export const generateCek = (alg) => crypto.getRandomValues(new Uint8Array(cekLength(alg) >> 3)); | ||
| export const generateCek = (enc) => crypto.getRandomValues(new Uint8Array(enc.cekBits >> 3)); | ||
| function checkCekLength(cek, expected) { | ||
@@ -30,22 +13,5 @@ const actual = cek.byteLength << 3; | ||
| } | ||
| function ivBitLength(alg) { | ||
| switch (alg) { | ||
| case 'A128GCM': | ||
| case 'A128GCMKW': | ||
| case 'A192GCM': | ||
| case 'A192GCMKW': | ||
| case 'A256GCM': | ||
| case 'A256GCMKW': | ||
| return 96; | ||
| case 'A128CBC-HS256': | ||
| case 'A192CBC-HS384': | ||
| case 'A256CBC-HS512': | ||
| return 128; | ||
| default: | ||
| throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`); | ||
| } | ||
| } | ||
| export const generateIv = (alg) => crypto.getRandomValues(new Uint8Array(ivBitLength(alg) >> 3)); | ||
| export const generateIv = (enc) => crypto.getRandomValues(new Uint8Array(enc.ivBits >> 3)); | ||
| export function checkIvLength(enc, iv) { | ||
| if (iv.length << 3 !== ivBitLength(enc)) { | ||
| if (iv.length << 3 !== enc.ivBits) { | ||
| throw new JWEInvalid('Invalid Initialization Vector length'); | ||
@@ -58,3 +24,3 @@ } | ||
| } | ||
| const keySize = parseInt(enc.slice(1, 4), 10); | ||
| const keySize = enc.cekBits >> 1; | ||
| const encKey = await crypto.subtle.importKey('raw', cek.subarray(keySize >> 3), 'AES-CBC', false, [usage]); | ||
@@ -76,3 +42,3 @@ const macKey = await crypto.subtle.importKey('raw', cek.subarray(0, keySize >> 3), { | ||
| }, encKey, plaintext)); | ||
| const macData = concat(aad, iv, ciphertext, uint64be(aad.length << 3)); | ||
| const macData = concat(aad, iv, ciphertext, uint64be(aad.length * 8)); | ||
| const tag = await cbcHmacTag(macKey, macData, keySize); | ||
@@ -101,3 +67,3 @@ return { ciphertext, tag, iv }; | ||
| const { encKey, macKey, keySize } = await cbcKeySetup(enc, cek, 'decrypt'); | ||
| const macData = concat(aad, iv, ciphertext, uint64be(aad.length << 3)); | ||
| const macData = concat(aad, iv, ciphertext, uint64be(aad.length * 8)); | ||
| const expectedTag = await cbcHmacTag(macKey, macData, keySize); | ||
@@ -130,3 +96,3 @@ let macCheckPassed; | ||
| else { | ||
| checkEncCryptoKey(cek, enc, 'encrypt'); | ||
| checkCryptoKey(cek, enc.subtle, 'encrypt'); | ||
| encKey = cek; | ||
@@ -150,3 +116,3 @@ } | ||
| else { | ||
| checkEncCryptoKey(cek, enc, 'decrypt'); | ||
| checkCryptoKey(cek, enc.subtle, 'decrypt'); | ||
| encKey = cek; | ||
@@ -166,3 +132,2 @@ } | ||
| } | ||
| const unsupportedEnc = 'Unsupported JWE Content Encryption Algorithm'; | ||
| export async function encrypt(enc, plaintext, cek, iv, aad) { | ||
@@ -178,20 +143,8 @@ if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) { | ||
| } | ||
| switch (enc) { | ||
| case 'A128CBC-HS256': | ||
| case 'A192CBC-HS384': | ||
| case 'A256CBC-HS512': | ||
| if (cek instanceof Uint8Array) { | ||
| checkCekLength(cek, parseInt(enc.slice(-3), 10)); | ||
| } | ||
| return cbcEncrypt(enc, plaintext, cek, iv, aad); | ||
| case 'A128GCM': | ||
| case 'A192GCM': | ||
| case 'A256GCM': | ||
| if (cek instanceof Uint8Array) { | ||
| checkCekLength(cek, parseInt(enc.slice(1, 4), 10)); | ||
| } | ||
| return gcmEncrypt(enc, plaintext, cek, iv, aad); | ||
| default: | ||
| throw new JOSENotSupported(unsupportedEnc); | ||
| if (cek instanceof Uint8Array) { | ||
| checkCekLength(cek, enc.cekBits); | ||
| } | ||
| return enc.cbc | ||
| ? cbcEncrypt(enc, plaintext, cek, iv, aad) | ||
| : gcmEncrypt(enc, plaintext, cek, iv, aad); | ||
| } | ||
@@ -209,18 +162,8 @@ export async function decrypt(enc, cek, ciphertext, iv, tag, aad) { | ||
| checkIvLength(enc, iv); | ||
| switch (enc) { | ||
| case 'A128CBC-HS256': | ||
| case 'A192CBC-HS384': | ||
| case 'A256CBC-HS512': | ||
| if (cek instanceof Uint8Array) | ||
| checkCekLength(cek, parseInt(enc.slice(-3), 10)); | ||
| return cbcDecrypt(enc, cek, ciphertext, iv, tag, aad); | ||
| case 'A128GCM': | ||
| case 'A192GCM': | ||
| case 'A256GCM': | ||
| if (cek instanceof Uint8Array) | ||
| checkCekLength(cek, parseInt(enc.slice(1, 4), 10)); | ||
| return gcmDecrypt(enc, cek, ciphertext, iv, tag, aad); | ||
| default: | ||
| throw new JOSENotSupported(unsupportedEnc); | ||
| if (cek instanceof Uint8Array) { | ||
| checkCekLength(cek, enc.cekBits); | ||
| } | ||
| return enc.cbc | ||
| ? cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) | ||
| : gcmDecrypt(enc, cek, ciphertext, iv, tag, aad); | ||
| } |
| const unusable = (name, prop = 'algorithm.name') => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`); | ||
| const isAlgorithm = (algorithm, name) => algorithm.name === name; | ||
| function getHashLength(hash) { | ||
| return parseInt(hash.name.slice(4), 10); | ||
| } | ||
| function checkHashLength(algorithm, expected) { | ||
| const actual = getHashLength(algorithm.hash); | ||
| if (actual !== expected) | ||
| throw unusable(`SHA-${expected}`, 'algorithm.hash'); | ||
| } | ||
| 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) { | ||
| export function checkUsage(key, usage) { | ||
| if (usage && !key.usages.includes(usage)) { | ||
@@ -28,110 +7,17 @@ throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`); | ||
| } | ||
| export function checkSigCryptoKey(key, alg, usage) { | ||
| switch (alg) { | ||
| case 'HS256': | ||
| case 'HS384': | ||
| case 'HS512': { | ||
| if (!isAlgorithm(key.algorithm, 'HMAC')) | ||
| throw unusable('HMAC'); | ||
| checkHashLength(key.algorithm, parseInt(alg.slice(2), 10)); | ||
| break; | ||
| } | ||
| case 'RS256': | ||
| case 'RS384': | ||
| case 'RS512': { | ||
| if (!isAlgorithm(key.algorithm, 'RSASSA-PKCS1-v1_5')) | ||
| throw unusable('RSASSA-PKCS1-v1_5'); | ||
| checkHashLength(key.algorithm, parseInt(alg.slice(2), 10)); | ||
| break; | ||
| } | ||
| case 'PS256': | ||
| case 'PS384': | ||
| case 'PS512': { | ||
| if (!isAlgorithm(key.algorithm, 'RSA-PSS')) | ||
| throw unusable('RSA-PSS'); | ||
| checkHashLength(key.algorithm, parseInt(alg.slice(2), 10)); | ||
| break; | ||
| } | ||
| case 'Ed25519': | ||
| case 'EdDSA': { | ||
| if (!isAlgorithm(key.algorithm, 'Ed25519')) | ||
| throw unusable('Ed25519'); | ||
| break; | ||
| } | ||
| case 'ML-DSA-44': | ||
| case 'ML-DSA-65': | ||
| case 'ML-DSA-87': { | ||
| if (!isAlgorithm(key.algorithm, alg)) | ||
| throw unusable(alg); | ||
| 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'); | ||
| export function checkCryptoKey(key, expected, usage) { | ||
| const algorithm = key.algorithm; | ||
| if (algorithm.name !== expected.name) { | ||
| throw unusable(expected.name); | ||
| } | ||
| checkUsage(key, usage); | ||
| } | ||
| export function checkEncCryptoKey(key, alg, usage) { | ||
| switch (alg) { | ||
| case 'A128GCM': | ||
| case 'A192GCM': | ||
| case 'A256GCM': { | ||
| if (!isAlgorithm(key.algorithm, 'AES-GCM')) | ||
| throw unusable('AES-GCM'); | ||
| const expected = parseInt(alg.slice(1, 4), 10); | ||
| const actual = key.algorithm.length; | ||
| if (actual !== expected) | ||
| throw unusable(expected, 'algorithm.length'); | ||
| break; | ||
| } | ||
| case 'A128KW': | ||
| case 'A192KW': | ||
| case 'A256KW': { | ||
| if (!isAlgorithm(key.algorithm, 'AES-KW')) | ||
| throw unusable('AES-KW'); | ||
| const expected = parseInt(alg.slice(1, 4), 10); | ||
| const actual = key.algorithm.length; | ||
| if (actual !== expected) | ||
| throw unusable(expected, 'algorithm.length'); | ||
| break; | ||
| } | ||
| case 'ECDH': { | ||
| switch (key.algorithm.name) { | ||
| case 'ECDH': | ||
| case 'X25519': | ||
| break; | ||
| default: | ||
| throw unusable('ECDH or X25519'); | ||
| } | ||
| break; | ||
| } | ||
| case 'PBES2-HS256+A128KW': | ||
| case 'PBES2-HS384+A192KW': | ||
| case 'PBES2-HS512+A256KW': | ||
| if (!isAlgorithm(key.algorithm, 'PBKDF2')) | ||
| throw unusable('PBKDF2'); | ||
| break; | ||
| case 'RSA-OAEP': | ||
| case 'RSA-OAEP-256': | ||
| case 'RSA-OAEP-384': | ||
| case 'RSA-OAEP-512': { | ||
| if (!isAlgorithm(key.algorithm, 'RSA-OAEP')) | ||
| throw unusable('RSA-OAEP'); | ||
| checkHashLength(key.algorithm, parseInt(alg.slice(9), 10) || 1); | ||
| break; | ||
| } | ||
| default: | ||
| throw new TypeError('CryptoKey does not support this operation'); | ||
| if (expected.hash && algorithm.hash?.name !== expected.hash) { | ||
| throw unusable(expected.hash, 'algorithm.hash'); | ||
| } | ||
| if (expected.namedCurve && algorithm.namedCurve !== expected.namedCurve) { | ||
| throw unusable(expected.namedCurve, 'algorithm.namedCurve'); | ||
| } | ||
| if (expected.length !== undefined && algorithm.length !== expected.length) { | ||
| throw unusable(expected.length, 'algorithm.length'); | ||
| } | ||
| checkUsage(key, usage); | ||
| } |
| import { decode } from '../util/base64url.js'; | ||
| import { encode, strictDecoder } from './buffer_utils.js'; | ||
| import { isObject } from './type_checks.js'; | ||
| export const unprotected = Symbol(); | ||
@@ -16,2 +18,10 @@ export function assertNotSet(value, name) { | ||
| } | ||
| export function encodeBase64url(value, label, ErrorClass) { | ||
| try { | ||
| return encode(value); | ||
| } | ||
| catch { | ||
| throw new ErrorClass(`The ${label} is not a valid base64url string`); | ||
| } | ||
| } | ||
| export async function digest(algorithm, data) { | ||
@@ -21,1 +31,14 @@ const subtleDigest = `SHA-${algorithm.slice(-3)}`; | ||
| } | ||
| export function parseJoseHeader(b64, ErrorClass, message) { | ||
| let parsed; | ||
| try { | ||
| parsed = JSON.parse(strictDecoder.decode(decode(b64))); | ||
| } | ||
| catch { | ||
| throw new ErrorClass(message); | ||
| } | ||
| if (!isObject(parsed)) { | ||
| throw new ErrorClass(message); | ||
| } | ||
| return parsed; | ||
| } |
| import { JOSENotSupported } from '../util/errors.js'; | ||
| const unsupportedAlg = 'Invalid or unsupported JWK "alg" (Algorithm) Parameter value'; | ||
| function subtleMapping(jwk) { | ||
| let algorithm; | ||
| let keyUsages; | ||
| switch (jwk.kty) { | ||
| case 'AKP': { | ||
| switch (jwk.alg) { | ||
| case 'ML-DSA-44': | ||
| case 'ML-DSA-65': | ||
| case 'ML-DSA-87': | ||
| algorithm = { name: jwk.alg }; | ||
| keyUsages = jwk.priv ? ['sign'] : ['verify']; | ||
| break; | ||
| default: | ||
| throw new JOSENotSupported(unsupportedAlg); | ||
| } | ||
| break; | ||
| } | ||
| case 'RSA': { | ||
| switch (jwk.alg) { | ||
| case 'PS256': | ||
| case 'PS384': | ||
| case 'PS512': | ||
| algorithm = { name: 'RSA-PSS', hash: `SHA-${jwk.alg.slice(-3)}` }; | ||
| keyUsages = jwk.d ? ['sign'] : ['verify']; | ||
| break; | ||
| case 'RS256': | ||
| case 'RS384': | ||
| case 'RS512': | ||
| algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: `SHA-${jwk.alg.slice(-3)}` }; | ||
| keyUsages = jwk.d ? ['sign'] : ['verify']; | ||
| break; | ||
| case 'RSA-OAEP': | ||
| case 'RSA-OAEP-256': | ||
| case 'RSA-OAEP-384': | ||
| case 'RSA-OAEP-512': | ||
| algorithm = { | ||
| name: 'RSA-OAEP', | ||
| hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}`, | ||
| }; | ||
| keyUsages = jwk.d ? ['decrypt', 'unwrapKey'] : ['encrypt', 'wrapKey']; | ||
| break; | ||
| default: | ||
| throw new JOSENotSupported(unsupportedAlg); | ||
| } | ||
| break; | ||
| } | ||
| case 'EC': { | ||
| switch (jwk.alg) { | ||
| case 'ES256': | ||
| case 'ES384': | ||
| case 'ES512': | ||
| algorithm = { | ||
| name: 'ECDSA', | ||
| namedCurve: { ES256: 'P-256', ES384: 'P-384', ES512: 'P-521' }[jwk.alg], | ||
| }; | ||
| keyUsages = jwk.d ? ['sign'] : ['verify']; | ||
| break; | ||
| case 'ECDH-ES': | ||
| case 'ECDH-ES+A128KW': | ||
| case 'ECDH-ES+A192KW': | ||
| case 'ECDH-ES+A256KW': | ||
| algorithm = { name: 'ECDH', namedCurve: jwk.crv }; | ||
| keyUsages = jwk.d ? ['deriveBits'] : []; | ||
| break; | ||
| default: | ||
| throw new JOSENotSupported(unsupportedAlg); | ||
| } | ||
| break; | ||
| } | ||
| case 'OKP': { | ||
| switch (jwk.alg) { | ||
| case 'Ed25519': | ||
| case 'EdDSA': | ||
| algorithm = { name: 'Ed25519' }; | ||
| keyUsages = jwk.d ? ['sign'] : ['verify']; | ||
| break; | ||
| case 'ECDH-ES': | ||
| case 'ECDH-ES+A128KW': | ||
| case 'ECDH-ES+A192KW': | ||
| case 'ECDH-ES+A256KW': | ||
| algorithm = { name: jwk.crv }; | ||
| keyUsages = jwk.d ? ['deriveBits'] : []; | ||
| break; | ||
| default: | ||
| throw new JOSENotSupported(unsupportedAlg); | ||
| } | ||
| break; | ||
| } | ||
| default: | ||
| throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value'); | ||
| function subtleParams(entry, jwk) { | ||
| if (!entry.kty.includes(jwk.kty)) { | ||
| throw new JOSENotSupported(unsupportedAlg); | ||
| } | ||
| return { algorithm, keyUsages }; | ||
| return entry.subtleFor?.({ kty: jwk.kty, crv: jwk.crv }) ?? entry.subtle; | ||
| } | ||
| export async function jwkToKey(jwk) { | ||
| if (!jwk.alg) { | ||
| throw new TypeError('"alg" argument is required when "jwk.alg" is not present'); | ||
| export async function jwkToKey(entry, jwk) { | ||
| if (jwk.kty === 'RSA' && 'oth' in jwk && jwk.oth !== undefined) { | ||
| throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported'); | ||
| } | ||
| const { algorithm, keyUsages } = subtleMapping(jwk); | ||
| const algorithm = subtleParams(entry, jwk); | ||
| const isPrivate = !!(jwk.d || jwk.priv); | ||
| const keyUsages = isPrivate ? entry.usages.private : entry.usages.public; | ||
| const keyData = { ...jwk }; | ||
@@ -106,3 +21,3 @@ if (keyData.kty !== 'AKP') { | ||
| delete keyData.use; | ||
| return crypto.subtle.importKey('jwk', keyData, algorithm, jwk.ext ?? (jwk.d || jwk.priv ? false : true), jwk.key_ops ?? keyUsages); | ||
| return crypto.subtle.importKey('jwk', keyData, algorithm, jwk.ext ?? (isPrivate ? false : true), jwk.key_ops ?? keyUsages); | ||
| } |
| import { JWTClaimValidationFailed, JWTExpired, JWTInvalid } from '../util/errors.js'; | ||
| import { encoder, decoder } from './buffer_utils.js'; | ||
| import { encoder, strictDecoder } from './buffer_utils.js'; | ||
| import { isObject } from './type_checks.js'; | ||
@@ -84,3 +84,3 @@ const epoch = (date) => Math.floor(date.getTime() / 1000); | ||
| try { | ||
| payload = JSON.parse(decoder.decode(encodedPayload)); | ||
| payload = JSON.parse(strictDecoder.decode(encodedPayload)); | ||
| } | ||
@@ -113,10 +113,10 @@ catch { | ||
| } | ||
| if (issuer && | ||
| if (issuer !== undefined && | ||
| !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) { | ||
| throw new JWTClaimValidationFailed('unexpected "iss" claim value', payload, 'iss', 'check_failed'); | ||
| } | ||
| if (subject && payload.sub !== subject) { | ||
| if (subject !== undefined && payload.sub !== subject) { | ||
| throw new JWTClaimValidationFailed('unexpected "sub" claim value', payload, 'sub', 'check_failed'); | ||
| } | ||
| if (audience && | ||
| if (audience !== undefined && | ||
| !checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience)) { | ||
@@ -139,5 +139,6 @@ throw new JWTClaimValidationFailed('unexpected "aud" claim value', payload, 'aud', 'check_failed'); | ||
| } | ||
| validateInput('clockTolerance option', tolerance); | ||
| const { currentDate } = options; | ||
| const now = epoch(currentDate || new Date()); | ||
| if ((payload.iat !== undefined || maxTokenAge) && typeof payload.iat !== 'number') { | ||
| const now = validateInput('currentDate option', epoch(currentDate || new Date())); | ||
| if ((payload.iat !== undefined || maxTokenAge !== undefined) && typeof payload.iat !== 'number') { | ||
| throw new JWTClaimValidationFailed('"iat" claim must be a number', payload, 'iat', 'invalid'); | ||
@@ -161,3 +162,3 @@ } | ||
| } | ||
| if (maxTokenAge) { | ||
| if (maxTokenAge !== undefined) { | ||
| const age = now - payload.iat; | ||
@@ -164,0 +165,0 @@ const max = typeof maxTokenAge === 'number' ? maxTokenAge : secs(maxTokenAge); |
@@ -1,15 +0,165 @@ | ||
| import * as aeskw from './aeskw.js'; | ||
| import * as ecdhes from './ecdhes.js'; | ||
| import * as pbes2kw from './pbes2kw.js'; | ||
| import * as rsaes from './rsaes.js'; | ||
| import { encode as b64u } from '../util/base64url.js'; | ||
| import { normalizeKey } from './normalize_key.js'; | ||
| import { prepareKey } from './key.js'; | ||
| import { jwkToKey } from './jwk_to_key.js'; | ||
| import { jweAlgorithm, jweEncryption } from './jwe_algorithms.js'; | ||
| import { JOSENotSupported, JWEInvalid } from '../util/errors.js'; | ||
| import { decodeBase64url } from './helpers.js'; | ||
| import { generateCek, cekLength } from './content_encryption.js'; | ||
| import { importJWK } from '../key/import.js'; | ||
| import { exportJWK } from '../key/export.js'; | ||
| import { decodeBase64url, digest } from './helpers.js'; | ||
| import { generateCek, encrypt, decrypt } from './content_encryption.js'; | ||
| import { isObject } from './type_checks.js'; | ||
| import { wrap as aesGcmKwWrap, unwrap as aesGcmKwUnwrap } from './aesgcmkw.js'; | ||
| import { checkCryptoKey, checkUsage } from './crypto_key.js'; | ||
| import { checkModulusLength } from './signing.js'; | ||
| import { concat, encode, uint32be } from './buffer_utils.js'; | ||
| import { assertCryptoKey } from './is_key_like.js'; | ||
| function checkEcdhCryptoKey(key, usage) { | ||
| switch (key.algorithm.name) { | ||
| case 'ECDH': | ||
| case 'X25519': | ||
| break; | ||
| default: | ||
| throw new TypeError('CryptoKey does not support this operation, its algorithm.name must be ECDH or X25519'); | ||
| } | ||
| checkUsage(key, usage); | ||
| } | ||
| function checkKeySize(key, alg) { | ||
| if (key.algorithm.length !== parseInt(alg.slice(1, 4), 10)) { | ||
| throw new TypeError(`Invalid key size for alg: ${alg}`); | ||
| } | ||
| } | ||
| function aeskwCryptoKey(key, alg, usage) { | ||
| if (key instanceof Uint8Array) { | ||
| return crypto.subtle.importKey('raw', key, 'AES-KW', true, [usage]); | ||
| } | ||
| checkCryptoKey(key, jweAlgorithm(alg).subtle, usage); | ||
| return key; | ||
| } | ||
| async function aeskwWrap(alg, key, cek) { | ||
| const cryptoKey = await aeskwCryptoKey(key, alg, 'wrapKey'); | ||
| checkKeySize(cryptoKey, alg); | ||
| const cryptoKeyCek = await crypto.subtle.importKey('raw', cek, { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']); | ||
| return new Uint8Array(await crypto.subtle.wrapKey('raw', cryptoKeyCek, cryptoKey, 'AES-KW')); | ||
| } | ||
| async function aeskwUnwrap(alg, key, encryptedKey) { | ||
| const cryptoKey = await aeskwCryptoKey(key, alg, 'unwrapKey'); | ||
| checkKeySize(cryptoKey, alg); | ||
| const cryptoKeyCek = await crypto.subtle.unwrapKey('raw', encryptedKey, cryptoKey, 'AES-KW', { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']); | ||
| return new Uint8Array(await crypto.subtle.exportKey('raw', cryptoKeyCek)); | ||
| } | ||
| async function aesGcmKwWrap(gcm, key, cek, iv) { | ||
| const wrapped = await encrypt(gcm, cek, key, iv, new Uint8Array()); | ||
| return { | ||
| encryptedKey: wrapped.ciphertext, | ||
| iv: b64u(wrapped.iv), | ||
| tag: b64u(wrapped.tag), | ||
| }; | ||
| } | ||
| async function aesGcmKwUnwrap(gcm, key, encryptedKey, iv, tag) { | ||
| return decrypt(gcm, key, encryptedKey, iv, tag, new Uint8Array()); | ||
| } | ||
| const subtleAlgorithm = (alg) => { | ||
| switch (alg) { | ||
| case 'RSA-OAEP': | ||
| case 'RSA-OAEP-256': | ||
| case 'RSA-OAEP-384': | ||
| case 'RSA-OAEP-512': | ||
| return 'RSA-OAEP'; | ||
| default: | ||
| throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); | ||
| } | ||
| }; | ||
| async function rsaesEncrypt(alg, key, cek) { | ||
| checkCryptoKey(key, jweAlgorithm(alg).subtle, 'encrypt'); | ||
| checkModulusLength(alg, key); | ||
| return new Uint8Array(await crypto.subtle.encrypt(subtleAlgorithm(alg), key, cek)); | ||
| } | ||
| async function rsaesDecrypt(alg, key, encryptedKey) { | ||
| checkCryptoKey(key, jweAlgorithm(alg).subtle, 'decrypt'); | ||
| checkModulusLength(alg, key); | ||
| return new Uint8Array(await crypto.subtle.decrypt(subtleAlgorithm(alg), key, encryptedKey)); | ||
| } | ||
| function pbes2CryptoKey(key, alg) { | ||
| if (key instanceof Uint8Array) { | ||
| return crypto.subtle.importKey('raw', key, 'PBKDF2', false, [ | ||
| 'deriveBits', | ||
| ]); | ||
| } | ||
| checkCryptoKey(key, jweAlgorithm(alg).subtle, 'deriveBits'); | ||
| return key; | ||
| } | ||
| const concatSalt = (alg, p2sInput) => concat(encode(alg), Uint8Array.of(0x00), p2sInput); | ||
| async function deriveKey(p2s, alg, p2c, key) { | ||
| if (!(p2s instanceof Uint8Array) || p2s.length < 8) { | ||
| throw new JWEInvalid('PBES2 Salt Input must be 8 or more octets'); | ||
| } | ||
| if (!Number.isSafeInteger(p2c) || Math.sign(p2c) !== 1) { | ||
| throw new JWEInvalid('PBES2 Count Input must be a positive integer'); | ||
| } | ||
| const salt = concatSalt(alg, p2s); | ||
| const keylen = parseInt(alg.slice(13, 16), 10); | ||
| const subtleAlg = { | ||
| hash: `SHA-${alg.slice(8, 11)}`, | ||
| iterations: p2c, | ||
| name: 'PBKDF2', | ||
| salt, | ||
| }; | ||
| const cryptoKey = await pbes2CryptoKey(key, alg); | ||
| return new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen)); | ||
| } | ||
| async function pbes2kwWrap(alg, key, cek, p2c = 2048, p2s = crypto.getRandomValues(new Uint8Array(16))) { | ||
| const derived = await deriveKey(p2s, alg, p2c, key); | ||
| const encryptedKey = await aeskwWrap(alg.slice(-6), derived, cek); | ||
| return { encryptedKey, p2c, p2s: b64u(p2s) }; | ||
| } | ||
| async function pbes2kwUnwrap(alg, key, encryptedKey, p2c, p2s) { | ||
| const derived = await deriveKey(p2s, alg, p2c, key); | ||
| return aeskwUnwrap(alg.slice(-6), derived, encryptedKey); | ||
| } | ||
| function lengthAndInput(input) { | ||
| return concat(uint32be(input.length), input); | ||
| } | ||
| async function concatKdf(Z, L, OtherInfo) { | ||
| const dkLen = L >> 3; | ||
| const hashLen = 32; | ||
| const reps = Math.ceil(dkLen / hashLen); | ||
| const dk = new Uint8Array(reps * hashLen); | ||
| for (let i = 1; i <= reps; i++) { | ||
| const hashInput = new Uint8Array(4 + Z.length + OtherInfo.length); | ||
| hashInput.set(uint32be(i), 0); | ||
| hashInput.set(Z, 4); | ||
| hashInput.set(OtherInfo, 4 + Z.length); | ||
| const hashResult = await digest('sha256', hashInput); | ||
| dk.set(hashResult, (i - 1) * hashLen); | ||
| } | ||
| return dk.slice(0, dkLen); | ||
| } | ||
| async function ecdhesDeriveKey(publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(), apv = new Uint8Array()) { | ||
| checkEcdhCryptoKey(publicKey); | ||
| checkEcdhCryptoKey(privateKey, 'deriveBits'); | ||
| const algorithmID = lengthAndInput(encode(algorithm)); | ||
| const partyUInfo = lengthAndInput(apu); | ||
| const partyVInfo = lengthAndInput(apv); | ||
| const suppPubInfo = uint32be(keyLength); | ||
| const suppPrivInfo = new Uint8Array(); | ||
| const otherInfo = concat(algorithmID, partyUInfo, partyVInfo, suppPubInfo, suppPrivInfo); | ||
| const Z = new Uint8Array(await crypto.subtle.deriveBits({ | ||
| name: publicKey.algorithm.name, | ||
| public: publicKey, | ||
| }, privateKey, getEcdhBitLength(publicKey))); | ||
| return concatKdf(Z, keyLength, otherInfo); | ||
| } | ||
| function getEcdhBitLength(publicKey) { | ||
| if (publicKey.algorithm.name === 'X25519') { | ||
| return 256; | ||
| } | ||
| return (Math.ceil(parseInt(publicKey.algorithm.namedCurve.slice(-3), 10) / 8) << 3); | ||
| } | ||
| function ecdhesAllowed(key) { | ||
| switch (key.algorithm.namedCurve) { | ||
| case 'P-256': | ||
| case 'P-384': | ||
| case 'P-521': | ||
| return true; | ||
| default: | ||
| return key.algorithm.name === 'X25519'; | ||
| } | ||
| } | ||
| const unsupportedAlgHeader = 'Invalid or unsupported "alg" (JWE Algorithm) header value'; | ||
@@ -20,3 +170,3 @@ function assertEncryptedKey(encryptedKey) { | ||
| } | ||
| export async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options) { | ||
| export async function decryptKeyManagement(alg, enc, key, encryptedKey, joseHeader, options) { | ||
| switch (alg) { | ||
@@ -37,6 +187,5 @@ case 'dir': { | ||
| assertCryptoKey(key); | ||
| if (!ecdhes.allowed(key)) | ||
| if (!ecdhesAllowed(key)) | ||
| throw new JOSENotSupported('ECDH with the provided key is not allowed or not supported by your javascript runtime'); | ||
| const epk = await importJWK(joseHeader.epk, alg); | ||
| assertCryptoKey(epk); | ||
| const epk = await jwkToKey(jweAlgorithm(alg), joseHeader.epk); | ||
| let partyUInfo; | ||
@@ -54,7 +203,7 @@ let partyVInfo; | ||
| } | ||
| const sharedSecret = await ecdhes.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, alg === 'ECDH-ES' ? cekLength(joseHeader.enc) : parseInt(alg.slice(-5, -2), 10), partyUInfo, partyVInfo); | ||
| const sharedSecret = await ecdhesDeriveKey(epk, key, alg === 'ECDH-ES' ? enc.alg : alg, alg === 'ECDH-ES' ? enc.cekBits : parseInt(alg.slice(-5, -2), 10), partyUInfo, partyVInfo); | ||
| if (alg === 'ECDH-ES') | ||
| return sharedSecret; | ||
| assertEncryptedKey(encryptedKey); | ||
| return aeskw.unwrap(alg.slice(-6), sharedSecret, encryptedKey); | ||
| return aeskwUnwrap(alg.slice(-6), sharedSecret, encryptedKey); | ||
| } | ||
@@ -67,3 +216,3 @@ case 'RSA-OAEP': | ||
| assertCryptoKey(key); | ||
| return rsaes.decrypt(alg, key, encryptedKey); | ||
| return rsaesDecrypt(alg, key, encryptedKey); | ||
| } | ||
@@ -83,3 +232,3 @@ case 'PBES2-HS256+A128KW': | ||
| p2s = decodeBase64url(joseHeader.p2s, 'p2s', JWEInvalid); | ||
| return pbes2kw.unwrap(alg, key, encryptedKey, joseHeader.p2c, p2s); | ||
| return pbes2kwUnwrap(alg, key, encryptedKey, joseHeader.p2c, p2s); | ||
| } | ||
@@ -90,3 +239,3 @@ case 'A128KW': | ||
| assertEncryptedKey(encryptedKey); | ||
| return aeskw.unwrap(alg, key, encryptedKey); | ||
| return aeskwUnwrap(alg, key, encryptedKey); | ||
| } | ||
@@ -105,3 +254,3 @@ case 'A128GCMKW': | ||
| tag = decodeBase64url(joseHeader.tag, 'tag', JWEInvalid); | ||
| return aesGcmKwUnwrap(alg, key, encryptedKey, iv, tag); | ||
| return aesGcmKwUnwrap(jweEncryption(jweAlgorithm(alg).gcmkw), key, encryptedKey, iv, tag); | ||
| } | ||
@@ -127,3 +276,3 @@ default: { | ||
| assertCryptoKey(key); | ||
| if (!ecdhes.allowed(key)) { | ||
| if (!ecdhesAllowed(key)) { | ||
| throw new JOSENotSupported('ECDH with the provided key is not allowed or not supported by your javascript runtime'); | ||
@@ -134,3 +283,3 @@ } | ||
| if (providedParameters.epk) { | ||
| ephemeralKey = (await normalizeKey(providedParameters.epk, alg)); | ||
| ephemeralKey = (await prepareKey(jweAlgorithm(alg), providedParameters.epk, 'decrypt')); | ||
| } | ||
@@ -140,4 +289,12 @@ else { | ||
| } | ||
| const { x, y, crv, kty } = await exportJWK(ephemeralKey); | ||
| const sharedSecret = await ecdhes.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, alg === 'ECDH-ES' ? cekLength(enc) : parseInt(alg.slice(-5, -2), 10), apu, apv); | ||
| const subtle = crypto.subtle; | ||
| let exportableEpk = ephemeralKey; | ||
| if (!exportableEpk.extractable) { | ||
| if (typeof subtle.getPublicKey !== 'function') { | ||
| throw new TypeError('CryptoKey for "epk" must be extractable'); | ||
| } | ||
| exportableEpk = await subtle.getPublicKey(ephemeralKey, []); | ||
| } | ||
| const { x, y, crv, kty } = (await subtle.exportKey('jwk', exportableEpk)); | ||
| const sharedSecret = await ecdhesDeriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc.alg : alg, alg === 'ECDH-ES' ? enc.cekBits : parseInt(alg.slice(-5, -2), 10), apu, apv); | ||
| parameters = { epk: { x, crv, kty } }; | ||
@@ -156,3 +313,3 @@ if (kty === 'EC') | ||
| const kwAlg = alg.slice(-6); | ||
| encryptedKey = await aeskw.wrap(kwAlg, sharedSecret, cek); | ||
| encryptedKey = await aeskwWrap(kwAlg, sharedSecret, cek); | ||
| break; | ||
@@ -166,3 +323,3 @@ } | ||
| assertCryptoKey(key); | ||
| encryptedKey = await rsaes.encrypt(alg, key, cek); | ||
| encryptedKey = await rsaesEncrypt(alg, key, cek); | ||
| break; | ||
@@ -175,3 +332,3 @@ } | ||
| const { p2c, p2s } = providedParameters; | ||
| ({ encryptedKey, ...parameters } = await pbes2kw.wrap(alg, key, cek, p2c, p2s)); | ||
| ({ encryptedKey, ...parameters } = await pbes2kwWrap(alg, key, cek, p2c, p2s)); | ||
| break; | ||
@@ -183,3 +340,3 @@ } | ||
| cek = providedCek || generateCek(enc); | ||
| encryptedKey = await aeskw.wrap(alg, key, cek); | ||
| encryptedKey = await aeskwWrap(alg, key, cek); | ||
| break; | ||
@@ -192,3 +349,3 @@ } | ||
| const { iv } = providedParameters; | ||
| ({ encryptedKey, ...parameters } = await aesGcmKwWrap(alg, key, cek, iv)); | ||
| ({ encryptedKey, ...parameters } = await aesGcmKwWrap(jweEncryption(jweAlgorithm(alg).gcmkw), key, cek, iv)); | ||
| break; | ||
@@ -195,0 +352,0 @@ } |
@@ -1,64 +0,32 @@ | ||
| import { JOSENotSupported } from '../util/errors.js'; | ||
| import { checkSigCryptoKey } from './crypto_key.js'; | ||
| import { invalidKeyInput } from './invalid_key_input.js'; | ||
| export function checkKeyLength(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`); | ||
| } | ||
| import { checkCryptoKey } from './crypto_key.js'; | ||
| export function checkModulusLength(alg, key) { | ||
| const { modulusLength } = key.algorithm; | ||
| if (typeof modulusLength !== 'number' || modulusLength < 2048) { | ||
| throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`); | ||
| } | ||
| } | ||
| function subtleAlgorithm(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': | ||
| case 'EdDSA': | ||
| return { name: 'Ed25519' }; | ||
| case 'ML-DSA-44': | ||
| case 'ML-DSA-65': | ||
| case 'ML-DSA-87': | ||
| return { name: alg }; | ||
| default: | ||
| throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); | ||
| function checkSigCryptoKey(entry, key, usage) { | ||
| checkCryptoKey(key, entry.subtle, usage); | ||
| if (entry.minModulusLength) { | ||
| checkModulusLength(entry.alg, key); | ||
| } | ||
| } | ||
| async function getSigKey(alg, key, usage) { | ||
| async function getSigKey(entry, key, usage) { | ||
| if (key instanceof Uint8Array) { | ||
| if (!alg.startsWith('HS')) { | ||
| throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'KeyObject', 'JSON Web Key')); | ||
| } | ||
| return crypto.subtle.importKey('raw', key, { hash: `SHA-${alg.slice(-3)}`, name: 'HMAC' }, false, [usage]); | ||
| return crypto.subtle.importKey('raw', key, entry.subtle, false, [ | ||
| usage, | ||
| ]); | ||
| } | ||
| checkSigCryptoKey(key, alg, usage); | ||
| checkSigCryptoKey(entry, key, usage); | ||
| return key; | ||
| } | ||
| export async function sign(alg, key, data) { | ||
| const cryptoKey = await getSigKey(alg, key, 'sign'); | ||
| checkKeyLength(alg, cryptoKey); | ||
| const signature = await crypto.subtle.sign(subtleAlgorithm(alg, cryptoKey.algorithm), cryptoKey, data); | ||
| export async function sign(entry, key, data) { | ||
| const cryptoKey = await getSigKey(entry, key, 'sign'); | ||
| const signature = await crypto.subtle.sign(entry.operation, cryptoKey, data); | ||
| return new Uint8Array(signature); | ||
| } | ||
| export async function verify(alg, key, signature, data) { | ||
| const cryptoKey = await getSigKey(alg, key, 'verify'); | ||
| checkKeyLength(alg, cryptoKey); | ||
| const algorithm = subtleAlgorithm(alg, cryptoKey.algorithm); | ||
| export async function verify(entry, key, signature, data) { | ||
| const cryptoKey = await getSigKey(entry, key, 'verify'); | ||
| try { | ||
| return await crypto.subtle.verify(algorithm, cryptoKey, signature, data); | ||
| return await crypto.subtle.verify(entry.operation, cryptoKey, signature, data); | ||
| } | ||
@@ -65,0 +33,0 @@ catch { |
@@ -5,5 +5,10 @@ import { encoder, decoder } from '../lib/buffer_utils.js'; | ||
| if (Uint8Array.fromBase64) { | ||
| return Uint8Array.fromBase64(typeof input === 'string' ? input : decoder.decode(input), { | ||
| alphabet: 'base64url', | ||
| }); | ||
| try { | ||
| return Uint8Array.fromBase64(typeof input === 'string' ? input : decoder.decode(input), { | ||
| alphabet: 'base64url', | ||
| }); | ||
| } | ||
| catch (cause) { | ||
| throw new TypeError('The input to be decoded is not correctly encoded.', { cause }); | ||
| } | ||
| } | ||
@@ -14,2 +19,5 @@ let encoded = input; | ||
| } | ||
| if (encoded.includes('+') || encoded.includes('/')) { | ||
| throw new TypeError('The input to be decoded is not correctly encoded.'); | ||
| } | ||
| encoded = encoded.replace(/-/g, '+').replace(/_/g, '/'); | ||
@@ -16,0 +24,0 @@ try { |
| import { decode as b64u } from './base64url.js'; | ||
| import { decoder } from '../lib/buffer_utils.js'; | ||
| import { strictDecoder } from '../lib/buffer_utils.js'; | ||
| import { isObject } from '../lib/type_checks.js'; | ||
@@ -24,3 +24,3 @@ import { JWTInvalid } from './errors.js'; | ||
| try { | ||
| result = JSON.parse(decoder.decode(decoded)); | ||
| result = JSON.parse(strictDecoder.decode(decoded)); | ||
| } | ||
@@ -27,0 +27,0 @@ catch { |
@@ -1,4 +0,2 @@ | ||
| import { decode as b64u } from './base64url.js'; | ||
| import { decoder } from '../lib/buffer_utils.js'; | ||
| import { isObject } from '../lib/type_checks.js'; | ||
| import { parseJoseHeader } from '../lib/helpers.js'; | ||
| export function decodeProtectedHeader(token) { | ||
@@ -21,15 +19,7 @@ let protectedB64u; | ||
| } | ||
| try { | ||
| if (typeof protectedB64u !== 'string' || !protectedB64u) { | ||
| throw new Error(); | ||
| } | ||
| const result = JSON.parse(decoder.decode(b64u(protectedB64u))); | ||
| if (!isObject(result)) { | ||
| throw new Error(); | ||
| } | ||
| return result; | ||
| const invalid = 'Invalid Token or Protected Header formatting'; | ||
| if (typeof protectedB64u !== 'string' || !protectedB64u) { | ||
| throw new TypeError(invalid); | ||
| } | ||
| catch { | ||
| throw new TypeError('Invalid Token or Protected Header formatting'); | ||
| } | ||
| return parseJoseHeader(protectedB64u, TypeError, invalid); | ||
| } |
@@ -79,3 +79,3 @@ export class JOSEError extends Error { | ||
| export class JWKSMultipleMatchingKeys extends JOSEError { | ||
| [Symbol.asyncIterator]; | ||
| [Symbol.asyncIterator] = async function* () { }; | ||
| static code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS'; | ||
@@ -82,0 +82,0 @@ code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS'; |
+2
-4
| { | ||
| "name": "jose", | ||
| "version": "6.2.4", | ||
| "version": "6.2.5", | ||
| "description": "JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes", | ||
@@ -196,6 +196,4 @@ "keywords": [ | ||
| "!dist/**/*.min.js", | ||
| "!dist/types/runtime/*", | ||
| "!dist/types/lib/*", | ||
| "!dist/deno/**/*" | ||
| "!dist/types/lib/**" | ||
| ] | ||
| } |
+12
-12
@@ -127,15 +127,15 @@ # jose | ||
| - JSON Web Signature (JWS) - [RFC7515](https://www.rfc-editor.org/rfc/rfc7515) | ||
| - JSON Web Encryption (JWE) - [RFC7516](https://www.rfc-editor.org/rfc/rfc7516) | ||
| - JSON Web Key (JWK) - [RFC7517](https://www.rfc-editor.org/rfc/rfc7517) | ||
| - JSON Web Algorithms (JWA) - [RFC7518](https://www.rfc-editor.org/rfc/rfc7518) | ||
| - JSON Web Token (JWT) - [RFC7519](https://www.rfc-editor.org/rfc/rfc7519) | ||
| - JSON Web Key Thumbprint - [RFC7638](https://www.rfc-editor.org/rfc/rfc7638) | ||
| - JSON Web Key Thumbprint URI - [RFC9278](https://www.rfc-editor.org/rfc/rfc9278) | ||
| - JWS Unencoded Payload Option - [RFC7797](https://www.rfc-editor.org/rfc/rfc7797) | ||
| - CFRG Elliptic Curve ECDH and Signatures - [RFC8037](https://www.rfc-editor.org/rfc/rfc8037) | ||
| - Fully-Specified Algorithms for JOSE - [RFC9864](https://www.rfc-editor.org/rfc/rfc9864.html) | ||
| - ML-DSA for JOSE - [RFC9964](https://www.rfc-editor.org/rfc/rfc9964.html) | ||
| - JSON Web Signature (JWS) - [RFC7515](https://www.rfc-editor.org/info/rfc7515/) | ||
| - JSON Web Encryption (JWE) - [RFC7516](https://www.rfc-editor.org/info/rfc7516/) | ||
| - JSON Web Key (JWK) - [RFC7517](https://www.rfc-editor.org/info/rfc7517/) | ||
| - JSON Web Algorithms (JWA) - [RFC7518](https://www.rfc-editor.org/info/rfc7518/) | ||
| - JSON Web Token (JWT) - [RFC7519](https://www.rfc-editor.org/info/rfc7519/) | ||
| - JSON Web Key Thumbprint - [RFC7638](https://www.rfc-editor.org/info/rfc7638/) | ||
| - JSON Web Key Thumbprint URI - [RFC9278](https://www.rfc-editor.org/info/rfc9278/) | ||
| - JWS Unencoded Payload Option - [RFC7797](https://www.rfc-editor.org/info/rfc7797/) | ||
| - CFRG Elliptic Curve ECDH and Signatures - [RFC8037](https://www.rfc-editor.org/info/rfc8037/) | ||
| - Fully-Specified Algorithms for JOSE - [RFC9864](https://www.rfc-editor.org/info/rfc9864/) | ||
| - ML-DSA for JOSE - [RFC9964](https://www.rfc-editor.org/info/rfc9964/) | ||
| The algorithm implementations in `jose` have been tested using test vectors from their respective specifications as well as [RFC7520](https://www.rfc-editor.org/rfc/rfc7520). | ||
| The algorithm implementations in `jose` have been tested using test vectors from their respective specifications as well as [RFC7520](https://www.rfc-editor.org/info/rfc7520/). | ||
@@ -142,0 +142,0 @@ </details> |
| import { encrypt, decrypt } from './content_encryption.js'; | ||
| import { encode as b64u } from '../util/base64url.js'; | ||
| export async function wrap(alg, key, cek, iv) { | ||
| const jweAlgorithm = alg.slice(0, 7); | ||
| const wrapped = await encrypt(jweAlgorithm, cek, key, iv, new Uint8Array()); | ||
| return { | ||
| encryptedKey: wrapped.ciphertext, | ||
| iv: b64u(wrapped.iv), | ||
| tag: b64u(wrapped.tag), | ||
| }; | ||
| } | ||
| export async function unwrap(alg, key, encryptedKey, iv, tag) { | ||
| const jweAlgorithm = alg.slice(0, 7); | ||
| return decrypt(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array()); | ||
| } |
| import { checkEncCryptoKey } from './crypto_key.js'; | ||
| function checkKeySize(key, alg) { | ||
| if (key.algorithm.length !== parseInt(alg.slice(1, 4), 10)) { | ||
| throw new TypeError(`Invalid key size for alg: ${alg}`); | ||
| } | ||
| } | ||
| function getCryptoKey(key, alg, usage) { | ||
| if (key instanceof Uint8Array) { | ||
| return crypto.subtle.importKey('raw', key, 'AES-KW', true, [usage]); | ||
| } | ||
| checkEncCryptoKey(key, alg, usage); | ||
| return key; | ||
| } | ||
| export async function wrap(alg, key, cek) { | ||
| const cryptoKey = await getCryptoKey(key, alg, 'wrapKey'); | ||
| checkKeySize(cryptoKey, alg); | ||
| const cryptoKeyCek = await crypto.subtle.importKey('raw', cek, { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']); | ||
| return new Uint8Array(await crypto.subtle.wrapKey('raw', cryptoKeyCek, cryptoKey, 'AES-KW')); | ||
| } | ||
| export async function unwrap(alg, key, encryptedKey) { | ||
| const cryptoKey = await getCryptoKey(key, alg, 'unwrapKey'); | ||
| checkKeySize(cryptoKey, alg); | ||
| const cryptoKeyCek = await crypto.subtle.unwrapKey('raw', encryptedKey, cryptoKey, 'AES-KW', { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']); | ||
| return new Uint8Array(await crypto.subtle.exportKey('raw', cryptoKeyCek)); | ||
| } |
| import { withAlg as invalidKeyInput } from './invalid_key_input.js'; | ||
| import { isKeyLike } from './is_key_like.js'; | ||
| import * as jwk from './type_checks.js'; | ||
| const tag = (key) => key?.[Symbol.toStringTag]; | ||
| const jwkMatchesOp = (alg, key, usage) => { | ||
| if (key.use !== undefined) { | ||
| let expected; | ||
| switch (usage) { | ||
| case 'sign': | ||
| case 'verify': | ||
| expected = 'sig'; | ||
| break; | ||
| case 'encrypt': | ||
| case 'decrypt': | ||
| expected = 'enc'; | ||
| break; | ||
| } | ||
| if (key.use !== expected) { | ||
| throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`); | ||
| } | ||
| } | ||
| if (key.alg !== undefined && key.alg !== alg) { | ||
| throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`); | ||
| } | ||
| if (Array.isArray(key.key_ops)) { | ||
| let expectedKeyOp; | ||
| switch (true) { | ||
| case usage === 'sign' || usage === 'verify': | ||
| case alg === 'dir': | ||
| case alg.includes('CBC-HS'): | ||
| expectedKeyOp = usage; | ||
| break; | ||
| case alg.startsWith('PBES2'): | ||
| expectedKeyOp = 'deriveBits'; | ||
| break; | ||
| case /^A\d{3}(?:GCM)?(?:KW)?$/.test(alg): | ||
| if (!alg.includes('GCM') && alg.endsWith('KW')) { | ||
| expectedKeyOp = usage === 'encrypt' ? 'wrapKey' : 'unwrapKey'; | ||
| } | ||
| else { | ||
| expectedKeyOp = usage; | ||
| } | ||
| break; | ||
| case usage === 'encrypt' && alg.startsWith('RSA'): | ||
| expectedKeyOp = 'wrapKey'; | ||
| break; | ||
| case usage === 'decrypt': | ||
| expectedKeyOp = alg.startsWith('RSA') ? 'unwrapKey' : 'deriveBits'; | ||
| break; | ||
| } | ||
| if (expectedKeyOp && key.key_ops?.includes?.(expectedKeyOp) === false) { | ||
| throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`); | ||
| } | ||
| } | ||
| return true; | ||
| }; | ||
| const symmetricTypeCheck = (alg, key, usage) => { | ||
| if (key instanceof Uint8Array) | ||
| return; | ||
| if (jwk.isJWK(key)) { | ||
| if (jwk.isSecretJWK(key) && jwkMatchesOp(alg, key, usage)) | ||
| return; | ||
| throw new TypeError(`JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`); | ||
| } | ||
| if (!isKeyLike(key)) { | ||
| throw new TypeError(invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key', 'Uint8Array')); | ||
| } | ||
| if (key.type !== 'secret') { | ||
| throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`); | ||
| } | ||
| }; | ||
| const asymmetricTypeCheck = (alg, key, usage) => { | ||
| if (jwk.isJWK(key)) { | ||
| switch (usage) { | ||
| case 'decrypt': | ||
| case 'sign': | ||
| if (jwk.isPrivateJWK(key) && jwkMatchesOp(alg, key, usage)) | ||
| return; | ||
| throw new TypeError(`JSON Web Key for this operation must be a private JWK`); | ||
| case 'encrypt': | ||
| case 'verify': | ||
| if (jwk.isPublicJWK(key) && jwkMatchesOp(alg, key, usage)) | ||
| return; | ||
| throw new TypeError(`JSON Web Key for this operation must be a public JWK`); | ||
| } | ||
| } | ||
| if (!isKeyLike(key)) { | ||
| throw new TypeError(invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key')); | ||
| } | ||
| if (key.type === 'secret') { | ||
| throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`); | ||
| } | ||
| if (key.type === 'public') { | ||
| switch (usage) { | ||
| case 'sign': | ||
| throw new TypeError(`${tag(key)} instances for asymmetric algorithm signing must be of type "private"`); | ||
| case 'decrypt': | ||
| throw new TypeError(`${tag(key)} instances for asymmetric algorithm decryption must be of type "private"`); | ||
| } | ||
| } | ||
| if (key.type === 'private') { | ||
| switch (usage) { | ||
| case 'verify': | ||
| throw new TypeError(`${tag(key)} instances for asymmetric algorithm verifying must be of type "public"`); | ||
| case 'encrypt': | ||
| throw new TypeError(`${tag(key)} instances for asymmetric algorithm encryption must be of type "public"`); | ||
| } | ||
| } | ||
| }; | ||
| export function checkKeyType(alg, key, usage) { | ||
| switch (alg.substring(0, 2)) { | ||
| case 'A1': | ||
| case 'A2': | ||
| case 'di': | ||
| case 'HS': | ||
| case 'PB': | ||
| symmetricTypeCheck(alg, key, usage); | ||
| break; | ||
| default: | ||
| asymmetricTypeCheck(alg, key, usage); | ||
| } | ||
| } |
| import { encode, concat, uint32be } from './buffer_utils.js'; | ||
| import { checkEncCryptoKey } from './crypto_key.js'; | ||
| import { digest } from './helpers.js'; | ||
| function lengthAndInput(input) { | ||
| return concat(uint32be(input.length), input); | ||
| } | ||
| async function concatKdf(Z, L, OtherInfo) { | ||
| const dkLen = L >> 3; | ||
| const hashLen = 32; | ||
| const reps = Math.ceil(dkLen / hashLen); | ||
| const dk = new Uint8Array(reps * hashLen); | ||
| for (let i = 1; i <= reps; i++) { | ||
| const hashInput = new Uint8Array(4 + Z.length + OtherInfo.length); | ||
| hashInput.set(uint32be(i), 0); | ||
| hashInput.set(Z, 4); | ||
| hashInput.set(OtherInfo, 4 + Z.length); | ||
| const hashResult = await digest('sha256', hashInput); | ||
| dk.set(hashResult, (i - 1) * hashLen); | ||
| } | ||
| return dk.slice(0, dkLen); | ||
| } | ||
| export async function deriveKey(publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(), apv = new Uint8Array()) { | ||
| checkEncCryptoKey(publicKey, 'ECDH'); | ||
| checkEncCryptoKey(privateKey, 'ECDH', 'deriveBits'); | ||
| const algorithmID = lengthAndInput(encode(algorithm)); | ||
| const partyUInfo = lengthAndInput(apu); | ||
| const partyVInfo = lengthAndInput(apv); | ||
| const suppPubInfo = uint32be(keyLength); | ||
| const suppPrivInfo = new Uint8Array(); | ||
| const otherInfo = concat(algorithmID, partyUInfo, partyVInfo, suppPubInfo, suppPrivInfo); | ||
| const Z = new Uint8Array(await crypto.subtle.deriveBits({ | ||
| name: publicKey.algorithm.name, | ||
| public: publicKey, | ||
| }, privateKey, getEcdhBitLength(publicKey))); | ||
| return concatKdf(Z, keyLength, otherInfo); | ||
| } | ||
| function getEcdhBitLength(publicKey) { | ||
| if (publicKey.algorithm.name === 'X25519') { | ||
| return 256; | ||
| } | ||
| return (Math.ceil(parseInt(publicKey.algorithm.namedCurve.slice(-3), 10) / 8) << 3); | ||
| } | ||
| export function allowed(key) { | ||
| switch (key.algorithm.namedCurve) { | ||
| case 'P-256': | ||
| case 'P-384': | ||
| case 'P-521': | ||
| return true; | ||
| default: | ||
| return key.algorithm.name === 'X25519'; | ||
| } | ||
| } |
| import { invalidKeyInput } from './invalid_key_input.js'; | ||
| import { encode as b64u } from '../util/base64url.js'; | ||
| import { isCryptoKey, isKeyObject } from './is_key_like.js'; | ||
| function omitUndefinedProperties(jwk) { | ||
| return Object.fromEntries(Object.entries(jwk).filter(([, value]) => value !== undefined)); | ||
| } | ||
| export async function keyToJWK(key) { | ||
| if (isKeyObject(key)) { | ||
| if (key.type === 'secret') { | ||
| key = key.export(); | ||
| } | ||
| else { | ||
| return key.export({ format: 'jwk' }); | ||
| } | ||
| } | ||
| if (key instanceof Uint8Array) { | ||
| return { | ||
| kty: 'oct', | ||
| k: b64u(key), | ||
| }; | ||
| } | ||
| if (!isCryptoKey(key)) { | ||
| throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'KeyObject', 'Uint8Array')); | ||
| } | ||
| if (!key.extractable) { | ||
| throw new TypeError('non-extractable CryptoKey cannot be exported as a JWK'); | ||
| } | ||
| const { ext, key_ops, alg, use, ...jwk } = omitUndefinedProperties(await crypto.subtle.exportKey('jwk', key)); | ||
| if (jwk.kty === 'AKP') { | ||
| ; | ||
| jwk.alg = alg; | ||
| } | ||
| return jwk; | ||
| } |
| import { isJWK } from './type_checks.js'; | ||
| import { decode } from '../util/base64url.js'; | ||
| import { jwkToKey } from './jwk_to_key.js'; | ||
| import { isCryptoKey, isKeyObject } from './is_key_like.js'; | ||
| const unusableForAlg = 'given KeyObject instance cannot be used for this algorithm'; | ||
| let cache; | ||
| const handleJWK = async (key, jwk, alg, freeze = false) => { | ||
| cache ||= new WeakMap(); | ||
| let cached = cache.get(key); | ||
| if (cached?.[alg]) { | ||
| return cached[alg]; | ||
| } | ||
| const cryptoKey = await jwkToKey({ ...jwk, alg }); | ||
| if (freeze) | ||
| Object.freeze(key); | ||
| if (!cached) { | ||
| cache.set(key, { [alg]: cryptoKey }); | ||
| } | ||
| else { | ||
| cached[alg] = cryptoKey; | ||
| } | ||
| return cryptoKey; | ||
| }; | ||
| const handleKeyObject = (keyObject, alg) => { | ||
| cache ||= new WeakMap(); | ||
| let cached = cache.get(keyObject); | ||
| if (cached?.[alg]) { | ||
| return cached[alg]; | ||
| } | ||
| const isPublic = keyObject.type === 'public'; | ||
| const extractable = isPublic ? true : false; | ||
| let cryptoKey; | ||
| if (keyObject.asymmetricKeyType === 'x25519') { | ||
| switch (alg) { | ||
| case 'ECDH-ES': | ||
| case 'ECDH-ES+A128KW': | ||
| case 'ECDH-ES+A192KW': | ||
| case 'ECDH-ES+A256KW': | ||
| break; | ||
| default: | ||
| throw new TypeError(unusableForAlg); | ||
| } | ||
| cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, isPublic ? [] : ['deriveBits']); | ||
| } | ||
| if (keyObject.asymmetricKeyType === 'ed25519') { | ||
| if (alg !== 'EdDSA' && alg !== 'Ed25519') { | ||
| throw new TypeError(unusableForAlg); | ||
| } | ||
| cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [ | ||
| isPublic ? 'verify' : 'sign', | ||
| ]); | ||
| } | ||
| switch (keyObject.asymmetricKeyType) { | ||
| case 'ml-dsa-44': | ||
| case 'ml-dsa-65': | ||
| case 'ml-dsa-87': { | ||
| if (alg !== keyObject.asymmetricKeyType.toUpperCase()) { | ||
| throw new TypeError(unusableForAlg); | ||
| } | ||
| cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [ | ||
| isPublic ? 'verify' : 'sign', | ||
| ]); | ||
| } | ||
| } | ||
| if (keyObject.asymmetricKeyType === 'rsa') { | ||
| let hash; | ||
| switch (alg) { | ||
| case 'RSA-OAEP': | ||
| hash = 'SHA-1'; | ||
| break; | ||
| case 'RS256': | ||
| case 'PS256': | ||
| case 'RSA-OAEP-256': | ||
| hash = 'SHA-256'; | ||
| break; | ||
| case 'RS384': | ||
| case 'PS384': | ||
| case 'RSA-OAEP-384': | ||
| hash = 'SHA-384'; | ||
| break; | ||
| case 'RS512': | ||
| case 'PS512': | ||
| case 'RSA-OAEP-512': | ||
| hash = 'SHA-512'; | ||
| break; | ||
| default: | ||
| throw new TypeError(unusableForAlg); | ||
| } | ||
| if (alg.startsWith('RSA-OAEP')) { | ||
| return keyObject.toCryptoKey({ | ||
| name: 'RSA-OAEP', | ||
| hash, | ||
| }, extractable, isPublic ? ['encrypt'] : ['decrypt']); | ||
| } | ||
| cryptoKey = keyObject.toCryptoKey({ | ||
| name: alg.startsWith('PS') ? 'RSA-PSS' : 'RSASSA-PKCS1-v1_5', | ||
| hash, | ||
| }, extractable, [isPublic ? 'verify' : 'sign']); | ||
| } | ||
| if (keyObject.asymmetricKeyType === 'ec') { | ||
| const nist = new Map([ | ||
| ['prime256v1', 'P-256'], | ||
| ['secp384r1', 'P-384'], | ||
| ['secp521r1', 'P-521'], | ||
| ]); | ||
| const namedCurve = nist.get(keyObject.asymmetricKeyDetails?.namedCurve); | ||
| if (!namedCurve) { | ||
| throw new TypeError(unusableForAlg); | ||
| } | ||
| const expectedCurve = { ES256: 'P-256', ES384: 'P-384', ES512: 'P-521' }; | ||
| if (expectedCurve[alg] && namedCurve === expectedCurve[alg]) { | ||
| cryptoKey = keyObject.toCryptoKey({ | ||
| name: 'ECDSA', | ||
| namedCurve, | ||
| }, extractable, [isPublic ? 'verify' : 'sign']); | ||
| } | ||
| if (alg.startsWith('ECDH-ES')) { | ||
| cryptoKey = keyObject.toCryptoKey({ | ||
| name: 'ECDH', | ||
| namedCurve, | ||
| }, extractable, isPublic ? [] : ['deriveBits']); | ||
| } | ||
| } | ||
| if (!cryptoKey) { | ||
| throw new TypeError(unusableForAlg); | ||
| } | ||
| if (!cached) { | ||
| cache.set(keyObject, { [alg]: cryptoKey }); | ||
| } | ||
| else { | ||
| cached[alg] = cryptoKey; | ||
| } | ||
| return cryptoKey; | ||
| }; | ||
| export async function normalizeKey(key, alg) { | ||
| if (key instanceof Uint8Array) { | ||
| return key; | ||
| } | ||
| if (isCryptoKey(key)) { | ||
| return key; | ||
| } | ||
| if (isKeyObject(key)) { | ||
| if (key.type === 'secret') { | ||
| return key.export(); | ||
| } | ||
| if ('toCryptoKey' in key && typeof key.toCryptoKey === 'function') { | ||
| try { | ||
| return handleKeyObject(key, alg); | ||
| } | ||
| catch (err) { | ||
| if (err instanceof TypeError) { | ||
| throw err; | ||
| } | ||
| } | ||
| } | ||
| let jwk = key.export({ format: 'jwk' }); | ||
| return handleJWK(key, jwk, alg); | ||
| } | ||
| if (isJWK(key)) { | ||
| if (key.k) { | ||
| return decode(key.k); | ||
| } | ||
| return handleJWK(key, key, alg, true); | ||
| } | ||
| throw new Error('unreachable'); | ||
| } |
| import { encode as b64u } from '../util/base64url.js'; | ||
| import * as aeskw from './aeskw.js'; | ||
| import { checkEncCryptoKey } from './crypto_key.js'; | ||
| import { concat, encode } from './buffer_utils.js'; | ||
| import { JWEInvalid } from '../util/errors.js'; | ||
| function getCryptoKey(key, alg) { | ||
| if (key instanceof Uint8Array) { | ||
| return crypto.subtle.importKey('raw', key, 'PBKDF2', false, [ | ||
| 'deriveBits', | ||
| ]); | ||
| } | ||
| checkEncCryptoKey(key, alg, 'deriveBits'); | ||
| return key; | ||
| } | ||
| const concatSalt = (alg, p2sInput) => concat(encode(alg), Uint8Array.of(0x00), p2sInput); | ||
| async function deriveKey(p2s, alg, p2c, key) { | ||
| if (!(p2s instanceof Uint8Array) || p2s.length < 8) { | ||
| throw new JWEInvalid('PBES2 Salt Input must be 8 or more octets'); | ||
| } | ||
| if (!Number.isSafeInteger(p2c) || Math.sign(p2c) !== 1) { | ||
| throw new JWEInvalid('PBES2 Count Input must be a positive integer'); | ||
| } | ||
| const salt = concatSalt(alg, p2s); | ||
| const keylen = parseInt(alg.slice(13, 16), 10); | ||
| const subtleAlg = { | ||
| hash: `SHA-${alg.slice(8, 11)}`, | ||
| iterations: p2c, | ||
| name: 'PBKDF2', | ||
| salt, | ||
| }; | ||
| const cryptoKey = await getCryptoKey(key, alg); | ||
| return new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen)); | ||
| } | ||
| export async function wrap(alg, key, cek, p2c = 2048, p2s = crypto.getRandomValues(new Uint8Array(16))) { | ||
| const derived = await deriveKey(p2s, alg, p2c, key); | ||
| const encryptedKey = await aeskw.wrap(alg.slice(-6), derived, cek); | ||
| return { encryptedKey, p2c, p2s: b64u(p2s) }; | ||
| } | ||
| export async function unwrap(alg, key, encryptedKey, p2c, p2s) { | ||
| const derived = await deriveKey(p2s, alg, p2c, key); | ||
| return aeskw.unwrap(alg.slice(-6), derived, encryptedKey); | ||
| } |
| import { checkEncCryptoKey } from './crypto_key.js'; | ||
| import { checkKeyLength } from './signing.js'; | ||
| import { JOSENotSupported } from '../util/errors.js'; | ||
| const subtleAlgorithm = (alg) => { | ||
| switch (alg) { | ||
| case 'RSA-OAEP': | ||
| case 'RSA-OAEP-256': | ||
| case 'RSA-OAEP-384': | ||
| case 'RSA-OAEP-512': | ||
| return 'RSA-OAEP'; | ||
| default: | ||
| throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); | ||
| } | ||
| }; | ||
| export async function encrypt(alg, key, cek) { | ||
| checkEncCryptoKey(key, alg, 'encrypt'); | ||
| checkKeyLength(alg, key); | ||
| return new Uint8Array(await crypto.subtle.encrypt(subtleAlgorithm(alg), key, cek)); | ||
| } | ||
| export async function decrypt(alg, key, encryptedKey) { | ||
| checkEncCryptoKey(key, alg, 'decrypt'); | ||
| checkKeyLength(alg, key); | ||
| return new Uint8Array(await crypto.subtle.decrypt(subtleAlgorithm(alg), key, encryptedKey)); | ||
| } |
| export function validateAlgorithms(option, algorithms) { | ||
| if (algorithms !== undefined && | ||
| (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== 'string'))) { | ||
| throw new TypeError(`"${option}" option must be an array of strings`); | ||
| } | ||
| if (!algorithms) { | ||
| return undefined; | ||
| } | ||
| return new Set(algorithms); | ||
| } |
| import { JOSENotSupported, JWEInvalid, JWSInvalid } from '../util/errors.js'; | ||
| export function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) { | ||
| if (joseHeader.crit !== undefined && protectedHeader?.crit === undefined) { | ||
| throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected'); | ||
| } | ||
| if (!protectedHeader || protectedHeader.crit === undefined) { | ||
| return new Set(); | ||
| } | ||
| if (!Array.isArray(protectedHeader.crit) || | ||
| protectedHeader.crit.length === 0 || | ||
| protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) { | ||
| throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present'); | ||
| } | ||
| let recognized; | ||
| if (recognizedOption !== undefined) { | ||
| recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]); | ||
| } | ||
| else { | ||
| recognized = recognizedDefault; | ||
| } | ||
| for (const parameter of protectedHeader.crit) { | ||
| if (!recognized.has(parameter)) { | ||
| throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`); | ||
| } | ||
| if (joseHeader[parameter] === undefined) { | ||
| throw new Err(`Extension Header Parameter "${parameter}" is missing`); | ||
| } | ||
| if (recognized.get(parameter) && protectedHeader[parameter] === undefined) { | ||
| throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`); | ||
| } | ||
| } | ||
| return new Set(protectedHeader.crit); | ||
| } |
257025
-0.14%5931
-5.98%