Files
jose/test/jwk/embedded.test.ts
Filip Skokan de5a61a7fd refactor: keep JWE out of the JWKS and embedded-JWK paths
Resolve JWKS and embedded-JWK imports against the JWS registry and import
with jwkToKey. Use registry metadata for candidate filtering and apply
RSA oth rejection in the shared import path.

Signed-off-by: Filip Skokan <[email protected]>
2026-07-29 18:52:03 +02:00

93 lines
3.0 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 {
importJWK,
EmbeddedJWK,
FlattenedSign,
flattenedVerify,
exportJWK,
generateKeyPair,
} from '../../src/index.js'
const mlDsaTest = SubtleCrypto.supports?.('generateKey', 'ML-DSA-65') === true ? test : test.skip
function pubjwk(jwk) {
const { d, p, q, dp, dq, qi, ext, alg, ...publicJwk } = jwk
return publicJwk
}
test.before(async (t) => {
const encode = TextEncoder.prototype.encode.bind(new TextEncoder())
t.context.key = {
crv: 'P-256',
alg: 'ES256',
ext: false,
x: 'Sp3KpzPjwcCF04_W2GvSSf-vGDvp3Iv2kQYqAjnMB-Y',
y: 'lZmecT2quXe0i9f7b4qHvDAFDpxs0oxCoJx4tOOqsks',
d: 'hRVo5TGE_d_4tQC1KEQIlCdo9rteZmLSmaMPpFOjeDI',
kty: 'EC',
}
const privateKey = await importJWK(t.context.key)
t.context.token = await new FlattenedSign(
encode('It’s a dangerous business, Frodo, going out your door.'),
)
.setProtectedHeader({ alg: 'ES256', jwk: pubjwk(t.context.key) })
.sign(privateKey)
t.context.tokenMissingJwk = await new FlattenedSign(
encode('It’s a dangerous business, Frodo, going out your door.'),
)
.setProtectedHeader({ alg: 'ES256' })
.sign(privateKey)
t.context.tokenInvalidJWK = await new FlattenedSign(
encode('It’s a dangerous business, Frodo, going out your door.'),
)
.setProtectedHeader({ alg: 'ES256', jwk: null })
.sign(privateKey)
t.context.tokenPrivateJWK = await new FlattenedSign(
encode('It’s a dangerous business, Frodo, going out your door.'),
)
.setProtectedHeader({ alg: 'ES256', jwk: t.context.key })
.sign(privateKey)
})
test('EmbeddedJWK', async (t) => {
await t.notThrowsAsync(async () => {
const { key: resolvedKey } = await flattenedVerify(t.context.token, EmbeddedJWK)
t.truthy(resolvedKey)
t.is(resolvedKey.type, 'public')
})
})
test('EmbeddedJWK requires "jwk" to be an object', async (t) => {
await t.throwsAsync(flattenedVerify(t.context.tokenMissingJwk, EmbeddedJWK), {
code: 'ERR_JWS_INVALID',
message: '"jwk" (JSON Web Key) Header Parameter must be a JSON object',
})
await t.throwsAsync(flattenedVerify(t.context.tokenInvalidJWK, EmbeddedJWK), {
code: 'ERR_JWS_INVALID',
message: '"jwk" (JSON Web Key) Header Parameter must be a JSON object',
})
})
test('EmbeddedJWK requires "jwk" to be a public one', async (t) => {
await t.throwsAsync(flattenedVerify(t.context.tokenPrivateJWK, EmbeddedJWK), {
code: 'ERR_JWS_INVALID',
message: '"jwk" (JSON Web Key) Header Parameter must be a public key',
})
})
mlDsaTest('EmbeddedJWK defers AKP "alg" validation to WebCrypto', async (t) => {
const { publicKey } = await generateKeyPair('ML-DSA-65', { extractable: true })
const { alg, ...jwk } = await exportJWK(publicKey)
for (const protectedHeader of [
{ alg: 'ML-DSA-65', jwk },
{ alg: 'ML-DSA-44', jwk: { ...jwk, alg } },
]) {
const error = await t.throwsAsync(EmbeddedJWK(protectedHeader))
t.true(error instanceof DOMException)
t.is(error.name, 'DataError')
}
})