From 19e525fdee04ba6281f70bd20523b878408aa7ee Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Mon, 27 Feb 2023 11:10:34 +0100 Subject: [PATCH] refactor: clarify when alg is used and required on key imports --- src/key/generate_key_pair.ts | 4 ++-- src/key/generate_secret.ts | 6 +++--- src/key/import.ts | 20 ++++++++++---------- src/runtime/browser/jwk_to_key.ts | 4 ++++ tap/jwk.ts | 24 ++++++++++++++++++++++++ test/jwk/jwk2key.test.mjs | 13 ------------- 6 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/key/generate_key_pair.ts b/src/key/generate_key_pair.ts index 39067079e9..21289cd862 100644 --- a/src/key/generate_key_pair.ts +++ b/src/key/generate_key_pair.ts @@ -24,7 +24,7 @@ export interface GenerateKeyPairOptions { modulusLength?: number /** - * (Web Cryptography API specific) The value to use as + * (Only effective in Web Crypto API runtimes) The value to use as * [SubtleCrypto.generateKey()](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey) * `extractable` argument. Default is false. */ @@ -35,7 +35,7 @@ export interface GenerateKeyPairOptions { * Generates a private and a public key for a given JWA algorithm identifier. This can only generate * asymmetric key pairs. For symmetric secrets use the `generateSecret` function. * - * Note: Under Web Cryptography API runtime the `privateKey` is generated with `extractable` set to + * Note: Under Web Crypto API runtime the `privateKey` is generated with `extractable` set to * `false` by default. * * @example Usage diff --git a/src/key/generate_secret.ts b/src/key/generate_secret.ts index ad40d88952..b9a22bab3b 100644 --- a/src/key/generate_secret.ts +++ b/src/key/generate_secret.ts @@ -4,7 +4,7 @@ import type { KeyLike } from '../types.d' export interface GenerateSecretOptions { /** - * (Web Cryptography API specific) The value to use as + * (Only effective in Web Crypto API runtimes) The value to use as * [SubtleCrypto.generateKey()](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey) * `extractable` argument. Default is false. */ @@ -14,8 +14,8 @@ export interface GenerateSecretOptions { /** * Generates a symmetric secret key for a given JWA algorithm identifier. * - * Note: Under Web Cryptography API runtime the secret key is generated with `extractable` set to - * `false` by default. + * Note: Under Web Crypto API runtime the secret key is generated with `extractable` set to `false` + * by default. * * @example Usage * diff --git a/src/key/import.ts b/src/key/import.ts index f092295a60..c3069607b3 100644 --- a/src/key/import.ts +++ b/src/key/import.ts @@ -8,7 +8,7 @@ import type { JWK, KeyLike } from '../types.d' export interface PEMImportOptions { /** - * (Web Cryptography API specific) The value to use as + * (Only effective in Web Crypto API runtimes) The value to use as * [SubtleCrypto.importKey()](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey) * `extractable` argument. Default is false. */ @@ -32,7 +32,8 @@ export interface PEMImportOptions { * ``` * * @param pem PEM-encoded SPKI string - * @param alg JSON Web Algorithm identifier to be used with the imported key. + * @param alg (Only effective in Web Crypto API runtimes) JSON Web Algorithm identifier to be used + * with the imported key, its presence is only enforced in Web Crypto API runtimes. */ export async function importSPKI( spki: string, @@ -69,7 +70,8 @@ export async function importSPKI( * ``` * * @param pem X.509 certificate string - * @param alg JSON Web Algorithm identifier to be used with the imported key. + * @param alg (Only effective in Web Crypto API runtimes) JSON Web Algorithm identifier to be used + * with the imported key, its presence is only enforced in Web Crypto API runtimes. */ export async function importX509( x509: string, @@ -100,7 +102,8 @@ export async function importX509( * ``` * * @param pem PEM-encoded PKCS#8 string - * @param alg JSON Web Algorithm identifier to be used with the imported key. + * @param alg (Only effective in Web Crypto API runtimes) JSON Web Algorithm identifier to be used + * with the imported key, its presence is only enforced in Web Crypto API runtimes. */ export async function importPKCS8( pkcs8: string, @@ -145,8 +148,9 @@ export async function importPKCS8( * ``` * * @param jwk JSON Web Key. - * @param alg JSON Web Algorithm identifier to be used with the imported key. Default is the "alg" - * property on the JWK. + * @param alg (Only effective in Web Crypto API runtimes) JSON Web Algorithm identifier to be used + * with the imported key. Default is the "alg" property on the JWK, its presence is only enforced + * in Web Crypto API runtimes. * @param octAsKeyObject Forces a symmetric key to be imported to a KeyObject or CryptoKey. Default * is true unless JWK "ext" (Extractable) is true. */ @@ -161,10 +165,6 @@ export async function importJWK( alg ||= jwk.alg - if (typeof alg !== 'string' || !alg) { - throw new TypeError('"alg" argument is required when "jwk.alg" is not present') - } - switch (jwk.kty) { case 'oct': if (typeof jwk.k !== 'string' || !jwk.k) { diff --git a/src/runtime/browser/jwk_to_key.ts b/src/runtime/browser/jwk_to_key.ts index dd4766e05a..983edf30c2 100644 --- a/src/runtime/browser/jwk_to_key.ts +++ b/src/runtime/browser/jwk_to_key.ts @@ -132,6 +132,10 @@ function subtleMapping(jwk: JWK): { } const parse: JWKImportFunction = async (jwk: JWK): Promise => { + if (!jwk.alg) { + throw new TypeError('"alg" argument is required when "jwk.alg" is not present') + } + const { algorithm, keyUsages } = subtleMapping(jwk) const rest: [RsaHashedImportParams | EcKeyAlgorithm | Algorithm, boolean, KeyUsage[]] = [ algorithm, diff --git a/tap/jwk.ts b/tap/jwk.ts index 288904957d..a3dff93a5e 100644 --- a/tap/jwk.ts +++ b/tap/jwk.ts @@ -88,4 +88,28 @@ export default (QUnit: QUnit, lib: typeof jose) => { }) } } + + if (env.isNodeCrypto || env.isElectron) { + test('alg argument and jwk.alg is ignored', async (t) => { + const oct = { + k: 'FyCq1CKBflh3I5gikEjpYrdOXllzxB_yc02za8ERknI', + kty: 'oct', + } + await lib.importJWK(oct) + t.ok(1) + }) + } else { + test('alg argument must be present if jwk does not have alg', async (t) => { + const oct = { + k: 'FyCq1CKBflh3I5gikEjpYrdOXllzxB_yc02za8ERknI', + kty: 'oct', + } + await t.rejects( + lib.importJWK(oct), + '"alg" argument is required when "jwk.alg" is not present', + ) + await lib.importJWK(oct, 'HS256') + await lib.importJWK({ ...oct, alg: 'HS256' }) + }) + } } diff --git a/test/jwk/jwk2key.test.mjs b/test/jwk/jwk2key.test.mjs index ca0ab1729b..7ad6de3c0a 100644 --- a/test/jwk/jwk2key.test.mjs +++ b/test/jwk/jwk2key.test.mjs @@ -39,19 +39,6 @@ test('JWK kty must be recognized', async (t) => { }) }) -test('alg argument must be present if jwk does not have alg', async (t) => { - const oct = { - k: 'FyCq1CKBflh3I5gikEjpYrdOXllzxB_yc02za8ERknI', - kty: 'oct', - } - await t.throwsAsync(importJWK(oct), { - instanceOf: TypeError, - message: '"alg" argument is required when "jwk.alg" is not present', - }) - await t.notThrowsAsync(importJWK(oct, 'HS256')) - await t.notThrowsAsync(importJWK({ ...oct, alg: 'HS256' })) -}) - test('oct JWK must have "k"', async (t) => { await t.throwsAsync(importJWK({ kty: 'oct' }, 'HS256'), { instanceOf: TypeError,