11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst common = require('../common');
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciif (!common.hasCrypto)
61cb0ef41Sopenharmony_ci  common.skip('missing crypto');
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ciconst assert = require('assert');
91cb0ef41Sopenharmony_ciconst { webcrypto } = require('crypto');
101cb0ef41Sopenharmony_ciconst { subtle } = webcrypto;
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ciconst kTests = [
131cb0ef41Sopenharmony_ci  {
141cb0ef41Sopenharmony_ci    namedCurve: 'P-521',
151cb0ef41Sopenharmony_ci    pkcs8: '3081ee020100301006072a8648ce3d020106052b810400230481d63081d302010' +
161cb0ef41Sopenharmony_ci           '1044201a67ed321915a64aa359b7d648ddc2618fa8e8d1867e8f71830b10d25ed' +
171cb0ef41Sopenharmony_ci           '2891faf12f3c7e75421a2ea264f9a915320d274fe1470742b984e96b98912081f' +
181cb0ef41Sopenharmony_ci           'acd478da18189038186000400209d483f28666881c6641f3a126f400f51e46511' +
191cb0ef41Sopenharmony_ci           '70fe678c75e85712e2868adc850824997bebf0bc82b43028a6d2ec1777ca45279' +
201cb0ef41Sopenharmony_ci           'f7206a3ea8b5cd2073f493e45000cb54c3a5acaa268c56710428878d98b8afbf6' +
211cb0ef41Sopenharmony_ci           '8a612153632846d807e92672698f1b9c611de7d38e34cd6c73889092c56e52d68' +
221cb0ef41Sopenharmony_ci           '0f1dfd092b87ac8ef9ff3c8fb48',
231cb0ef41Sopenharmony_ci    spki: '30819b301006072a8648ce3d020106052b81040023038186000400ee69f94715d7' +
241cb0ef41Sopenharmony_ci          '01e9e2011333d4f4f96cba7d91f88b112baf75cf09cc1f8aca97618da9389822d2' +
251cb0ef41Sopenharmony_ci          '9b6fe9996a61203ef752b771e8958fc4677bb3778565ab60d6ed00deab6761895b' +
261cb0ef41Sopenharmony_ci          '935e3ad325fb8549e56f13786aa73f88a2ecfe40933473d8aef240c4dfd7d506f2' +
271cb0ef41Sopenharmony_ci          '2cdd0e55558f3fbf05ebf7efef7a72d78f46469b8448f26e2712',
281cb0ef41Sopenharmony_ci    result: '009c2bce57be80adab3b07385b8e5990eb7d6fdebdb01bf35371a4f6075e9d28',
291cb0ef41Sopenharmony_ci  },
301cb0ef41Sopenharmony_ci  {
311cb0ef41Sopenharmony_ci    namedCurve: 'P-384',
321cb0ef41Sopenharmony_ci    pkcs8: '3081b6020100301006072a8648ce3d020106052b8104002204819e30819b02010' +
331cb0ef41Sopenharmony_ci           '10430f871a5666589c14a5747263ef85b319cc023db6e35676c3d781eef8b055f' +
341cb0ef41Sopenharmony_ci           'cfbe86fa0d06d056b5195fb1323af8de25b3a16403620004f11965df7dd4594d0' +
351cb0ef41Sopenharmony_ci           '419c5086482a3b826b9797f9be0bd0d109c9e1e9989c1b9a92b8f269f98e17ad1' +
361cb0ef41Sopenharmony_ci           '84ba73c1f79762af45af8141602642da271a6bb0ffeb0cb4478fcf707e661aa6d' +
371cb0ef41Sopenharmony_ci           '6cdf51549c88c3f130be9e8201f6f6a09f4185aaf95c4',
381cb0ef41Sopenharmony_ci    spki: '3076301006072a8648ce3d020106052b810400220362000491822dc2af59c18f5b' +
391cb0ef41Sopenharmony_ci          '67f80df61a2603c2a8f0b3c0af822d63c279701a824560404401dde9a56ee52757' +
401cb0ef41Sopenharmony_ci          'ea8bc748d4c82b5337b48d7b65583a3d572438880036bac6730f42ca5278966bd5' +
411cb0ef41Sopenharmony_ci          'f21e86e21d30c5a6d0463ec513dd509ffcdcaf1ff5',
421cb0ef41Sopenharmony_ci    result: 'e0bd6bce0aef8ca48838a6e2fcc57e67b9c5e8860c5f0be9dabec53e454e18a0',
431cb0ef41Sopenharmony_ci  },
441cb0ef41Sopenharmony_ci];
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ciasync function prepareKeys() {
471cb0ef41Sopenharmony_ci  const keys = {};
481cb0ef41Sopenharmony_ci  await Promise.all(
491cb0ef41Sopenharmony_ci    kTests.map(async ({ namedCurve, size, pkcs8, spki, result }) => {
501cb0ef41Sopenharmony_ci      const [
511cb0ef41Sopenharmony_ci        privateKey,
521cb0ef41Sopenharmony_ci        publicKey,
531cb0ef41Sopenharmony_ci      ] = await Promise.all([
541cb0ef41Sopenharmony_ci        subtle.importKey(
551cb0ef41Sopenharmony_ci          'pkcs8',
561cb0ef41Sopenharmony_ci          Buffer.from(pkcs8, 'hex'),
571cb0ef41Sopenharmony_ci          {
581cb0ef41Sopenharmony_ci            name: 'ECDH',
591cb0ef41Sopenharmony_ci            namedCurve
601cb0ef41Sopenharmony_ci          },
611cb0ef41Sopenharmony_ci          true,
621cb0ef41Sopenharmony_ci          ['deriveKey', 'deriveBits']),
631cb0ef41Sopenharmony_ci        subtle.importKey(
641cb0ef41Sopenharmony_ci          'spki',
651cb0ef41Sopenharmony_ci          Buffer.from(spki, 'hex'),
661cb0ef41Sopenharmony_ci          {
671cb0ef41Sopenharmony_ci            name: 'ECDH',
681cb0ef41Sopenharmony_ci            namedCurve
691cb0ef41Sopenharmony_ci          },
701cb0ef41Sopenharmony_ci          true,
711cb0ef41Sopenharmony_ci          []),
721cb0ef41Sopenharmony_ci      ]);
731cb0ef41Sopenharmony_ci      keys[namedCurve] = {
741cb0ef41Sopenharmony_ci        privateKey,
751cb0ef41Sopenharmony_ci        publicKey,
761cb0ef41Sopenharmony_ci        size,
771cb0ef41Sopenharmony_ci        result,
781cb0ef41Sopenharmony_ci      };
791cb0ef41Sopenharmony_ci    }));
801cb0ef41Sopenharmony_ci  return keys;
811cb0ef41Sopenharmony_ci}
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci(async function() {
841cb0ef41Sopenharmony_ci  const keys = await prepareKeys();
851cb0ef41Sopenharmony_ci  const otherArgs = [
861cb0ef41Sopenharmony_ci    { name: 'HMAC', hash: 'SHA-256', length: 256 },
871cb0ef41Sopenharmony_ci    true,
881cb0ef41Sopenharmony_ci    ['sign', 'verify']];
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci  await Promise.all(
911cb0ef41Sopenharmony_ci    Object.keys(keys).map(async (namedCurve) => {
921cb0ef41Sopenharmony_ci      const { result, privateKey, publicKey } = keys[namedCurve];
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci      {
951cb0ef41Sopenharmony_ci        // Good parameters
961cb0ef41Sopenharmony_ci        const key = await subtle.deriveKey({
971cb0ef41Sopenharmony_ci          name: 'ECDH',
981cb0ef41Sopenharmony_ci          public: publicKey
991cb0ef41Sopenharmony_ci        }, privateKey, ...otherArgs);
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci        const raw = await subtle.exportKey('raw', key);
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci        assert.strictEqual(Buffer.from(raw).toString('hex'), result);
1041cb0ef41Sopenharmony_ci      }
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci      {
1071cb0ef41Sopenharmony_ci        // Case insensitivity
1081cb0ef41Sopenharmony_ci        const key = await subtle.deriveKey({
1091cb0ef41Sopenharmony_ci          name: 'eCdH',
1101cb0ef41Sopenharmony_ci          public: publicKey
1111cb0ef41Sopenharmony_ci        }, privateKey, {
1121cb0ef41Sopenharmony_ci          name: 'HmAc',
1131cb0ef41Sopenharmony_ci          hash: 'SHA-256',
1141cb0ef41Sopenharmony_ci          length: 256
1151cb0ef41Sopenharmony_ci        }, true, ['sign', 'verify']);
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci        const raw = await subtle.exportKey('raw', key);
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci        assert.strictEqual(Buffer.from(raw).toString('hex'), result);
1201cb0ef41Sopenharmony_ci      }
1211cb0ef41Sopenharmony_ci    }));
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  // Error tests
1241cb0ef41Sopenharmony_ci  {
1251cb0ef41Sopenharmony_ci    // Missing public property
1261cb0ef41Sopenharmony_ci    await assert.rejects(
1271cb0ef41Sopenharmony_ci      subtle.deriveKey(
1281cb0ef41Sopenharmony_ci        { name: 'ECDH' },
1291cb0ef41Sopenharmony_ci        keys['P-384'].privateKey,
1301cb0ef41Sopenharmony_ci        ...otherArgs),
1311cb0ef41Sopenharmony_ci      { code: 'ERR_MISSING_OPTION' });
1321cb0ef41Sopenharmony_ci  }
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci  {
1351cb0ef41Sopenharmony_ci    // The public property is not a CryptoKey
1361cb0ef41Sopenharmony_ci    await assert.rejects(
1371cb0ef41Sopenharmony_ci      subtle.deriveKey(
1381cb0ef41Sopenharmony_ci        {
1391cb0ef41Sopenharmony_ci          name: 'ECDH',
1401cb0ef41Sopenharmony_ci          public: { message: 'Not a CryptoKey' }
1411cb0ef41Sopenharmony_ci        },
1421cb0ef41Sopenharmony_ci        keys['P-384'].privateKey,
1431cb0ef41Sopenharmony_ci        ...otherArgs),
1441cb0ef41Sopenharmony_ci      { code: 'ERR_INVALID_ARG_TYPE' });
1451cb0ef41Sopenharmony_ci  }
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  {
1481cb0ef41Sopenharmony_ci    // Mismatched named curves
1491cb0ef41Sopenharmony_ci    await assert.rejects(
1501cb0ef41Sopenharmony_ci      subtle.deriveKey(
1511cb0ef41Sopenharmony_ci        {
1521cb0ef41Sopenharmony_ci          name: 'ECDH',
1531cb0ef41Sopenharmony_ci          public: keys['P-384'].publicKey
1541cb0ef41Sopenharmony_ci        },
1551cb0ef41Sopenharmony_ci        keys['P-521'].privateKey,
1561cb0ef41Sopenharmony_ci        ...otherArgs),
1571cb0ef41Sopenharmony_ci      { message: /Named curve mismatch/ });
1581cb0ef41Sopenharmony_ci  }
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  {
1611cb0ef41Sopenharmony_ci    // Incorrect public key algorithm
1621cb0ef41Sopenharmony_ci    const { publicKey } = await subtle.generateKey(
1631cb0ef41Sopenharmony_ci      {
1641cb0ef41Sopenharmony_ci        name: 'ECDSA',
1651cb0ef41Sopenharmony_ci        namedCurve: 'P-521'
1661cb0ef41Sopenharmony_ci      },
1671cb0ef41Sopenharmony_ci      false,
1681cb0ef41Sopenharmony_ci      ['sign', 'verify']);
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci    await assert.rejects(
1711cb0ef41Sopenharmony_ci      subtle.deriveKey(
1721cb0ef41Sopenharmony_ci        {
1731cb0ef41Sopenharmony_ci          name: 'ECDH',
1741cb0ef41Sopenharmony_ci          public: publicKey
1751cb0ef41Sopenharmony_ci        },
1761cb0ef41Sopenharmony_ci        keys['P-521'].privateKey,
1771cb0ef41Sopenharmony_ci        ...otherArgs),
1781cb0ef41Sopenharmony_ci      { message: /Keys must be ECDH, X25519, or X448 keys/ });
1791cb0ef41Sopenharmony_ci  }
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci  {
1821cb0ef41Sopenharmony_ci    // Private key does not have correct usages
1831cb0ef41Sopenharmony_ci    const privateKey = await subtle.importKey(
1841cb0ef41Sopenharmony_ci      'pkcs8',
1851cb0ef41Sopenharmony_ci      Buffer.from(kTests[0].pkcs8, 'hex'),
1861cb0ef41Sopenharmony_ci      {
1871cb0ef41Sopenharmony_ci        name: 'ECDH',
1881cb0ef41Sopenharmony_ci        namedCurve: 'P-521'
1891cb0ef41Sopenharmony_ci      }, false, ['deriveBits']);
1901cb0ef41Sopenharmony_ci
1911cb0ef41Sopenharmony_ci    await assert.rejects(
1921cb0ef41Sopenharmony_ci      subtle.deriveKey(
1931cb0ef41Sopenharmony_ci        {
1941cb0ef41Sopenharmony_ci          name: 'ECDH',
1951cb0ef41Sopenharmony_ci          public: keys['P-521'].publicKey,
1961cb0ef41Sopenharmony_ci        },
1971cb0ef41Sopenharmony_ci        privateKey,
1981cb0ef41Sopenharmony_ci        ...otherArgs),
1991cb0ef41Sopenharmony_ci      { message: /baseKey does not have deriveKey usage/ });
2001cb0ef41Sopenharmony_ci  }
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci  {
2031cb0ef41Sopenharmony_ci    // Base key is not a private key
2041cb0ef41Sopenharmony_ci    await assert.rejects(
2051cb0ef41Sopenharmony_ci      subtle.deriveKey(
2061cb0ef41Sopenharmony_ci        {
2071cb0ef41Sopenharmony_ci          name: 'ECDH',
2081cb0ef41Sopenharmony_ci          public: keys['P-521'].publicKey
2091cb0ef41Sopenharmony_ci        },
2101cb0ef41Sopenharmony_ci        keys['P-521'].publicKey,
2111cb0ef41Sopenharmony_ci        ...otherArgs),
2121cb0ef41Sopenharmony_ci      { name: 'InvalidAccessError' });
2131cb0ef41Sopenharmony_ci  }
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ci  {
2161cb0ef41Sopenharmony_ci    // Base key is not a private key
2171cb0ef41Sopenharmony_ci    await assert.rejects(
2181cb0ef41Sopenharmony_ci      subtle.deriveKey(
2191cb0ef41Sopenharmony_ci        {
2201cb0ef41Sopenharmony_ci          name: 'ECDH',
2211cb0ef41Sopenharmony_ci          public: keys['P-521'].privateKey
2221cb0ef41Sopenharmony_ci        },
2231cb0ef41Sopenharmony_ci        keys['P-521'].publicKey,
2241cb0ef41Sopenharmony_ci        ...otherArgs),
2251cb0ef41Sopenharmony_ci      { name: 'InvalidAccessError' });
2261cb0ef41Sopenharmony_ci  }
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_ci  {
2291cb0ef41Sopenharmony_ci    // Public is a secret key
2301cb0ef41Sopenharmony_ci    const keyData = webcrypto.getRandomValues(new Uint8Array(32));
2311cb0ef41Sopenharmony_ci    const key = await subtle.importKey(
2321cb0ef41Sopenharmony_ci      'raw',
2331cb0ef41Sopenharmony_ci      keyData,
2341cb0ef41Sopenharmony_ci      { name: 'AES-CBC', length: 256 },
2351cb0ef41Sopenharmony_ci      false, ['encrypt']);
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci    await assert.rejects(
2381cb0ef41Sopenharmony_ci      subtle.deriveKey(
2391cb0ef41Sopenharmony_ci        {
2401cb0ef41Sopenharmony_ci          name: 'ECDH',
2411cb0ef41Sopenharmony_ci          public: key
2421cb0ef41Sopenharmony_ci        },
2431cb0ef41Sopenharmony_ci        keys['P-521'].publicKey,
2441cb0ef41Sopenharmony_ci        ...otherArgs),
2451cb0ef41Sopenharmony_ci      { name: 'InvalidAccessError' });
2461cb0ef41Sopenharmony_ci  }
2471cb0ef41Sopenharmony_ci})().then(common.mustCall());
248