Files
jose/test/jws/restrictions.test.ts
Filip Skokan eebee55a01 refactor: restructure src/lib and src/runtime now that runtime is fixed
BREAKING CHANGE: createRemoteJWKSet now uses fetch, because of that its Node.js only options.agent property has been removed and new fetch-related options were added
2025-02-22 15:16:04 +01:00

124 lines
6.3 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import test from 'ava'
import * as crypto from 'crypto'
import {
base64url,
exportPKCS8,
flattenedDecrypt,
FlattenedEncrypt,
FlattenedSign,
flattenedVerify,
generateKeyPair,
importJWK,
} from '../../src/index.js'
function pubjwk(jwk) {
const { d, p, q, dp, dq, qi, ...publicJwk } = jwk
return publicJwk
}
test.before((t) => {
const encode = TextEncoder.prototype.encode.bind(new TextEncoder())
t.context.payload = encode('It’s a dangerous business, Frodo, going out your door.')
t.context.rsa2040 = {
e: 'AQAB',
n: '4waoB9XUAsGc-bhkfY-v3hKEqmLYF4nS-8nji5R5KoOOeWC2hCkvbMfd2IlKRdMU7EmGXNx2BD2FVIqN9mWyZKJlzR2125lgJ-VxCymGv1A9057LEAFIrXsCUqwjPO07hCzZNv8IAAQzq53pnlAgb3TbfrxW24tamhCtaKHb5upAwo4jhYnfzex2--vD7mPxMoTuikno-eD_hxYmA52Uh1gu3wEWy44KA6aFJBpP7m4G5StuHSCXxiOWDaqMeFsMX1jqrom7SwbGJ7j0sf3ZqWrZR4x1pB3wk5Sixi_lmDfOkXhiizYnvJJ5rzr_f0bVdXeAe2U8vpEJSQeA36T7',
d: 'T7ZPm2it50XZ-yiOSDQCWSQBZt4L57_hz7ykY6b_IDlO9jlJ_H-FgllvAI-7_2ZNC2YJgmN6IKUFQpjfnas5hvIqcmnDJ9bjlz6NgZDUGipvevVfcUAyJ49wUlzUhpj5c8BXiGLliTPwfIqWs5qIuPm78_TnPnDgoAXJDVr_njr_C6CJFVfWni_6MTeT8iSApGrIJ-tovLlUWSQAyKfWT0QK8dclmREla6-B4YPFwMuBViiSI8dGFpw1O-sEn7D1aMWRepWKr-dgvukuksdL39LxBeGz-iHpI_DMdSB63t5kyjT7GPlbBkD__4ie_Vl4bG30dUZvH_Vt6nXxyXEh',
p: 'D0TqaIEyAQHzW1SnC_b1AM9sehg6baMhw4mwSQHqVQreS6a2FKor2xVUdWzT3EurRJ-NThGyi81b30MsKjV_eZ1pIA2r5ulab5CgsV4pkk9LZPZYtz4Rylv9RY3ArtBxziF_BPhTbyy5LXUr5TZUpTQn-LGPOc2sjDaB80uD9XE',
q: 'Dt5ET14bw-tNwsgBK-IuhuPzxeCYSi6AkiDqdJuykcN8z8Of-OyPbQSVgTNbvQSZ1anaV0-pvrkER5ilIjcaGtaBmQmCUZe0vKBynakRWXR16SE2mqJAjAmO6VD25cxdnNghdg8ue5XsdyjuQ0dnTXibsIcVyjfaIZgjbhi6mys',
dp: 'BD0cWXBsAi2ZceQZD1A6CUSLl4U8Sw07JT4Gyu2WMI940EVyTGBFFmdgb8yLL59t5vnnzyFIkFisxVivXPRG8-rHsRc6fjqPWWMryLEcFzqd8mQUkqHPbH6G25UTRTQmM5PG4AlTmAwxR7Y8PkAL1WSaKAaafPBkkvPatUBkXHE',
dq: 'Bv-nBfkVdr6PRu2gZ4i7P_GTMQTMirai_KYT1rnnb2emm6HI7oJj7PwoZ73GJA5DX2jphwnPrCApHI6ExLtNRW7NaD0qo7-WaufXq9EGgqYoTom8y0MuwPxK0hazcW4mborqDUmOJsxml5yjsvWscbIhDxI3No3d1sxneQ6Y4Cs',
qi: 'AkpKJwYKvaB73G7IQK5yxXCOvypwSEUK1bOcbhOZSQPPNtKvov11dVsGs-pqHo0Su06IXQv0Ayyy3uxXvsY8CyZ3CbPWMXM06Z3Gr0kZWWfNu8NiFwXvkbe24P-KeXIQGFTfdqSMTfm2an1YNE9e9F36rZ0EkhdKzmwzudA7jtw',
kty: 'RSA',
}
t.context.rsa2048 = {
e: 'AQAB',
n: '3egkthDOqRIif9azx83Q-HKcVNUeDALom8e5L1rjljB82EKYt5zgfKlgLW4NuJQgLDx5jA7Ez_nz-8lIcVTez-C75_M-Thv2wLhk4ZAYAZZPEmZr76zH8-lClnhxcqFnkOABqLmopr2gF1gBG_IkqEnH_h_yH486YkCd0G2ZNJAzjCOCQMR5pzBnIxC4YUAX7r_-9ilQ8Lv3MSJ0MLv6cujJTneyjWnoh_SfOXRsY6f3gkfR9APj9Q5A8PA8gvbYyN8EHr4OYb1KwNjs_0_X0Aq0e1NJx3H5eiZe6UaFleIbEVZYoNtlNJO3kmGESaxepkWTRAqBZVTfj4KnKX_9Ow',
d: 'Q17sbl4x8ACyeq97i4jADf312oeNhMYJSupbHbZxbDKyZJHrfatiOFbP_VrxTX2jOurtWAlP1Xiki2fz13yV3PT095nQ67PvuVkCP70YnLq-rO5tjKmfVz0VW0ub3dqE7-YietBLFLxzc0Ljq1FbscAcuNmID-7TIetOPm5X2i3wxOuiEV2xz1nHVuys3yoO3z4rAitGFl943k71P4FKxK9mp9oTQTnDfKauP0eSOD10L2NiYLkUTg9YC8A0EQopdZatDVAz3hWitNpJg28fWe7rp7yR2YBb4nFcNuygZmzEzp7x0r87NnTt9t4Hjd1rNFbd3hdT6Dy9_pejkmdU2Q',
p: '8_HZDF8wp0ujYxiyvAXOL6Xsnv08bQ80uzDOGCnHWWKeFn8n43gc49AdBiJ2ljmfQxExiK0wmetR76zdxTJBIWQdGI2ZJkb6lAIOEBhrXzrWXUSMPgc3qYbQRkmexrAAdwG1nWUymMDd36K5d_YEmL172a-gyEAXMGGW81AaeVU',
q: '6N9-STJXjcrwedkJpmmjKLBpU_Nw0UfpKAkh3Xf6jpaF-A2Cvr07JqDVzExMfpYDCcki7IW8SLK5wXVfWCZqXXl4bsb5LAJLnRIglgnDxItlmRf5CWHw7lmBD6BguEIhXU3xPiNrK3XiBVS4k2yDaYHHoAPYXDfTCGpbts7SXE8',
dp: 'k_OmtH43P__8BGpCXQ8YUoXL0VG9iFekn7OmC7mrEmdhgjt0sd1ziCf8sm_MhKhGE6Ml68M-qtuyQi8SAjvMjLfvfajDrhd2erYUWWa2GHfS85ZTiHtQIx2EzFxyVAcDASqkP-XUnhi7eJt06XDosMqbhxeh6FIWvl0x9DgtFlE',
dq: 'UqK8VY0ftJlHLHXwDrV9yHqRZdEFP76c5jAXbFee-epAL_3bX4QW8WYxeAW7P1BMU7SkR_pNDh8d-6CC7Oz04aaxLd49nXhTDLHaDmP4rE4rB2CSZtnyfSIVwk3PBJOy80EtUjePWCTEx8-AkA_5sf7zr7ytkkvc_yd-1CggTdE',
qi: 'd72eV7EbpvaSA3ZiQdGXpMMr41o0ih1WnV80Bxraugj1vMqxLlhVdDhDCVoF3LEoXVz8n2NEl1F6k2o3Gt9C5pXUDJwRGS41FwYVp8RN-aWviJM43mM0oQndJomZyDzjOKzpTzlNlAkFQQbfoagc4sbg-0JxK9rWdnMDW5AR1BU',
kty: 'RSA',
}
})
async function testRSAsig(t, alg) {
const message = `${alg} requires key modulusLength to be 2048 bits or larger`
const keyBad = t.context.rsa2040
const keyOk = t.context.rsa2048
await t.throwsAsync(
new FlattenedSign(t.context.payload)
.setProtectedHeader({ alg })
.sign(await importJWK(keyBad, alg)),
{ instanceOf: TypeError, message },
)
const jws = await new FlattenedSign(t.context.payload)
.setProtectedHeader({ alg })
.sign(await importJWK(keyOk, alg))
await t.throwsAsync(flattenedVerify(jws, await importJWK(pubjwk(keyBad), alg)), {
instanceOf: TypeError,
message,
})
}
testRSAsig.title = (title, alg) => `${alg} requires key modulusLength to be 2048 bits or larger`
async function testRSAenc(t, alg) {
const message = `${alg} requires key modulusLength to be 2048 bits or larger`
const keyBad = t.context.rsa2040
const keyOk = t.context.rsa2048
await t.throwsAsync(
new FlattenedEncrypt(t.context.payload)
.setProtectedHeader({ alg, enc: 'A256GCM' })
.encrypt(await importJWK(pubjwk(keyBad), alg)),
{ instanceOf: TypeError, message },
)
const jwe = await new FlattenedEncrypt(t.context.payload)
.setProtectedHeader({ alg, enc: 'A256GCM' })
.encrypt(await importJWK(pubjwk(keyOk), alg))
await t.throwsAsync(flattenedDecrypt(jwe, await importJWK(keyBad, alg)), {
instanceOf: TypeError,
message,
})
}
testRSAenc.title = (title, alg) => `${alg} requires key modulusLength to be 2048 bits or larger`
async function testECDSASigEncoding(t, alg) {
const { privateKey, publicKey } = await generateKeyPair(alg, { extractable: true })
const jws = await new FlattenedSign(t.context.payload)
.setProtectedHeader({ alg })
.sign(privateKey)
const derEncodedSignature = base64url.encode(
crypto.sign(`sha${alg.slice(2, 5)}`, Buffer.from('foo'), await exportPKCS8(privateKey)),
)
await t.throwsAsync(flattenedVerify({ ...jws, signature: derEncodedSignature }, publicKey), {
message: 'signature verification failed',
code: 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED',
})
}
testECDSASigEncoding.title = (title, alg) => `${alg} swallows invalid signature encoding errors`
test(testRSAsig, 'RS256')
test(testRSAsig, 'PS256')
test(testRSAsig, 'RS384')
test(testRSAsig, 'PS384')
test(testRSAsig, 'RS512')
test(testRSAsig, 'PS512')
test(testRSAenc, 'RSA-OAEP')
test(testRSAenc, 'RSA-OAEP-256')
test(testRSAenc, 'RSA-OAEP-384')
test(testRSAenc, 'RSA-OAEP-512')
test(testECDSASigEncoding, 'ES256')
test(testECDSASigEncoding, 'ES384')
test(testECDSASigEncoding, 'ES512')