Skip to content

Commit

Permalink
fix(types): iv and tag is optional in JSON serializations
Browse files Browse the repository at this point in the history
  • Loading branch information
panva committed Feb 11, 2024
1 parent f23a29a commit 53019cd
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 73 deletions.
40 changes: 20 additions & 20 deletions docs/interfaces/types.FlattenedJWE.md
Expand Up @@ -13,12 +13,12 @@ Flattened JWE definition.
### Properties

- [ciphertext](types.FlattenedJWE.md#ciphertext)
- [iv](types.FlattenedJWE.md#iv)
- [tag](types.FlattenedJWE.md#tag)
- [aad](types.FlattenedJWE.md#aad)
- [encrypted\_key](types.FlattenedJWE.md#encrypted_key)
- [header](types.FlattenedJWE.md#header)
- [iv](types.FlattenedJWE.md#iv)
- [protected](types.FlattenedJWE.md#protected)
- [tag](types.FlattenedJWE.md#tag)
- [unprotected](types.FlattenedJWE.md#unprotected)

## Properties
Expand All @@ -31,24 +31,6 @@ The "ciphertext" member MUST be present and contain the value BASE64URL(JWE Ciph

___

### iv

**iv**: `string`

The "iv" member MUST be present and contain the value BASE64URL(JWE Initialization Vector) when
the JWE Initialization Vector value is non-empty; otherwise, it MUST be absent.

___

### tag

**tag**: `string`

The "tag" member MUST be present and contain the value BASE64URL(JWE Authentication Tag) when
the JWE Authentication Tag value is non-empty; otherwise, it MUST be absent.

___

### aad

`Optional` **aad**: `string`
Expand Down Expand Up @@ -79,6 +61,15 @@ Parameter values are not integrity protected.

___

### iv

`Optional` **iv**: `string`

The "iv" member MUST be present and contain the value BASE64URL(JWE Initialization Vector) when
the JWE Initialization Vector value is non-empty; otherwise, it MUST be absent.

___

### protected

`Optional` **protected**: `string`
Expand All @@ -89,6 +80,15 @@ Header Parameter values are integrity protected.

___

### tag

`Optional` **tag**: `string`

The "tag" member MUST be present and contain the value BASE64URL(JWE Authentication Tag) when
the JWE Authentication Tag value is non-empty; otherwise, it MUST be absent.

___

### unprotected

`Optional` **unprotected**: [`JWEHeaderParameters`](types.JWEHeaderParameters.md)
Expand Down
40 changes: 20 additions & 20 deletions docs/interfaces/types.GeneralJWE.md
Expand Up @@ -11,11 +11,11 @@ Support from the community to continue maintaining and improving this module is
### Properties

- [ciphertext](types.GeneralJWE.md#ciphertext)
- [iv](types.GeneralJWE.md#iv)
- [recipients](types.GeneralJWE.md#recipients)
- [tag](types.GeneralJWE.md#tag)
- [aad](types.GeneralJWE.md#aad)
- [iv](types.GeneralJWE.md#iv)
- [protected](types.GeneralJWE.md#protected)
- [tag](types.GeneralJWE.md#tag)
- [unprotected](types.GeneralJWE.md#unprotected)

## Properties
Expand All @@ -28,30 +28,12 @@ The "ciphertext" member MUST be present and contain the value BASE64URL(JWE Ciph

___

### iv

**iv**: `string`

The "iv" member MUST be present and contain the value BASE64URL(JWE Initialization Vector) when
the JWE Initialization Vector value is non-empty; otherwise, it MUST be absent.

___

### recipients

**recipients**: [`Pick`]( https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys )\<[`FlattenedJWE`](types.FlattenedJWE.md), ``"header"`` \| ``"encrypted_key"``\>[]

___

### tag

**tag**: `string`

The "tag" member MUST be present and contain the value BASE64URL(JWE Authentication Tag) when
the JWE Authentication Tag value is non-empty; otherwise, it MUST be absent.

___

### aad

`Optional` **aad**: `string`
Expand All @@ -62,6 +44,15 @@ base64url-encoded value to be integrity protected but not encrypted.

___

### iv

`Optional` **iv**: `string`

The "iv" member MUST be present and contain the value BASE64URL(JWE Initialization Vector) when
the JWE Initialization Vector value is non-empty; otherwise, it MUST be absent.

___

### protected

`Optional` **protected**: `string`
Expand All @@ -72,6 +63,15 @@ Header Parameter values are integrity protected.

___

### tag

`Optional` **tag**: `string`

The "tag" member MUST be present and contain the value BASE64URL(JWE Authentication Tag) when
the JWE Authentication Tag value is non-empty; otherwise, it MUST be absent.

___

### unprotected

`Optional` **unprotected**: [`JWEHeaderParameters`](types.JWEHeaderParameters.md)
Expand Down
6 changes: 3 additions & 3 deletions src/jwe/compact/decrypt.ts
Expand Up @@ -82,9 +82,9 @@ export async function compactDecrypt(
const decrypted = await flattenedDecrypt(
{
ciphertext,
iv: <string>(iv || undefined),
protected: protectedHeader || undefined,
tag: <string>(tag || undefined),
iv: iv || undefined,
protected: protectedHeader,
tag: tag || undefined,
encrypted_key: encryptedKey || undefined,
},
<Parameters<typeof flattenedDecrypt>[1]>key,
Expand Down
32 changes: 18 additions & 14 deletions src/jwe/flattened/decrypt.ts
Expand Up @@ -85,16 +85,16 @@ export async function flattenedDecrypt(
throw new JWEInvalid('JOSE Header missing')
}

if (typeof jwe.iv !== 'string') {
throw new JWEInvalid('JWE Initialization Vector missing or incorrect type')
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 (typeof jwe.tag !== 'string') {
throw new JWEInvalid('JWE Authentication Tag 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') {
Expand Down Expand Up @@ -205,17 +205,21 @@ export async function flattenedDecrypt(
cek = generateCek(enc)
}

let iv: Uint8Array
let tag: Uint8Array
try {
iv = base64url(jwe.iv)
} catch {
throw new JWEInvalid('Failed to base64url decode the iv')
let iv: Uint8Array | undefined
let tag: Uint8Array | undefined
if (jwe.iv !== undefined) {
try {
iv = base64url(jwe.iv)
} catch {
throw new JWEInvalid('Failed to base64url decode the iv')
}
}
try {
tag = base64url(jwe.tag)
} catch {
throw new JWEInvalid('Failed to base64url decode the tag')
if (jwe.tag !== undefined) {
try {
tag = base64url(jwe.tag)
} catch {
throw new JWEInvalid('Failed to base64url decode the tag')
}
}

const protectedHeader: Uint8Array = encoder.encode(jwe.protected ?? '')
Expand Down
13 changes: 10 additions & 3 deletions src/runtime/browser/decrypt.ts
Expand Up @@ -4,7 +4,7 @@ import type { DecryptFunction } from '../interfaces.d'
import checkIvLength from '../../lib/check_iv_length.js'
import checkCekLength from './check_cek_length.js'
import timingSafeEqual from './timing_safe_equal.js'
import { JOSENotSupported, JWEDecryptionFailed } from '../../util/errors.js'
import { JOSENotSupported, JWEDecryptionFailed, JWEInvalid } from '../../util/errors.js'
import crypto, { isCryptoKey } from './webcrypto.js'
import { checkEncCryptoKey } from '../../lib/crypto_key.js'
import invalidKeyInput from '../../lib/invalid_key_input.js'
Expand Down Expand Up @@ -108,14 +108,21 @@ const decrypt: DecryptFunction = async (
enc: string,
cek: unknown,
ciphertext: Uint8Array,
iv: Uint8Array,
tag: Uint8Array,
iv: Uint8Array | undefined,
tag: Uint8Array | undefined,
aad: Uint8Array,
) => {
if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) {
throw new TypeError(invalidKeyInput(cek, ...types, 'Uint8Array'))
}

if (!iv) {
throw new JWEInvalid('JWE Initialization Vector missing')
}
if (!tag) {
throw new JWEInvalid('JWE Authentication Tag missing')
}

checkIvLength(enc, iv)

switch (enc) {
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/interfaces.d.ts
Expand Up @@ -63,8 +63,8 @@ export interface DecryptFunction {
enc: string,
cek: unknown,
ciphertext: Uint8Array,
iv: Uint8Array,
tag: Uint8Array,
iv: Uint8Array | undefined,
tag: Uint8Array | undefined,
additionalData: Uint8Array,
): AsyncOrSync<Uint8Array>
}
Expand Down
13 changes: 10 additions & 3 deletions src/runtime/node/decrypt.ts
Expand Up @@ -5,7 +5,7 @@ import type { DecryptFunction } from '../interfaces.d'
import checkIvLength from '../../lib/check_iv_length.js'
import checkCekLength from './check_cek_length.js'
import { concat } from '../../lib/buffer_utils.js'
import { JOSENotSupported, JWEDecryptionFailed } from '../../util/errors.js'
import { JOSENotSupported, JWEDecryptionFailed, JWEInvalid } from '../../util/errors.js'
import timingSafeEqual from './timing_safe_equal.js'
import cbcTag from './cbc_tag.js'
import { isCryptoKey } from './webcrypto.js'
Expand Down Expand Up @@ -97,8 +97,8 @@ const decrypt: DecryptFunction = (
enc: string,
cek: unknown,
ciphertext: Uint8Array,
iv: Uint8Array,
tag: Uint8Array,
iv: Uint8Array | undefined,
tag: Uint8Array | undefined,
aad: Uint8Array,
) => {
let key: KeyObject | Uint8Array
Expand All @@ -111,6 +111,13 @@ const decrypt: DecryptFunction = (
throw new TypeError(invalidKeyInput(cek, ...types, 'Uint8Array'))
}

if (!iv) {
throw new JWEInvalid('JWE Initialization Vector missing')
}
if (!tag) {
throw new JWEInvalid('JWE Authentication Tag missing')
}

checkCekLength(enc, key)
checkIvLength(enc, iv)

Expand Down
4 changes: 2 additions & 2 deletions src/types.d.ts
Expand Up @@ -334,7 +334,7 @@ export interface FlattenedJWE {
* The "iv" member MUST be present and contain the value BASE64URL(JWE Initialization Vector) when
* the JWE Initialization Vector value is non-empty; otherwise, it MUST be absent.
*/
iv: string
iv?: string

/**
* The "protected" member MUST be present and contain the value BASE64URL(UTF8(JWE Protected
Expand All @@ -347,7 +347,7 @@ export interface FlattenedJWE {
* The "tag" member MUST be present and contain the value BASE64URL(JWE Authentication Tag) when
* the JWE Authentication Tag value is non-empty; otherwise, it MUST be absent.
*/
tag: string
tag?: string

/**
* The "unprotected" member MUST be present and contain the value JWE Shared Unprotected Header
Expand Down
20 changes: 14 additions & 6 deletions test/jwe/flattened.decrypt.test.mjs
Expand Up @@ -40,16 +40,20 @@ test('JWE format validation', async (t) => {

{
const jwe = { ...fullJwe }
jwe.iv = undefined
const assertion = {
message: 'JWE Initialization Vector missing or incorrect type',
message: 'JWE Initialization Vector incorrect type',
code: 'ERR_JWE_INVALID',
}

jwe.iv = 12
await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), assertion)
jwe.iv = null

await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), assertion)
jwe.iv = undefined
await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), {
message: 'JWE Initialization Vector missing',
code: 'ERR_JWE_INVALID',
})
}

{
Expand All @@ -68,16 +72,20 @@ test('JWE format validation', async (t) => {

{
const jwe = { ...fullJwe }
jwe.tag = undefined
const assertion = {
message: 'JWE Authentication Tag missing or incorrect type',
message: 'JWE Authentication Tag incorrect type',
code: 'ERR_JWE_INVALID',
}

jwe.tag = 12
await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), assertion)
jwe.tag = null

await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), assertion)
jwe.tag = undefined
await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), {
message: 'JWE Authentication Tag missing',
code: 'ERR_JWE_INVALID',
})
}

{
Expand Down

0 comments on commit 53019cd

Please sign in to comment.