Skip to content

Commit 2c938d7

Browse files
panvajuanarbol
authored andcommittedOct 11, 2022
crypto: fix webcrypto operation errors to be OperationError
PR-URL: #44171 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Backport-PR-URL: #44872
1 parent a6e2cb4 commit 2c938d7

File tree

9 files changed

+185
-205
lines changed

9 files changed

+185
-205
lines changed
 

‎lib/internal/crypto/aes.js

+15-17
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ const {
77
ArrayPrototypeIncludes,
88
ArrayPrototypePush,
99
MathFloor,
10-
Promise,
1110
SafeSet,
1211
TypedArrayPrototypeSlice,
1312
} = primordials;
@@ -46,6 +45,7 @@ const {
4645

4746
const {
4847
lazyDOMException,
48+
promisify,
4949
} = require('internal/util');
5050

5151
const { PromiseReject } = primordials;
@@ -57,11 +57,12 @@ const {
5757
} = require('internal/crypto/keys');
5858

5959
const {
60-
generateKey,
60+
generateKey: _generateKey,
6161
} = require('internal/crypto/keygen');
6262

6363
const kMaxCounterLength = 128;
6464
const kTagLengths = [32, 64, 96, 104, 112, 120, 128];
65+
const generateKey = promisify(_generateKey);
6566

6667
function getAlgorithmName(name, length) {
6768
switch (name) {
@@ -239,22 +240,19 @@ async function aesGenerateKey(algorithm, extractable, keyUsages) {
239240
'SyntaxError');
240241
}
241242

242-
return new Promise((resolve, reject) => {
243-
generateKey('aes', { length }, (err, key) => {
244-
if (err) {
245-
return reject(lazyDOMException(
246-
'The operation failed for an operation-specific reason ' +
247-
`[${err.message}]`,
248-
'OperationError'));
249-
}
250-
251-
resolve(new InternalCryptoKey(
252-
key,
253-
{ name, length },
254-
ArrayFrom(usagesSet),
255-
extractable));
256-
});
243+
const key = await generateKey('aes', { length }).catch((err) => {
244+
// TODO(@panva): add err as cause to DOMException
245+
throw lazyDOMException(
246+
'The operation failed for an operation-specific reason' +
247+
`[${err.message}]`,
248+
'OperationError');
257249
});
250+
251+
return new InternalCryptoKey(
252+
key,
253+
{ name, length },
254+
ArrayFrom(usagesSet),
255+
extractable);
258256
}
259257

260258
async function aesImportKey(

‎lib/internal/crypto/cfrg.js

+58-58
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict';
22

33
const {
4-
Promise,
54
SafeSet,
65
} = primordials;
76

@@ -31,10 +30,11 @@ const {
3130
const {
3231
emitExperimentalWarning,
3332
lazyDOMException,
33+
promisify,
3434
} = require('internal/util');
3535

3636
const {
37-
generateKeyPair,
37+
generateKeyPair: _generateKeyPair,
3838
} = require('internal/crypto/keygen');
3939

4040
const {
@@ -45,6 +45,8 @@ const {
4545
createPublicKey,
4646
} = require('internal/crypto/keys');
4747

48+
const generateKeyPair = promisify(_generateKeyPair);
49+
4850
function verifyAcceptableCfrgKeyUse(name, type, usages) {
4951
let checkSet;
5052
switch (name) {
@@ -131,65 +133,63 @@ async function cfrgGenerateKey(algorithm, extractable, keyUsages) {
131133
}
132134
break;
133135
}
134-
return new Promise((resolve, reject) => {
135-
let genKeyType;
136-
switch (name) {
137-
case 'Ed25519':
138-
genKeyType = 'ed25519';
139-
break;
140-
case 'Ed448':
141-
genKeyType = 'ed448';
142-
break;
143-
case 'X25519':
144-
genKeyType = 'x25519';
145-
break;
146-
case 'X448':
147-
genKeyType = 'x448';
148-
break;
149-
}
150-
generateKeyPair(genKeyType, undefined, (err, pubKey, privKey) => {
151-
if (err) {
152-
return reject(lazyDOMException(
153-
'The operation failed for an operation-specific reason',
154-
'OperationError'));
155-
}
136+
let genKeyType;
137+
switch (name) {
138+
case 'Ed25519':
139+
genKeyType = 'ed25519';
140+
break;
141+
case 'Ed448':
142+
genKeyType = 'ed448';
143+
break;
144+
case 'X25519':
145+
genKeyType = 'x25519';
146+
break;
147+
case 'X448':
148+
genKeyType = 'x448';
149+
break;
150+
}
156151

157-
const algorithm = { name };
152+
const keyPair = await generateKeyPair(genKeyType).catch((err) => {
153+
// TODO(@panva): add err as cause to DOMException
154+
throw lazyDOMException(
155+
'The operation failed for an operation-specific reason',
156+
'OperationError');
157+
});
158158

159-
let publicUsages;
160-
let privateUsages;
161-
switch (name) {
162-
case 'Ed25519':
163-
// Fall through
164-
case 'Ed448':
165-
publicUsages = getUsagesUnion(usageSet, 'verify');
166-
privateUsages = getUsagesUnion(usageSet, 'sign');
167-
break;
168-
case 'X25519':
169-
// Fall through
170-
case 'X448':
171-
publicUsages = [];
172-
privateUsages = getUsagesUnion(usageSet, 'deriveKey', 'deriveBits');
173-
break;
174-
}
159+
let publicUsages;
160+
let privateUsages;
161+
switch (name) {
162+
case 'Ed25519':
163+
// Fall through
164+
case 'Ed448':
165+
publicUsages = getUsagesUnion(usageSet, 'verify');
166+
privateUsages = getUsagesUnion(usageSet, 'sign');
167+
break;
168+
case 'X25519':
169+
// Fall through
170+
case 'X448':
171+
publicUsages = [];
172+
privateUsages = getUsagesUnion(usageSet, 'deriveKey', 'deriveBits');
173+
break;
174+
}
175175

176-
const publicKey =
177-
new InternalCryptoKey(
178-
pubKey,
179-
algorithm,
180-
publicUsages,
181-
true);
182-
183-
const privateKey =
184-
new InternalCryptoKey(
185-
privKey,
186-
algorithm,
187-
privateUsages,
188-
extractable);
189-
190-
resolve({ publicKey, privateKey });
191-
});
192-
});
176+
const keyAlgorithm = { name };
177+
178+
const publicKey =
179+
new InternalCryptoKey(
180+
keyPair.publicKey,
181+
keyAlgorithm,
182+
publicUsages,
183+
true);
184+
185+
const privateKey =
186+
new InternalCryptoKey(
187+
keyPair.privateKey,
188+
keyAlgorithm,
189+
privateUsages,
190+
extractable);
191+
192+
return { privateKey, publicKey };
193193
}
194194

195195
function cfrgExportKey(key, format) {

‎lib/internal/crypto/ec.js

+39-39
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
const {
44
ObjectKeys,
5-
Promise,
65
SafeSet,
76
} = primordials;
87

@@ -42,10 +41,11 @@ const {
4241

4342
const {
4443
lazyDOMException,
44+
promisify,
4545
} = require('internal/util');
4646

4747
const {
48-
generateKeyPair,
48+
generateKeyPair: _generateKeyPair,
4949
} = require('internal/crypto/keygen');
5050

5151
const {
@@ -56,6 +56,8 @@ const {
5656
createPublicKey,
5757
} = require('internal/crypto/keys');
5858

59+
const generateKeyPair = promisify(_generateKeyPair);
60+
5961
function verifyAcceptableEcKeyUse(name, type, usages) {
6062
let checkSet;
6163
switch (name) {
@@ -111,46 +113,44 @@ async function ecGenerateKey(algorithm, extractable, keyUsages) {
111113
}
112114
// Fall through
113115
}
114-
return new Promise((resolve, reject) => {
115-
generateKeyPair('ec', { namedCurve }, (err, pubKey, privKey) => {
116-
if (err) {
117-
return reject(lazyDOMException(
118-
'The operation failed for an operation-specific reason',
119-
'OperationError'));
120-
}
121116

122-
const algorithm = { name, namedCurve };
117+
const keypair = await generateKeyPair('ec', { namedCurve }).catch((err) => {
118+
// TODO(@panva): add err as cause to DOMException
119+
throw lazyDOMException(
120+
'The operation failed for an operation-specific reason',
121+
'OperationError');
122+
});
123123

124-
let publicUsages;
125-
let privateUsages;
126-
switch (name) {
127-
case 'ECDSA':
128-
publicUsages = getUsagesUnion(usageSet, 'verify');
129-
privateUsages = getUsagesUnion(usageSet, 'sign');
130-
break;
131-
case 'ECDH':
132-
publicUsages = [];
133-
privateUsages = getUsagesUnion(usageSet, 'deriveKey', 'deriveBits');
134-
break;
135-
}
124+
let publicUsages;
125+
let privateUsages;
126+
switch (name) {
127+
case 'ECDSA':
128+
publicUsages = getUsagesUnion(usageSet, 'verify');
129+
privateUsages = getUsagesUnion(usageSet, 'sign');
130+
break;
131+
case 'ECDH':
132+
publicUsages = [];
133+
privateUsages = getUsagesUnion(usageSet, 'deriveKey', 'deriveBits');
134+
break;
135+
}
136136

137-
const publicKey =
138-
new InternalCryptoKey(
139-
pubKey,
140-
algorithm,
141-
publicUsages,
142-
true);
143-
144-
const privateKey =
145-
new InternalCryptoKey(
146-
privKey,
147-
algorithm,
148-
privateUsages,
149-
extractable);
150-
151-
resolve({ publicKey, privateKey });
152-
});
153-
});
137+
const keyAlgorithm = { name, namedCurve };
138+
139+
const publicKey =
140+
new InternalCryptoKey(
141+
keypair.publicKey,
142+
keyAlgorithm,
143+
publicUsages,
144+
true);
145+
146+
const privateKey =
147+
new InternalCryptoKey(
148+
keypair.privateKey,
149+
keyAlgorithm,
150+
privateUsages,
151+
extractable);
152+
153+
return { publicKey, privateKey };
154154
}
155155

156156
function ecExportKey(key, format) {

‎lib/internal/crypto/mac.js

+15-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
const {
44
ArrayFrom,
5-
Promise,
65
SafeSet,
76
} = primordials;
87

@@ -27,6 +26,7 @@ const {
2726

2827
const {
2928
lazyDOMException,
29+
promisify,
3030
} = require('internal/util');
3131

3232
const {
@@ -36,7 +36,7 @@ const {
3636
} = require('internal/errors');
3737

3838
const {
39-
generateKey,
39+
generateKey: _generateKey,
4040
} = require('internal/crypto/keygen');
4141

4242
const {
@@ -45,6 +45,8 @@ const {
4545
createSecretKey,
4646
} = require('internal/crypto/keys');
4747

48+
const generateKey = promisify(_generateKey);
49+
4850
async function hmacGenerateKey(algorithm, extractable, keyUsages) {
4951
const { hash, name } = algorithm;
5052
let { length } = algorithm;
@@ -62,21 +64,19 @@ async function hmacGenerateKey(algorithm, extractable, keyUsages) {
6264
'Unsupported key usage for an HMAC key',
6365
'SyntaxError');
6466
}
65-
return new Promise((resolve, reject) => {
66-
generateKey('hmac', { length }, (err, key) => {
67-
if (err) {
68-
return reject(lazyDOMException(
69-
'The operation failed for an operation-specific reason',
70-
'OperationError'));
71-
}
7267

73-
resolve(new InternalCryptoKey(
74-
key,
75-
{ name, length, hash: { name: hash.name } },
76-
ArrayFrom(usageSet),
77-
extractable));
78-
});
68+
const key = await generateKey('hmac', { length }).catch((err) => {
69+
// TODO(@panva): add err as cause to DOMException
70+
throw lazyDOMException(
71+
'The operation failed for an operation-specific reason',
72+
'OperationError');
7973
});
74+
75+
return new InternalCryptoKey(
76+
key,
77+
{ name, length, hash: { name: hash.name } },
78+
ArrayFrom(usageSet),
79+
extractable);
8080
}
8181

8282
async function hmacImportKey(

‎lib/internal/crypto/rsa.js

+48-50
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict';
22

33
const {
4-
Promise,
54
SafeSet,
65
Uint8Array,
76
} = primordials;
@@ -49,6 +48,7 @@ const {
4948

5049
const {
5150
lazyDOMException,
51+
promisify,
5252
} = require('internal/util');
5353

5454
const {
@@ -64,14 +64,15 @@ const {
6464
} = require('internal/crypto/keys');
6565

6666
const {
67-
generateKeyPair,
67+
generateKeyPair: _generateKeyPair,
6868
} = require('internal/crypto/keygen');
6969

7070
const kRsaVariants = {
7171
'RSASSA-PKCS1-v1_5': kKeyVariantRSA_SSA_PKCS1_v1_5,
7272
'RSA-PSS': kKeyVariantRSA_PSS,
7373
'RSA-OAEP': kKeyVariantRSA_OAEP,
7474
};
75+
const generateKeyPair = promisify(_generateKeyPair);
7576

7677
function verifyAcceptableRsaKeyUse(name, type, usages) {
7778
let checkSet;
@@ -173,56 +174,53 @@ async function rsaKeyGenerate(
173174
}
174175
}
175176

176-
return new Promise((resolve, reject) => {
177-
generateKeyPair('rsa', {
178-
modulusLength,
179-
publicExponent: publicExponentConverted,
180-
}, (err, pubKey, privKey) => {
181-
if (err) {
182-
return reject(lazyDOMException(
183-
'The operation failed for an operation-specific reason',
184-
'OperationError'));
185-
}
177+
const keypair = await generateKeyPair('rsa', {
178+
modulusLength,
179+
publicExponent: publicExponentConverted,
180+
}).catch((err) => {
181+
// TODO(@panva): add err as cause to DOMException
182+
throw lazyDOMException(
183+
'The operation failed for an operation-specific reason',
184+
'OperationError');
185+
});
186186

187-
const algorithm = {
188-
name,
189-
modulusLength,
190-
publicExponent,
191-
hash: { name: hash.name }
192-
};
193-
194-
let publicUsages;
195-
let privateUsages;
196-
switch (name) {
197-
case 'RSA-OAEP': {
198-
publicUsages = getUsagesUnion(usageSet, 'encrypt', 'wrapKey');
199-
privateUsages = getUsagesUnion(usageSet, 'decrypt', 'unwrapKey');
200-
break;
201-
}
202-
default: {
203-
publicUsages = getUsagesUnion(usageSet, 'verify');
204-
privateUsages = getUsagesUnion(usageSet, 'sign');
205-
break;
206-
}
207-
}
187+
const keyAlgorithm = {
188+
name,
189+
modulusLength,
190+
publicExponent,
191+
hash: { name: hash.name }
192+
};
208193

209-
const publicKey =
210-
new InternalCryptoKey(
211-
pubKey,
212-
algorithm,
213-
publicUsages,
214-
true);
215-
216-
const privateKey =
217-
new InternalCryptoKey(
218-
privKey,
219-
algorithm,
220-
privateUsages,
221-
extractable);
222-
223-
resolve({ publicKey, privateKey });
224-
});
225-
});
194+
let publicUsages;
195+
let privateUsages;
196+
switch (name) {
197+
case 'RSA-OAEP': {
198+
publicUsages = getUsagesUnion(usageSet, 'encrypt', 'wrapKey');
199+
privateUsages = getUsagesUnion(usageSet, 'decrypt', 'unwrapKey');
200+
break;
201+
}
202+
default: {
203+
publicUsages = getUsagesUnion(usageSet, 'verify');
204+
privateUsages = getUsagesUnion(usageSet, 'sign');
205+
break;
206+
}
207+
}
208+
209+
const publicKey =
210+
new InternalCryptoKey(
211+
keypair.publicKey,
212+
keyAlgorithm,
213+
publicUsages,
214+
true);
215+
216+
const privateKey =
217+
new InternalCryptoKey(
218+
keypair.privateKey,
219+
keyAlgorithm,
220+
privateUsages,
221+
extractable);
222+
223+
return { publicKey, privateKey };
226224
}
227225

228226
function rsaExportKey(key, format) {

‎lib/internal/crypto/util.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,12 @@ const validateByteSource = hideStackFrames((val, name) => {
278278
});
279279

280280
function onDone(resolve, reject, err, result) {
281-
if (err) return reject(err);
281+
if (err) {
282+
// TODO(@panva): add err as cause to DOMException
283+
return reject(lazyDOMException(
284+
'The operation failed for an operation-specific reason',
285+
'OperationError'));
286+
}
282287
resolve(result);
283288
}
284289

‎test/parallel/test-webcrypto-encrypt-decrypt-aes.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ async function testDecrypt({ keyBuffer, algorithm, result }) {
119119

120120
decryptionFailing.forEach((vector) => {
121121
variations.push(assert.rejects(testDecrypt(vector), {
122-
message: /bad decrypt/
122+
name: 'OperationError'
123123
}));
124124
});
125125

@@ -158,7 +158,7 @@ async function testDecrypt({ keyBuffer, algorithm, result }) {
158158

159159
decryptionFailing.forEach((vector) => {
160160
variations.push(assert.rejects(testDecrypt(vector), {
161-
message: /bad decrypt/
161+
name: 'OperationError'
162162
}));
163163
});
164164

@@ -195,7 +195,7 @@ async function testDecrypt({ keyBuffer, algorithm, result }) {
195195

196196
decryptionFailing.forEach((vector) => {
197197
variations.push(assert.rejects(testDecrypt(vector), {
198-
message: /bad decrypt/
198+
name: 'OperationError'
199199
}));
200200
});
201201

‎test/parallel/test-webcrypto-encrypt-decrypt-rsa.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ async function testEncryptionLongPlaintext({ algorithm,
127127

128128
return assert.rejects(
129129
subtle.encrypt(algorithm, publicKey, newplaintext), {
130-
message: /data too large/
130+
name: 'OperationError'
131131
});
132132
}
133133

‎test/wpt/status/WebCryptoAPI.json

-21
Original file line numberDiff line numberDiff line change
@@ -2654,33 +2654,12 @@
26542654
"encrypt_decrypt/aes_cbc.https.any.js": {
26552655
"fail": {
26562656
"expected": [
2657-
"AES-CBC 128-bit key, zeroPadChar",
2658-
"AES-CBC 128-bit key, bigPadChar",
2659-
"AES-CBC 128-bit key, inconsistentPadChars",
2660-
"AES-CBC 192-bit key, zeroPadChar",
2661-
"AES-CBC 192-bit key, bigPadChar",
2662-
"AES-CBC 192-bit key, inconsistentPadChars",
2663-
"AES-CBC 256-bit key, zeroPadChar",
2664-
"AES-CBC 256-bit key, bigPadChar",
2665-
"AES-CBC 256-bit key, inconsistentPadChars"
26662657
]
26672658
}
26682659
},
26692660
"encrypt_decrypt/rsa_oaep.https.any.js": {
26702661
"fail": {
26712662
"expected": [
2672-
"RSA-OAEP with SHA-1 and no label too long plaintext",
2673-
"RSA-OAEP with SHA-256 and no label too long plaintext",
2674-
"RSA-OAEP with SHA-384 and no label too long plaintext",
2675-
"RSA-OAEP with SHA-512 and no label too long plaintext",
2676-
"RSA-OAEP with SHA-1 and empty label too long plaintext",
2677-
"RSA-OAEP with SHA-256 and empty label too long plaintext",
2678-
"RSA-OAEP with SHA-384 and empty label too long plaintext",
2679-
"RSA-OAEP with SHA-512 and empty label too long plaintext",
2680-
"RSA-OAEP with SHA-1 and a label too long plaintext",
2681-
"RSA-OAEP with SHA-256 and a label too long plaintext",
2682-
"RSA-OAEP with SHA-384 and a label too long plaintext",
2683-
"RSA-OAEP with SHA-512 and a label too long plaintext"
26842663
]
26852664
}
26862665
},

0 commit comments

Comments
 (0)
Please sign in to comment.