mirror of
https://github.com/nodejs/node.git
synced 2025-05-13 05:38:36 +00:00

This will be a start to generalize all argument validation errors. As currently we throw ARG/OPT, OUT_OF_RANGE, and other more specific errors. The OPT errors didn't bring much to the errors as it's just another variant of ARG error which is sometimes more confusing (some of our code used OPT errors to denote just argument validation errors presumably because of similarity of OPT to 'option' and not 'options-object') and they don't specify the name of the options object where the invalid value is located. Much better approach would be to just specify path to the invalid value in the name of the value as it is done in this PR (i.e. 'options.format', 'options.publicKey.type' etc) Also since this decreases a variety of errors we have it'd be easier to reuse validation code across the codebase. Refs: https://github.com/nodejs/node/pull/31251 Refs: https://github.com/nodejs/node/pull/34070#discussion_r467251009 Signed-off-by: Denys Otrishko <shishugi@gmail.com> PR-URL: https://github.com/nodejs/node/pull/34682 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
236 lines
5.8 KiB
JavaScript
236 lines
5.8 KiB
JavaScript
'use strict';
|
|
|
|
const {
|
|
ObjectSetPrototypeOf,
|
|
} = primordials;
|
|
|
|
const {
|
|
ERR_CRYPTO_SIGN_KEY_REQUIRED,
|
|
ERR_INVALID_ARG_TYPE,
|
|
ERR_INVALID_ARG_VALUE,
|
|
} = require('internal/errors').codes;
|
|
const { validateEncoding, validateString } = require('internal/validators');
|
|
const {
|
|
Sign: _Sign,
|
|
Verify: _Verify,
|
|
kSigEncDER,
|
|
kSigEncP1363,
|
|
signOneShot: _signOneShot,
|
|
verifyOneShot: _verifyOneShot
|
|
} = internalBinding('crypto');
|
|
const {
|
|
getDefaultEncoding,
|
|
kHandle,
|
|
getArrayBufferView,
|
|
} = require('internal/crypto/util');
|
|
const {
|
|
preparePrivateKey,
|
|
preparePublicOrPrivateKey
|
|
} = require('internal/crypto/keys');
|
|
const { Writable } = require('stream');
|
|
const { isArrayBufferView } = require('internal/util/types');
|
|
|
|
function Sign(algorithm, options) {
|
|
if (!(this instanceof Sign))
|
|
return new Sign(algorithm, options);
|
|
validateString(algorithm, 'algorithm');
|
|
this[kHandle] = new _Sign();
|
|
this[kHandle].init(algorithm);
|
|
|
|
Writable.call(this, options);
|
|
}
|
|
|
|
ObjectSetPrototypeOf(Sign.prototype, Writable.prototype);
|
|
ObjectSetPrototypeOf(Sign, Writable);
|
|
|
|
Sign.prototype._write = function _write(chunk, encoding, callback) {
|
|
this.update(chunk, encoding);
|
|
callback();
|
|
};
|
|
|
|
Sign.prototype.update = function update(data, encoding) {
|
|
encoding = encoding || getDefaultEncoding();
|
|
|
|
if (typeof data === 'string') {
|
|
validateEncoding(data, encoding);
|
|
} else if (!isArrayBufferView(data)) {
|
|
throw new ERR_INVALID_ARG_TYPE(
|
|
'data', ['string', 'Buffer', 'TypedArray', 'DataView'], data);
|
|
}
|
|
|
|
this[kHandle].update(data, encoding);
|
|
return this;
|
|
};
|
|
|
|
function getPadding(options) {
|
|
return getIntOption('padding', options);
|
|
}
|
|
|
|
function getSaltLength(options) {
|
|
return getIntOption('saltLength', options);
|
|
}
|
|
|
|
function getDSASignatureEncoding(options) {
|
|
if (typeof options === 'object') {
|
|
const { dsaEncoding = 'der' } = options;
|
|
if (dsaEncoding === 'der')
|
|
return kSigEncDER;
|
|
else if (dsaEncoding === 'ieee-p1363')
|
|
return kSigEncP1363;
|
|
throw new ERR_INVALID_ARG_VALUE('options.dsaEncoding', dsaEncoding);
|
|
}
|
|
|
|
return kSigEncDER;
|
|
}
|
|
|
|
function getIntOption(name, options) {
|
|
const value = options[name];
|
|
if (value !== undefined) {
|
|
if (value === value >> 0) {
|
|
return value;
|
|
}
|
|
throw new ERR_INVALID_ARG_VALUE(`options.${name}`, value);
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
Sign.prototype.sign = function sign(options, encoding) {
|
|
if (!options)
|
|
throw new ERR_CRYPTO_SIGN_KEY_REQUIRED();
|
|
|
|
const { data, format, type, passphrase } = preparePrivateKey(options, true);
|
|
|
|
// Options specific to RSA
|
|
const rsaPadding = getPadding(options);
|
|
const pssSaltLength = getSaltLength(options);
|
|
|
|
// Options specific to (EC)DSA
|
|
const dsaSigEnc = getDSASignatureEncoding(options);
|
|
|
|
const ret = this[kHandle].sign(data, format, type, passphrase, rsaPadding,
|
|
pssSaltLength, dsaSigEnc);
|
|
|
|
encoding = encoding || getDefaultEncoding();
|
|
if (encoding && encoding !== 'buffer')
|
|
return ret.toString(encoding);
|
|
|
|
return ret;
|
|
};
|
|
|
|
function signOneShot(algorithm, data, key) {
|
|
if (algorithm != null)
|
|
validateString(algorithm, 'algorithm');
|
|
|
|
if (!isArrayBufferView(data)) {
|
|
throw new ERR_INVALID_ARG_TYPE(
|
|
'data',
|
|
['Buffer', 'TypedArray', 'DataView'],
|
|
data
|
|
);
|
|
}
|
|
|
|
if (!key)
|
|
throw new ERR_CRYPTO_SIGN_KEY_REQUIRED();
|
|
|
|
const {
|
|
data: keyData,
|
|
format: keyFormat,
|
|
type: keyType,
|
|
passphrase: keyPassphrase
|
|
} = preparePrivateKey(key);
|
|
|
|
// Options specific to RSA
|
|
const rsaPadding = getPadding(key);
|
|
const pssSaltLength = getSaltLength(key);
|
|
|
|
// Options specific to (EC)DSA
|
|
const dsaSigEnc = getDSASignatureEncoding(key);
|
|
|
|
return _signOneShot(keyData, keyFormat, keyType, keyPassphrase, data,
|
|
algorithm, rsaPadding, pssSaltLength, dsaSigEnc);
|
|
}
|
|
|
|
function Verify(algorithm, options) {
|
|
if (!(this instanceof Verify))
|
|
return new Verify(algorithm, options);
|
|
validateString(algorithm, 'algorithm');
|
|
this[kHandle] = new _Verify();
|
|
this[kHandle].init(algorithm);
|
|
|
|
Writable.call(this, options);
|
|
}
|
|
|
|
ObjectSetPrototypeOf(Verify.prototype, Writable.prototype);
|
|
ObjectSetPrototypeOf(Verify, Writable);
|
|
|
|
Verify.prototype._write = Sign.prototype._write;
|
|
Verify.prototype.update = Sign.prototype.update;
|
|
|
|
Verify.prototype.verify = function verify(options, signature, sigEncoding) {
|
|
const {
|
|
data,
|
|
format,
|
|
type,
|
|
passphrase
|
|
} = preparePublicOrPrivateKey(options, true);
|
|
|
|
sigEncoding = sigEncoding || getDefaultEncoding();
|
|
|
|
// Options specific to RSA
|
|
const rsaPadding = getPadding(options);
|
|
const pssSaltLength = getSaltLength(options);
|
|
|
|
// Options specific to (EC)DSA
|
|
const dsaSigEnc = getDSASignatureEncoding(options);
|
|
|
|
signature = getArrayBufferView(signature, 'signature', sigEncoding);
|
|
|
|
return this[kHandle].verify(data, format, type, passphrase, signature,
|
|
rsaPadding, pssSaltLength, dsaSigEnc);
|
|
};
|
|
|
|
function verifyOneShot(algorithm, data, key, signature) {
|
|
if (algorithm != null)
|
|
validateString(algorithm, 'algorithm');
|
|
|
|
if (!isArrayBufferView(data)) {
|
|
throw new ERR_INVALID_ARG_TYPE(
|
|
'data',
|
|
['Buffer', 'TypedArray', 'DataView'],
|
|
data
|
|
);
|
|
}
|
|
|
|
const {
|
|
data: keyData,
|
|
format: keyFormat,
|
|
type: keyType,
|
|
passphrase: keyPassphrase
|
|
} = preparePublicOrPrivateKey(key);
|
|
|
|
// Options specific to RSA
|
|
const rsaPadding = getPadding(key);
|
|
const pssSaltLength = getSaltLength(key);
|
|
|
|
// Options specific to (EC)DSA
|
|
const dsaSigEnc = getDSASignatureEncoding(key);
|
|
|
|
if (!isArrayBufferView(signature)) {
|
|
throw new ERR_INVALID_ARG_TYPE(
|
|
'signature',
|
|
['Buffer', 'TypedArray', 'DataView'],
|
|
signature
|
|
);
|
|
}
|
|
|
|
return _verifyOneShot(keyData, keyFormat, keyType, keyPassphrase, signature,
|
|
data, algorithm, rsaPadding, pssSaltLength, dsaSigEnc);
|
|
}
|
|
|
|
module.exports = {
|
|
Sign,
|
|
signOneShot,
|
|
Verify,
|
|
verifyOneShot
|
|
};
|