Skip to content

Commit

Permalink
refactor: PBES2 Algorithms require explicit opt-in during verification
Browse files Browse the repository at this point in the history
BREAKING CHANGE: PBES2 Key Management Algorithms' use in decrypt
functions now requires the use of the keyManagementAlgorithms option
to explicitly opt-in for their use.
  • Loading branch information
panva committed Oct 25, 2023
1 parent fe8114c commit e2da031
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 10 deletions.
5 changes: 4 additions & 1 deletion src/jwe/flattened/decrypt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ export async function flattenedDecrypt(
options &&
validateAlgorithms('contentEncryptionAlgorithms', options.contentEncryptionAlgorithms)

if (keyManagementAlgorithms && !keyManagementAlgorithms.has(alg)) {
if (
(keyManagementAlgorithms && !keyManagementAlgorithms.has(alg)) ||
(!keyManagementAlgorithms && alg.startsWith('PBES2'))
) {
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed')
}

Expand Down
6 changes: 5 additions & 1 deletion src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,11 @@ export interface CritOption {

/** JWE Decryption options. */
export interface DecryptOptions extends CritOption {
/** A list of accepted JWE "alg" (Algorithm) Header Parameter values. */
/**
* A list of accepted JWE "alg" (Algorithm) Header Parameter values. By default all "alg"
* (Algorithm) Header Parameter values applicable for the used key/secret are allowed except for
* all PBES2 Key Management Algorithms, these need to be explicitly allowed using this option.
*/
keyManagementAlgorithms?: string[]

/**
Expand Down
15 changes: 12 additions & 3 deletions tap/cookbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,18 +272,27 @@ export default (QUnit: QUnit, lib: typeof jose) => {
}

const result = await encrypt.encrypt(publicKey)
await flattened.decrypt(result, privateKey)
await flattened.decrypt(result, privateKey, {
keyManagementAlgorithms: [vector.input.alg],
contentEncryptionAlgorithms: [vector.input.enc],
})
}

const privateKey = await lib.importJWK(
toJWK(vector.input.pwd || vector.input.key),
dir ? vector.input.enc : vector.input.alg,
)
if (vector.output.json_flat) {
await flattened.decrypt(vector.output.json_flat, privateKey)
await flattened.decrypt(vector.output.json_flat, privateKey, {
keyManagementAlgorithms: [vector.input.alg],
contentEncryptionAlgorithms: [vector.input.enc],
})
}
if (vector.output.compact) {
await compact.decrypt(vector.output.compact, privateKey)
await compact.decrypt(vector.output.compact, privateKey, {
keyManagementAlgorithms: [vector.input.alg],
contentEncryptionAlgorithms: [vector.input.enc],
})
}
t.ok(1)
}
Expand Down
10 changes: 8 additions & 2 deletions tap/encrypt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ export async function jwe(
.setAdditionalAuthenticatedData(aad)
.encrypt(eKey)

const decrypted = await lib.flattenedDecrypt(jwe, dKey)
const decrypted = await lib.flattenedDecrypt(jwe, dKey, {
keyManagementAlgorithms: [alg],
contentEncryptionAlgorithms: [enc],
})
t.deepEqual([...decrypted.plaintext], [...cleartext])
t.deepEqual([...decrypted.additionalAuthenticatedData!], [...aad])
}
Expand All @@ -44,7 +47,10 @@ export async function jwt(
.setProtectedHeader({ alg, enc })
.encrypt(eKey)

const decrypted = await lib.jwtDecrypt(jwt, dKey)
const decrypted = await lib.jwtDecrypt(jwt, dKey, {
keyManagementAlgorithms: [alg],
contentEncryptionAlgorithms: [enc],
})
t.propContains(decrypted, {
payload: {
foo: 'bar',
Expand Down
23 changes: 20 additions & 3 deletions test/jwe/flattened.decrypt.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,25 @@ test('decrypt PBES2 p2c limit', async (t) => {
.setKeyManagementParameters({ p2c: 2049 })
.encrypt(new Uint8Array(32))

await t.throwsAsync(flattenedDecrypt(jwe, new Uint8Array(32), { maxPBES2Count: 2048 }), {
message: 'JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds',
code: 'ERR_JWE_INVALID',
await t.throwsAsync(
flattenedDecrypt(jwe, new Uint8Array(32), {
maxPBES2Count: 2048,
keyManagementAlgorithms: ['PBES2-HS256+A128KW'],
}),
{
message: 'JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds',
code: 'ERR_JWE_INVALID',
},
)
})

test('decrypt with PBES2 is not allowed by default', async (t) => {
const jwe = await new FlattenedEncrypt(new Uint8Array(0))
.setProtectedHeader({ alg: 'PBES2-HS256+A128KW', enc: 'A128CBC-HS256' })
.encrypt(new Uint8Array(32))

await t.throwsAsync(flattenedDecrypt(jwe, new Uint8Array(32)), {
message: '"alg" (Algorithm) Header Parameter value not allowed',
code: 'ERR_JOSE_ALG_NOT_ALLOWED',
})
})

0 comments on commit e2da031

Please sign in to comment.