11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci SafeSet, 51cb0ef41Sopenharmony_ci} = primordials; 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciconst { Buffer } = require('buffer'); 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciconst { 101cb0ef41Sopenharmony_ci ECKeyExportJob, 111cb0ef41Sopenharmony_ci KeyObjectHandle, 121cb0ef41Sopenharmony_ci SignJob, 131cb0ef41Sopenharmony_ci kCryptoJobAsync, 141cb0ef41Sopenharmony_ci kKeyTypePrivate, 151cb0ef41Sopenharmony_ci kKeyTypePublic, 161cb0ef41Sopenharmony_ci kSignJobModeSign, 171cb0ef41Sopenharmony_ci kSignJobModeVerify, 181cb0ef41Sopenharmony_ci} = internalBinding('crypto'); 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ciconst { 211cb0ef41Sopenharmony_ci getUsagesUnion, 221cb0ef41Sopenharmony_ci hasAnyNotIn, 231cb0ef41Sopenharmony_ci jobPromise, 241cb0ef41Sopenharmony_ci validateKeyOps, 251cb0ef41Sopenharmony_ci kHandle, 261cb0ef41Sopenharmony_ci kKeyObject, 271cb0ef41Sopenharmony_ci} = require('internal/crypto/util'); 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ciconst { 301cb0ef41Sopenharmony_ci emitExperimentalWarning, 311cb0ef41Sopenharmony_ci lazyDOMException, 321cb0ef41Sopenharmony_ci promisify, 331cb0ef41Sopenharmony_ci} = require('internal/util'); 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ciconst { 361cb0ef41Sopenharmony_ci generateKeyPair: _generateKeyPair, 371cb0ef41Sopenharmony_ci} = require('internal/crypto/keygen'); 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ciconst { 401cb0ef41Sopenharmony_ci InternalCryptoKey, 411cb0ef41Sopenharmony_ci PrivateKeyObject, 421cb0ef41Sopenharmony_ci PublicKeyObject, 431cb0ef41Sopenharmony_ci createPrivateKey, 441cb0ef41Sopenharmony_ci createPublicKey, 451cb0ef41Sopenharmony_ci} = require('internal/crypto/keys'); 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ciconst generateKeyPair = promisify(_generateKeyPair); 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_cifunction verifyAcceptableCfrgKeyUse(name, isPublic, usages) { 501cb0ef41Sopenharmony_ci let checkSet; 511cb0ef41Sopenharmony_ci switch (name) { 521cb0ef41Sopenharmony_ci case 'X25519': 531cb0ef41Sopenharmony_ci // Fall through 541cb0ef41Sopenharmony_ci case 'X448': 551cb0ef41Sopenharmony_ci checkSet = isPublic ? [] : ['deriveKey', 'deriveBits']; 561cb0ef41Sopenharmony_ci break; 571cb0ef41Sopenharmony_ci case 'Ed25519': 581cb0ef41Sopenharmony_ci // Fall through 591cb0ef41Sopenharmony_ci case 'Ed448': 601cb0ef41Sopenharmony_ci checkSet = isPublic ? ['verify'] : ['sign']; 611cb0ef41Sopenharmony_ci break; 621cb0ef41Sopenharmony_ci default: 631cb0ef41Sopenharmony_ci throw lazyDOMException( 641cb0ef41Sopenharmony_ci 'The algorithm is not supported', 'NotSupportedError'); 651cb0ef41Sopenharmony_ci } 661cb0ef41Sopenharmony_ci if (hasAnyNotIn(usages, checkSet)) { 671cb0ef41Sopenharmony_ci throw lazyDOMException( 681cb0ef41Sopenharmony_ci `Unsupported key usage for a ${name} key`, 691cb0ef41Sopenharmony_ci 'SyntaxError'); 701cb0ef41Sopenharmony_ci } 711cb0ef41Sopenharmony_ci} 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_cifunction createCFRGRawKey(name, keyData, isPublic) { 741cb0ef41Sopenharmony_ci const handle = new KeyObjectHandle(); 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci switch (name) { 771cb0ef41Sopenharmony_ci case 'Ed25519': 781cb0ef41Sopenharmony_ci case 'X25519': 791cb0ef41Sopenharmony_ci if (keyData.byteLength !== 32) { 801cb0ef41Sopenharmony_ci throw lazyDOMException( 811cb0ef41Sopenharmony_ci `${name} raw keys must be exactly 32-bytes`, 'DataError'); 821cb0ef41Sopenharmony_ci } 831cb0ef41Sopenharmony_ci break; 841cb0ef41Sopenharmony_ci case 'Ed448': 851cb0ef41Sopenharmony_ci if (keyData.byteLength !== 57) { 861cb0ef41Sopenharmony_ci throw lazyDOMException( 871cb0ef41Sopenharmony_ci `${name} raw keys must be exactly 57-bytes`, 'DataError'); 881cb0ef41Sopenharmony_ci } 891cb0ef41Sopenharmony_ci break; 901cb0ef41Sopenharmony_ci case 'X448': 911cb0ef41Sopenharmony_ci if (keyData.byteLength !== 56) { 921cb0ef41Sopenharmony_ci throw lazyDOMException( 931cb0ef41Sopenharmony_ci `${name} raw keys must be exactly 56-bytes`, 'DataError'); 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci break; 961cb0ef41Sopenharmony_ci } 971cb0ef41Sopenharmony_ci 981cb0ef41Sopenharmony_ci const keyType = isPublic ? kKeyTypePublic : kKeyTypePrivate; 991cb0ef41Sopenharmony_ci if (!handle.initEDRaw(name, keyData, keyType)) { 1001cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid keyData', 'DataError'); 1011cb0ef41Sopenharmony_ci } 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci return isPublic ? new PublicKeyObject(handle) : new PrivateKeyObject(handle); 1041cb0ef41Sopenharmony_ci} 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ciasync function cfrgGenerateKey(algorithm, extractable, keyUsages) { 1071cb0ef41Sopenharmony_ci const { name } = algorithm; 1081cb0ef41Sopenharmony_ci emitExperimentalWarning(`The ${name} Web Crypto API algorithm`); 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci const usageSet = new SafeSet(keyUsages); 1111cb0ef41Sopenharmony_ci switch (name) { 1121cb0ef41Sopenharmony_ci case 'Ed25519': 1131cb0ef41Sopenharmony_ci // Fall through 1141cb0ef41Sopenharmony_ci case 'Ed448': 1151cb0ef41Sopenharmony_ci if (hasAnyNotIn(usageSet, ['sign', 'verify'])) { 1161cb0ef41Sopenharmony_ci throw lazyDOMException( 1171cb0ef41Sopenharmony_ci `Unsupported key usage for an ${name} key`, 1181cb0ef41Sopenharmony_ci 'SyntaxError'); 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci break; 1211cb0ef41Sopenharmony_ci case 'X25519': 1221cb0ef41Sopenharmony_ci // Fall through 1231cb0ef41Sopenharmony_ci case 'X448': 1241cb0ef41Sopenharmony_ci if (hasAnyNotIn(usageSet, ['deriveKey', 'deriveBits'])) { 1251cb0ef41Sopenharmony_ci throw lazyDOMException( 1261cb0ef41Sopenharmony_ci `Unsupported key usage for an ${name} key`, 1271cb0ef41Sopenharmony_ci 'SyntaxError'); 1281cb0ef41Sopenharmony_ci } 1291cb0ef41Sopenharmony_ci break; 1301cb0ef41Sopenharmony_ci } 1311cb0ef41Sopenharmony_ci let genKeyType; 1321cb0ef41Sopenharmony_ci switch (name) { 1331cb0ef41Sopenharmony_ci case 'Ed25519': 1341cb0ef41Sopenharmony_ci genKeyType = 'ed25519'; 1351cb0ef41Sopenharmony_ci break; 1361cb0ef41Sopenharmony_ci case 'Ed448': 1371cb0ef41Sopenharmony_ci genKeyType = 'ed448'; 1381cb0ef41Sopenharmony_ci break; 1391cb0ef41Sopenharmony_ci case 'X25519': 1401cb0ef41Sopenharmony_ci genKeyType = 'x25519'; 1411cb0ef41Sopenharmony_ci break; 1421cb0ef41Sopenharmony_ci case 'X448': 1431cb0ef41Sopenharmony_ci genKeyType = 'x448'; 1441cb0ef41Sopenharmony_ci break; 1451cb0ef41Sopenharmony_ci } 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci const keyPair = await generateKeyPair(genKeyType).catch((err) => { 1481cb0ef41Sopenharmony_ci throw lazyDOMException( 1491cb0ef41Sopenharmony_ci 'The operation failed for an operation-specific reason', 1501cb0ef41Sopenharmony_ci { name: 'OperationError', cause: err }); 1511cb0ef41Sopenharmony_ci }); 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ci let publicUsages; 1541cb0ef41Sopenharmony_ci let privateUsages; 1551cb0ef41Sopenharmony_ci switch (name) { 1561cb0ef41Sopenharmony_ci case 'Ed25519': 1571cb0ef41Sopenharmony_ci // Fall through 1581cb0ef41Sopenharmony_ci case 'Ed448': 1591cb0ef41Sopenharmony_ci publicUsages = getUsagesUnion(usageSet, 'verify'); 1601cb0ef41Sopenharmony_ci privateUsages = getUsagesUnion(usageSet, 'sign'); 1611cb0ef41Sopenharmony_ci break; 1621cb0ef41Sopenharmony_ci case 'X25519': 1631cb0ef41Sopenharmony_ci // Fall through 1641cb0ef41Sopenharmony_ci case 'X448': 1651cb0ef41Sopenharmony_ci publicUsages = []; 1661cb0ef41Sopenharmony_ci privateUsages = getUsagesUnion(usageSet, 'deriveKey', 'deriveBits'); 1671cb0ef41Sopenharmony_ci break; 1681cb0ef41Sopenharmony_ci } 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_ci const keyAlgorithm = { name }; 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci const publicKey = 1731cb0ef41Sopenharmony_ci new InternalCryptoKey( 1741cb0ef41Sopenharmony_ci keyPair.publicKey, 1751cb0ef41Sopenharmony_ci keyAlgorithm, 1761cb0ef41Sopenharmony_ci publicUsages, 1771cb0ef41Sopenharmony_ci true); 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ci const privateKey = 1801cb0ef41Sopenharmony_ci new InternalCryptoKey( 1811cb0ef41Sopenharmony_ci keyPair.privateKey, 1821cb0ef41Sopenharmony_ci keyAlgorithm, 1831cb0ef41Sopenharmony_ci privateUsages, 1841cb0ef41Sopenharmony_ci extractable); 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_ci return { privateKey, publicKey }; 1871cb0ef41Sopenharmony_ci} 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_cifunction cfrgExportKey(key, format) { 1901cb0ef41Sopenharmony_ci emitExperimentalWarning(`The ${key.algorithm.name} Web Crypto API algorithm`); 1911cb0ef41Sopenharmony_ci return jobPromise(() => new ECKeyExportJob( 1921cb0ef41Sopenharmony_ci kCryptoJobAsync, 1931cb0ef41Sopenharmony_ci format, 1941cb0ef41Sopenharmony_ci key[kKeyObject][kHandle])); 1951cb0ef41Sopenharmony_ci} 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ciasync function cfrgImportKey( 1981cb0ef41Sopenharmony_ci format, 1991cb0ef41Sopenharmony_ci keyData, 2001cb0ef41Sopenharmony_ci algorithm, 2011cb0ef41Sopenharmony_ci extractable, 2021cb0ef41Sopenharmony_ci keyUsages) { 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci const { name } = algorithm; 2051cb0ef41Sopenharmony_ci emitExperimentalWarning(`The ${name} Web Crypto API algorithm`); 2061cb0ef41Sopenharmony_ci let keyObject; 2071cb0ef41Sopenharmony_ci const usagesSet = new SafeSet(keyUsages); 2081cb0ef41Sopenharmony_ci switch (format) { 2091cb0ef41Sopenharmony_ci case 'spki': { 2101cb0ef41Sopenharmony_ci verifyAcceptableCfrgKeyUse(name, true, usagesSet); 2111cb0ef41Sopenharmony_ci try { 2121cb0ef41Sopenharmony_ci keyObject = createPublicKey({ 2131cb0ef41Sopenharmony_ci key: keyData, 2141cb0ef41Sopenharmony_ci format: 'der', 2151cb0ef41Sopenharmony_ci type: 'spki', 2161cb0ef41Sopenharmony_ci }); 2171cb0ef41Sopenharmony_ci } catch (err) { 2181cb0ef41Sopenharmony_ci throw lazyDOMException( 2191cb0ef41Sopenharmony_ci 'Invalid keyData', { name: 'DataError', cause: err }); 2201cb0ef41Sopenharmony_ci } 2211cb0ef41Sopenharmony_ci break; 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci case 'pkcs8': { 2241cb0ef41Sopenharmony_ci verifyAcceptableCfrgKeyUse(name, false, usagesSet); 2251cb0ef41Sopenharmony_ci try { 2261cb0ef41Sopenharmony_ci keyObject = createPrivateKey({ 2271cb0ef41Sopenharmony_ci key: keyData, 2281cb0ef41Sopenharmony_ci format: 'der', 2291cb0ef41Sopenharmony_ci type: 'pkcs8', 2301cb0ef41Sopenharmony_ci }); 2311cb0ef41Sopenharmony_ci } catch (err) { 2321cb0ef41Sopenharmony_ci throw lazyDOMException( 2331cb0ef41Sopenharmony_ci 'Invalid keyData', { name: 'DataError', cause: err }); 2341cb0ef41Sopenharmony_ci } 2351cb0ef41Sopenharmony_ci break; 2361cb0ef41Sopenharmony_ci } 2371cb0ef41Sopenharmony_ci case 'jwk': { 2381cb0ef41Sopenharmony_ci if (!keyData.kty) 2391cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid keyData', 'DataError'); 2401cb0ef41Sopenharmony_ci if (keyData.kty !== 'OKP') 2411cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError'); 2421cb0ef41Sopenharmony_ci if (keyData.crv !== name) 2431cb0ef41Sopenharmony_ci throw lazyDOMException( 2441cb0ef41Sopenharmony_ci 'JWK "crv" Parameter and algorithm name mismatch', 'DataError'); 2451cb0ef41Sopenharmony_ci const isPublic = keyData.d === undefined; 2461cb0ef41Sopenharmony_ci 2471cb0ef41Sopenharmony_ci if (usagesSet.size > 0 && keyData.use !== undefined) { 2481cb0ef41Sopenharmony_ci let checkUse; 2491cb0ef41Sopenharmony_ci switch (name) { 2501cb0ef41Sopenharmony_ci case 'Ed25519': 2511cb0ef41Sopenharmony_ci // Fall through 2521cb0ef41Sopenharmony_ci case 'Ed448': 2531cb0ef41Sopenharmony_ci checkUse = 'sig'; 2541cb0ef41Sopenharmony_ci break; 2551cb0ef41Sopenharmony_ci case 'X25519': 2561cb0ef41Sopenharmony_ci // Fall through 2571cb0ef41Sopenharmony_ci case 'X448': 2581cb0ef41Sopenharmony_ci checkUse = 'enc'; 2591cb0ef41Sopenharmony_ci break; 2601cb0ef41Sopenharmony_ci } 2611cb0ef41Sopenharmony_ci if (keyData.use !== checkUse) 2621cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid JWK "use" Parameter', 'DataError'); 2631cb0ef41Sopenharmony_ci } 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci validateKeyOps(keyData.key_ops, usagesSet); 2661cb0ef41Sopenharmony_ci 2671cb0ef41Sopenharmony_ci if (keyData.ext !== undefined && 2681cb0ef41Sopenharmony_ci keyData.ext === false && 2691cb0ef41Sopenharmony_ci extractable === true) { 2701cb0ef41Sopenharmony_ci throw lazyDOMException( 2711cb0ef41Sopenharmony_ci 'JWK "ext" Parameter and extractable mismatch', 2721cb0ef41Sopenharmony_ci 'DataError'); 2731cb0ef41Sopenharmony_ci } 2741cb0ef41Sopenharmony_ci 2751cb0ef41Sopenharmony_ci if (keyData.alg !== undefined) { 2761cb0ef41Sopenharmony_ci if ( 2771cb0ef41Sopenharmony_ci (name === 'Ed25519' || name === 'Ed448') && 2781cb0ef41Sopenharmony_ci keyData.alg !== 'EdDSA' 2791cb0ef41Sopenharmony_ci ) { 2801cb0ef41Sopenharmony_ci throw lazyDOMException( 2811cb0ef41Sopenharmony_ci 'JWK "alg" does not match the requested algorithm', 2821cb0ef41Sopenharmony_ci 'DataError'); 2831cb0ef41Sopenharmony_ci } 2841cb0ef41Sopenharmony_ci } 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ci if (!isPublic && typeof keyData.x !== 'string') { 2871cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid JWK', 'DataError'); 2881cb0ef41Sopenharmony_ci } 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci verifyAcceptableCfrgKeyUse( 2911cb0ef41Sopenharmony_ci name, 2921cb0ef41Sopenharmony_ci isPublic, 2931cb0ef41Sopenharmony_ci usagesSet); 2941cb0ef41Sopenharmony_ci 2951cb0ef41Sopenharmony_ci const publicKeyObject = createCFRGRawKey( 2961cb0ef41Sopenharmony_ci name, 2971cb0ef41Sopenharmony_ci Buffer.from(keyData.x, 'base64'), 2981cb0ef41Sopenharmony_ci true); 2991cb0ef41Sopenharmony_ci 3001cb0ef41Sopenharmony_ci if (isPublic) { 3011cb0ef41Sopenharmony_ci keyObject = publicKeyObject; 3021cb0ef41Sopenharmony_ci } else { 3031cb0ef41Sopenharmony_ci keyObject = createCFRGRawKey( 3041cb0ef41Sopenharmony_ci name, 3051cb0ef41Sopenharmony_ci Buffer.from(keyData.d, 'base64'), 3061cb0ef41Sopenharmony_ci false); 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ci if (!createPublicKey(keyObject).equals(publicKeyObject)) { 3091cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid JWK', 'DataError'); 3101cb0ef41Sopenharmony_ci } 3111cb0ef41Sopenharmony_ci } 3121cb0ef41Sopenharmony_ci break; 3131cb0ef41Sopenharmony_ci } 3141cb0ef41Sopenharmony_ci case 'raw': { 3151cb0ef41Sopenharmony_ci verifyAcceptableCfrgKeyUse(name, true, usagesSet); 3161cb0ef41Sopenharmony_ci keyObject = createCFRGRawKey(name, keyData, true); 3171cb0ef41Sopenharmony_ci break; 3181cb0ef41Sopenharmony_ci } 3191cb0ef41Sopenharmony_ci } 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_ci if (keyObject.asymmetricKeyType !== name.toLowerCase()) { 3221cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid key type', 'DataError'); 3231cb0ef41Sopenharmony_ci } 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ci return new InternalCryptoKey( 3261cb0ef41Sopenharmony_ci keyObject, 3271cb0ef41Sopenharmony_ci { name }, 3281cb0ef41Sopenharmony_ci keyUsages, 3291cb0ef41Sopenharmony_ci extractable); 3301cb0ef41Sopenharmony_ci} 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_cifunction eddsaSignVerify(key, data, { name, context }, signature) { 3331cb0ef41Sopenharmony_ci emitExperimentalWarning(`The ${name} Web Crypto API algorithm`); 3341cb0ef41Sopenharmony_ci const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify; 3351cb0ef41Sopenharmony_ci const type = mode === kSignJobModeSign ? 'private' : 'public'; 3361cb0ef41Sopenharmony_ci 3371cb0ef41Sopenharmony_ci if (key.type !== type) 3381cb0ef41Sopenharmony_ci throw lazyDOMException(`Key must be a ${type} key`, 'InvalidAccessError'); 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ci if (name === 'Ed448' && context?.byteLength) { 3411cb0ef41Sopenharmony_ci throw lazyDOMException( 3421cb0ef41Sopenharmony_ci 'Non zero-length context is not yet supported.', 'NotSupportedError'); 3431cb0ef41Sopenharmony_ci } 3441cb0ef41Sopenharmony_ci 3451cb0ef41Sopenharmony_ci return jobPromise(() => new SignJob( 3461cb0ef41Sopenharmony_ci kCryptoJobAsync, 3471cb0ef41Sopenharmony_ci mode, 3481cb0ef41Sopenharmony_ci key[kKeyObject][kHandle], 3491cb0ef41Sopenharmony_ci undefined, 3501cb0ef41Sopenharmony_ci undefined, 3511cb0ef41Sopenharmony_ci undefined, 3521cb0ef41Sopenharmony_ci data, 3531cb0ef41Sopenharmony_ci undefined, 3541cb0ef41Sopenharmony_ci undefined, 3551cb0ef41Sopenharmony_ci undefined, 3561cb0ef41Sopenharmony_ci undefined, 3571cb0ef41Sopenharmony_ci signature)); 3581cb0ef41Sopenharmony_ci} 3591cb0ef41Sopenharmony_ci 3601cb0ef41Sopenharmony_cimodule.exports = { 3611cb0ef41Sopenharmony_ci cfrgExportKey, 3621cb0ef41Sopenharmony_ci cfrgImportKey, 3631cb0ef41Sopenharmony_ci cfrgGenerateKey, 3641cb0ef41Sopenharmony_ci eddsaSignVerify, 3651cb0ef41Sopenharmony_ci}; 366