Skip to content

Commit 8d55707

Browse files
committed
crypto: update WebCryptoAPI Ed25519/448 JWK alg handling
1 parent c8e511b commit 8d55707

File tree

3 files changed

+66
-23
lines changed

3 files changed

+66
-23
lines changed

lib/internal/crypto/cfrg.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,14 @@ function cfrgImportKey(
279279
'DataError');
280280
}
281281

282+
if (keyData.alg !== undefined && (name === 'Ed25519' || name === 'Ed448')) {
283+
if (keyData.alg !== name && keyData.alg !== 'EdDSA') {
284+
throw lazyDOMException(
285+
'JWK "alg" does not match the requested algorithm',
286+
'DataError');
287+
}
288+
}
289+
282290
if (!isPublic && typeof keyData.x !== 'string') {
283291
throw lazyDOMException('Invalid JWK', 'DataError');
284292
}

lib/internal/crypto/webcrypto.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ async function exportKeyJWK(key) {
467467
// Fall through
468468
case 'Ed448':
469469
jwk.crv ||= key.algorithm.name;
470+
jwk.alg = key.algorithm.name;
470471
return jwk;
471472
case 'AES-CTR':
472473
// Fall through

test/parallel/test-webcrypto-export-import-cfrg.js

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const { subtle } = globalThis.crypto;
1212

1313
const keyData = {
1414
'Ed25519': {
15-
jwsAlg: 'EdDSA',
15+
jwsAlg: 'Ed25519',
1616
spki: Buffer.from(
1717
'302a300506032b6570032100a054b618c12b26c8d43595a5c38dd2b0140b944a' +
1818
'151f75003278c2b6c58ec08f', 'hex'),
@@ -27,7 +27,7 @@ const keyData = {
2727
}
2828
},
2929
'Ed448': {
30-
jwsAlg: 'EdDSA',
30+
jwsAlg: 'Ed448',
3131
spki: Buffer.from(
3232
'3043300506032b6571033a0008cc38160c85bca5656ac4924af7ea97a9161b20' +
3333
'2528273dcb84afd2eeb99ac912a401b34ef15ef4d9486406a6eecc31e5909219' +
@@ -183,10 +183,7 @@ async function testImportJwk({ name, publicUsages, privateUsages }, extractable)
183183

184184
const jwk = keyData[name].jwk;
185185

186-
const [
187-
publicKey,
188-
privateKey,
189-
] = await Promise.all([
186+
const tests = [
190187
subtle.importKey(
191188
'jwk',
192189
{
@@ -221,7 +218,37 @@ async function testImportJwk({ name, publicUsages, privateUsages }, extractable)
221218
{ name },
222219
extractable,
223220
privateUsages),
224-
]);
221+
];
222+
223+
// Test the deprecated "alg" value
224+
if (keyData[name].jwsAlg?.startsWith('Ed')) {
225+
tests.push(
226+
subtle.importKey(
227+
'jwk',
228+
{
229+
alg: 'EdDSA',
230+
kty: jwk.kty,
231+
crv: jwk.crv,
232+
x: jwk.x,
233+
},
234+
{ name },
235+
extractable, publicUsages),
236+
subtle.importKey(
237+
'jwk',
238+
{
239+
...jwk,
240+
alg: 'EdDSA',
241+
},
242+
{ name },
243+
extractable,
244+
privateUsages),
245+
);
246+
}
247+
248+
const [
249+
publicKey,
250+
privateKey,
251+
] = await Promise.all(tests);
225252

226253
assert.strictEqual(publicKey.type, 'public');
227254
assert.strictEqual(privateKey.type, 'private');
@@ -259,8 +286,13 @@ async function testImportJwk({ name, publicUsages, privateUsages }, extractable)
259286
assert.strictEqual(pvtJwk.crv, jwk.crv);
260287
assert.strictEqual(pvtJwk.d, jwk.d);
261288

262-
assert.strictEqual(pubJwk.alg, undefined);
263-
assert.strictEqual(pvtJwk.alg, undefined);
289+
if (jwk.crv.startsWith('Ed')) {
290+
assert.strictEqual(pubJwk.alg, jwk.crv);
291+
assert.strictEqual(pvtJwk.alg, jwk.crv);
292+
} else {
293+
assert.strictEqual(pubJwk.alg, undefined);
294+
assert.strictEqual(pvtJwk.alg, undefined);
295+
}
264296
} else {
265297
await assert.rejects(
266298
subtle.exportKey('jwk', publicKey), {
@@ -284,22 +316,24 @@ async function testImportJwk({ name, publicUsages, privateUsages }, extractable)
284316
{ message: 'Invalid JWK "use" Parameter' });
285317
}
286318

287-
// The JWK alg member is ignored
288-
// https://github.com/WICG/webcrypto-secure-curves/pull/24
289319
if (name.startsWith('Ed')) {
290-
await subtle.importKey(
291-
'jwk',
292-
{ kty: jwk.kty, x: jwk.x, crv: jwk.crv, alg: 'foo' },
293-
{ name },
294-
extractable,
295-
publicUsages);
320+
await assert.rejects(
321+
subtle.importKey(
322+
'jwk',
323+
{ kty: jwk.kty, x: jwk.x, crv: jwk.crv, alg: 'foo' },
324+
{ name },
325+
extractable,
326+
publicUsages),
327+
{ message: 'JWK "alg" does not match the requested algorithm' });
296328

297-
await subtle.importKey(
298-
'jwk',
299-
{ ...jwk, alg: 'foo' },
300-
{ name },
301-
extractable,
302-
privateUsages);
329+
await assert.rejects(
330+
subtle.importKey(
331+
'jwk',
332+
{ ...jwk, alg: 'foo' },
333+
{ name },
334+
extractable,
335+
privateUsages),
336+
{ message: 'JWK "alg" does not match the requested algorithm' });
303337
}
304338

305339
for (const crv of [undefined, name === 'Ed25519' ? 'Ed448' : 'Ed25519']) {

0 commit comments

Comments
 (0)