11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst common = require('../common');
31cb0ef41Sopenharmony_ciif (!common.hasCrypto)
41cb0ef41Sopenharmony_ci  common.skip('missing crypto');
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ciconst assert = require('assert');
71cb0ef41Sopenharmony_ciconst crypto = require('crypto');
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci// Second OAKLEY group, see
101cb0ef41Sopenharmony_ci// https://github.com/nodejs/node-v0.x-archive/issues/2338 and
111cb0ef41Sopenharmony_ci// https://xml2rfc.tools.ietf.org/public/rfc/html/rfc2412.html#anchor49
121cb0ef41Sopenharmony_ciconst p = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' +
131cb0ef41Sopenharmony_ci          '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' +
141cb0ef41Sopenharmony_ci          '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' +
151cb0ef41Sopenharmony_ci          'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
161cb0ef41Sopenharmony_cicrypto.createDiffieHellman(p, 'hex');
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci// Confirm DH_check() results are exposed for optional examination.
191cb0ef41Sopenharmony_ciconst bad_dh = crypto.createDiffieHellman('02', 'hex');
201cb0ef41Sopenharmony_ciassert.notStrictEqual(bad_dh.verifyError, 0);
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ciconst availableCurves = new Set(crypto.getCurves());
231cb0ef41Sopenharmony_ciconst availableHashes = new Set(crypto.getHashes());
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci// Oakley curves do not clean up ERR stack, it was causing unexpected failure
261cb0ef41Sopenharmony_ci// when accessing other OpenSSL APIs afterwards.
271cb0ef41Sopenharmony_ciif (availableCurves.has('Oakley-EC2N-3')) {
281cb0ef41Sopenharmony_ci  crypto.createECDH('Oakley-EC2N-3');
291cb0ef41Sopenharmony_ci  crypto.createHash('sha256');
301cb0ef41Sopenharmony_ci}
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci// Test ECDH
331cb0ef41Sopenharmony_ciif (availableCurves.has('prime256v1') && availableCurves.has('secp256k1')) {
341cb0ef41Sopenharmony_ci  const ecdh1 = crypto.createECDH('prime256v1');
351cb0ef41Sopenharmony_ci  const ecdh2 = crypto.createECDH('prime256v1');
361cb0ef41Sopenharmony_ci  const key1 = ecdh1.generateKeys();
371cb0ef41Sopenharmony_ci  const key2 = ecdh2.generateKeys('hex');
381cb0ef41Sopenharmony_ci  const secret1 = ecdh1.computeSecret(key2, 'hex', 'base64');
391cb0ef41Sopenharmony_ci  const secret2 = ecdh2.computeSecret(key1, 'latin1', 'buffer');
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci  assert.strictEqual(secret1, secret2.toString('base64'));
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  // Point formats
441cb0ef41Sopenharmony_ci  assert.strictEqual(ecdh1.getPublicKey('buffer', 'uncompressed')[0], 4);
451cb0ef41Sopenharmony_ci  let firstByte = ecdh1.getPublicKey('buffer', 'compressed')[0];
461cb0ef41Sopenharmony_ci  assert(firstByte === 2 || firstByte === 3);
471cb0ef41Sopenharmony_ci  firstByte = ecdh1.getPublicKey('buffer', 'hybrid')[0];
481cb0ef41Sopenharmony_ci  assert(firstByte === 6 || firstByte === 7);
491cb0ef41Sopenharmony_ci  // Format value should be string
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci  assert.throws(
521cb0ef41Sopenharmony_ci    () => ecdh1.getPublicKey('buffer', 10),
531cb0ef41Sopenharmony_ci    {
541cb0ef41Sopenharmony_ci      code: 'ERR_CRYPTO_ECDH_INVALID_FORMAT',
551cb0ef41Sopenharmony_ci      name: 'TypeError',
561cb0ef41Sopenharmony_ci      message: 'Invalid ECDH format: 10'
571cb0ef41Sopenharmony_ci    });
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci  // ECDH should check that point is on curve
601cb0ef41Sopenharmony_ci  const ecdh3 = crypto.createECDH('secp256k1');
611cb0ef41Sopenharmony_ci  const key3 = ecdh3.generateKeys();
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci  assert.throws(
641cb0ef41Sopenharmony_ci    () => ecdh2.computeSecret(key3, 'latin1', 'buffer'),
651cb0ef41Sopenharmony_ci    {
661cb0ef41Sopenharmony_ci      code: 'ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY',
671cb0ef41Sopenharmony_ci      name: 'Error',
681cb0ef41Sopenharmony_ci      message: 'Public key is not valid for specified curve'
691cb0ef41Sopenharmony_ci    });
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  // ECDH should allow .setPrivateKey()/.setPublicKey()
721cb0ef41Sopenharmony_ci  const ecdh4 = crypto.createECDH('prime256v1');
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  ecdh4.setPrivateKey(ecdh1.getPrivateKey());
751cb0ef41Sopenharmony_ci  ecdh4.setPublicKey(ecdh1.getPublicKey());
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  assert.throws(() => {
781cb0ef41Sopenharmony_ci    ecdh4.setPublicKey(ecdh3.getPublicKey());
791cb0ef41Sopenharmony_ci  }, { message: 'Failed to convert Buffer to EC_POINT' });
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  // Verify that we can use ECDH without having to use newly generated keys.
821cb0ef41Sopenharmony_ci  const ecdh5 = crypto.createECDH('secp256k1');
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci  // Verify errors are thrown when retrieving keys from an uninitialized object.
851cb0ef41Sopenharmony_ci  assert.throws(() => {
861cb0ef41Sopenharmony_ci    ecdh5.getPublicKey();
871cb0ef41Sopenharmony_ci  }, /^Error: Failed to get ECDH public key$/);
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci  assert.throws(() => {
901cb0ef41Sopenharmony_ci    ecdh5.getPrivateKey();
911cb0ef41Sopenharmony_ci  }, /^Error: Failed to get ECDH private key$/);
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci  // A valid private key for the secp256k1 curve.
941cb0ef41Sopenharmony_ci  const cafebabeKey = 'cafebabe'.repeat(8);
951cb0ef41Sopenharmony_ci  // Associated compressed and uncompressed public keys (points).
961cb0ef41Sopenharmony_ci  const cafebabePubPtComp =
971cb0ef41Sopenharmony_ci  '03672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3';
981cb0ef41Sopenharmony_ci  const cafebabePubPtUnComp =
991cb0ef41Sopenharmony_ci  '04672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3' +
1001cb0ef41Sopenharmony_ci  '2e02c7f93d13dc2732b760ca377a5897b9dd41a1c1b29dc0442fdce6d0a04d1d';
1011cb0ef41Sopenharmony_ci  ecdh5.setPrivateKey(cafebabeKey, 'hex');
1021cb0ef41Sopenharmony_ci  assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
1031cb0ef41Sopenharmony_ci  // Show that the public point (key) is generated while setting the
1041cb0ef41Sopenharmony_ci  // private key.
1051cb0ef41Sopenharmony_ci  assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci  // Compressed and uncompressed public points/keys for other party's
1081cb0ef41Sopenharmony_ci  // private key.
1091cb0ef41Sopenharmony_ci  // 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
1101cb0ef41Sopenharmony_ci  const peerPubPtComp =
1111cb0ef41Sopenharmony_ci  '02c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae';
1121cb0ef41Sopenharmony_ci  const peerPubPtUnComp =
1131cb0ef41Sopenharmony_ci  '04c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae' +
1141cb0ef41Sopenharmony_ci  'b651944a574a362082a77e3f2b5d9223eb54d7f2f76846522bf75f3bedb8178e';
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci  const sharedSecret =
1171cb0ef41Sopenharmony_ci  '1da220b5329bbe8bfd19ceef5a5898593f411a6f12ea40f2a8eead9a5cf59970';
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  assert.strictEqual(ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'),
1201cb0ef41Sopenharmony_ci                     sharedSecret);
1211cb0ef41Sopenharmony_ci  assert.strictEqual(ecdh5.computeSecret(peerPubPtUnComp, 'hex', 'hex'),
1221cb0ef41Sopenharmony_ci                     sharedSecret);
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci  // Verify that we still have the same key pair as before the computation.
1251cb0ef41Sopenharmony_ci  assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
1261cb0ef41Sopenharmony_ci  assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci  // Verify setting and getting compressed and non-compressed serializations.
1291cb0ef41Sopenharmony_ci  ecdh5.setPublicKey(cafebabePubPtComp, 'hex');
1301cb0ef41Sopenharmony_ci  assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
1311cb0ef41Sopenharmony_ci  assert.strictEqual(
1321cb0ef41Sopenharmony_ci    ecdh5.getPublicKey('hex', 'compressed'),
1331cb0ef41Sopenharmony_ci    cafebabePubPtComp
1341cb0ef41Sopenharmony_ci  );
1351cb0ef41Sopenharmony_ci  ecdh5.setPublicKey(cafebabePubPtUnComp, 'hex');
1361cb0ef41Sopenharmony_ci  assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
1371cb0ef41Sopenharmony_ci  assert.strictEqual(
1381cb0ef41Sopenharmony_ci    ecdh5.getPublicKey('hex', 'compressed'),
1391cb0ef41Sopenharmony_ci    cafebabePubPtComp
1401cb0ef41Sopenharmony_ci  );
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci  // Show why allowing the public key to be set on this type
1431cb0ef41Sopenharmony_ci  // does not make sense.
1441cb0ef41Sopenharmony_ci  ecdh5.setPublicKey(peerPubPtComp, 'hex');
1451cb0ef41Sopenharmony_ci  assert.strictEqual(ecdh5.getPublicKey('hex'), peerPubPtUnComp);
1461cb0ef41Sopenharmony_ci  assert.throws(() => {
1471cb0ef41Sopenharmony_ci    // Error because the public key does not match the private key anymore.
1481cb0ef41Sopenharmony_ci    ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex');
1491cb0ef41Sopenharmony_ci  }, /Invalid key pair/);
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci  // Set to a valid key to show that later attempts to set an invalid key are
1521cb0ef41Sopenharmony_ci  // rejected.
1531cb0ef41Sopenharmony_ci  ecdh5.setPrivateKey(cafebabeKey, 'hex');
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci  // Some invalid private keys for the secp256k1 curve.
1561cb0ef41Sopenharmony_ci  const errMessage = /Private key is not valid for specified curve/;
1571cb0ef41Sopenharmony_ci  ['0000000000000000000000000000000000000000000000000000000000000000',
1581cb0ef41Sopenharmony_ci   'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141',
1591cb0ef41Sopenharmony_ci   'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
1601cb0ef41Sopenharmony_ci  ].forEach((element) => {
1611cb0ef41Sopenharmony_ci    assert.throws(() => {
1621cb0ef41Sopenharmony_ci      ecdh5.setPrivateKey(element, 'hex');
1631cb0ef41Sopenharmony_ci    }, errMessage);
1641cb0ef41Sopenharmony_ci    // Verify object state did not change.
1651cb0ef41Sopenharmony_ci    assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
1661cb0ef41Sopenharmony_ci  });
1671cb0ef41Sopenharmony_ci}
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci// Use of invalid keys was not cleaning up ERR stack, and was causing
1701cb0ef41Sopenharmony_ci// unexpected failure in subsequent signing operations.
1711cb0ef41Sopenharmony_ciif (availableCurves.has('prime256v1') && availableHashes.has('sha256')) {
1721cb0ef41Sopenharmony_ci  const curve = crypto.createECDH('prime256v1');
1731cb0ef41Sopenharmony_ci  const invalidKey = Buffer.alloc(65);
1741cb0ef41Sopenharmony_ci  invalidKey.fill('\0');
1751cb0ef41Sopenharmony_ci  curve.generateKeys();
1761cb0ef41Sopenharmony_ci  assert.throws(
1771cb0ef41Sopenharmony_ci    () => curve.computeSecret(invalidKey),
1781cb0ef41Sopenharmony_ci    {
1791cb0ef41Sopenharmony_ci      code: 'ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY',
1801cb0ef41Sopenharmony_ci      name: 'Error',
1811cb0ef41Sopenharmony_ci      message: 'Public key is not valid for specified curve'
1821cb0ef41Sopenharmony_ci    });
1831cb0ef41Sopenharmony_ci  // Check that signing operations are not impacted by the above error.
1841cb0ef41Sopenharmony_ci  const ecPrivateKey =
1851cb0ef41Sopenharmony_ci    '-----BEGIN EC PRIVATE KEY-----\n' +
1861cb0ef41Sopenharmony_ci    'MHcCAQEEIF+jnWY1D5kbVYDNvxxo/Y+ku2uJPDwS0r/VuPZQrjjVoAoGCCqGSM49\n' +
1871cb0ef41Sopenharmony_ci    'AwEHoUQDQgAEurOxfSxmqIRYzJVagdZfMMSjRNNhB8i3mXyIMq704m2m52FdfKZ2\n' +
1881cb0ef41Sopenharmony_ci    'pQhByd5eyj3lgZ7m7jbchtdgyOF8Io/1ng==\n' +
1891cb0ef41Sopenharmony_ci    '-----END EC PRIVATE KEY-----';
1901cb0ef41Sopenharmony_ci  crypto.createSign('SHA256').sign(ecPrivateKey);
1911cb0ef41Sopenharmony_ci}
192