Skip to content

Commit ebda967

Browse files
committed
feat!: JSON Web Key is now an allowed input everywhere
BREAKING CHANGE: resolved keys returned as part of verify/decrypt operations (when get key functions are used) are always normalized to either Uint8Array / CryptoKey depending on what's more efficient for the executed operation BREAKING CHANGE: Key "Type" Generics are removed
1 parent 161de46 commit ebda967

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+662
-570
lines changed

.electron_flags.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ echo $(electron -i <<< 'process.exit(0)' 2> /dev/null | grep "Using" | awk '{$1=
22

33
electron -i <<< 'process.exit(parseInt(process.versions.node, 10))' &> /dev/null
44
NODE_VERSION=$?
5-
export NODE_OPTIONS='--no-warnings'
5+
export NODE_OPTIONS='--no-warnings --enable-source-maps'
66

77
if [[ $NODE_VERSION -eq 18 ]]; then
88
export NODE_OPTIONS+=' --experimental-global-webcrypto'

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@ dist-browser-tests
121121

122122
.npmrc
123123
tap/*.js
124+
tap/*.js.map
124125
tap/run-*.mjs
126+
tap/run-*.mjs.map
125127
*.bak
126128
*.bun
127129
tap/.workerd.capnp

.node_flags.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ echo "Using Node.js $(node --version)"
22

33
node -e 'process.exit(parseInt(process.versions.node, 10))' &> /dev/null
44
NODE_VERSION=$?
5-
export NODE_OPTIONS='--no-warnings'
5+
export NODE_OPTIONS='--no-warnings --enable-source-maps'
66

77
if [[ $NODE_VERSION -eq 18 ]]; then
88
export NODE_OPTIONS+=' --experimental-global-webcrypto'

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ export type { GenerateSecretOptions } from './key/generate_secret.js'
6060
export * as base64url from './util/base64url.js'
6161

6262
export type {
63+
CryptoKey,
64+
KeyObject,
6365
KeyLike,
6466
JWK,
6567
JWKParameters,

src/jwe/compact/decrypt.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import { flattenedDecrypt } from '../flattened/decrypt.js'
22
import { JWEInvalid } from '../../util/errors.js'
33
import { decoder } from '../../lib/buffer_utils.js'
44
import type {
5-
KeyLike,
5+
CryptoKey,
66
DecryptOptions,
77
CompactJWEHeaderParameters,
88
GetKeyFunction,
99
FlattenedJWE,
1010
CompactDecryptResult,
1111
ResolvedKey,
12+
KeyObject,
13+
JWK,
1214
} from '../../types.d.ts'
1315

1416
/**
@@ -43,7 +45,7 @@ export interface CompactDecryptGetKey
4345
*/
4446
export async function compactDecrypt(
4547
jwe: string | Uint8Array,
46-
key: KeyLike | Uint8Array,
48+
key: CryptoKey | KeyObject | JWK | Uint8Array,
4749
options?: DecryptOptions,
4850
): Promise<CompactDecryptResult>
4951
/**
@@ -52,14 +54,14 @@ export async function compactDecrypt(
5254
* {@link https://github.com/panva/jose/issues/210#jwe-alg Algorithm Key Requirements}.
5355
* @param options JWE Decryption options.
5456
*/
55-
export async function compactDecrypt<KeyLikeType extends KeyLike = KeyLike>(
57+
export async function compactDecrypt(
5658
jwe: string | Uint8Array,
5759
getKey: CompactDecryptGetKey,
5860
options?: DecryptOptions,
59-
): Promise<CompactDecryptResult & ResolvedKey<KeyLikeType>>
61+
): Promise<CompactDecryptResult & ResolvedKey>
6062
export async function compactDecrypt(
6163
jwe: string | Uint8Array,
62-
key: KeyLike | Uint8Array | CompactDecryptGetKey,
64+
key: CryptoKey | KeyObject | JWK | Uint8Array | CompactDecryptGetKey,
6365
options?: DecryptOptions,
6466
) {
6567
if (jwe instanceof Uint8Array) {

src/jwe/compact/encrypt.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { FlattenedEncrypt } from '../flattened/encrypt.js'
22
import type {
3-
KeyLike,
3+
KeyObject,
4+
CryptoKey,
45
JWEKeyManagementHeaderParameters,
56
CompactJWEHeaderParameters,
67
EncryptOptions,
8+
JWK,
79
} from '../../types.d.ts'
810

911
/**
@@ -89,7 +91,10 @@ export class CompactEncrypt {
8991
* {@link https://github.com/panva/jose/issues/210#jwe-alg Algorithm Key Requirements}.
9092
* @param options JWE Encryption options.
9193
*/
92-
async encrypt(key: KeyLike | Uint8Array, options?: EncryptOptions): Promise<string> {
94+
async encrypt(
95+
key: CryptoKey | KeyObject | JWK | Uint8Array,
96+
options?: EncryptOptions,
97+
): Promise<string> {
9398
const jwe = await this._flattened.encrypt(key, options)
9499

95100
return [jwe.protected, jwe.encrypted_key, jwe.iv, jwe.ciphertext, jwe.tag].join('.')

src/jwe/flattened/decrypt.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,21 @@ import isObject from '../../lib/is_object.js'
77
import decryptKeyManagement from '../../lib/decrypt_key_management.js'
88
import type {
99
FlattenedDecryptResult,
10-
KeyLike,
10+
CryptoKey,
1111
FlattenedJWE,
1212
JWEHeaderParameters,
1313
DecryptOptions,
1414
GetKeyFunction,
1515
ResolvedKey,
16+
KeyObject,
17+
JWK,
1618
} from '../../types.d.ts'
1719
import { encoder, decoder, concat } from '../../lib/buffer_utils.js'
1820
import generateCek from '../../lib/cek.js'
1921
import validateCrit from '../../lib/validate_crit.js'
2022
import validateAlgorithms from '../../lib/validate_algorithms.js'
23+
import normalizeKey from '../../runtime/normalize_key.js'
24+
import checkKeyType from '../../lib/check_key_type.js'
2125

2226
/**
2327
* Interface for Flattened JWE Decryption dynamic key resolution. No token components have been
@@ -61,7 +65,7 @@ export interface FlattenedDecryptGetKey
6165
*/
6266
export function flattenedDecrypt(
6367
jwe: FlattenedJWE,
64-
key: KeyLike | Uint8Array,
68+
key: CryptoKey | KeyObject | JWK | Uint8Array,
6569
options?: DecryptOptions,
6670
): Promise<FlattenedDecryptResult>
6771
/**
@@ -70,14 +74,14 @@ export function flattenedDecrypt(
7074
* {@link https://github.com/panva/jose/issues/210#jwe-alg Algorithm Key Requirements}.
7175
* @param options JWE Decryption options.
7276
*/
73-
export function flattenedDecrypt<KeyLikeType extends KeyLike = KeyLike>(
77+
export function flattenedDecrypt(
7478
jwe: FlattenedJWE,
7579
getKey: FlattenedDecryptGetKey,
7680
options?: DecryptOptions,
77-
): Promise<FlattenedDecryptResult & ResolvedKey<KeyLikeType>>
81+
): Promise<FlattenedDecryptResult & ResolvedKey>
7882
export async function flattenedDecrypt(
7983
jwe: FlattenedJWE,
80-
key: KeyLike | Uint8Array | FlattenedDecryptGetKey,
84+
key: CryptoKey | KeyObject | JWK | Uint8Array | FlattenedDecryptGetKey,
8185
options?: DecryptOptions,
8286
) {
8387
if (!isObject(jwe)) {
@@ -190,10 +194,12 @@ export async function flattenedDecrypt(
190194
key = await key(parsedProt, jwe)
191195
resolvedKey = true
192196
}
197+
checkKeyType(alg === 'dir' ? enc : alg, key, 'decrypt')
193198

194-
let cek: KeyLike | Uint8Array
199+
const k = await normalizeKey(key, alg)
200+
let cek: CryptoKey | Uint8Array
195201
try {
196-
cek = await decryptKeyManagement(alg, key, encryptedKey, joseHeader, options)
202+
cek = await decryptKeyManagement(alg, k, encryptedKey, joseHeader, options)
197203
} catch (err) {
198204
if (err instanceof TypeError || err instanceof JWEInvalid || err instanceof JOSENotSupported) {
199205
throw err
@@ -265,7 +271,7 @@ export async function flattenedDecrypt(
265271
}
266272

267273
if (resolvedKey) {
268-
return { ...result, key }
274+
return { ...result, key: k }
269275
}
270276

271277
return result

src/jwe/flattened/encrypt.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,21 @@ import { unprotected } from '../../lib/private_symbols.js'
33
import encrypt from '../../runtime/encrypt.js'
44

55
import type {
6-
KeyLike,
6+
CryptoKey,
77
FlattenedJWE,
88
JWEHeaderParameters,
99
JWEKeyManagementHeaderParameters,
1010
EncryptOptions,
11+
KeyObject,
12+
JWK,
1113
} from '../../types.d.ts'
1214
import encryptKeyManagement from '../../lib/encrypt_key_management.js'
1315
import { JOSENotSupported, JWEInvalid } from '../../util/errors.js'
1416
import isDisjoint from '../../lib/is_disjoint.js'
1517
import { encoder, decoder, concat } from '../../lib/buffer_utils.js'
1618
import validateCrit from '../../lib/validate_crit.js'
19+
import normalizeKey from '../../runtime/normalize_key.js'
20+
import checkKeyType from '../../lib/check_key_type.js'
1721

1822
/**
1923
* The FlattenedEncrypt class is used to build and encrypt Flattened JWE objects.
@@ -165,7 +169,10 @@ export class FlattenedEncrypt {
165169
* {@link https://github.com/panva/jose/issues/210#jwe-alg Algorithm Key Requirements}.
166170
* @param options JWE Encryption options.
167171
*/
168-
async encrypt(key: KeyLike | Uint8Array, options?: EncryptOptions): Promise<FlattenedJWE> {
172+
async encrypt(
173+
key: CryptoKey | KeyObject | JWK | Uint8Array,
174+
options?: EncryptOptions,
175+
): Promise<FlattenedJWE> {
169176
if (!this._protectedHeader && !this._unprotectedHeader && !this._sharedUnprotectedHeader) {
170177
throw new JWEInvalid(
171178
'either setProtectedHeader, setUnprotectedHeader, or sharedUnprotectedHeader must be called before #encrypt()',
@@ -212,13 +219,16 @@ export class FlattenedEncrypt {
212219
)
213220
}
214221

215-
let cek: KeyLike | Uint8Array
222+
checkKeyType(alg === 'dir' ? enc : alg, key, 'encrypt')
223+
224+
let cek: CryptoKey | Uint8Array
216225
{
217226
let parameters: { [propName: string]: unknown } | undefined
227+
const k = await normalizeKey(key, alg)
218228
;({ cek, encryptedKey, parameters } = await encryptKeyManagement(
219229
alg,
220230
enc,
221-
key,
231+
k,
222232
this._cek,
223233
this._keyManagementParameters,
224234
))

src/jwe/general/decrypt.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import { flattenedDecrypt } from '../flattened/decrypt.js'
22
import { JWEDecryptionFailed, JWEInvalid } from '../../util/errors.js'
33
import type {
4-
KeyLike,
4+
CryptoKey,
55
DecryptOptions,
66
JWEHeaderParameters,
77
GetKeyFunction,
88
FlattenedJWE,
99
GeneralJWE,
1010
GeneralDecryptResult,
1111
ResolvedKey,
12+
KeyObject,
13+
JWK,
1214
} from '../../types.d.ts'
1315
import isObject from '../../lib/is_object.js'
1416

@@ -57,7 +59,7 @@ export interface GeneralDecryptGetKey extends GetKeyFunction<JWEHeaderParameters
5759
*/
5860
export function generalDecrypt(
5961
jwe: GeneralJWE,
60-
key: KeyLike | Uint8Array,
62+
key: CryptoKey | KeyObject | JWK | Uint8Array,
6163
options?: DecryptOptions,
6264
): Promise<GeneralDecryptResult>
6365
/**
@@ -66,14 +68,14 @@ export function generalDecrypt(
6668
* {@link https://github.com/panva/jose/issues/210#jwe-alg Algorithm Key Requirements}.
6769
* @param options JWE Decryption options.
6870
*/
69-
export function generalDecrypt<KeyLikeType extends KeyLike = KeyLike>(
71+
export function generalDecrypt(
7072
jwe: GeneralJWE,
7173
getKey: GeneralDecryptGetKey,
7274
options?: DecryptOptions,
73-
): Promise<GeneralDecryptResult & ResolvedKey<KeyLikeType>>
75+
): Promise<GeneralDecryptResult & ResolvedKey>
7476
export async function generalDecrypt(
7577
jwe: GeneralJWE,
76-
key: KeyLike | Uint8Array | GeneralDecryptGetKey,
78+
key: CryptoKey | KeyObject | JWK | Uint8Array | GeneralDecryptGetKey,
7779
options?: DecryptOptions,
7880
) {
7981
if (!isObject(jwe)) {

src/jwe/general/encrypt.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,16 @@ import encryptKeyManagement from '../../lib/encrypt_key_management.js'
77
import { encode as base64url } from '../../runtime/base64url.js'
88
import validateCrit from '../../lib/validate_crit.js'
99

10-
import type { KeyLike, GeneralJWE, JWEHeaderParameters, CritOption } from '../../types.d.ts'
10+
import type {
11+
CryptoKey,
12+
GeneralJWE,
13+
JWEHeaderParameters,
14+
CritOption,
15+
KeyObject,
16+
JWK,
17+
} from '../../types.d.ts'
18+
import normalizeKey from '../../runtime/normalize_key.js'
19+
import checkKeyType from '../../lib/check_key_type.js'
1120

1221
export interface Recipient {
1322
/**
@@ -30,10 +39,14 @@ export interface Recipient {
3039
class IndividualRecipient implements Recipient {
3140
private parent: GeneralEncrypt
3241
unprotectedHeader?: JWEHeaderParameters
33-
key: KeyLike | Uint8Array
42+
key: CryptoKey | KeyObject | JWK | Uint8Array
3443
options: CritOption
3544

36-
constructor(enc: GeneralEncrypt, key: KeyLike | Uint8Array, options: CritOption) {
45+
constructor(
46+
enc: GeneralEncrypt,
47+
key: CryptoKey | KeyObject | JWK | Uint8Array,
48+
options: CritOption,
49+
) {
3750
this.parent = enc
3851
this.key = key
3952
this.options = options
@@ -105,7 +118,7 @@ export class GeneralEncrypt {
105118
* See {@link https://github.com/panva/jose/issues/210#jwe-alg Algorithm Key Requirements}.
106119
* @param options JWE Encryption options.
107120
*/
108-
addRecipient(key: KeyLike | Uint8Array, options?: CritOption): Recipient {
121+
addRecipient(key: CryptoKey | KeyObject | JWK | Uint8Array, options?: CritOption): Recipient {
109122
const recipient = new IndividualRecipient(this, key, { crit: options?.crit })
110123
this._recipients.push(recipient)
111124
return recipient
@@ -277,15 +290,15 @@ export class GeneralEncrypt {
277290
continue
278291
}
279292

280-
const { encryptedKey, parameters } = await encryptKeyManagement(
293+
const alg =
281294
recipient.unprotectedHeader?.alg! ||
282-
this._protectedHeader?.alg! ||
283-
this._unprotectedHeader?.alg!,
284-
enc,
285-
recipient.key,
286-
cek,
287-
{ p2c },
288-
)
295+
this._protectedHeader?.alg! ||
296+
this._unprotectedHeader?.alg!
297+
298+
checkKeyType(alg === 'dir' ? enc : alg, recipient.key, 'encrypt')
299+
300+
const k = await normalizeKey(recipient.key, alg)
301+
const { encryptedKey, parameters } = await encryptKeyManagement(alg, enc, k, cek, { p2c })
289302
target.encrypted_key = base64url(encryptedKey!)
290303
if (recipient.unprotectedHeader || parameters)
291304
target.header = { ...recipient.unprotectedHeader, ...parameters }

0 commit comments

Comments
 (0)