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