Skip to content

Commit de1338d

Browse files
panvaMoLow
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 81d8d95 commit de1338d

9 files changed

+101
-47
lines changed

lib/internal/crypto/webcrypto.js

+22-7
Original file line numberDiff line numberDiff line change
@@ -600,52 +600,67 @@ async function importKey(
600600
});
601601

602602
algorithm = normalizeAlgorithm(algorithm, 'importKey');
603+
let result;
603604
switch (algorithm.name) {
604605
case 'RSASSA-PKCS1-v1_5':
605606
// Fall through
606607
case 'RSA-PSS':
607608
// Fall through
608609
case 'RSA-OAEP':
609-
return require('internal/crypto/rsa')
610+
result = await require('internal/crypto/rsa')
610611
.rsaImportKey(format, keyData, algorithm, extractable, keyUsages);
612+
break;
611613
case 'ECDSA':
612614
// Fall through
613615
case 'ECDH':
614-
return require('internal/crypto/ec')
616+
result = await require('internal/crypto/ec')
615617
.ecImportKey(format, keyData, algorithm, extractable, keyUsages);
618+
break;
616619
case 'Ed25519':
617620
// Fall through
618621
case 'Ed448':
619622
// Fall through
620623
case 'X25519':
621624
// Fall through
622625
case 'X448':
623-
return require('internal/crypto/cfrg')
626+
result = await require('internal/crypto/cfrg')
624627
.cfrgImportKey(format, keyData, algorithm, extractable, keyUsages);
628+
break;
625629
case 'HMAC':
626-
return require('internal/crypto/mac')
630+
result = await require('internal/crypto/mac')
627631
.hmacImportKey(format, keyData, algorithm, extractable, keyUsages);
632+
break;
628633
case 'AES-CTR':
629634
// Fall through
630635
case 'AES-CBC':
631636
// Fall through
632637
case 'AES-GCM':
633638
// Fall through
634639
case 'AES-KW':
635-
return require('internal/crypto/aes')
640+
result = await require('internal/crypto/aes')
636641
.aesImportKey(algorithm, format, keyData, extractable, keyUsages);
642+
break;
637643
case 'HKDF':
638644
// Fall through
639645
case 'PBKDF2':
640-
return importGenericSecretKey(
646+
result = await importGenericSecretKey(
641647
algorithm,
642648
format,
643649
keyData,
644650
extractable,
645651
keyUsages);
652+
break;
653+
default:
654+
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
646655
}
647656

648-
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
657+
if ((result.type === 'secret' || result.type === 'private') && result.usages.length === 0) {
658+
throw lazyDOMException(
659+
`Usages cannot be empty when importing a ${result.type} key.`,
660+
'SyntaxError');
661+
}
662+
663+
return result;
649664
}
650665

651666
// 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
@@ -96,6 +96,18 @@ const { subtle } = webcrypto;
9696
assert.deepStrictEqual(
9797
Buffer.from(jwk.k, 'base64').toString('hex'),
9898
Buffer.from(raw).toString('hex'));
99+
100+
await assert.rejects(
101+
subtle.importKey(
102+
'raw',
103+
keyData,
104+
{
105+
name: 'HMAC',
106+
hash: 'SHA-256'
107+
},
108+
true,
109+
[/* empty usages */]),
110+
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a secret key.' });
99111
}
100112

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

131155
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)