Skip to content

Commit 09fb74a

Browse files
panvatargos
authored andcommitted
crypto: fix webcrypto private/secret import with empty usages
Refs: #47864 PR-URL: #47877 Refs: #47864 Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 7e34f77 commit 09fb74a

9 files changed

+101
-47
lines changed

lib/internal/crypto/webcrypto.js

+22-7
Original file line numberDiff line numberDiff line change
@@ -605,52 +605,67 @@ async function importKey(
605605
});
606606

607607
algorithm = normalizeAlgorithm(algorithm, 'importKey');
608+
let result;
608609
switch (algorithm.name) {
609610
case 'RSASSA-PKCS1-v1_5':
610611
// Fall through
611612
case 'RSA-PSS':
612613
// Fall through
613614
case 'RSA-OAEP':
614-
return require('internal/crypto/rsa')
615+
result = await require('internal/crypto/rsa')
615616
.rsaImportKey(format, keyData, algorithm, extractable, keyUsages);
617+
break;
616618
case 'ECDSA':
617619
// Fall through
618620
case 'ECDH':
619-
return require('internal/crypto/ec')
621+
result = await require('internal/crypto/ec')
620622
.ecImportKey(format, keyData, algorithm, extractable, keyUsages);
623+
break;
621624
case 'Ed25519':
622625
// Fall through
623626
case 'Ed448':
624627
// Fall through
625628
case 'X25519':
626629
// Fall through
627630
case 'X448':
628-
return require('internal/crypto/cfrg')
631+
result = await require('internal/crypto/cfrg')
629632
.cfrgImportKey(format, keyData, algorithm, extractable, keyUsages);
633+
break;
630634
case 'HMAC':
631-
return require('internal/crypto/mac')
635+
result = await require('internal/crypto/mac')
632636
.hmacImportKey(format, keyData, algorithm, extractable, keyUsages);
637+
break;
633638
case 'AES-CTR':
634639
// Fall through
635640
case 'AES-CBC':
636641
// Fall through
637642
case 'AES-GCM':
638643
// Fall through
639644
case 'AES-KW':
640-
return require('internal/crypto/aes')
645+
result = await require('internal/crypto/aes')
641646
.aesImportKey(algorithm, format, keyData, extractable, keyUsages);
647+
break;
642648
case 'HKDF':
643649
// Fall through
644650
case 'PBKDF2':
645-
return importGenericSecretKey(
651+
result = await importGenericSecretKey(
646652
algorithm,
647653
format,
648654
keyData,
649655
extractable,
650656
keyUsages);
657+
break;
658+
default:
659+
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
651660
}
652661

653-
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
662+
if ((result.type === 'secret' || result.type === 'private') && result.usages.length === 0) {
663+
throw lazyDOMException(
664+
`Usages cannot be empty when importing a ${result.type} key.`,
665+
'SyntaxError');
666+
}
667+
668+
return result;
654669
}
655670

656671
// subtle.wrapKey() is essentially a subtle.exportKey() followed

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

+18
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,15 @@ async function testImportPkcs8({ name, privateUsages }, extractable) {
164164
message: /key is not extractable/
165165
});
166166
}
167+
168+
await assert.rejects(
169+
subtle.importKey(
170+
'pkcs8',
171+
keyData[name].pkcs8,
172+
{ name },
173+
extractable,
174+
[/* empty usages */]),
175+
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a private key.' });
167176
}
168177

169178
async function testImportJwk({ name, publicUsages, privateUsages }, extractable) {
@@ -311,6 +320,15 @@ async function testImportJwk({ name, publicUsages, privateUsages }, extractable)
311320
publicUsages),
312321
{ message: 'JWK "crv" Parameter and algorithm name mismatch' });
313322
}
323+
324+
await assert.rejects(
325+
subtle.importKey(
326+
'jwk',
327+
{ ...jwk },
328+
{ name },
329+
extractable,
330+
[/* empty usages */]),
331+
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a private key.' });
314332
}
315333

316334
async function testImportRaw({ name, publicUsages }) {

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

+18
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,15 @@ async function testImportPkcs8(
164164
message: /key is not extractable/
165165
});
166166
}
167+
168+
await assert.rejects(
169+
subtle.importKey(
170+
'pkcs8',
171+
keyData[namedCurve].pkcs8,
172+
{ name, namedCurve },
173+
extractable,
174+
[/* empty usages */]),
175+
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a private key.' });
167176
}
168177

169178
async function testImportJwk(
@@ -312,6 +321,15 @@ async function testImportJwk(
312321
privateUsages),
313322
{ message: 'JWK "crv" does not match the requested algorithm' });
314323
}
324+
325+
await assert.rejects(
326+
subtle.importKey(
327+
'jwk',
328+
{ ...jwk },
329+
{ name, namedCurve },
330+
extractable,
331+
[/* empty usages */]),
332+
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a private key.' });
315333
}
316334

317335
async function testImportRaw({ name, publicUsages }, namedCurve) {

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

+18
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,15 @@ async function testImportPkcs8(
361361
message: /key is not extractable/
362362
});
363363
}
364+
365+
await assert.rejects(
366+
subtle.importKey(
367+
'pkcs8',
368+
keyData[size].pkcs8,
369+
{ name, hash },
370+
extractable,
371+
[/* empty usages */]),
372+
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a private key.' });
364373
}
365374

366375
async function testImportJwk(
@@ -495,6 +504,15 @@ async function testImportJwk(
495504
privateUsages),
496505
{ message: 'JWK "alg" does not match the requested algorithm' });
497506
}
507+
508+
await assert.rejects(
509+
subtle.importKey(
510+
'jwk',
511+
{ ...jwk },
512+
{ name, hash },
513+
extractable,
514+
[/* empty usages */]),
515+
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a private key.' });
498516
}
499517

500518
// combinations to test

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

+24
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,18 @@ const { subtle } = globalThis.crypto;
9595
assert.deepStrictEqual(
9696
Buffer.from(jwk.k, 'base64').toString('hex'),
9797
Buffer.from(raw).toString('hex'));
98+
99+
await assert.rejects(
100+
subtle.importKey(
101+
'raw',
102+
keyData,
103+
{
104+
name: 'HMAC',
105+
hash: 'SHA-256'
106+
},
107+
true,
108+
[/* empty usages */]),
109+
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a secret key.' });
98110
}
99111

100112
test().then(common.mustCall());
@@ -125,6 +137,18 @@ const { subtle } = globalThis.crypto;
125137
assert.deepStrictEqual(
126138
Buffer.from(jwk.k, 'base64').toString('hex'),
127139
Buffer.from(raw).toString('hex'));
140+
141+
await assert.rejects(
142+
subtle.importKey(
143+
'raw',
144+
keyData,
145+
{
146+
name: 'AES-CTR',
147+
length: 256,
148+
},
149+
true,
150+
[/* empty usages */]),
151+
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a secret key.' });
128152
}
129153

130154
test().then(common.mustCall());

test/parallel/test-webcrypto-sign-verify-ecdsa.js

-13
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ async function testSign({ name,
149149
plaintext }) {
150150
const [
151151
publicKey,
152-
noSignPrivateKey,
153152
privateKey,
154153
hmacKey,
155154
rsaKeys,
@@ -161,12 +160,6 @@ async function testSign({ name,
161160
{ name, namedCurve },
162161
false,
163162
['verify']),
164-
subtle.importKey(
165-
'pkcs8',
166-
privateKeyBuffer,
167-
{ name, namedCurve },
168-
false,
169-
[ /* No usages */ ]),
170163
subtle.importKey(
171164
'pkcs8',
172165
privateKeyBuffer,
@@ -214,12 +207,6 @@ async function testSign({ name,
214207
message: /Unable to use this key to sign/
215208
});
216209

217-
// Test failure when no sign usage
218-
await assert.rejects(
219-
subtle.sign({ name, hash }, noSignPrivateKey, plaintext), {
220-
message: /Unable to use this key to sign/
221-
});
222-
223210
// Test failure when using the wrong algorithms
224211
await assert.rejects(
225212
subtle.sign({ name, hash }, hmacKey, plaintext), {

test/parallel/test-webcrypto-sign-verify-eddsa.js

-13
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ async function testSign({ name,
131131
data }) {
132132
const [
133133
publicKey,
134-
noSignPrivateKey,
135134
privateKey,
136135
hmacKey,
137136
rsaKeys,
@@ -143,12 +142,6 @@ async function testSign({ name,
143142
{ name },
144143
false,
145144
['verify']),
146-
subtle.importKey(
147-
'pkcs8',
148-
privateKeyBuffer,
149-
{ name },
150-
false,
151-
[ /* No usages */ ]),
152145
subtle.importKey(
153146
'pkcs8',
154147
privateKeyBuffer,
@@ -197,12 +190,6 @@ async function testSign({ name,
197190
message: /Unable to use this key to sign/
198191
});
199192

200-
// Test failure when no sign usage
201-
await assert.rejects(
202-
subtle.sign({ name }, noSignPrivateKey, data), {
203-
message: /Unable to use this key to sign/
204-
});
205-
206193
// Test failure when using the wrong algorithms
207194
await assert.rejects(
208195
subtle.sign({ name }, hmacKey, data), {

test/parallel/test-webcrypto-sign-verify-hmac.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ async function testVerify({ hash,
3131
keyBuffer,
3232
{ name, hash },
3333
false,
34-
[ /* No usages */ ]),
34+
['sign']),
3535
subtle.generateKey(
3636
{
3737
name: 'RSA-PSS',

test/parallel/test-webcrypto-sign-verify-rsa.js

-13
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ async function testSign({
132132
}) {
133133
const [
134134
publicKey,
135-
noSignPrivateKey,
136135
privateKey,
137136
hmacKey,
138137
ecdsaKeys,
@@ -143,12 +142,6 @@ async function testSign({
143142
{ name: algorithm.name, hash },
144143
false,
145144
['verify']),
146-
subtle.importKey(
147-
'pkcs8',
148-
privateKeyBuffer,
149-
{ name: algorithm.name, hash },
150-
false,
151-
[ /* No usages */ ]),
152145
subtle.importKey(
153146
'pkcs8',
154147
privateKeyBuffer,
@@ -189,12 +182,6 @@ async function testSign({
189182
message: /Unable to use this key to sign/
190183
});
191184

192-
// Test failure when no sign usage
193-
await assert.rejects(
194-
subtle.sign(algorithm, noSignPrivateKey, plaintext), {
195-
message: /Unable to use this key to sign/
196-
});
197-
198185
// Test failure when using the wrong algorithms
199186
await assert.rejects(
200187
subtle.sign(algorithm, hmacKey, plaintext), {

0 commit comments

Comments
 (0)