11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors. 21cb0ef41Sopenharmony_ci// 31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the 51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including 61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish, 71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit 81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the 91cb0ef41Sopenharmony_ci// following conditions: 101cb0ef41Sopenharmony_ci// 111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included 121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software. 131cb0ef41Sopenharmony_ci// 141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE. 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci'use strict'; 231cb0ef41Sopenharmony_ciconst common = require('../common'); 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ciif (!common.hasCrypto) 261cb0ef41Sopenharmony_ci common.skip('missing crypto'); 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_cicommon.expectWarning({ 291cb0ef41Sopenharmony_ci DeprecationWarning: [ 301cb0ef41Sopenharmony_ci ['crypto.createCipher is deprecated.', 'DEP0106'], 311cb0ef41Sopenharmony_ci ] 321cb0ef41Sopenharmony_ci}); 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ciconst assert = require('assert'); 351cb0ef41Sopenharmony_ciconst crypto = require('crypto'); 361cb0ef41Sopenharmony_ciconst tls = require('tls'); 371cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures'); 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci// Test Certificates 401cb0ef41Sopenharmony_ciconst certPfx = fixtures.readKey('rsa_cert.pfx'); 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci// 'this' safety 431cb0ef41Sopenharmony_ci// https://github.com/joyent/node/issues/6690 441cb0ef41Sopenharmony_ciassert.throws(() => { 451cb0ef41Sopenharmony_ci const credentials = tls.createSecureContext(); 461cb0ef41Sopenharmony_ci const context = credentials.context; 471cb0ef41Sopenharmony_ci const notcontext = { setOptions: context.setOptions }; 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci // Methods of native objects should not segfault when reassigned to a new 501cb0ef41Sopenharmony_ci // object and called illegally. This core dumped in 0.10 and was fixed in 511cb0ef41Sopenharmony_ci // 0.11. 521cb0ef41Sopenharmony_ci notcontext.setOptions(); 531cb0ef41Sopenharmony_ci}, (err) => { 541cb0ef41Sopenharmony_ci // Throws TypeError, so there is no opensslErrorStack property. 551cb0ef41Sopenharmony_ci return err instanceof TypeError && 561cb0ef41Sopenharmony_ci err.name === 'TypeError' && 571cb0ef41Sopenharmony_ci /^TypeError: Illegal invocation$/.test(err) && 581cb0ef41Sopenharmony_ci !('opensslErrorStack' in err); 591cb0ef41Sopenharmony_ci}); 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci// PFX tests 621cb0ef41Sopenharmony_citls.createSecureContext({ pfx: certPfx, passphrase: 'sample' }); 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ciassert.throws(() => { 651cb0ef41Sopenharmony_ci tls.createSecureContext({ pfx: certPfx }); 661cb0ef41Sopenharmony_ci}, (err) => { 671cb0ef41Sopenharmony_ci // Throws general Error, so there is no opensslErrorStack property. 681cb0ef41Sopenharmony_ci return err instanceof Error && 691cb0ef41Sopenharmony_ci err.name === 'Error' && 701cb0ef41Sopenharmony_ci /^Error: mac verify failure$/.test(err) && 711cb0ef41Sopenharmony_ci !('opensslErrorStack' in err); 721cb0ef41Sopenharmony_ci}); 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ciassert.throws(() => { 751cb0ef41Sopenharmony_ci tls.createSecureContext({ pfx: certPfx, passphrase: 'test' }); 761cb0ef41Sopenharmony_ci}, (err) => { 771cb0ef41Sopenharmony_ci // Throws general Error, so there is no opensslErrorStack property. 781cb0ef41Sopenharmony_ci return err instanceof Error && 791cb0ef41Sopenharmony_ci err.name === 'Error' && 801cb0ef41Sopenharmony_ci /^Error: mac verify failure$/.test(err) && 811cb0ef41Sopenharmony_ci !('opensslErrorStack' in err); 821cb0ef41Sopenharmony_ci}); 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ciassert.throws(() => { 851cb0ef41Sopenharmony_ci tls.createSecureContext({ pfx: 'sample', passphrase: 'test' }); 861cb0ef41Sopenharmony_ci}, (err) => { 871cb0ef41Sopenharmony_ci // Throws general Error, so there is no opensslErrorStack property. 881cb0ef41Sopenharmony_ci return err instanceof Error && 891cb0ef41Sopenharmony_ci err.name === 'Error' && 901cb0ef41Sopenharmony_ci /^Error: not enough data$/.test(err) && 911cb0ef41Sopenharmony_ci !('opensslErrorStack' in err); 921cb0ef41Sopenharmony_ci}); 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci// update() should only take buffers / strings 961cb0ef41Sopenharmony_ciassert.throws( 971cb0ef41Sopenharmony_ci () => crypto.createHash('sha1').update({ foo: 'bar' }), 981cb0ef41Sopenharmony_ci { 991cb0ef41Sopenharmony_ci code: 'ERR_INVALID_ARG_TYPE', 1001cb0ef41Sopenharmony_ci name: 'TypeError' 1011cb0ef41Sopenharmony_ci }); 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_cifunction validateList(list) { 1051cb0ef41Sopenharmony_ci // The list must not be empty 1061cb0ef41Sopenharmony_ci assert(list.length > 0); 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci // The list should be sorted. 1091cb0ef41Sopenharmony_ci // Array#sort() modifies the list in place so make a copy. 1101cb0ef41Sopenharmony_ci const sorted = [...list].sort(); 1111cb0ef41Sopenharmony_ci assert.deepStrictEqual(list, sorted); 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci // Each element should be unique. 1141cb0ef41Sopenharmony_ci assert.strictEqual([...new Set(list)].length, list.length); 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci // Each element should be a string. 1171cb0ef41Sopenharmony_ci assert(list.every((value) => typeof value === 'string')); 1181cb0ef41Sopenharmony_ci} 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci// Assume that we have at least AES-128-CBC. 1211cb0ef41Sopenharmony_ciconst cryptoCiphers = crypto.getCiphers(); 1221cb0ef41Sopenharmony_ciassert(crypto.getCiphers().includes('aes-128-cbc')); 1231cb0ef41Sopenharmony_civalidateList(cryptoCiphers); 1241cb0ef41Sopenharmony_ci// Make sure all of the ciphers are supported by OpenSSL 1251cb0ef41Sopenharmony_cifor (const algo of cryptoCiphers) { 1261cb0ef41Sopenharmony_ci const { ivLength, keyLength, mode } = crypto.getCipherInfo(algo); 1271cb0ef41Sopenharmony_ci let options; 1281cb0ef41Sopenharmony_ci if (mode === 'ccm') 1291cb0ef41Sopenharmony_ci options = { authTagLength: 8 }; 1301cb0ef41Sopenharmony_ci else if (mode === 'ocb' || algo === 'chacha20-poly1305') 1311cb0ef41Sopenharmony_ci options = { authTagLength: 16 }; 1321cb0ef41Sopenharmony_ci crypto.createCipheriv(algo, 1331cb0ef41Sopenharmony_ci crypto.randomBytes(keyLength), 1341cb0ef41Sopenharmony_ci crypto.randomBytes(ivLength || 0), 1351cb0ef41Sopenharmony_ci options); 1361cb0ef41Sopenharmony_ci} 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ci// Assume that we have at least AES256-SHA. 1391cb0ef41Sopenharmony_ciconst tlsCiphers = tls.getCiphers(); 1401cb0ef41Sopenharmony_ciassert(tls.getCiphers().includes('aes256-sha')); 1411cb0ef41Sopenharmony_ciassert(tls.getCiphers().includes('tls_aes_128_ccm_8_sha256')); 1421cb0ef41Sopenharmony_ci// There should be no capital letters in any element. 1431cb0ef41Sopenharmony_ciconst noCapitals = /^[^A-Z]+$/; 1441cb0ef41Sopenharmony_ciassert(tlsCiphers.every((value) => noCapitals.test(value))); 1451cb0ef41Sopenharmony_civalidateList(tlsCiphers); 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci// Assert that we have sha1 and sha256 but not SHA1 and SHA256. 1481cb0ef41Sopenharmony_ciassert.notStrictEqual(crypto.getHashes().length, 0); 1491cb0ef41Sopenharmony_ciassert(crypto.getHashes().includes('sha1')); 1501cb0ef41Sopenharmony_ciassert(crypto.getHashes().includes('sha256')); 1511cb0ef41Sopenharmony_ciassert(!crypto.getHashes().includes('SHA1')); 1521cb0ef41Sopenharmony_ciassert(!crypto.getHashes().includes('SHA256')); 1531cb0ef41Sopenharmony_ciassert(crypto.getHashes().includes('RSA-SHA1')); 1541cb0ef41Sopenharmony_ciassert(!crypto.getHashes().includes('rsa-sha1')); 1551cb0ef41Sopenharmony_civalidateList(crypto.getHashes()); 1561cb0ef41Sopenharmony_ci// Make sure all of the hashes are supported by OpenSSL 1571cb0ef41Sopenharmony_cifor (const algo of crypto.getHashes()) 1581cb0ef41Sopenharmony_ci crypto.createHash(algo); 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ci// Assume that we have at least secp384r1. 1611cb0ef41Sopenharmony_ciassert.notStrictEqual(crypto.getCurves().length, 0); 1621cb0ef41Sopenharmony_ciassert(crypto.getCurves().includes('secp384r1')); 1631cb0ef41Sopenharmony_ciassert(!crypto.getCurves().includes('SECP384R1')); 1641cb0ef41Sopenharmony_civalidateList(crypto.getCurves()); 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci// Modifying return value from get* functions should not mutate subsequent 1671cb0ef41Sopenharmony_ci// return values. 1681cb0ef41Sopenharmony_cifunction testImmutability(fn) { 1691cb0ef41Sopenharmony_ci const list = fn(); 1701cb0ef41Sopenharmony_ci const copy = [...list]; 1711cb0ef41Sopenharmony_ci list.push('some-arbitrary-value'); 1721cb0ef41Sopenharmony_ci assert.deepStrictEqual(fn(), copy); 1731cb0ef41Sopenharmony_ci} 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_citestImmutability(crypto.getCiphers); 1761cb0ef41Sopenharmony_citestImmutability(tls.getCiphers); 1771cb0ef41Sopenharmony_citestImmutability(crypto.getHashes); 1781cb0ef41Sopenharmony_citestImmutability(crypto.getCurves); 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ciconst encodingError = { 1811cb0ef41Sopenharmony_ci code: 'ERR_INVALID_ARG_VALUE', 1821cb0ef41Sopenharmony_ci name: 'TypeError', 1831cb0ef41Sopenharmony_ci message: "The argument 'encoding' is invalid for data of length 1." + 1841cb0ef41Sopenharmony_ci " Received 'hex'", 1851cb0ef41Sopenharmony_ci}; 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci// Regression tests for https://github.com/nodejs/node-v0.x-archive/pull/5725: 1881cb0ef41Sopenharmony_ci// hex input that's not a power of two should throw, not assert in C++ land. 1891cb0ef41Sopenharmony_ci['createCipher', 'createDecipher'].forEach((funcName) => { 1901cb0ef41Sopenharmony_ci assert.throws( 1911cb0ef41Sopenharmony_ci () => crypto[funcName]('aes192', 'test').update('0', 'hex'), 1921cb0ef41Sopenharmony_ci (error) => { 1931cb0ef41Sopenharmony_ci assert.ok(!('opensslErrorStack' in error)); 1941cb0ef41Sopenharmony_ci if (common.hasFipsCrypto) { 1951cb0ef41Sopenharmony_ci return error instanceof Error && 1961cb0ef41Sopenharmony_ci error.name === 'Error' && 1971cb0ef41Sopenharmony_ci /^Error: not supported in FIPS mode$/.test(error); 1981cb0ef41Sopenharmony_ci } 1991cb0ef41Sopenharmony_ci assert.throws(() => { throw error; }, encodingError); 2001cb0ef41Sopenharmony_ci return true; 2011cb0ef41Sopenharmony_ci } 2021cb0ef41Sopenharmony_ci ); 2031cb0ef41Sopenharmony_ci}); 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ciassert.throws( 2061cb0ef41Sopenharmony_ci () => crypto.createHash('sha1').update('0', 'hex'), 2071cb0ef41Sopenharmony_ci (error) => { 2081cb0ef41Sopenharmony_ci assert.ok(!('opensslErrorStack' in error)); 2091cb0ef41Sopenharmony_ci assert.throws(() => { throw error; }, encodingError); 2101cb0ef41Sopenharmony_ci return true; 2111cb0ef41Sopenharmony_ci } 2121cb0ef41Sopenharmony_ci); 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ciassert.throws( 2151cb0ef41Sopenharmony_ci () => crypto.createHmac('sha256', 'a secret').update('0', 'hex'), 2161cb0ef41Sopenharmony_ci (error) => { 2171cb0ef41Sopenharmony_ci assert.ok(!('opensslErrorStack' in error)); 2181cb0ef41Sopenharmony_ci assert.throws(() => { throw error; }, encodingError); 2191cb0ef41Sopenharmony_ci return true; 2201cb0ef41Sopenharmony_ci } 2211cb0ef41Sopenharmony_ci); 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_ciassert.throws(() => { 2241cb0ef41Sopenharmony_ci const priv = [ 2251cb0ef41Sopenharmony_ci '-----BEGIN RSA PRIVATE KEY-----', 2261cb0ef41Sopenharmony_ci 'MIGrAgEAAiEA+3z+1QNF2/unumadiwEr+C5vfhezsb3hp4jAnCNRpPcCAwEAAQIgQNriSQK4', 2271cb0ef41Sopenharmony_ci 'EFwczDhMZp2dvbcz7OUUyt36z3S4usFPHSECEQD/41K7SujrstBfoCPzwC1xAhEA+5kt4BJy', 2281cb0ef41Sopenharmony_ci 'eKN7LggbF3Dk5wIQN6SL+fQ5H/+7NgARsVBp0QIRANxYRukavs4QvuyNhMx+vrkCEQCbf6j/', 2291cb0ef41Sopenharmony_ci 'Ig6/HueCK/0Jkmp+', 2301cb0ef41Sopenharmony_ci '-----END RSA PRIVATE KEY-----', 2311cb0ef41Sopenharmony_ci '', 2321cb0ef41Sopenharmony_ci ].join('\n'); 2331cb0ef41Sopenharmony_ci crypto.createSign('SHA256').update('test').sign(priv); 2341cb0ef41Sopenharmony_ci}, (err) => { 2351cb0ef41Sopenharmony_ci if (!common.hasOpenSSL3) 2361cb0ef41Sopenharmony_ci assert.ok(!('opensslErrorStack' in err)); 2371cb0ef41Sopenharmony_ci assert.throws(() => { throw err; }, common.hasOpenSSL3 ? { 2381cb0ef41Sopenharmony_ci name: 'Error', 2391cb0ef41Sopenharmony_ci message: 'error:02000070:rsa routines::digest too big for rsa key', 2401cb0ef41Sopenharmony_ci library: 'rsa routines', 2411cb0ef41Sopenharmony_ci } : { 2421cb0ef41Sopenharmony_ci name: 'Error', 2431cb0ef41Sopenharmony_ci message: /routines:RSA_sign:digest too big for rsa key$/, 2441cb0ef41Sopenharmony_ci library: 'rsa routines', 2451cb0ef41Sopenharmony_ci function: 'RSA_sign', 2461cb0ef41Sopenharmony_ci reason: 'digest too big for rsa key', 2471cb0ef41Sopenharmony_ci code: 'ERR_OSSL_RSA_DIGEST_TOO_BIG_FOR_RSA_KEY' 2481cb0ef41Sopenharmony_ci }); 2491cb0ef41Sopenharmony_ci return true; 2501cb0ef41Sopenharmony_ci}); 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_ciif (!common.hasOpenSSL3) { 2531cb0ef41Sopenharmony_ci assert.throws(() => { 2541cb0ef41Sopenharmony_ci // The correct header inside `rsa_private_pkcs8_bad.pem` should have been 2551cb0ef41Sopenharmony_ci // -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----- 2561cb0ef41Sopenharmony_ci // instead of 2571cb0ef41Sopenharmony_ci // -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY----- 2581cb0ef41Sopenharmony_ci const sha1_privateKey = fixtures.readKey('rsa_private_pkcs8_bad.pem', 2591cb0ef41Sopenharmony_ci 'ascii'); 2601cb0ef41Sopenharmony_ci // This would inject errors onto OpenSSL's error stack 2611cb0ef41Sopenharmony_ci crypto.createSign('sha1').sign(sha1_privateKey); 2621cb0ef41Sopenharmony_ci }, (err) => { 2631cb0ef41Sopenharmony_ci // Do the standard checks, but then do some custom checks afterwards. 2641cb0ef41Sopenharmony_ci assert.throws(() => { throw err; }, { 2651cb0ef41Sopenharmony_ci message: 'error:0D0680A8:asn1 encoding routines:asn1_check_tlen:' + 2661cb0ef41Sopenharmony_ci 'wrong tag', 2671cb0ef41Sopenharmony_ci library: 'asn1 encoding routines', 2681cb0ef41Sopenharmony_ci function: 'asn1_check_tlen', 2691cb0ef41Sopenharmony_ci reason: 'wrong tag', 2701cb0ef41Sopenharmony_ci code: 'ERR_OSSL_ASN1_WRONG_TAG', 2711cb0ef41Sopenharmony_ci }); 2721cb0ef41Sopenharmony_ci // Throws crypto error, so there is an opensslErrorStack property. 2731cb0ef41Sopenharmony_ci // The openSSL stack should have content. 2741cb0ef41Sopenharmony_ci assert(Array.isArray(err.opensslErrorStack)); 2751cb0ef41Sopenharmony_ci assert(err.opensslErrorStack.length > 0); 2761cb0ef41Sopenharmony_ci return true; 2771cb0ef41Sopenharmony_ci }); 2781cb0ef41Sopenharmony_ci} 2791cb0ef41Sopenharmony_ci 2801cb0ef41Sopenharmony_ci// Make sure memory isn't released before being returned 2811cb0ef41Sopenharmony_ciconsole.log(crypto.randomBytes(16)); 2821cb0ef41Sopenharmony_ci 2831cb0ef41Sopenharmony_ciassert.throws(() => { 2841cb0ef41Sopenharmony_ci tls.createSecureContext({ crl: 'not a CRL' }); 2851cb0ef41Sopenharmony_ci}, (err) => { 2861cb0ef41Sopenharmony_ci // Throws general error, so there is no opensslErrorStack property. 2871cb0ef41Sopenharmony_ci return err instanceof Error && 2881cb0ef41Sopenharmony_ci /^Error: Failed to parse CRL$/.test(err) && 2891cb0ef41Sopenharmony_ci !('opensslErrorStack' in err); 2901cb0ef41Sopenharmony_ci}); 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_ci/** 2931cb0ef41Sopenharmony_ci * Check if the stream function uses utf8 as a default encoding. 2941cb0ef41Sopenharmony_ci */ 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_cifunction testEncoding(options, assertionHash) { 2971cb0ef41Sopenharmony_ci const hash = crypto.createHash('sha256', options); 2981cb0ef41Sopenharmony_ci let hashValue = ''; 2991cb0ef41Sopenharmony_ci 3001cb0ef41Sopenharmony_ci hash.on('data', (data) => { 3011cb0ef41Sopenharmony_ci hashValue += data.toString('hex'); 3021cb0ef41Sopenharmony_ci }); 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_ci hash.on('end', common.mustCall(() => { 3051cb0ef41Sopenharmony_ci assert.strictEqual(hashValue, assertionHash); 3061cb0ef41Sopenharmony_ci })); 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ci hash.write('öäü'); 3091cb0ef41Sopenharmony_ci hash.end(); 3101cb0ef41Sopenharmony_ci} 3111cb0ef41Sopenharmony_ci 3121cb0ef41Sopenharmony_ci// Hash of "öäü" in utf8 format 3131cb0ef41Sopenharmony_ciconst assertionHashUtf8 = 3141cb0ef41Sopenharmony_ci '4f53d15bee524f082380e6d7247cc541e7cb0d10c64efdcc935ceeb1e7ea345c'; 3151cb0ef41Sopenharmony_ci 3161cb0ef41Sopenharmony_ci// Hash of "öäü" in latin1 format 3171cb0ef41Sopenharmony_ciconst assertionHashLatin1 = 3181cb0ef41Sopenharmony_ci 'cd37bccd5786e2e76d9b18c871e919e6eb11cc12d868f5ae41c40ccff8e44830'; 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_citestEncoding(undefined, assertionHashUtf8); 3211cb0ef41Sopenharmony_citestEncoding({}, assertionHashUtf8); 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_citestEncoding({ 3241cb0ef41Sopenharmony_ci defaultEncoding: 'utf8' 3251cb0ef41Sopenharmony_ci}, assertionHashUtf8); 3261cb0ef41Sopenharmony_ci 3271cb0ef41Sopenharmony_citestEncoding({ 3281cb0ef41Sopenharmony_ci defaultEncoding: 'latin1' 3291cb0ef41Sopenharmony_ci}, assertionHashLatin1); 330