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