2017-09-06 15:10:34 +00:00
|
|
|
'use strict';
|
|
|
|
|
2019-11-30 15:55:29 +00:00
|
|
|
const {
|
2023-01-17 08:57:58 +00:00
|
|
|
ArrayBufferIsView,
|
|
|
|
ArrayBufferPrototypeGetByteLength,
|
2020-08-25 17:05:51 +00:00
|
|
|
ArrayPrototypeIncludes,
|
|
|
|
ArrayPrototypePush,
|
2020-11-20 11:59:13 +00:00
|
|
|
BigInt,
|
2023-01-17 08:57:58 +00:00
|
|
|
DataViewPrototypeGetBuffer,
|
|
|
|
DataViewPrototypeGetByteLength,
|
|
|
|
DataViewPrototypeGetByteOffset,
|
2020-08-25 17:05:51 +00:00
|
|
|
FunctionPrototypeBind,
|
2021-01-04 17:06:26 +00:00
|
|
|
Number,
|
2024-08-30 21:50:10 +00:00
|
|
|
ObjectDefineProperty,
|
|
|
|
ObjectEntries,
|
2021-04-01 20:06:39 +00:00
|
|
|
ObjectKeys,
|
2023-01-17 08:57:58 +00:00
|
|
|
ObjectPrototypeHasOwnProperty,
|
2020-08-25 17:05:51 +00:00
|
|
|
Promise,
|
2023-01-17 08:57:58 +00:00
|
|
|
StringPrototypeToUpperCase,
|
2019-11-30 15:55:29 +00:00
|
|
|
Symbol,
|
2023-01-17 08:57:58 +00:00
|
|
|
TypedArrayPrototypeGetBuffer,
|
|
|
|
TypedArrayPrototypeGetByteLength,
|
|
|
|
TypedArrayPrototypeGetByteOffset,
|
|
|
|
TypedArrayPrototypeSlice,
|
|
|
|
Uint8Array,
|
2019-11-30 15:55:29 +00:00
|
|
|
} = primordials;
|
|
|
|
|
2017-09-06 15:10:34 +00:00
|
|
|
const {
|
|
|
|
getCiphers: _getCiphers,
|
|
|
|
getCurves: _getCurves,
|
|
|
|
getHashes: _getHashes,
|
2017-10-24 17:04:25 +00:00
|
|
|
setEngine: _setEngine,
|
2021-01-04 17:06:26 +00:00
|
|
|
secureHeapUsed: _secureHeapUsed,
|
2024-01-05 22:16:27 +00:00
|
|
|
getCachedAliases,
|
2018-08-21 06:54:02 +00:00
|
|
|
} = internalBinding('crypto');
|
2017-09-06 15:10:34 +00:00
|
|
|
|
2021-01-04 17:06:26 +00:00
|
|
|
const { getOptionValue } = require('internal/options');
|
|
|
|
|
2017-09-06 15:10:34 +00:00
|
|
|
const {
|
2020-08-25 17:05:51 +00:00
|
|
|
crypto: {
|
2023-02-28 11:14:11 +00:00
|
|
|
ENGINE_METHOD_ALL,
|
|
|
|
},
|
2020-08-25 17:05:51 +00:00
|
|
|
} = internalBinding('constants');
|
|
|
|
|
|
|
|
const normalizeHashName = require('internal/crypto/hashnames');
|
2017-09-06 15:10:34 +00:00
|
|
|
|
2018-03-04 21:16:24 +00:00
|
|
|
const {
|
2019-09-23 21:35:24 +00:00
|
|
|
codes: {
|
2023-05-15 15:39:11 +00:00
|
|
|
ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED,
|
2019-09-23 21:35:24 +00:00
|
|
|
ERR_CRYPTO_ENGINE_UNKNOWN,
|
|
|
|
ERR_INVALID_ARG_TYPE,
|
2020-08-25 17:05:51 +00:00
|
|
|
ERR_INVALID_ARG_VALUE,
|
|
|
|
ERR_OUT_OF_RANGE,
|
2023-02-28 11:14:11 +00:00
|
|
|
},
|
2024-04-23 17:05:38 +00:00
|
|
|
hideStackFrames,
|
2019-09-23 21:35:24 +00:00
|
|
|
} = require('internal/errors');
|
2020-08-25 17:05:51 +00:00
|
|
|
|
|
|
|
const {
|
|
|
|
validateArray,
|
2021-01-19 11:23:27 +00:00
|
|
|
validateNumber,
|
2023-02-28 11:14:11 +00:00
|
|
|
validateString,
|
2020-08-25 17:05:51 +00:00
|
|
|
} = require('internal/validators');
|
|
|
|
|
2017-09-06 15:10:34 +00:00
|
|
|
const { Buffer } = require('buffer');
|
2020-08-25 17:05:51 +00:00
|
|
|
|
2017-09-06 15:10:34 +00:00
|
|
|
const {
|
|
|
|
cachedResult,
|
2024-08-30 21:50:10 +00:00
|
|
|
emitExperimentalWarning,
|
2020-08-25 17:05:51 +00:00
|
|
|
filterDuplicateStrings,
|
2021-06-21 03:34:48 +00:00
|
|
|
lazyDOMException,
|
2017-09-06 15:10:34 +00:00
|
|
|
} = require('internal/util');
|
2020-08-25 17:05:51 +00:00
|
|
|
|
2024-01-05 22:16:27 +00:00
|
|
|
const {
|
|
|
|
namespace: {
|
|
|
|
isBuildingSnapshot,
|
|
|
|
addSerializeCallback,
|
|
|
|
},
|
|
|
|
} = require('internal/v8/startup_snapshot');
|
|
|
|
|
2017-10-24 17:04:25 +00:00
|
|
|
const {
|
2023-01-17 08:57:58 +00:00
|
|
|
isDataView,
|
2020-08-25 17:05:51 +00:00
|
|
|
isArrayBufferView,
|
|
|
|
isAnyArrayBuffer,
|
2017-10-24 17:04:25 +00:00
|
|
|
} = require('internal/util/types');
|
2017-09-06 15:10:34 +00:00
|
|
|
|
2018-09-05 09:55:00 +00:00
|
|
|
const kHandle = Symbol('kHandle');
|
2020-08-25 17:05:51 +00:00
|
|
|
const kKeyObject = Symbol('kKeyObject');
|
|
|
|
|
2017-09-06 15:10:34 +00:00
|
|
|
// This is here because many functions accepted binary strings without
|
|
|
|
// any explicit encoding in older versions of node, and we don't want
|
|
|
|
// to break them unnecessarily.
|
2019-03-20 12:05:12 +00:00
|
|
|
function toBuf(val, encoding) {
|
|
|
|
if (typeof val === 'string') {
|
|
|
|
if (encoding === 'buffer')
|
2017-09-06 15:10:34 +00:00
|
|
|
encoding = 'utf8';
|
2019-03-20 12:05:12 +00:00
|
|
|
return Buffer.from(val, encoding);
|
2017-09-06 15:10:34 +00:00
|
|
|
}
|
2019-03-20 12:05:12 +00:00
|
|
|
return val;
|
2017-09-06 15:10:34 +00:00
|
|
|
}
|
|
|
|
|
2024-01-05 22:16:27 +00:00
|
|
|
let _hashCache;
|
|
|
|
function getHashCache() {
|
|
|
|
if (_hashCache === undefined) {
|
|
|
|
_hashCache = getCachedAliases();
|
|
|
|
if (isBuildingSnapshot()) {
|
|
|
|
// For dynamic linking, clear the map.
|
|
|
|
addSerializeCallback(() => { _hashCache = undefined; });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return _hashCache;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getCachedHashId(algorithm) {
|
|
|
|
const result = getHashCache()[algorithm];
|
|
|
|
return result === undefined ? -1 : result;
|
|
|
|
}
|
|
|
|
|
2017-09-06 15:10:34 +00:00
|
|
|
const getCiphers = cachedResult(() => filterDuplicateStrings(_getCiphers()));
|
|
|
|
const getHashes = cachedResult(() => filterDuplicateStrings(_getHashes()));
|
|
|
|
const getCurves = cachedResult(() => filterDuplicateStrings(_getCurves()));
|
|
|
|
|
|
|
|
function setEngine(id, flags) {
|
2018-08-02 22:51:02 +00:00
|
|
|
validateString(id, 'id');
|
2021-01-19 11:23:27 +00:00
|
|
|
if (flags)
|
|
|
|
validateNumber(flags, 'flags');
|
2017-09-06 15:10:34 +00:00
|
|
|
flags = flags >>> 0;
|
|
|
|
|
|
|
|
// Use provided engine for everything by default
|
|
|
|
if (flags === 0)
|
|
|
|
flags = ENGINE_METHOD_ALL;
|
|
|
|
|
2023-05-15 15:39:11 +00:00
|
|
|
if (typeof _setEngine !== 'function')
|
|
|
|
throw new ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED();
|
2017-10-24 06:06:53 +00:00
|
|
|
if (!_setEngine(id, flags))
|
2018-03-04 21:16:24 +00:00
|
|
|
throw new ERR_CRYPTO_ENGINE_UNKNOWN(id);
|
2017-09-06 15:10:34 +00:00
|
|
|
}
|
|
|
|
|
2020-08-25 17:05:51 +00:00
|
|
|
const getArrayBufferOrView = hideStackFrames((buffer, name, encoding) => {
|
|
|
|
if (isAnyArrayBuffer(buffer))
|
|
|
|
return buffer;
|
2019-09-23 21:35:24 +00:00
|
|
|
if (typeof buffer === 'string') {
|
|
|
|
if (encoding === 'buffer')
|
|
|
|
encoding = 'utf8';
|
|
|
|
return Buffer.from(buffer, encoding);
|
|
|
|
}
|
2018-04-24 11:42:44 +00:00
|
|
|
if (!isArrayBufferView(buffer)) {
|
2023-11-11 16:25:08 +00:00
|
|
|
throw new ERR_INVALID_ARG_TYPE.HideStackFramesError(
|
2018-04-24 11:42:44 +00:00
|
|
|
name,
|
2020-08-25 17:05:51 +00:00
|
|
|
[
|
|
|
|
'string',
|
|
|
|
'ArrayBuffer',
|
|
|
|
'Buffer',
|
|
|
|
'TypedArray',
|
2021-02-06 13:36:58 +00:00
|
|
|
'DataView',
|
2020-08-25 17:05:51 +00:00
|
|
|
],
|
2023-02-14 17:45:16 +00:00
|
|
|
buffer,
|
2018-04-24 11:42:44 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
return buffer;
|
2019-09-23 21:35:24 +00:00
|
|
|
});
|
2018-04-24 11:42:44 +00:00
|
|
|
|
2020-08-25 17:05:51 +00:00
|
|
|
// The maximum buffer size that we'll support in the WebCrypto impl
|
|
|
|
const kMaxBufferLength = (2 ** 31) - 1;
|
|
|
|
|
|
|
|
// The EC named curves that we currently support via the Web Crypto API.
|
|
|
|
const kNamedCurveAliases = {
|
|
|
|
'P-256': 'prime256v1',
|
|
|
|
'P-384': 'secp384r1',
|
|
|
|
'P-521': 'secp521r1',
|
|
|
|
};
|
|
|
|
|
|
|
|
const kAesKeyLengths = [128, 192, 256];
|
|
|
|
|
2023-01-17 08:57:58 +00:00
|
|
|
const kSupportedAlgorithms = {
|
|
|
|
'digest': {
|
|
|
|
'SHA-1': null,
|
|
|
|
'SHA-256': null,
|
|
|
|
'SHA-384': null,
|
|
|
|
'SHA-512': null,
|
|
|
|
},
|
|
|
|
'generateKey': {
|
|
|
|
'RSASSA-PKCS1-v1_5': 'RsaHashedKeyGenParams',
|
|
|
|
'RSA-PSS': 'RsaHashedKeyGenParams',
|
|
|
|
'RSA-OAEP': 'RsaHashedKeyGenParams',
|
|
|
|
'ECDSA': 'EcKeyGenParams',
|
|
|
|
'ECDH': 'EcKeyGenParams',
|
|
|
|
'AES-CTR': 'AesKeyGenParams',
|
|
|
|
'AES-CBC': 'AesKeyGenParams',
|
|
|
|
'AES-GCM': 'AesKeyGenParams',
|
|
|
|
'AES-KW': 'AesKeyGenParams',
|
|
|
|
'HMAC': 'HmacKeyGenParams',
|
|
|
|
},
|
|
|
|
'sign': {
|
|
|
|
'RSASSA-PKCS1-v1_5': null,
|
|
|
|
'RSA-PSS': 'RsaPssParams',
|
|
|
|
'ECDSA': 'EcdsaParams',
|
|
|
|
'HMAC': null,
|
|
|
|
},
|
|
|
|
'verify': {
|
|
|
|
'RSASSA-PKCS1-v1_5': null,
|
|
|
|
'RSA-PSS': 'RsaPssParams',
|
|
|
|
'ECDSA': 'EcdsaParams',
|
|
|
|
'HMAC': null,
|
|
|
|
},
|
|
|
|
'importKey': {
|
|
|
|
'RSASSA-PKCS1-v1_5': 'RsaHashedImportParams',
|
|
|
|
'RSA-PSS': 'RsaHashedImportParams',
|
|
|
|
'RSA-OAEP': 'RsaHashedImportParams',
|
|
|
|
'ECDSA': 'EcKeyImportParams',
|
|
|
|
'ECDH': 'EcKeyImportParams',
|
|
|
|
'HMAC': 'HmacImportParams',
|
|
|
|
'HKDF': null,
|
|
|
|
'PBKDF2': null,
|
|
|
|
'AES-CTR': null,
|
|
|
|
'AES-CBC': null,
|
|
|
|
'AES-GCM': null,
|
|
|
|
'AES-KW': null,
|
|
|
|
},
|
|
|
|
'deriveBits': {
|
|
|
|
'HKDF': 'HkdfParams',
|
|
|
|
'PBKDF2': 'Pbkdf2Params',
|
|
|
|
'ECDH': 'EcdhKeyDeriveParams',
|
|
|
|
},
|
|
|
|
'encrypt': {
|
|
|
|
'RSA-OAEP': 'RsaOaepParams',
|
|
|
|
'AES-CBC': 'AesCbcParams',
|
|
|
|
'AES-GCM': 'AesGcmParams',
|
|
|
|
'AES-CTR': 'AesCtrParams',
|
|
|
|
},
|
|
|
|
'decrypt': {
|
|
|
|
'RSA-OAEP': 'RsaOaepParams',
|
|
|
|
'AES-CBC': 'AesCbcParams',
|
|
|
|
'AES-GCM': 'AesGcmParams',
|
|
|
|
'AES-CTR': 'AesCtrParams',
|
|
|
|
},
|
|
|
|
'get key length': {
|
|
|
|
'AES-CBC': 'AesDerivedKeyParams',
|
|
|
|
'AES-CTR': 'AesDerivedKeyParams',
|
|
|
|
'AES-GCM': 'AesDerivedKeyParams',
|
|
|
|
'AES-KW': 'AesDerivedKeyParams',
|
|
|
|
'HMAC': 'HmacImportParams',
|
|
|
|
'HKDF': null,
|
|
|
|
'PBKDF2': null,
|
|
|
|
},
|
|
|
|
'wrapKey': {
|
|
|
|
'AES-KW': null,
|
|
|
|
},
|
|
|
|
'unwrapKey': {
|
|
|
|
'AES-KW': null,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2024-08-30 21:50:10 +00:00
|
|
|
const experimentalAlgorithms = ObjectEntries({
|
|
|
|
'X25519': {
|
|
|
|
generateKey: null,
|
|
|
|
importKey: null,
|
|
|
|
deriveBits: 'EcdhKeyDeriveParams',
|
|
|
|
},
|
|
|
|
'Ed25519': {
|
|
|
|
generateKey: null,
|
|
|
|
sign: null,
|
|
|
|
verify: null,
|
|
|
|
importKey: null,
|
|
|
|
},
|
|
|
|
'X448': {
|
|
|
|
generateKey: null,
|
|
|
|
importKey: null,
|
|
|
|
deriveBits: 'EcdhKeyDeriveParams',
|
|
|
|
},
|
|
|
|
'Ed448': {
|
|
|
|
generateKey: null,
|
|
|
|
sign: 'Ed448Params',
|
|
|
|
verify: 'Ed448Params',
|
|
|
|
importKey: null,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
for (let i = 0; i < experimentalAlgorithms.length; i++) {
|
|
|
|
const name = experimentalAlgorithms[i][0];
|
|
|
|
const ops = ObjectEntries(experimentalAlgorithms[i][1]);
|
|
|
|
for (let j = 0; j < ops.length; j++) {
|
|
|
|
const { 0: op, 1: dict } = ops[j];
|
|
|
|
ObjectDefineProperty(kSupportedAlgorithms[op], name, {
|
|
|
|
get() {
|
|
|
|
emitExperimentalWarning(`The ${name} Web Crypto API algorithm`);
|
|
|
|
return dict;
|
|
|
|
},
|
|
|
|
__proto__: null,
|
|
|
|
enumerable: true,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-17 08:57:58 +00:00
|
|
|
const simpleAlgorithmDictionaries = {
|
|
|
|
AesGcmParams: { iv: 'BufferSource', additionalData: 'BufferSource' },
|
|
|
|
RsaHashedKeyGenParams: { hash: 'HashAlgorithmIdentifier' },
|
|
|
|
EcKeyGenParams: {},
|
|
|
|
HmacKeyGenParams: { hash: 'HashAlgorithmIdentifier' },
|
|
|
|
RsaPssParams: {},
|
|
|
|
EcdsaParams: { hash: 'HashAlgorithmIdentifier' },
|
|
|
|
HmacImportParams: { hash: 'HashAlgorithmIdentifier' },
|
|
|
|
HkdfParams: {
|
|
|
|
hash: 'HashAlgorithmIdentifier',
|
|
|
|
salt: 'BufferSource',
|
|
|
|
info: 'BufferSource',
|
|
|
|
},
|
|
|
|
Ed448Params: { context: 'BufferSource' },
|
|
|
|
Pbkdf2Params: { hash: 'HashAlgorithmIdentifier', salt: 'BufferSource' },
|
|
|
|
RsaOaepParams: { label: 'BufferSource' },
|
|
|
|
RsaHashedImportParams: { hash: 'HashAlgorithmIdentifier' },
|
|
|
|
EcKeyImportParams: {},
|
|
|
|
};
|
|
|
|
|
2020-08-25 17:05:51 +00:00
|
|
|
function validateMaxBufferLength(data, name) {
|
|
|
|
if (data.byteLength > kMaxBufferLength) {
|
|
|
|
throw lazyDOMException(
|
|
|
|
`${name} must be less than ${kMaxBufferLength + 1} bits`,
|
|
|
|
'OperationError');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-17 08:57:58 +00:00
|
|
|
let webidl;
|
|
|
|
|
|
|
|
// https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm
|
|
|
|
// adapted for Node.js from Deno's implementation
|
|
|
|
// https://github.com/denoland/deno/blob/v1.29.1/ext/crypto/00_crypto.js#L195
|
|
|
|
function normalizeAlgorithm(algorithm, op) {
|
|
|
|
if (typeof algorithm === 'string')
|
|
|
|
return normalizeAlgorithm({ name: algorithm }, op);
|
|
|
|
|
|
|
|
webidl ??= require('internal/crypto/webidl');
|
|
|
|
|
|
|
|
// 1.
|
|
|
|
const registeredAlgorithms = kSupportedAlgorithms[op];
|
|
|
|
// 2. 3.
|
|
|
|
const initialAlg = webidl.converters.Algorithm(algorithm, {
|
|
|
|
prefix: 'Failed to normalize algorithm',
|
|
|
|
context: 'passed algorithm',
|
|
|
|
});
|
|
|
|
// 4.
|
|
|
|
let algName = initialAlg.name;
|
|
|
|
|
|
|
|
// 5.
|
|
|
|
let desiredType;
|
|
|
|
for (const key in registeredAlgorithms) {
|
|
|
|
if (!ObjectPrototypeHasOwnProperty(registeredAlgorithms, key)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
StringPrototypeToUpperCase(key) === StringPrototypeToUpperCase(algName)
|
|
|
|
) {
|
|
|
|
algName = key;
|
|
|
|
desiredType = registeredAlgorithms[key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (desiredType === undefined)
|
|
|
|
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
|
|
|
|
|
|
|
|
// Fast path everything below if the registered dictionary is null
|
|
|
|
if (desiredType === null)
|
|
|
|
return { name: algName };
|
|
|
|
|
|
|
|
// 6.
|
|
|
|
const normalizedAlgorithm = webidl.converters[desiredType](algorithm, {
|
|
|
|
prefix: 'Failed to normalize algorithm',
|
|
|
|
context: 'passed algorithm',
|
|
|
|
});
|
|
|
|
// 7.
|
|
|
|
normalizedAlgorithm.name = algName;
|
|
|
|
|
|
|
|
// 9.
|
|
|
|
const dict = simpleAlgorithmDictionaries[desiredType];
|
|
|
|
// 10.
|
|
|
|
const dictKeys = dict ? ObjectKeys(dict) : [];
|
|
|
|
for (let i = 0; i < dictKeys.length; i++) {
|
|
|
|
const member = dictKeys[i];
|
|
|
|
if (!ObjectPrototypeHasOwnProperty(dict, member))
|
|
|
|
continue;
|
|
|
|
const idlType = dict[member];
|
|
|
|
const idlValue = normalizedAlgorithm[member];
|
|
|
|
// 3.
|
|
|
|
if (idlType === 'BufferSource' && idlValue) {
|
|
|
|
const isView = ArrayBufferIsView(idlValue);
|
|
|
|
normalizedAlgorithm[member] = TypedArrayPrototypeSlice(
|
|
|
|
new Uint8Array(
|
|
|
|
isView ? getDataViewOrTypedArrayBuffer(idlValue) : idlValue,
|
|
|
|
isView ? getDataViewOrTypedArrayByteOffset(idlValue) : 0,
|
|
|
|
isView ? getDataViewOrTypedArrayByteLength(idlValue) : ArrayBufferPrototypeGetByteLength(idlValue),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
} else if (idlType === 'HashAlgorithmIdentifier') {
|
|
|
|
normalizedAlgorithm[member] = normalizeAlgorithm(idlValue, 'digest');
|
|
|
|
} else if (idlType === 'AlgorithmIdentifier') {
|
|
|
|
// This extension point is not used by any supported algorithm (yet?)
|
|
|
|
throw lazyDOMException('Not implemented.', 'NotSupportedError');
|
2020-08-25 17:05:51 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-17 08:57:58 +00:00
|
|
|
|
|
|
|
return normalizedAlgorithm;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getDataViewOrTypedArrayBuffer(V) {
|
|
|
|
return isDataView(V) ?
|
|
|
|
DataViewPrototypeGetBuffer(V) : TypedArrayPrototypeGetBuffer(V);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getDataViewOrTypedArrayByteOffset(V) {
|
|
|
|
return isDataView(V) ?
|
|
|
|
DataViewPrototypeGetByteOffset(V) : TypedArrayPrototypeGetByteOffset(V);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getDataViewOrTypedArrayByteLength(V) {
|
|
|
|
return isDataView(V) ?
|
|
|
|
DataViewPrototypeGetByteLength(V) : TypedArrayPrototypeGetByteLength(V);
|
2020-08-25 17:05:51 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 13:51:48 +00:00
|
|
|
function hasAnyNotIn(set, checks) {
|
2020-08-25 17:05:51 +00:00
|
|
|
for (const s of set)
|
2021-02-18 13:51:48 +00:00
|
|
|
if (!ArrayPrototypeIncludes(checks, s))
|
2020-08-25 17:05:51 +00:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function validateBitLength(length, name, required = false) {
|
|
|
|
if (length !== undefined || required) {
|
2021-01-19 11:23:27 +00:00
|
|
|
validateNumber(length, name);
|
2020-08-25 17:05:51 +00:00
|
|
|
if (length < 0)
|
|
|
|
throw new ERR_OUT_OF_RANGE(name, '> 0');
|
|
|
|
if (length % 8) {
|
|
|
|
throw new ERR_INVALID_ARG_VALUE(
|
|
|
|
name,
|
|
|
|
length,
|
|
|
|
'must be a multiple of 8');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function validateByteLength(buf, name, target) {
|
|
|
|
if (buf.byteLength !== target) {
|
|
|
|
throw lazyDOMException(
|
|
|
|
`${name} must contain exactly ${target} bytes`,
|
|
|
|
'OperationError');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const validateByteSource = hideStackFrames((val, name) => {
|
|
|
|
val = toBuf(val);
|
|
|
|
|
|
|
|
if (isAnyArrayBuffer(val) || isArrayBufferView(val))
|
2022-05-02 17:46:04 +00:00
|
|
|
return val;
|
2020-08-25 17:05:51 +00:00
|
|
|
|
2023-11-11 16:25:08 +00:00
|
|
|
throw new ERR_INVALID_ARG_TYPE.HideStackFramesError(
|
2020-08-25 17:05:51 +00:00
|
|
|
name,
|
|
|
|
[
|
|
|
|
'string',
|
|
|
|
'ArrayBuffer',
|
|
|
|
'TypedArray',
|
|
|
|
'DataView',
|
2021-02-06 13:36:58 +00:00
|
|
|
'Buffer',
|
2020-08-25 17:05:51 +00:00
|
|
|
],
|
|
|
|
val);
|
|
|
|
});
|
|
|
|
|
|
|
|
function onDone(resolve, reject, err, result) {
|
2022-08-12 19:29:14 +00:00
|
|
|
if (err) {
|
|
|
|
return reject(lazyDOMException(
|
|
|
|
'The operation failed for an operation-specific reason',
|
2022-10-10 01:12:28 +00:00
|
|
|
{ name: 'OperationError', cause: err }));
|
2022-08-12 19:29:14 +00:00
|
|
|
}
|
2020-08-25 17:05:51 +00:00
|
|
|
resolve(result);
|
|
|
|
}
|
|
|
|
|
2022-11-07 06:35:35 +00:00
|
|
|
function jobPromise(getJob) {
|
2020-08-25 17:05:51 +00:00
|
|
|
return new Promise((resolve, reject) => {
|
2022-11-07 06:35:35 +00:00
|
|
|
try {
|
|
|
|
const job = getJob();
|
|
|
|
job.ondone = FunctionPrototypeBind(onDone, job, resolve, reject);
|
|
|
|
job.run();
|
|
|
|
} catch (err) {
|
|
|
|
onDone(resolve, reject, err);
|
|
|
|
}
|
2020-08-25 17:05:51 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// In WebCrypto, the publicExponent option in RSA is represented as a
|
|
|
|
// WebIDL "BigInteger"... that is, a Uint8Array that allows an arbitrary
|
|
|
|
// number of leading zero bits. Our conventional APIs for reading
|
|
|
|
// an unsigned int from a Buffer are not adequate. The implementation
|
|
|
|
// here is adapted from the chromium implementation here:
|
2021-05-03 09:15:35 +00:00
|
|
|
// https://github.com/chromium/chromium/blob/HEAD/third_party/blink/public/platform/web_crypto_algorithm_params.h, but ported to JavaScript
|
2020-08-25 17:05:51 +00:00
|
|
|
// Returns undefined if the conversion was unsuccessful.
|
|
|
|
function bigIntArrayToUnsignedInt(input) {
|
|
|
|
let result = 0;
|
|
|
|
|
|
|
|
for (let n = 0; n < input.length; ++n) {
|
|
|
|
const n_reversed = input.length - n - 1;
|
|
|
|
if (n_reversed >= 4 && input[n])
|
|
|
|
return; // Too large
|
|
|
|
result |= input[n] << 8 * n_reversed;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-11-20 11:59:13 +00:00
|
|
|
function bigIntArrayToUnsignedBigInt(input) {
|
|
|
|
let result = 0n;
|
|
|
|
|
|
|
|
for (let n = 0; n < input.length; ++n) {
|
|
|
|
const n_reversed = input.length - n - 1;
|
|
|
|
result |= BigInt(input[n]) << 8n * BigInt(n_reversed);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-08-25 17:05:51 +00:00
|
|
|
function getStringOption(options, key) {
|
|
|
|
let value;
|
|
|
|
if (options && (value = options[key]) != null)
|
|
|
|
validateString(value, `options.${key}`);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getUsagesUnion(usageSet, ...usages) {
|
|
|
|
const newset = [];
|
|
|
|
for (let n = 0; n < usages.length; n++) {
|
|
|
|
if (usageSet.has(usages[n]))
|
|
|
|
ArrayPrototypePush(newset, usages[n]);
|
|
|
|
}
|
|
|
|
return newset;
|
|
|
|
}
|
|
|
|
|
2022-10-12 19:18:38 +00:00
|
|
|
function getBlockSize(name) {
|
2020-08-25 17:05:51 +00:00
|
|
|
switch (name) {
|
2024-05-12 19:17:14 +00:00
|
|
|
case 'SHA-1':
|
|
|
|
// Fall through
|
|
|
|
case 'SHA-256':
|
|
|
|
return 512;
|
|
|
|
case 'SHA-384':
|
|
|
|
// Fall through
|
|
|
|
case 'SHA-512':
|
|
|
|
return 1024;
|
2020-08-25 17:05:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-03 05:16:10 +00:00
|
|
|
function getDigestSizeInBytes(name) {
|
|
|
|
switch (name) {
|
|
|
|
case 'SHA-1': return 20;
|
|
|
|
case 'SHA-256': return 32;
|
|
|
|
case 'SHA-384': return 48;
|
|
|
|
case 'SHA-512': return 64;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-25 17:05:51 +00:00
|
|
|
const kKeyOps = {
|
|
|
|
sign: 1,
|
|
|
|
verify: 2,
|
|
|
|
encrypt: 3,
|
|
|
|
decrypt: 4,
|
|
|
|
wrapKey: 5,
|
|
|
|
unwrapKey: 6,
|
|
|
|
deriveKey: 7,
|
|
|
|
deriveBits: 8,
|
|
|
|
};
|
|
|
|
|
|
|
|
function validateKeyOps(keyOps, usagesSet) {
|
|
|
|
if (keyOps === undefined) return;
|
|
|
|
validateArray(keyOps, 'keyData.key_ops');
|
|
|
|
let flags = 0;
|
|
|
|
for (let n = 0; n < keyOps.length; n++) {
|
|
|
|
const op = keyOps[n];
|
|
|
|
const op_flag = kKeyOps[op];
|
|
|
|
// Skipping unknown key ops
|
|
|
|
if (op_flag === undefined)
|
|
|
|
continue;
|
|
|
|
// Have we seen it already? if so, error
|
|
|
|
if (flags & (1 << op_flag))
|
|
|
|
throw lazyDOMException('Duplicate key operation', 'DataError');
|
|
|
|
flags |= (1 << op_flag);
|
|
|
|
|
|
|
|
// TODO(@jasnell): RFC7517 section 4.3 strong recommends validating
|
|
|
|
// key usage combinations. Specifically, it says that unrelated key
|
|
|
|
// ops SHOULD NOT be used together. We're not yet validating that here.
|
|
|
|
}
|
|
|
|
|
|
|
|
if (usagesSet !== undefined) {
|
|
|
|
for (const use of usagesSet) {
|
|
|
|
if (!ArrayPrototypeIncludes(keyOps, use)) {
|
|
|
|
throw lazyDOMException(
|
|
|
|
'Key operations and usage mismatch',
|
|
|
|
'DataError');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-04 17:06:26 +00:00
|
|
|
function secureHeapUsed() {
|
|
|
|
const val = _secureHeapUsed();
|
|
|
|
if (val === undefined)
|
|
|
|
return { total: 0, used: 0, utilization: 0, min: 0 };
|
|
|
|
const used = Number(_secureHeapUsed());
|
|
|
|
const total = Number(getOptionValue('--secure-heap'));
|
|
|
|
const min = Number(getOptionValue('--secure-heap-min'));
|
|
|
|
const utilization = used / total;
|
|
|
|
return { total, used, utilization, min };
|
|
|
|
}
|
|
|
|
|
2017-09-06 15:10:34 +00:00
|
|
|
module.exports = {
|
2020-08-25 17:05:51 +00:00
|
|
|
getArrayBufferOrView,
|
2017-09-06 15:10:34 +00:00
|
|
|
getCiphers,
|
|
|
|
getCurves,
|
2023-01-17 08:57:58 +00:00
|
|
|
getDataViewOrTypedArrayBuffer,
|
2017-09-06 15:10:34 +00:00
|
|
|
getHashes,
|
2018-09-05 09:55:00 +00:00
|
|
|
kHandle,
|
2020-08-25 17:05:51 +00:00
|
|
|
kKeyObject,
|
2017-09-06 15:10:34 +00:00
|
|
|
setEngine,
|
2020-08-25 17:05:51 +00:00
|
|
|
toBuf,
|
|
|
|
|
|
|
|
kNamedCurveAliases,
|
|
|
|
kAesKeyLengths,
|
|
|
|
normalizeAlgorithm,
|
|
|
|
normalizeHashName,
|
|
|
|
hasAnyNotIn,
|
|
|
|
validateBitLength,
|
|
|
|
validateByteLength,
|
|
|
|
validateByteSource,
|
|
|
|
validateKeyOps,
|
|
|
|
jobPromise,
|
|
|
|
validateMaxBufferLength,
|
2020-11-20 11:59:13 +00:00
|
|
|
bigIntArrayToUnsignedBigInt,
|
2020-08-25 17:05:51 +00:00
|
|
|
bigIntArrayToUnsignedInt,
|
2022-10-12 19:18:38 +00:00
|
|
|
getBlockSize,
|
2024-04-03 05:16:10 +00:00
|
|
|
getDigestSizeInBytes,
|
2020-08-25 17:05:51 +00:00
|
|
|
getStringOption,
|
|
|
|
getUsagesUnion,
|
2021-01-04 17:06:26 +00:00
|
|
|
secureHeapUsed,
|
2024-01-05 22:16:27 +00:00
|
|
|
getCachedHashId,
|
|
|
|
getHashCache,
|
2017-09-06 15:10:34 +00:00
|
|
|
};
|