-
Notifications
You must be signed in to change notification settings - Fork 30.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
crypto: refactor to avoid unsafe array iteration #37364
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,10 +2,12 @@ | |
|
||
const { | ||
ArrayBufferPrototypeSlice, | ||
ArrayPrototypePush, | ||
FunctionPrototypeCall, | ||
MathFloor, | ||
ObjectDefineProperty, | ||
Promise, | ||
ReflectApply, | ||
SafeSet, | ||
} = primordials; | ||
|
||
|
@@ -347,16 +349,15 @@ function deriveBitsDH(publicKey, privateKey, callback) { | |
} | ||
|
||
function verifyAcceptableDhKeyUse(name, type, usages) { | ||
let checkSet; | ||
const args = [usages]; | ||
switch (type) { | ||
case 'private': | ||
checkSet = ['deriveBits', 'deriveKey']; | ||
ArrayPrototypePush(args, 'deriveBits', 'deriveKey'); | ||
break; | ||
case 'public': | ||
checkSet = []; | ||
break; | ||
} | ||
if (hasAnyNotIn(usages, ...checkSet)) { | ||
if (ReflectApply(hasAnyNotIn, null, args)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dito. |
||
throw lazyDOMException( | ||
`Unsupported key usage for an ${name} key`, | ||
'SyntaxError'); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,16 +51,16 @@ const { | |
} = require('internal/crypto/util'); | ||
|
||
function verifyAcceptableDsaKeyUse(name, type, usages) { | ||
let checkSet; | ||
let check; | ||
switch (type) { | ||
case 'private': | ||
checkSet = ['sign']; | ||
check = 'sign'; | ||
break; | ||
case 'public': | ||
checkSet = ['verify']; | ||
check = 'verify'; | ||
break; | ||
} | ||
if (hasAnyNotIn(usages, ...checkSet)) { | ||
if (hasAnyNotIn(usages, check)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dito. |
||
throw lazyDOMException( | ||
`Unsupported key usage for an ${name} key`, | ||
'SyntaxError'); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
'use strict'; | ||
|
||
const { | ||
ArrayPrototypePush, | ||
ObjectKeys, | ||
Promise, | ||
ReflectApply, | ||
SafeSet, | ||
} = primordials; | ||
|
||
|
@@ -59,10 +61,10 @@ const { | |
} = require('internal/crypto/keys'); | ||
|
||
function verifyAcceptableEcKeyUse(name, type, usages) { | ||
let checkSet; | ||
const args = [usages]; | ||
switch (name) { | ||
case 'ECDH': | ||
checkSet = ['deriveKey', 'deriveBits']; | ||
ArrayPrototypePush(args, 'deriveKey', 'deriveBits'); | ||
break; | ||
case 'NODE-ED25519': | ||
// Fall through | ||
|
@@ -71,14 +73,14 @@ function verifyAcceptableEcKeyUse(name, type, usages) { | |
case 'ECDSA': | ||
switch (type) { | ||
case 'private': | ||
checkSet = ['sign']; | ||
ArrayPrototypePush(args, 'sign'); | ||
break; | ||
case 'public': | ||
checkSet = ['verify']; | ||
ArrayPrototypePush(args, 'verify'); | ||
break; | ||
} | ||
} | ||
if (hasAnyNotIn(usages, ...checkSet)) { | ||
if (ReflectApply(hasAnyNotIn, null, args)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dito. |
||
throw lazyDOMException( | ||
`Unsupported key usage for a ${name} key`, | ||
'SyntaxError'); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
|
||
const { | ||
ArrayFrom, | ||
ArrayPrototypeSlice, | ||
ObjectDefineProperty, | ||
ObjectSetPrototypeOf, | ||
Symbol, | ||
|
@@ -160,6 +161,11 @@ const [ | |
} | ||
|
||
class AsymmetricKeyObject extends KeyObject { | ||
// eslint-disable-next-line no-useless-constructor | ||
constructor(type, handle) { | ||
super(type, handle); | ||
} | ||
aduh95 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
get asymmetricKeyType() { | ||
return this[kAsymmetricKeyType] || | ||
(this[kAsymmetricKeyType] = this[kHandle].getAsymmetricKeyType()); | ||
|
@@ -390,13 +396,21 @@ function getKeyObjectHandle(key, ctx) { | |
} | ||
|
||
function getKeyTypes(allowKeyObject, bufferOnly = false) { | ||
return [ | ||
const types = [ | ||
'ArrayBuffer', | ||
'Buffer', | ||
'TypedArray', | ||
'DataView', | ||
...(!bufferOnly ? ['string'] : []), | ||
...(!bufferOnly && allowKeyObject ? ['KeyObject', 'CryptoKey'] : [])]; | ||
'string', // Only if bufferOnly == false | ||
'KeyObject', // Only if allowKeyObject == true && bufferOnly == false | ||
'CryptoKey', // Only if allowKeyObject == true && bufferOnly == false | ||
]; | ||
if (bufferOnly) { | ||
return ArrayPrototypeSlice(types, 0, 4); | ||
} else if (!allowKeyObject) { | ||
return ArrayPrototypeSlice(types, 0, 5); | ||
} | ||
return types; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is so much less intuitive than the original implementation... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, I have considered using |
||
} | ||
|
||
function prepareAsymmetricKey(key, ctx) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
'use strict'; | ||
|
||
const { | ||
ArrayPrototypePush, | ||
Promise, | ||
ReflectApply, | ||
SafeSet, | ||
Uint8Array, | ||
} = primordials; | ||
|
@@ -71,29 +73,29 @@ const kRsaVariants = { | |
}; | ||
|
||
function verifyAcceptableRsaKeyUse(name, type, usages) { | ||
let checkSet; | ||
const args = [usages]; | ||
switch (name) { | ||
case 'RSA-OAEP': | ||
switch (type) { | ||
case 'private': | ||
checkSet = ['decrypt', 'unwrapKey']; | ||
ArrayPrototypePush(args, 'decrypt', 'unwrapKey'); | ||
break; | ||
case 'public': | ||
checkSet = ['encrypt', 'wrapKey']; | ||
ArrayPrototypePush(args, 'encrypt', 'wrapKey'); | ||
break; | ||
} | ||
break; | ||
default: | ||
switch (type) { | ||
case 'private': | ||
checkSet = ['sign']; | ||
ArrayPrototypePush(args, 'sign'); | ||
break; | ||
case 'public': | ||
checkSet = ['verify']; | ||
ArrayPrototypePush(args, 'verify'); | ||
break; | ||
} | ||
} | ||
if (hasAnyNotIn(usages, ...checkSet)) { | ||
if (ReflectApply(hasAnyNotIn, null, args)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dito. |
||
throw lazyDOMException( | ||
`Unsupported key usage for an ${name} key`, | ||
'SyntaxError'); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These call sites of
hasAnyNotIn
are much harder to read now, for no real benefit.It might be better to simply change
hasAnyNotIn
to accept an array as the second argument instead of a variable number of arguments.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I'll try that, if it doesn't have a negative perf impact I'm all for it.