/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
lib/internal/crypto/webcrypto_util.js
258 строк
7 KB
Filip Skokan
crypto: read WebCrypto inputs through primordials
09 авг 2026, 22:10
09 авг 2026, 22:10
e04663a
Код
Авторство
О чём код?
'use strict'; const { ArrayPrototypePushApply, SafeSet, } = primordials; const { KeyObjectHandle, kKeyFormatDER, kKeyFormatJWK, kKeyEncodingPKCS8, kKeyEncodingSPKI, kKeyTypePublic, kKeyTypePrivate, kKeyTypeSecret, } = internalBinding('crypto'); const { hasAnyNotIn, validateKeyOps, toUsagesSet, } = require('internal/crypto/util'); const { lazyDOMException, } = require('internal/util'); /** * @typedef {object} KeyUsageLists * @property {string[]} public Usages accepted for public keys. * @property {string[]} private Usages accepted for private keys. * @property {string[]} keygen Usages accepted during key generation. */ /** * @typedef {object} KeyUsageSets * @property {SafeSet<string>} public Requested public key usages. * @property {SafeSet<string>} private Requested private key usages. */ /** * Validates that every requested key usage is allowed for `subject`. * @param {string} subject * @param {SafeSet<string>} usagesSet * @param {string[]} allowed */ function verifyAcceptableKeyUse(subject, usagesSet, allowed) { if (hasAnyNotIn(usagesSet, allowed)) { throw lazyDOMException( `Unsupported key usage for ${subject} key`, 'SyntaxError'); } } /** * Converts a usage list to a set and validates it against `allowed`. * @param {string[]} usages * @param {string[]} allowed * @param {string} subject * @returns {SafeSet<string>} */ function validateKeyUsages(usages, allowed, subject) { const usagesSet = toUsagesSet(usages); verifyAcceptableKeyUse(subject, usagesSet, allowed); return usagesSet; } /** * Validates that a usage set is not empty. * @param {SafeSet<string>} usagesSet * @returns {SafeSet<string>} */ function validateUsagesNotEmpty(usagesSet) { if (usagesSet.size === 0) { throw lazyDOMException( 'Usages cannot be empty when creating a key.', 'SyntaxError'); } return usagesSet; } /** * Returns the requested usages that are present in `usagesSet`. * @param {SafeSet<string>} usagesSet * @param {string[]} usages * @returns {SafeSet<string>} */ function getUsagesUnion(usagesSet, usages) { const newset = new SafeSet(); for (let n = 0; n < usages.length; n++) { if (usagesSet.has(usages[n])) newset.add(usages[n]); } return newset; } /** * Splits requested usages into public and private key usage sets. * @param {SafeSet<string>} usagesSet * @param {KeyUsageLists} allowed * @returns {KeyUsageSets} */ function getKeyPairUsages(usagesSet, allowed) { return { public: getUsagesUnion(usagesSet, allowed.public), private: getUsagesUnion(usagesSet, allowed.private), }; } /** * Creates the accepted public, private, and key generation usage lists. * @param {string[]} publicUsages * @param {string[]} privateUsages * @returns {KeyUsageLists} */ function createKeyUsages(publicUsages, privateUsages) { const keygen = []; ArrayPrototypePushApply(keygen, publicUsages); ArrayPrototypePushApply(keygen, privateUsages); return { __proto__: null, public: publicUsages, private: privateUsages, keygen, }; } function importDerKey(keyData, isPublic) { const handle = new KeyObjectHandle(); const keyType = isPublic ? kKeyTypePublic : kKeyTypePrivate; const encoding = isPublic ? kKeyEncodingSPKI : kKeyEncodingPKCS8; try { handle.init(keyType, keyData, kKeyFormatDER, encoding, null, null); } catch (err) { throw lazyDOMException( 'Invalid keyData', { name: 'DataError', cause: err }); } return handle; } function validateJwk(keyData, kty, extractable, usagesSet, expectedUse) { if (typeof keyData.kty !== 'string') throw lazyDOMException('Invalid keyData', 'DataError'); if (keyData.kty !== kty) throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError'); switch (kty) { case 'RSA': if (typeof keyData.n !== 'string' || typeof keyData.e !== 'string' || (keyData.d !== undefined && typeof keyData.d !== 'string')) throw lazyDOMException('Invalid keyData', 'DataError'); if (typeof keyData.d === 'string' && (typeof keyData.p !== 'string' || typeof keyData.q !== 'string' || typeof keyData.dp !== 'string' || typeof keyData.dq !== 'string' || typeof keyData.qi !== 'string')) throw lazyDOMException('Invalid keyData', 'DataError'); break; case 'EC': if (typeof keyData.crv !== 'string' || typeof keyData.x !== 'string' || typeof keyData.y !== 'string' || (keyData.d !== undefined && typeof keyData.d !== 'string')) throw lazyDOMException('Invalid keyData', 'DataError'); break; case 'OKP': if (typeof keyData.crv !== 'string' || typeof keyData.x !== 'string' || (keyData.d !== undefined && typeof keyData.d !== 'string')) throw lazyDOMException('Invalid keyData', 'DataError'); break; case 'oct': if (typeof keyData.k !== 'string') throw lazyDOMException('Invalid keyData', 'DataError'); break; case 'AKP': if (typeof keyData.alg !== 'string' || typeof keyData.pub !== 'string' || (keyData.priv !== undefined && typeof keyData.priv !== 'string')) throw lazyDOMException('Invalid keyData', 'DataError'); break; /* c8 ignore start */ default: { const assert = require('internal/assert'); assert.fail('Unreachable code'); } /* c8 ignore stop */ } if (usagesSet.size > 0 && keyData.use !== undefined) { if (keyData.use !== expectedUse) throw lazyDOMException('Invalid JWK "use" Parameter', 'DataError'); } validateKeyOps(keyData.key_ops, usagesSet); if (keyData.ext !== undefined && keyData.ext === false && extractable === true) { throw lazyDOMException( 'JWK "ext" Parameter and extractable mismatch', 'DataError'); } } function importJwkKey(isPublic, keyData) { const handle = new KeyObjectHandle(); const keyType = isPublic ? kKeyTypePublic : kKeyTypePrivate; try { handle.init(keyType, keyData, kKeyFormatJWK, null, null, null); } catch (err) { throw lazyDOMException( 'Invalid keyData', { name: 'DataError', cause: err }); } return handle; } function importRawKey(isPublic, keyData, format, name, namedCurve) { const handle = new KeyObjectHandle(); const keyType = isPublic ? kKeyTypePublic : kKeyTypePrivate; try { handle.init(keyType, keyData, format, name ?? null, null, namedCurve ?? null); } catch (err) { throw lazyDOMException( 'Invalid keyData', { name: 'DataError', cause: err }); } return handle; } function importSecretKey(keyData) { const handle = new KeyObjectHandle(); handle.init(kKeyTypeSecret, keyData); return handle; } function importJwkSecretKey(keyData) { const handle = new KeyObjectHandle(); try { handle.init(kKeyTypeSecret, keyData, kKeyFormatJWK, null, null); } catch (err) { throw lazyDOMException( 'Invalid keyData', { name: 'DataError', cause: err }); } return handle; } module.exports = { createKeyUsages, getKeyPairUsages, importDerKey, importJwkKey, importJwkSecretKey, importRawKey, importSecretKey, validateJwk, validateKeyUsages, validateUsagesNotEmpty, verifyAcceptableKeyUse, };