11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci SafeSet, 51cb0ef41Sopenharmony_ci Uint8Array, 61cb0ef41Sopenharmony_ci} = primordials; 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ciconst { 91cb0ef41Sopenharmony_ci KeyObjectHandle, 101cb0ef41Sopenharmony_ci RSACipherJob, 111cb0ef41Sopenharmony_ci RSAKeyExportJob, 121cb0ef41Sopenharmony_ci SignJob, 131cb0ef41Sopenharmony_ci kCryptoJobAsync, 141cb0ef41Sopenharmony_ci kSignJobModeSign, 151cb0ef41Sopenharmony_ci kSignJobModeVerify, 161cb0ef41Sopenharmony_ci kKeyVariantRSA_SSA_PKCS1_v1_5, 171cb0ef41Sopenharmony_ci kKeyVariantRSA_PSS, 181cb0ef41Sopenharmony_ci kKeyVariantRSA_OAEP, 191cb0ef41Sopenharmony_ci kKeyTypePrivate, 201cb0ef41Sopenharmony_ci kWebCryptoCipherEncrypt, 211cb0ef41Sopenharmony_ci RSA_PKCS1_PSS_PADDING, 221cb0ef41Sopenharmony_ci} = internalBinding('crypto'); 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ciconst { 251cb0ef41Sopenharmony_ci validateInt32, 261cb0ef41Sopenharmony_ci} = require('internal/validators'); 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ciconst { 291cb0ef41Sopenharmony_ci bigIntArrayToUnsignedInt, 301cb0ef41Sopenharmony_ci getUsagesUnion, 311cb0ef41Sopenharmony_ci hasAnyNotIn, 321cb0ef41Sopenharmony_ci jobPromise, 331cb0ef41Sopenharmony_ci normalizeHashName, 341cb0ef41Sopenharmony_ci validateKeyOps, 351cb0ef41Sopenharmony_ci validateMaxBufferLength, 361cb0ef41Sopenharmony_ci kHandle, 371cb0ef41Sopenharmony_ci kKeyObject, 381cb0ef41Sopenharmony_ci} = require('internal/crypto/util'); 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ciconst { 411cb0ef41Sopenharmony_ci lazyDOMException, 421cb0ef41Sopenharmony_ci promisify, 431cb0ef41Sopenharmony_ci} = require('internal/util'); 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ciconst { 461cb0ef41Sopenharmony_ci InternalCryptoKey, 471cb0ef41Sopenharmony_ci PrivateKeyObject, 481cb0ef41Sopenharmony_ci PublicKeyObject, 491cb0ef41Sopenharmony_ci createPublicKey, 501cb0ef41Sopenharmony_ci createPrivateKey, 511cb0ef41Sopenharmony_ci} = require('internal/crypto/keys'); 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ciconst { 541cb0ef41Sopenharmony_ci generateKeyPair: _generateKeyPair, 551cb0ef41Sopenharmony_ci} = require('internal/crypto/keygen'); 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ciconst kRsaVariants = { 581cb0ef41Sopenharmony_ci 'RSASSA-PKCS1-v1_5': kKeyVariantRSA_SSA_PKCS1_v1_5, 591cb0ef41Sopenharmony_ci 'RSA-PSS': kKeyVariantRSA_PSS, 601cb0ef41Sopenharmony_ci 'RSA-OAEP': kKeyVariantRSA_OAEP, 611cb0ef41Sopenharmony_ci}; 621cb0ef41Sopenharmony_ciconst generateKeyPair = promisify(_generateKeyPair); 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_cifunction verifyAcceptableRsaKeyUse(name, isPublic, usages) { 651cb0ef41Sopenharmony_ci let checkSet; 661cb0ef41Sopenharmony_ci switch (name) { 671cb0ef41Sopenharmony_ci case 'RSA-OAEP': 681cb0ef41Sopenharmony_ci checkSet = isPublic ? ['encrypt', 'wrapKey'] : ['decrypt', 'unwrapKey']; 691cb0ef41Sopenharmony_ci break; 701cb0ef41Sopenharmony_ci case 'RSA-PSS': 711cb0ef41Sopenharmony_ci // Fall through 721cb0ef41Sopenharmony_ci case 'RSASSA-PKCS1-v1_5': 731cb0ef41Sopenharmony_ci checkSet = isPublic ? ['verify'] : ['sign']; 741cb0ef41Sopenharmony_ci break; 751cb0ef41Sopenharmony_ci default: 761cb0ef41Sopenharmony_ci throw lazyDOMException( 771cb0ef41Sopenharmony_ci 'The algorithm is not supported', 'NotSupportedError'); 781cb0ef41Sopenharmony_ci } 791cb0ef41Sopenharmony_ci if (hasAnyNotIn(usages, checkSet)) { 801cb0ef41Sopenharmony_ci throw lazyDOMException( 811cb0ef41Sopenharmony_ci `Unsupported key usage for an ${name} key`, 821cb0ef41Sopenharmony_ci 'SyntaxError'); 831cb0ef41Sopenharmony_ci } 841cb0ef41Sopenharmony_ci} 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_cifunction rsaOaepCipher(mode, key, data, { label }) { 871cb0ef41Sopenharmony_ci const type = mode === kWebCryptoCipherEncrypt ? 'public' : 'private'; 881cb0ef41Sopenharmony_ci if (key.type !== type) { 891cb0ef41Sopenharmony_ci throw lazyDOMException( 901cb0ef41Sopenharmony_ci 'The requested operation is not valid for the provided key', 911cb0ef41Sopenharmony_ci 'InvalidAccessError'); 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci if (label !== undefined) { 941cb0ef41Sopenharmony_ci validateMaxBufferLength(label, 'algorithm.label'); 951cb0ef41Sopenharmony_ci } 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci return jobPromise(() => new RSACipherJob( 981cb0ef41Sopenharmony_ci kCryptoJobAsync, 991cb0ef41Sopenharmony_ci mode, 1001cb0ef41Sopenharmony_ci key[kKeyObject][kHandle], 1011cb0ef41Sopenharmony_ci data, 1021cb0ef41Sopenharmony_ci kKeyVariantRSA_OAEP, 1031cb0ef41Sopenharmony_ci normalizeHashName(key.algorithm.hash.name), 1041cb0ef41Sopenharmony_ci label)); 1051cb0ef41Sopenharmony_ci} 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ciasync function rsaKeyGenerate( 1081cb0ef41Sopenharmony_ci algorithm, 1091cb0ef41Sopenharmony_ci extractable, 1101cb0ef41Sopenharmony_ci keyUsages) { 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci const { 1131cb0ef41Sopenharmony_ci name, 1141cb0ef41Sopenharmony_ci modulusLength, 1151cb0ef41Sopenharmony_ci publicExponent, 1161cb0ef41Sopenharmony_ci hash, 1171cb0ef41Sopenharmony_ci } = algorithm; 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci const usageSet = new SafeSet(keyUsages); 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci const publicExponentConverted = bigIntArrayToUnsignedInt(publicExponent); 1221cb0ef41Sopenharmony_ci if (publicExponentConverted === undefined) { 1231cb0ef41Sopenharmony_ci throw lazyDOMException( 1241cb0ef41Sopenharmony_ci 'The publicExponent must be equivalent to an unsigned 32-bit value', 1251cb0ef41Sopenharmony_ci 'OperationError'); 1261cb0ef41Sopenharmony_ci } 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci switch (name) { 1291cb0ef41Sopenharmony_ci case 'RSA-OAEP': 1301cb0ef41Sopenharmony_ci if (hasAnyNotIn(usageSet, 1311cb0ef41Sopenharmony_ci ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'])) { 1321cb0ef41Sopenharmony_ci throw lazyDOMException( 1331cb0ef41Sopenharmony_ci 'Unsupported key usage for a RSA key', 1341cb0ef41Sopenharmony_ci 'SyntaxError'); 1351cb0ef41Sopenharmony_ci } 1361cb0ef41Sopenharmony_ci break; 1371cb0ef41Sopenharmony_ci default: 1381cb0ef41Sopenharmony_ci if (hasAnyNotIn(usageSet, ['sign', 'verify'])) { 1391cb0ef41Sopenharmony_ci throw lazyDOMException( 1401cb0ef41Sopenharmony_ci 'Unsupported key usage for a RSA key', 1411cb0ef41Sopenharmony_ci 'SyntaxError'); 1421cb0ef41Sopenharmony_ci } 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci const keypair = await generateKeyPair('rsa', { 1461cb0ef41Sopenharmony_ci modulusLength, 1471cb0ef41Sopenharmony_ci publicExponent: publicExponentConverted, 1481cb0ef41Sopenharmony_ci }).catch((err) => { 1491cb0ef41Sopenharmony_ci throw lazyDOMException( 1501cb0ef41Sopenharmony_ci 'The operation failed for an operation-specific reason', 1511cb0ef41Sopenharmony_ci { name: 'OperationError', cause: err }); 1521cb0ef41Sopenharmony_ci }); 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci const keyAlgorithm = { 1551cb0ef41Sopenharmony_ci name, 1561cb0ef41Sopenharmony_ci modulusLength, 1571cb0ef41Sopenharmony_ci publicExponent, 1581cb0ef41Sopenharmony_ci hash: { name: hash.name }, 1591cb0ef41Sopenharmony_ci }; 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci let publicUsages; 1621cb0ef41Sopenharmony_ci let privateUsages; 1631cb0ef41Sopenharmony_ci switch (name) { 1641cb0ef41Sopenharmony_ci case 'RSA-OAEP': { 1651cb0ef41Sopenharmony_ci publicUsages = getUsagesUnion(usageSet, 'encrypt', 'wrapKey'); 1661cb0ef41Sopenharmony_ci privateUsages = getUsagesUnion(usageSet, 'decrypt', 'unwrapKey'); 1671cb0ef41Sopenharmony_ci break; 1681cb0ef41Sopenharmony_ci } 1691cb0ef41Sopenharmony_ci default: { 1701cb0ef41Sopenharmony_ci publicUsages = getUsagesUnion(usageSet, 'verify'); 1711cb0ef41Sopenharmony_ci privateUsages = getUsagesUnion(usageSet, 'sign'); 1721cb0ef41Sopenharmony_ci break; 1731cb0ef41Sopenharmony_ci } 1741cb0ef41Sopenharmony_ci } 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_ci const publicKey = 1771cb0ef41Sopenharmony_ci new InternalCryptoKey( 1781cb0ef41Sopenharmony_ci keypair.publicKey, 1791cb0ef41Sopenharmony_ci keyAlgorithm, 1801cb0ef41Sopenharmony_ci publicUsages, 1811cb0ef41Sopenharmony_ci true); 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ci const privateKey = 1841cb0ef41Sopenharmony_ci new InternalCryptoKey( 1851cb0ef41Sopenharmony_ci keypair.privateKey, 1861cb0ef41Sopenharmony_ci keyAlgorithm, 1871cb0ef41Sopenharmony_ci privateUsages, 1881cb0ef41Sopenharmony_ci extractable); 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci return { publicKey, privateKey }; 1911cb0ef41Sopenharmony_ci} 1921cb0ef41Sopenharmony_ci 1931cb0ef41Sopenharmony_cifunction rsaExportKey(key, format) { 1941cb0ef41Sopenharmony_ci return jobPromise(() => new RSAKeyExportJob( 1951cb0ef41Sopenharmony_ci kCryptoJobAsync, 1961cb0ef41Sopenharmony_ci format, 1971cb0ef41Sopenharmony_ci key[kKeyObject][kHandle], 1981cb0ef41Sopenharmony_ci kRsaVariants[key.algorithm.name])); 1991cb0ef41Sopenharmony_ci} 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ciasync function rsaImportKey( 2021cb0ef41Sopenharmony_ci format, 2031cb0ef41Sopenharmony_ci keyData, 2041cb0ef41Sopenharmony_ci algorithm, 2051cb0ef41Sopenharmony_ci extractable, 2061cb0ef41Sopenharmony_ci keyUsages) { 2071cb0ef41Sopenharmony_ci const usagesSet = new SafeSet(keyUsages); 2081cb0ef41Sopenharmony_ci let keyObject; 2091cb0ef41Sopenharmony_ci switch (format) { 2101cb0ef41Sopenharmony_ci case 'spki': { 2111cb0ef41Sopenharmony_ci verifyAcceptableRsaKeyUse(algorithm.name, true, usagesSet); 2121cb0ef41Sopenharmony_ci try { 2131cb0ef41Sopenharmony_ci keyObject = createPublicKey({ 2141cb0ef41Sopenharmony_ci key: keyData, 2151cb0ef41Sopenharmony_ci format: 'der', 2161cb0ef41Sopenharmony_ci type: 'spki', 2171cb0ef41Sopenharmony_ci }); 2181cb0ef41Sopenharmony_ci } catch (err) { 2191cb0ef41Sopenharmony_ci throw lazyDOMException( 2201cb0ef41Sopenharmony_ci 'Invalid keyData', { name: 'DataError', cause: err }); 2211cb0ef41Sopenharmony_ci } 2221cb0ef41Sopenharmony_ci break; 2231cb0ef41Sopenharmony_ci } 2241cb0ef41Sopenharmony_ci case 'pkcs8': { 2251cb0ef41Sopenharmony_ci verifyAcceptableRsaKeyUse(algorithm.name, false, usagesSet); 2261cb0ef41Sopenharmony_ci try { 2271cb0ef41Sopenharmony_ci keyObject = createPrivateKey({ 2281cb0ef41Sopenharmony_ci key: keyData, 2291cb0ef41Sopenharmony_ci format: 'der', 2301cb0ef41Sopenharmony_ci type: 'pkcs8', 2311cb0ef41Sopenharmony_ci }); 2321cb0ef41Sopenharmony_ci } catch (err) { 2331cb0ef41Sopenharmony_ci throw lazyDOMException( 2341cb0ef41Sopenharmony_ci 'Invalid keyData', { name: 'DataError', cause: err }); 2351cb0ef41Sopenharmony_ci } 2361cb0ef41Sopenharmony_ci break; 2371cb0ef41Sopenharmony_ci } 2381cb0ef41Sopenharmony_ci case 'jwk': { 2391cb0ef41Sopenharmony_ci if (!keyData.kty) 2401cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid keyData', 'DataError'); 2411cb0ef41Sopenharmony_ci 2421cb0ef41Sopenharmony_ci if (keyData.kty !== 'RSA') 2431cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError'); 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci verifyAcceptableRsaKeyUse( 2461cb0ef41Sopenharmony_ci algorithm.name, 2471cb0ef41Sopenharmony_ci keyData.d === undefined, 2481cb0ef41Sopenharmony_ci usagesSet); 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_ci if (usagesSet.size > 0 && keyData.use !== undefined) { 2511cb0ef41Sopenharmony_ci const checkUse = algorithm.name === 'RSA-OAEP' ? 'enc' : 'sig'; 2521cb0ef41Sopenharmony_ci if (keyData.use !== checkUse) 2531cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid JWK "use" Parameter', 'DataError'); 2541cb0ef41Sopenharmony_ci } 2551cb0ef41Sopenharmony_ci 2561cb0ef41Sopenharmony_ci validateKeyOps(keyData.key_ops, usagesSet); 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_ci if (keyData.ext !== undefined && 2591cb0ef41Sopenharmony_ci keyData.ext === false && 2601cb0ef41Sopenharmony_ci extractable === true) { 2611cb0ef41Sopenharmony_ci throw lazyDOMException( 2621cb0ef41Sopenharmony_ci 'JWK "ext" Parameter and extractable mismatch', 2631cb0ef41Sopenharmony_ci 'DataError'); 2641cb0ef41Sopenharmony_ci } 2651cb0ef41Sopenharmony_ci 2661cb0ef41Sopenharmony_ci if (keyData.alg !== undefined) { 2671cb0ef41Sopenharmony_ci const hash = 2681cb0ef41Sopenharmony_ci normalizeHashName(keyData.alg, normalizeHashName.kContextWebCrypto); 2691cb0ef41Sopenharmony_ci if (hash !== algorithm.hash.name) 2701cb0ef41Sopenharmony_ci throw lazyDOMException( 2711cb0ef41Sopenharmony_ci 'JWK "alg" does not match the requested algorithm', 2721cb0ef41Sopenharmony_ci 'DataError'); 2731cb0ef41Sopenharmony_ci } 2741cb0ef41Sopenharmony_ci 2751cb0ef41Sopenharmony_ci const handle = new KeyObjectHandle(); 2761cb0ef41Sopenharmony_ci const type = handle.initJwk(keyData); 2771cb0ef41Sopenharmony_ci if (type === undefined) 2781cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid JWK', 'DataError'); 2791cb0ef41Sopenharmony_ci 2801cb0ef41Sopenharmony_ci keyObject = type === kKeyTypePrivate ? 2811cb0ef41Sopenharmony_ci new PrivateKeyObject(handle) : 2821cb0ef41Sopenharmony_ci new PublicKeyObject(handle); 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_ci break; 2851cb0ef41Sopenharmony_ci } 2861cb0ef41Sopenharmony_ci default: 2871cb0ef41Sopenharmony_ci throw lazyDOMException( 2881cb0ef41Sopenharmony_ci `Unable to import RSA key with format ${format}`, 2891cb0ef41Sopenharmony_ci 'NotSupportedError'); 2901cb0ef41Sopenharmony_ci } 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_ci if (keyObject.asymmetricKeyType !== 'rsa') { 2931cb0ef41Sopenharmony_ci throw lazyDOMException('Invalid key type', 'DataError'); 2941cb0ef41Sopenharmony_ci } 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_ci const { 2971cb0ef41Sopenharmony_ci modulusLength, 2981cb0ef41Sopenharmony_ci publicExponent, 2991cb0ef41Sopenharmony_ci } = keyObject[kHandle].keyDetail({}); 3001cb0ef41Sopenharmony_ci 3011cb0ef41Sopenharmony_ci return new InternalCryptoKey(keyObject, { 3021cb0ef41Sopenharmony_ci name: algorithm.name, 3031cb0ef41Sopenharmony_ci modulusLength, 3041cb0ef41Sopenharmony_ci publicExponent: new Uint8Array(publicExponent), 3051cb0ef41Sopenharmony_ci hash: algorithm.hash, 3061cb0ef41Sopenharmony_ci }, keyUsages, extractable); 3071cb0ef41Sopenharmony_ci} 3081cb0ef41Sopenharmony_ci 3091cb0ef41Sopenharmony_cifunction rsaSignVerify(key, data, { saltLength }, signature) { 3101cb0ef41Sopenharmony_ci let padding; 3111cb0ef41Sopenharmony_ci if (key.algorithm.name === 'RSA-PSS') { 3121cb0ef41Sopenharmony_ci padding = RSA_PKCS1_PSS_PADDING; 3131cb0ef41Sopenharmony_ci // TODO(@jasnell): Validate maximum size of saltLength 3141cb0ef41Sopenharmony_ci // based on the key size: 3151cb0ef41Sopenharmony_ci // Math.ceil((keySizeInBits - 1)/8) - digestSizeInBytes - 2 3161cb0ef41Sopenharmony_ci validateInt32(saltLength, 'algorithm.saltLength', -2); 3171cb0ef41Sopenharmony_ci } 3181cb0ef41Sopenharmony_ci 3191cb0ef41Sopenharmony_ci const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify; 3201cb0ef41Sopenharmony_ci const type = mode === kSignJobModeSign ? 'private' : 'public'; 3211cb0ef41Sopenharmony_ci 3221cb0ef41Sopenharmony_ci if (key.type !== type) 3231cb0ef41Sopenharmony_ci throw lazyDOMException(`Key must be a ${type} key`, 'InvalidAccessError'); 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ci return jobPromise(() => new SignJob( 3261cb0ef41Sopenharmony_ci kCryptoJobAsync, 3271cb0ef41Sopenharmony_ci signature === undefined ? kSignJobModeSign : kSignJobModeVerify, 3281cb0ef41Sopenharmony_ci key[kKeyObject][kHandle], 3291cb0ef41Sopenharmony_ci undefined, 3301cb0ef41Sopenharmony_ci undefined, 3311cb0ef41Sopenharmony_ci undefined, 3321cb0ef41Sopenharmony_ci data, 3331cb0ef41Sopenharmony_ci normalizeHashName(key.algorithm.hash.name), 3341cb0ef41Sopenharmony_ci saltLength, 3351cb0ef41Sopenharmony_ci padding, 3361cb0ef41Sopenharmony_ci undefined, 3371cb0ef41Sopenharmony_ci signature)); 3381cb0ef41Sopenharmony_ci} 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ci 3411cb0ef41Sopenharmony_cimodule.exports = { 3421cb0ef41Sopenharmony_ci rsaCipher: rsaOaepCipher, 3431cb0ef41Sopenharmony_ci rsaExportKey, 3441cb0ef41Sopenharmony_ci rsaImportKey, 3451cb0ef41Sopenharmony_ci rsaKeyGenerate, 3461cb0ef41Sopenharmony_ci rsaSignVerify, 3471cb0ef41Sopenharmony_ci}; 348