From 16998b15c75d90b64eb5b0fa0713cfdfa7896757 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Wed, 18 Oct 2023 10:05:40 +0200 Subject: [PATCH] refactor: remove support for JWE "zip" (Compression Algorithm) Header Parameter BREAKING CHANGE: The JWE "zip" (Compression Algorithm) Header Parameter is no longer supported by this JOSE implementation. --- src/index.ts | 3 --- src/jwe/flattened/decrypt.ts | 17 +++----------- src/jwe/flattened/encrypt.ts | 23 ++++-------------- src/jwe/general/encrypt.ts | 24 ++++++------------- src/runtime/browser/zlib.ts | 13 ----------- src/runtime/node/zlib.ts | 10 -------- src/types.d.ts | 45 ++---------------------------------- tap/cookbook.ts | 2 +- tap/env.ts | 3 --- 9 files changed, 17 insertions(+), 123 deletions(-) delete mode 100644 src/runtime/browser/zlib.ts delete mode 100644 src/runtime/node/zlib.ts diff --git a/src/index.ts b/src/index.ts index 97b4a623af..9443ea7433 100644 --- a/src/index.ts +++ b/src/index.ts @@ -73,15 +73,12 @@ export type { GeneralJWE, JWEHeaderParameters, CritOption, - DeflateOption, DecryptOptions, EncryptOptions, JWTClaimVerificationOptions, VerifyOptions, SignOptions, JWTPayload, - DeflateFunction, - InflateFunction, FlattenedDecryptResult, GeneralDecryptResult, CompactDecryptResult, diff --git a/src/jwe/flattened/decrypt.ts b/src/jwe/flattened/decrypt.ts index bd2a12acc4..01ec25161e 100644 --- a/src/jwe/flattened/decrypt.ts +++ b/src/jwe/flattened/decrypt.ts @@ -1,6 +1,5 @@ import { decode as base64url } from '../../runtime/base64url.js' import decrypt from '../../runtime/decrypt.js' -import { inflate } from '../../runtime/zlib.js' import { JOSEAlgNotAllowed, JOSENotSupported, JWEInvalid } from '../../util/errors.js' import isDisjoint from '../../lib/is_disjoint.js' @@ -142,15 +141,9 @@ export async function flattenedDecrypt( validateCrit(JWEInvalid, new Map(), options?.crit, parsedProt, joseHeader) if (joseHeader.zip !== undefined) { - if (!parsedProt || !parsedProt.zip) { - throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected') - } - - if (joseHeader.zip !== 'DEF') { - throw new JOSENotSupported( - 'Unsupported JWE "zip" (Compression Algorithm) Header Parameter value', - ) - } + throw new JOSENotSupported( + 'JWE "zip" (Compression Algorithm) Header Parameter is not supported.', + ) } const { alg, enc } = joseHeader @@ -239,10 +232,6 @@ export async function flattenedDecrypt( } let plaintext = await decrypt(enc, cek, ciphertext, iv, tag, additionalData) - if (joseHeader.zip === 'DEF') { - plaintext = await (options?.inflateRaw || inflate)(plaintext) - } - const result: FlattenedDecryptResult = { plaintext } if (jwe.protected !== undefined) { diff --git a/src/jwe/flattened/encrypt.ts b/src/jwe/flattened/encrypt.ts index d0f0e840da..81cfc50e19 100644 --- a/src/jwe/flattened/encrypt.ts +++ b/src/jwe/flattened/encrypt.ts @@ -1,6 +1,5 @@ import { encode as base64url } from '../../runtime/base64url.js' import encrypt from '../../runtime/encrypt.js' -import { deflate } from '../../runtime/zlib.js' import type { KeyLike, @@ -190,15 +189,9 @@ export class FlattenedEncrypt { validateCrit(JWEInvalid, new Map(), options?.crit, this._protectedHeader, joseHeader) if (joseHeader.zip !== undefined) { - if (!this._protectedHeader || !this._protectedHeader.zip) { - throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected') - } - - if (joseHeader.zip !== 'DEF') { - throw new JOSENotSupported( - 'Unsupported JWE "zip" (Compression Algorithm) Header Parameter value', - ) - } + throw new JOSENotSupported( + 'JWE "zip" (Compression Algorithm) Header Parameter is not supported.', + ) } const { alg, enc } = joseHeader @@ -271,15 +264,7 @@ export class FlattenedEncrypt { additionalData = protectedHeader } - let ciphertext: Uint8Array - let tag: Uint8Array - - if (joseHeader.zip === 'DEF') { - const deflated = await (options?.deflateRaw || deflate)(this._plaintext) - ;({ ciphertext, tag } = await encrypt(enc, deflated, cek, this._iv, additionalData)) - } else { - ;({ ciphertext, tag } = await encrypt(enc, this._plaintext, cek, this._iv, additionalData)) - } + const { ciphertext, tag } = await encrypt(enc, this._plaintext, cek, this._iv, additionalData) const jwe: FlattenedJWE = { ciphertext: base64url(ciphertext), diff --git a/src/jwe/general/encrypt.ts b/src/jwe/general/encrypt.ts index c1e683a46e..8017be1da1 100644 --- a/src/jwe/general/encrypt.ts +++ b/src/jwe/general/encrypt.ts @@ -1,5 +1,5 @@ import { FlattenedEncrypt, unprotected } from '../flattened/encrypt.js' -import { JWEInvalid } from '../../util/errors.js' +import { JOSENotSupported, JWEInvalid } from '../../util/errors.js' import generateCek from '../../lib/cek.js' import isDisjoint from '../../lib/is_disjoint.js' import encryptKeyManagement from '../../lib/encrypt_key_management.js' @@ -11,7 +11,6 @@ import type { GeneralJWE, JWEHeaderParameters, CritOption, - DeflateOption, } from '../../types.d' export interface Recipient { @@ -149,18 +148,12 @@ export class GeneralEncrypt { return this } - /** - * Encrypts and resolves the value of the General JWE object. - * - * @param options JWE Encryption options. - */ - async encrypt(options?: DeflateOption): Promise { + /** Encrypts and resolves the value of the General JWE object. */ + async encrypt(): Promise { if (!this._recipients.length) { throw new JWEInvalid('at least one recipient must be added') } - options = { deflateRaw: options?.deflateRaw } - if (this._recipients.length === 1) { const [recipient] = this._recipients @@ -169,7 +162,7 @@ export class GeneralEncrypt { .setProtectedHeader(this._protectedHeader) .setSharedUnprotectedHeader(this._unprotectedHeader) .setUnprotectedHeader(recipient.unprotectedHeader!) - .encrypt(recipient.key, { ...recipient.options, ...options }) + .encrypt(recipient.key, { ...recipient.options }) let jwe: GeneralJWE = { ciphertext: flattened.ciphertext, @@ -229,11 +222,9 @@ export class GeneralEncrypt { validateCrit(JWEInvalid, new Map(), recipient.options.crit, this._protectedHeader, joseHeader) if (joseHeader.zip !== undefined) { - if (!this._protectedHeader || !this._protectedHeader.zip) { - throw new JWEInvalid( - 'JWE "zip" (Compression Algorithm) Header MUST be integrity protected', - ) - } + throw new JOSENotSupported( + 'JWE "zip" (Compression Algorithm) Header Parameter is not supported.', + ) } } @@ -269,7 +260,6 @@ export class GeneralEncrypt { .setKeyManagementParameters({ p2c }) .encrypt(recipient.key, { ...recipient.options, - ...options, // @ts-expect-error [unprotected]: true, }) diff --git a/src/runtime/browser/zlib.ts b/src/runtime/browser/zlib.ts deleted file mode 100644 index 6c4aee80db..0000000000 --- a/src/runtime/browser/zlib.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { JOSENotSupported } from '../../util/errors.js' -import type { InflateFunction, DeflateFunction } from '../../types.d' - -export const inflate: InflateFunction = async () => { - throw new JOSENotSupported( - 'JWE "zip" (Compression Algorithm) Header Parameter is not supported by your javascript runtime. You need to use the `inflateRaw` decrypt option to provide Inflate Raw implementation.', - ) -} -export const deflate: DeflateFunction = async () => { - throw new JOSENotSupported( - 'JWE "zip" (Compression Algorithm) Header Parameter is not supported by your javascript runtime. You need to use the `deflateRaw` encrypt option to provide Deflate Raw implementation.', - ) -} diff --git a/src/runtime/node/zlib.ts b/src/runtime/node/zlib.ts deleted file mode 100644 index 30801a95bd..0000000000 --- a/src/runtime/node/zlib.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { promisify } from 'util' -import { inflateRaw as inflateRawCb, deflateRaw as deflateRawCb } from 'zlib' - -import type { InflateFunction, DeflateFunction } from '../../types.d' - -const inflateRaw = promisify(inflateRawCb) -const deflateRaw = promisify(deflateRawCb) - -export const inflate: InflateFunction = (input: Uint8Array) => inflateRaw(input) -export const deflate: DeflateFunction = (input: Uint8Array) => deflateRaw(input) diff --git a/src/types.d.ts b/src/types.d.ts index 1ee6d56ff5..4e348953c9 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -366,7 +366,7 @@ export interface JWEHeaderParameters extends JoseHeaderParameters { crit?: string[] /** - * JWE "zip" (Compression Algorithm) Header Parameter. + * JWE "zip" (Compression Algorithm) Header Parameter. This parameter is not supported anymore. * * @deprecated Compression of data SHOULD NOT be done before encryption, because such compressed * data often reveals information about the plaintext. @@ -415,12 +415,6 @@ export interface DecryptOptions extends CritOption { */ contentEncryptionAlgorithms?: string[] - /** - * In a browser runtime you have to provide an implementation for Inflate Raw when you expect JWEs - * with compressed plaintext. - */ - inflateRaw?: InflateFunction - /** * (PBES2 Key Management Algorithms only) Maximum allowed "p2c" (PBES2 Count) Header Parameter * value. The PBKDF2 iteration count defines the algorithm's computational expense. By default @@ -429,17 +423,8 @@ export interface DecryptOptions extends CritOption { maxPBES2Count?: number } -/** JWE Deflate option. */ -export interface DeflateOption { - /** - * In a browser runtime you have to provide an implementation for Deflate Raw when you will be - * producing JWEs with compressed plaintext. - */ - deflateRaw?: DeflateFunction -} - /** JWE Encryption options. */ -export interface EncryptOptions extends CritOption, DeflateOption {} +export interface EncryptOptions extends CritOption {} /** JWT Claims Set verification options. */ export interface JWTClaimVerificationOptions { @@ -553,32 +538,6 @@ export interface JWTPayload { [propName: string]: unknown } -/** - * Deflate Raw implementation, e.g. promisified - * {@link https://nodejs.org/api/zlib.html#zlibdeflaterawbuffer-options-callback zlib.deflateRaw}. - * - * @deprecated Compression of data SHOULD NOT be done before encryption, because such compressed - * data often reveals information about the plaintext. - * - * @see {@link https://www.rfc-editor.org/rfc/rfc8725#name-avoid-compression-of-encryp Avoid Compression of Encryption Inputs} - */ -export interface DeflateFunction { - (input: Uint8Array): Promise -} - -/** - * Inflate Raw implementation, e.g. promisified - * {@link https://nodejs.org/api/zlib.html#zlibinflaterawbuffer-options-callback zlib.inflateRaw}. - * - * @deprecated Compression of data SHOULD NOT be done before encryption, because such compressed - * data often reveals information about the plaintext. - * - * @see {@link https://www.rfc-editor.org/rfc/rfc8725#name-avoid-compression-of-encryp Avoid Compression of Encryption Inputs} - */ -export interface InflateFunction { - (input: Uint8Array): Promise -} - export interface FlattenedDecryptResult { /** JWE AAD. */ additionalAuthenticatedData?: Uint8Array diff --git a/tap/cookbook.ts b/tap/cookbook.ts index f6ae9c4cb7..6094e69a82 100644 --- a/tap/cookbook.ts +++ b/tap/cookbook.ts @@ -150,7 +150,7 @@ export default (QUnit: QUnit, lib: typeof jose) => { if (env.isElectron && vector.electron === false) { return false } - if (vector.input.zip && !env.hasZlib) { + if (vector.input.zip) { return false } return true diff --git a/tap/env.ts b/tap/env.ts index 1515114591..f23afa95e1 100644 --- a/tap/env.ts +++ b/tap/env.ts @@ -50,6 +50,3 @@ export const isWebKit = isBrowser && (await isEngine('WebKit')) export const isWebKitAbove17 = isBrowser && isWebKit && (await isVersionAtLeast(17)) export const isGecko = isBrowser && (await isEngine('Gecko')) - -// @ts-ignore -export const hasZlib = isNode && [...process.argv].reverse()[0] !== '#dist/webapi'