11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci ArrayPrototypeIncludes, 51cb0ef41Sopenharmony_ci ObjectKeys, 61cb0ef41Sopenharmony_ci SafeSet, 71cb0ef41Sopenharmony_ci} = primordials; 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciconst { 101cb0ef41Sopenharmony_ci ECKeyExportJob, 111cb0ef41Sopenharmony_ci KeyObjectHandle, 121cb0ef41Sopenharmony_ci SignJob, 131cb0ef41Sopenharmony_ci kCryptoJobAsync, 141cb0ef41Sopenharmony_ci kKeyTypePrivate, 151cb0ef41Sopenharmony_ci kSignJobModeSign, 161cb0ef41Sopenharmony_ci kSignJobModeVerify, 171cb0ef41Sopenharmony_ci kSigEncP1363, 181cb0ef41Sopenharmony_ci} = internalBinding('crypto'); 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ciconst { 211cb0ef41Sopenharmony_ci getUsagesUnion, 221cb0ef41Sopenharmony_ci hasAnyNotIn, 231cb0ef41Sopenharmony_ci jobPromise, 241cb0ef41Sopenharmony_ci normalizeHashName, 251cb0ef41Sopenharmony_ci validateKeyOps, 261cb0ef41Sopenharmony_ci kHandle, 271cb0ef41Sopenharmony_ci kKeyObject, 281cb0ef41Sopenharmony_ci kNamedCurveAliases, 291cb0ef41Sopenharmony_ci} = require('internal/crypto/util'); 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ciconst { 321cb0ef41Sopenharmony_ci lazyDOMException, 331cb0ef41Sopenharmony_ci promisify, 341cb0ef41Sopenharmony_ci} = require('internal/util'); 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ciconst { 371cb0ef41Sopenharmony_ci generateKeyPair: _generateKeyPair, 381cb0ef41Sopenharmony_ci} = require('internal/crypto/keygen'); 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ciconst { 411cb0ef41Sopenharmony_ci InternalCryptoKey, 421cb0ef41Sopenharmony_ci PrivateKeyObject, 431cb0ef41Sopenharmony_ci PublicKeyObject, 441cb0ef41Sopenharmony_ci createPrivateKey, 451cb0ef41Sopenharmony_ci createPublicKey, 461cb0ef41Sopenharmony_ci} = require('internal/crypto/keys'); 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ciconst generateKeyPair = promisify(_generateKeyPair); 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_cifunction verifyAcceptableEcKeyUse(name, isPublic, usages) { 511cb0ef41Sopenharmony_ci let checkSet; 521cb0ef41Sopenharmony_ci switch (name) { 531cb0ef41Sopenharmony_ci case 'ECDH': 541cb0ef41Sopenharmony_ci checkSet = isPublic ? [] : ['deriveKey', 'deriveBits']; 551cb0ef41Sopenharmony_ci break; 561cb0ef41Sopenharmony_ci case 'ECDSA': 571cb0ef41Sopenharmony_ci checkSet = isPublic ? ['verify'] : ['sign']; 581cb0ef41Sopenharmony_ci break; 591cb0ef41Sopenharmony_ci default: 601cb0ef41Sopenharmony_ci throw lazyDOMException( 611cb0ef41Sopenharmony_ci 'The algorithm is not supported', 'NotSupportedError'); 621cb0ef41Sopenharmony_ci } 631cb0ef41Sopenharmony_ci if (hasAnyNotIn(usages, checkSet)) { 641cb0ef41Sopenharmony_ci throw lazyDOMException( 651cb0ef41Sopenharmony_ci `Unsupported key usage for a ${name} key`, 661cb0ef41Sopenharmony_ci 'SyntaxError'); 671cb0ef41Sopenharmony_ci } 681cb0ef41Sopenharmony_ci} 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_cifunction createECPublicKeyRaw(namedCurve, keyData) { 711cb0ef41Sopenharmony_ci const handle = new KeyObjectHandle(); 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci if (!handle.initECRaw(kNamedCurveAliases[namedCurve], keyData)) { 741cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid keyData', 'DataError'); 751cb0ef41Sopenharmony_ci } 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci return new PublicKeyObject(handle); 781cb0ef41Sopenharmony_ci} 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ciasync function ecGenerateKey(algorithm, extractable, keyUsages) { 811cb0ef41Sopenharmony_ci const { name, namedCurve } = algorithm; 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci if (!ArrayPrototypeIncludes(ObjectKeys(kNamedCurveAliases), namedCurve)) { 841cb0ef41Sopenharmony_ci throw lazyDOMException( 851cb0ef41Sopenharmony_ci 'Unrecognized namedCurve', 861cb0ef41Sopenharmony_ci 'NotSupportedError'); 871cb0ef41Sopenharmony_ci } 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci const usageSet = new SafeSet(keyUsages); 901cb0ef41Sopenharmony_ci switch (name) { 911cb0ef41Sopenharmony_ci case 'ECDSA': 921cb0ef41Sopenharmony_ci if (hasAnyNotIn(usageSet, ['sign', 'verify'])) { 931cb0ef41Sopenharmony_ci throw lazyDOMException( 941cb0ef41Sopenharmony_ci 'Unsupported key usage for an ECDSA key', 951cb0ef41Sopenharmony_ci 'SyntaxError'); 961cb0ef41Sopenharmony_ci } 971cb0ef41Sopenharmony_ci break; 981cb0ef41Sopenharmony_ci case 'ECDH': 991cb0ef41Sopenharmony_ci if (hasAnyNotIn(usageSet, ['deriveKey', 'deriveBits'])) { 1001cb0ef41Sopenharmony_ci throw lazyDOMException( 1011cb0ef41Sopenharmony_ci 'Unsupported key usage for an ECDH key', 1021cb0ef41Sopenharmony_ci 'SyntaxError'); 1031cb0ef41Sopenharmony_ci } 1041cb0ef41Sopenharmony_ci // Fall through 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci const keypair = await generateKeyPair('ec', { namedCurve }).catch((err) => { 1081cb0ef41Sopenharmony_ci throw lazyDOMException( 1091cb0ef41Sopenharmony_ci 'The operation failed for an operation-specific reason', 1101cb0ef41Sopenharmony_ci { name: 'OperationError', cause: err }); 1111cb0ef41Sopenharmony_ci }); 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci let publicUsages; 1141cb0ef41Sopenharmony_ci let privateUsages; 1151cb0ef41Sopenharmony_ci switch (name) { 1161cb0ef41Sopenharmony_ci case 'ECDSA': 1171cb0ef41Sopenharmony_ci publicUsages = getUsagesUnion(usageSet, 'verify'); 1181cb0ef41Sopenharmony_ci privateUsages = getUsagesUnion(usageSet, 'sign'); 1191cb0ef41Sopenharmony_ci break; 1201cb0ef41Sopenharmony_ci case 'ECDH': 1211cb0ef41Sopenharmony_ci publicUsages = []; 1221cb0ef41Sopenharmony_ci privateUsages = getUsagesUnion(usageSet, 'deriveKey', 'deriveBits'); 1231cb0ef41Sopenharmony_ci break; 1241cb0ef41Sopenharmony_ci } 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci const keyAlgorithm = { name, namedCurve }; 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci const publicKey = 1291cb0ef41Sopenharmony_ci new InternalCryptoKey( 1301cb0ef41Sopenharmony_ci keypair.publicKey, 1311cb0ef41Sopenharmony_ci keyAlgorithm, 1321cb0ef41Sopenharmony_ci publicUsages, 1331cb0ef41Sopenharmony_ci true); 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci const privateKey = 1361cb0ef41Sopenharmony_ci new InternalCryptoKey( 1371cb0ef41Sopenharmony_ci keypair.privateKey, 1381cb0ef41Sopenharmony_ci keyAlgorithm, 1391cb0ef41Sopenharmony_ci privateUsages, 1401cb0ef41Sopenharmony_ci extractable); 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci return { publicKey, privateKey }; 1431cb0ef41Sopenharmony_ci} 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_cifunction ecExportKey(key, format) { 1461cb0ef41Sopenharmony_ci return jobPromise(() => new ECKeyExportJob( 1471cb0ef41Sopenharmony_ci kCryptoJobAsync, 1481cb0ef41Sopenharmony_ci format, 1491cb0ef41Sopenharmony_ci key[kKeyObject][kHandle])); 1501cb0ef41Sopenharmony_ci} 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ciasync function ecImportKey( 1531cb0ef41Sopenharmony_ci format, 1541cb0ef41Sopenharmony_ci keyData, 1551cb0ef41Sopenharmony_ci algorithm, 1561cb0ef41Sopenharmony_ci extractable, 1571cb0ef41Sopenharmony_ci keyUsages) { 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci const { name, namedCurve } = algorithm; 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci if (!ArrayPrototypeIncludes(ObjectKeys(kNamedCurveAliases), namedCurve)) { 1621cb0ef41Sopenharmony_ci throw lazyDOMException( 1631cb0ef41Sopenharmony_ci 'Unrecognized namedCurve', 1641cb0ef41Sopenharmony_ci 'NotSupportedError'); 1651cb0ef41Sopenharmony_ci } 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci let keyObject; 1681cb0ef41Sopenharmony_ci const usagesSet = new SafeSet(keyUsages); 1691cb0ef41Sopenharmony_ci switch (format) { 1701cb0ef41Sopenharmony_ci case 'spki': { 1711cb0ef41Sopenharmony_ci verifyAcceptableEcKeyUse(name, true, usagesSet); 1721cb0ef41Sopenharmony_ci try { 1731cb0ef41Sopenharmony_ci keyObject = createPublicKey({ 1741cb0ef41Sopenharmony_ci key: keyData, 1751cb0ef41Sopenharmony_ci format: 'der', 1761cb0ef41Sopenharmony_ci type: 'spki', 1771cb0ef41Sopenharmony_ci }); 1781cb0ef41Sopenharmony_ci } catch (err) { 1791cb0ef41Sopenharmony_ci throw lazyDOMException( 1801cb0ef41Sopenharmony_ci 'Invalid keyData', { name: 'DataError', cause: err }); 1811cb0ef41Sopenharmony_ci } 1821cb0ef41Sopenharmony_ci break; 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci case 'pkcs8': { 1851cb0ef41Sopenharmony_ci verifyAcceptableEcKeyUse(name, false, usagesSet); 1861cb0ef41Sopenharmony_ci try { 1871cb0ef41Sopenharmony_ci keyObject = createPrivateKey({ 1881cb0ef41Sopenharmony_ci key: keyData, 1891cb0ef41Sopenharmony_ci format: 'der', 1901cb0ef41Sopenharmony_ci type: 'pkcs8', 1911cb0ef41Sopenharmony_ci }); 1921cb0ef41Sopenharmony_ci } catch (err) { 1931cb0ef41Sopenharmony_ci throw lazyDOMException( 1941cb0ef41Sopenharmony_ci 'Invalid keyData', { name: 'DataError', cause: err }); 1951cb0ef41Sopenharmony_ci } 1961cb0ef41Sopenharmony_ci break; 1971cb0ef41Sopenharmony_ci } 1981cb0ef41Sopenharmony_ci case 'jwk': { 1991cb0ef41Sopenharmony_ci if (!keyData.kty) 2001cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid keyData', 'DataError'); 2011cb0ef41Sopenharmony_ci if (keyData.kty !== 'EC') 2021cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError'); 2031cb0ef41Sopenharmony_ci if (keyData.crv !== namedCurve) 2041cb0ef41Sopenharmony_ci throw lazyDOMException( 2051cb0ef41Sopenharmony_ci 'JWK "crv" does not match the requested algorithm', 2061cb0ef41Sopenharmony_ci 'DataError'); 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci verifyAcceptableEcKeyUse( 2091cb0ef41Sopenharmony_ci name, 2101cb0ef41Sopenharmony_ci keyData.d === undefined, 2111cb0ef41Sopenharmony_ci usagesSet); 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_ci if (usagesSet.size > 0 && keyData.use !== undefined) { 2141cb0ef41Sopenharmony_ci const checkUse = name === 'ECDH' ? 'enc' : 'sig'; 2151cb0ef41Sopenharmony_ci if (keyData.use !== checkUse) 2161cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid JWK "use" Parameter', 'DataError'); 2171cb0ef41Sopenharmony_ci } 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci validateKeyOps(keyData.key_ops, usagesSet); 2201cb0ef41Sopenharmony_ci 2211cb0ef41Sopenharmony_ci if (keyData.ext !== undefined && 2221cb0ef41Sopenharmony_ci keyData.ext === false && 2231cb0ef41Sopenharmony_ci extractable === true) { 2241cb0ef41Sopenharmony_ci throw lazyDOMException( 2251cb0ef41Sopenharmony_ci 'JWK "ext" Parameter and extractable mismatch', 2261cb0ef41Sopenharmony_ci 'DataError'); 2271cb0ef41Sopenharmony_ci } 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci if (algorithm.name === 'ECDSA' && keyData.alg !== undefined) { 2301cb0ef41Sopenharmony_ci let algNamedCurve; 2311cb0ef41Sopenharmony_ci switch (keyData.alg) { 2321cb0ef41Sopenharmony_ci case 'ES256': algNamedCurve = 'P-256'; break; 2331cb0ef41Sopenharmony_ci case 'ES384': algNamedCurve = 'P-384'; break; 2341cb0ef41Sopenharmony_ci case 'ES512': algNamedCurve = 'P-521'; break; 2351cb0ef41Sopenharmony_ci } 2361cb0ef41Sopenharmony_ci if (algNamedCurve !== namedCurve) 2371cb0ef41Sopenharmony_ci throw lazyDOMException( 2381cb0ef41Sopenharmony_ci 'JWK "alg" does not match the requested algorithm', 2391cb0ef41Sopenharmony_ci 'DataError'); 2401cb0ef41Sopenharmony_ci } 2411cb0ef41Sopenharmony_ci 2421cb0ef41Sopenharmony_ci const handle = new KeyObjectHandle(); 2431cb0ef41Sopenharmony_ci const type = handle.initJwk(keyData, namedCurve); 2441cb0ef41Sopenharmony_ci if (type === undefined) 2451cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid JWK', 'DataError'); 2461cb0ef41Sopenharmony_ci keyObject = type === kKeyTypePrivate ? 2471cb0ef41Sopenharmony_ci new PrivateKeyObject(handle) : 2481cb0ef41Sopenharmony_ci new PublicKeyObject(handle); 2491cb0ef41Sopenharmony_ci break; 2501cb0ef41Sopenharmony_ci } 2511cb0ef41Sopenharmony_ci case 'raw': { 2521cb0ef41Sopenharmony_ci verifyAcceptableEcKeyUse(name, true, usagesSet); 2531cb0ef41Sopenharmony_ci keyObject = createECPublicKeyRaw(namedCurve, keyData); 2541cb0ef41Sopenharmony_ci break; 2551cb0ef41Sopenharmony_ci } 2561cb0ef41Sopenharmony_ci } 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_ci switch (algorithm.name) { 2591cb0ef41Sopenharmony_ci case 'ECDSA': 2601cb0ef41Sopenharmony_ci // Fall through 2611cb0ef41Sopenharmony_ci case 'ECDH': 2621cb0ef41Sopenharmony_ci if (keyObject.asymmetricKeyType !== 'ec') 2631cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid key type', 'DataError'); 2641cb0ef41Sopenharmony_ci break; 2651cb0ef41Sopenharmony_ci } 2661cb0ef41Sopenharmony_ci 2671cb0ef41Sopenharmony_ci if (!keyObject[kHandle].checkEcKeyData()) { 2681cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid keyData', 'DataError'); 2691cb0ef41Sopenharmony_ci } 2701cb0ef41Sopenharmony_ci 2711cb0ef41Sopenharmony_ci const { 2721cb0ef41Sopenharmony_ci namedCurve: checkNamedCurve, 2731cb0ef41Sopenharmony_ci } = keyObject[kHandle].keyDetail({}); 2741cb0ef41Sopenharmony_ci if (kNamedCurveAliases[namedCurve] !== checkNamedCurve) 2751cb0ef41Sopenharmony_ci throw lazyDOMException('Named curve mismatch', 'DataError'); 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ci return new InternalCryptoKey( 2781cb0ef41Sopenharmony_ci keyObject, 2791cb0ef41Sopenharmony_ci { name, namedCurve }, 2801cb0ef41Sopenharmony_ci keyUsages, 2811cb0ef41Sopenharmony_ci extractable); 2821cb0ef41Sopenharmony_ci} 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_cifunction ecdsaSignVerify(key, data, { name, hash }, signature) { 2851cb0ef41Sopenharmony_ci const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify; 2861cb0ef41Sopenharmony_ci const type = mode === kSignJobModeSign ? 'private' : 'public'; 2871cb0ef41Sopenharmony_ci 2881cb0ef41Sopenharmony_ci if (key.type !== type) 2891cb0ef41Sopenharmony_ci throw lazyDOMException(`Key must be a ${type} key`, 'InvalidAccessError'); 2901cb0ef41Sopenharmony_ci 2911cb0ef41Sopenharmony_ci const hashname = normalizeHashName(hash.name); 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_ci return jobPromise(() => new SignJob( 2941cb0ef41Sopenharmony_ci kCryptoJobAsync, 2951cb0ef41Sopenharmony_ci mode, 2961cb0ef41Sopenharmony_ci key[kKeyObject][kHandle], 2971cb0ef41Sopenharmony_ci undefined, 2981cb0ef41Sopenharmony_ci undefined, 2991cb0ef41Sopenharmony_ci undefined, 3001cb0ef41Sopenharmony_ci data, 3011cb0ef41Sopenharmony_ci hashname, 3021cb0ef41Sopenharmony_ci undefined, // Salt length, not used with ECDSA 3031cb0ef41Sopenharmony_ci undefined, // PSS Padding, not used with ECDSA 3041cb0ef41Sopenharmony_ci kSigEncP1363, 3051cb0ef41Sopenharmony_ci signature)); 3061cb0ef41Sopenharmony_ci} 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_cimodule.exports = { 3091cb0ef41Sopenharmony_ci ecExportKey, 3101cb0ef41Sopenharmony_ci ecImportKey, 3111cb0ef41Sopenharmony_ci ecGenerateKey, 3121cb0ef41Sopenharmony_ci ecdsaSignVerify, 3131cb0ef41Sopenharmony_ci}; 314