Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 9227f2a

Browse filesBrowse files
joyeecheungtargos
authored andcommitted
test: split test-crypto-dh.js
Split test-crypto-dh.js so that it is less likely to timeout on less powerful bots. PR-URL: #40451 Refs: nodejs/reliability#86 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
1 parent 143c881 commit 9227f2a
Copy full SHA for 9227f2a

File tree

Expand file treeCollapse file tree

8 files changed

+389
-305
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

8 files changed

+389
-305
lines changed
Open diff view settings
Collapse file

‎test/common/crypto.js‎

Copy file name to clipboard
+48Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
if (!common.hasCrypto)
5+
common.skip('missing crypto');
6+
7+
const assert = require('assert');
8+
const crypto = require('crypto');
9+
10+
// The values below (modp2/modp2buf) are for a 1024 bits long prime from
11+
// RFC 2412 E.2, see https://tools.ietf.org/html/rfc2412. */
12+
const modp2buf = Buffer.from([
13+
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f,
14+
0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b,
15+
0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67,
16+
0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22,
17+
0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, 0xef, 0x95,
18+
0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d,
19+
0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51,
20+
0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
21+
0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff,
22+
0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, 0xee, 0x38, 0x6b, 0xfb,
23+
0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b,
24+
0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe6, 0x53, 0x81,
25+
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
26+
]);
27+
28+
function testDH({ publicKey: alicePublicKey, privateKey: alicePrivateKey },
29+
{ publicKey: bobPublicKey, privateKey: bobPrivateKey },
30+
expectedValue) {
31+
const buf1 = crypto.diffieHellman({
32+
privateKey: alicePrivateKey,
33+
publicKey: bobPublicKey
34+
});
35+
const buf2 = crypto.diffieHellman({
36+
privateKey: bobPrivateKey,
37+
publicKey: alicePublicKey
38+
});
39+
assert.deepStrictEqual(buf1, buf2);
40+
41+
if (expectedValue !== undefined)
42+
assert.deepStrictEqual(buf1, expectedValue);
43+
}
44+
45+
module.exports = {
46+
modp2buf,
47+
testDH
48+
};
Collapse file
+34Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use strict';
2+
const common = require('../common');
3+
if (!common.hasCrypto)
4+
common.skip('missing crypto');
5+
6+
const assert = require('assert');
7+
const crypto = require('crypto');
8+
9+
const size = common.hasFipsCrypto || common.hasOpenSSL3 ? 1024 : 256;
10+
const dh1 = crypto.createDiffieHellman(size);
11+
const p1 = dh1.getPrime('buffer');
12+
13+
{
14+
const DiffieHellman = crypto.DiffieHellman;
15+
16+
const dh = DiffieHellman(p1, 'buffer');
17+
assert(dh instanceof DiffieHellman, 'DiffieHellman is expected to return a ' +
18+
'new instance when called without `new`');
19+
}
20+
21+
{
22+
const DiffieHellmanGroup = crypto.DiffieHellmanGroup;
23+
const dhg = DiffieHellmanGroup('modp5');
24+
assert(dhg instanceof DiffieHellmanGroup, 'DiffieHellmanGroup is expected ' +
25+
'to return a new instance when ' +
26+
'called without `new`');
27+
}
28+
29+
{
30+
const ECDH = crypto.ECDH;
31+
const ecdh = ECDH('prime256v1');
32+
assert(ecdh instanceof ECDH, 'ECDH is expected to return a new instance ' +
33+
'when called without `new`');
34+
}
Collapse file
+191Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
'use strict';
2+
const common = require('../common');
3+
if (!common.hasCrypto)
4+
common.skip('missing crypto');
5+
6+
const assert = require('assert');
7+
const crypto = require('crypto');
8+
9+
// Second OAKLEY group, see
10+
// https://github.com/nodejs/node-v0.x-archive/issues/2338 and
11+
// https://xml2rfc.tools.ietf.org/public/rfc/html/rfc2412.html#anchor49
12+
const p = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' +
13+
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' +
14+
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' +
15+
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
16+
crypto.createDiffieHellman(p, 'hex');
17+
18+
// Confirm DH_check() results are exposed for optional examination.
19+
const bad_dh = crypto.createDiffieHellman('02', 'hex');
20+
assert.notStrictEqual(bad_dh.verifyError, 0);
21+
22+
const availableCurves = new Set(crypto.getCurves());
23+
const availableHashes = new Set(crypto.getHashes());
24+
25+
// Oakley curves do not clean up ERR stack, it was causing unexpected failure
26+
// when accessing other OpenSSL APIs afterwards.
27+
if (availableCurves.has('Oakley-EC2N-3')) {
28+
crypto.createECDH('Oakley-EC2N-3');
29+
crypto.createHash('sha256');
30+
}
31+
32+
// Test ECDH
33+
if (availableCurves.has('prime256v1') && availableCurves.has('secp256k1')) {
34+
const ecdh1 = crypto.createECDH('prime256v1');
35+
const ecdh2 = crypto.createECDH('prime256v1');
36+
const key1 = ecdh1.generateKeys();
37+
const key2 = ecdh2.generateKeys('hex');
38+
const secret1 = ecdh1.computeSecret(key2, 'hex', 'base64');
39+
const secret2 = ecdh2.computeSecret(key1, 'latin1', 'buffer');
40+
41+
assert.strictEqual(secret1, secret2.toString('base64'));
42+
43+
// Point formats
44+
assert.strictEqual(ecdh1.getPublicKey('buffer', 'uncompressed')[0], 4);
45+
let firstByte = ecdh1.getPublicKey('buffer', 'compressed')[0];
46+
assert(firstByte === 2 || firstByte === 3);
47+
firstByte = ecdh1.getPublicKey('buffer', 'hybrid')[0];
48+
assert(firstByte === 6 || firstByte === 7);
49+
// Format value should be string
50+
51+
assert.throws(
52+
() => ecdh1.getPublicKey('buffer', 10),
53+
{
54+
code: 'ERR_CRYPTO_ECDH_INVALID_FORMAT',
55+
name: 'TypeError',
56+
message: 'Invalid ECDH format: 10'
57+
});
58+
59+
// ECDH should check that point is on curve
60+
const ecdh3 = crypto.createECDH('secp256k1');
61+
const key3 = ecdh3.generateKeys();
62+
63+
assert.throws(
64+
() => ecdh2.computeSecret(key3, 'latin1', 'buffer'),
65+
{
66+
code: 'ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY',
67+
name: 'Error',
68+
message: 'Public key is not valid for specified curve'
69+
});
70+
71+
// ECDH should allow .setPrivateKey()/.setPublicKey()
72+
const ecdh4 = crypto.createECDH('prime256v1');
73+
74+
ecdh4.setPrivateKey(ecdh1.getPrivateKey());
75+
ecdh4.setPublicKey(ecdh1.getPublicKey());
76+
77+
assert.throws(() => {
78+
ecdh4.setPublicKey(ecdh3.getPublicKey());
79+
}, { message: 'Failed to convert Buffer to EC_POINT' });
80+
81+
// Verify that we can use ECDH without having to use newly generated keys.
82+
const ecdh5 = crypto.createECDH('secp256k1');
83+
84+
// Verify errors are thrown when retrieving keys from an uninitialized object.
85+
assert.throws(() => {
86+
ecdh5.getPublicKey();
87+
}, /^Error: Failed to get ECDH public key$/);
88+
89+
assert.throws(() => {
90+
ecdh5.getPrivateKey();
91+
}, /^Error: Failed to get ECDH private key$/);
92+
93+
// A valid private key for the secp256k1 curve.
94+
const cafebabeKey = 'cafebabe'.repeat(8);
95+
// Associated compressed and uncompressed public keys (points).
96+
const cafebabePubPtComp =
97+
'03672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3';
98+
const cafebabePubPtUnComp =
99+
'04672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3' +
100+
'2e02c7f93d13dc2732b760ca377a5897b9dd41a1c1b29dc0442fdce6d0a04d1d';
101+
ecdh5.setPrivateKey(cafebabeKey, 'hex');
102+
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
103+
// Show that the public point (key) is generated while setting the
104+
// private key.
105+
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
106+
107+
// Compressed and uncompressed public points/keys for other party's
108+
// private key.
109+
// 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
110+
const peerPubPtComp =
111+
'02c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae';
112+
const peerPubPtUnComp =
113+
'04c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae' +
114+
'b651944a574a362082a77e3f2b5d9223eb54d7f2f76846522bf75f3bedb8178e';
115+
116+
const sharedSecret =
117+
'1da220b5329bbe8bfd19ceef5a5898593f411a6f12ea40f2a8eead9a5cf59970';
118+
119+
assert.strictEqual(ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'),
120+
sharedSecret);
121+
assert.strictEqual(ecdh5.computeSecret(peerPubPtUnComp, 'hex', 'hex'),
122+
sharedSecret);
123+
124+
// Verify that we still have the same key pair as before the computation.
125+
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
126+
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
127+
128+
// Verify setting and getting compressed and non-compressed serializations.
129+
ecdh5.setPublicKey(cafebabePubPtComp, 'hex');
130+
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
131+
assert.strictEqual(
132+
ecdh5.getPublicKey('hex', 'compressed'),
133+
cafebabePubPtComp
134+
);
135+
ecdh5.setPublicKey(cafebabePubPtUnComp, 'hex');
136+
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
137+
assert.strictEqual(
138+
ecdh5.getPublicKey('hex', 'compressed'),
139+
cafebabePubPtComp
140+
);
141+
142+
// Show why allowing the public key to be set on this type
143+
// does not make sense.
144+
ecdh5.setPublicKey(peerPubPtComp, 'hex');
145+
assert.strictEqual(ecdh5.getPublicKey('hex'), peerPubPtUnComp);
146+
assert.throws(() => {
147+
// Error because the public key does not match the private key anymore.
148+
ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex');
149+
}, /Invalid key pair/);
150+
151+
// Set to a valid key to show that later attempts to set an invalid key are
152+
// rejected.
153+
ecdh5.setPrivateKey(cafebabeKey, 'hex');
154+
155+
// Some invalid private keys for the secp256k1 curve.
156+
const errMessage = /Private key is not valid for specified curve/;
157+
['0000000000000000000000000000000000000000000000000000000000000000',
158+
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141',
159+
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
160+
].forEach((element) => {
161+
assert.throws(() => {
162+
ecdh5.setPrivateKey(element, 'hex');
163+
}, errMessage);
164+
// Verify object state did not change.
165+
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
166+
});
167+
}
168+
169+
// Use of invalid keys was not cleaning up ERR stack, and was causing
170+
// unexpected failure in subsequent signing operations.
171+
if (availableCurves.has('prime256v1') && availableHashes.has('sha256')) {
172+
const curve = crypto.createECDH('prime256v1');
173+
const invalidKey = Buffer.alloc(65);
174+
invalidKey.fill('\0');
175+
curve.generateKeys();
176+
assert.throws(
177+
() => curve.computeSecret(invalidKey),
178+
{
179+
code: 'ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY',
180+
name: 'Error',
181+
message: 'Public key is not valid for specified curve'
182+
});
183+
// Check that signing operations are not impacted by the above error.
184+
const ecPrivateKey =
185+
'-----BEGIN EC PRIVATE KEY-----\n' +
186+
'MHcCAQEEIF+jnWY1D5kbVYDNvxxo/Y+ku2uJPDwS0r/VuPZQrjjVoAoGCCqGSM49\n' +
187+
'AwEHoUQDQgAEurOxfSxmqIRYzJVagdZfMMSjRNNhB8i3mXyIMq704m2m52FdfKZ2\n' +
188+
'pQhByd5eyj3lgZ7m7jbchtdgyOF8Io/1ng==\n' +
189+
'-----END EC PRIVATE KEY-----';
190+
crypto.createSign('SHA256').sign(ecPrivateKey);
191+
}
Collapse file
+24Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
const common = require('../common');
3+
if (!common.hasCrypto)
4+
common.skip('missing crypto');
5+
6+
const assert = require('assert');
7+
const crypto = require('crypto');
8+
const { modp2buf } = require('../common/crypto');
9+
10+
const modp2 = crypto.createDiffieHellmanGroup('modp2');
11+
12+
const views = common.getArrayBufferViews(modp2buf);
13+
for (const buf of [modp2buf, ...views]) {
14+
// Ensure specific generator (string with encoding) works as expected with
15+
// any ArrayBufferViews as the first argument to createDiffieHellman().
16+
const exmodp2 = crypto.createDiffieHellman(buf, '02', 'hex');
17+
modp2.generateKeys();
18+
exmodp2.generateKeys();
19+
const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey())
20+
.toString('hex');
21+
const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey())
22+
.toString('hex');
23+
assert.strictEqual(modp2Secret, exmodp2Secret);
24+
}
Collapse file
+43Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use strict';
2+
const common = require('../common');
3+
if (!common.hasCrypto)
4+
common.skip('missing crypto');
5+
6+
const assert = require('assert');
7+
const crypto = require('crypto');
8+
const { modp2buf } = require('../common/crypto');
9+
const modp2 = crypto.createDiffieHellmanGroup('modp2');
10+
11+
{
12+
// Ensure specific generator (buffer) works as expected.
13+
const exmodp2 = crypto.createDiffieHellman(modp2buf, Buffer.from([2]));
14+
modp2.generateKeys();
15+
exmodp2.generateKeys();
16+
const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey())
17+
.toString('hex');
18+
const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey())
19+
.toString('hex');
20+
assert.strictEqual(modp2Secret, exmodp2Secret);
21+
}
22+
23+
{
24+
// Ensure specific generator (string without encoding) works as expected.
25+
const exmodp2 = crypto.createDiffieHellman(modp2buf, '\x02');
26+
exmodp2.generateKeys();
27+
const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey())
28+
.toString('hex');
29+
const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey())
30+
.toString('hex');
31+
assert.strictEqual(modp2Secret, exmodp2Secret);
32+
}
33+
34+
{
35+
// Ensure specific generator (numeric) works as expected.
36+
const exmodp2 = crypto.createDiffieHellman(modp2buf, 2);
37+
exmodp2.generateKeys();
38+
const modp2Secret = modp2.computeSecret(exmodp2.getPublicKey())
39+
.toString('hex');
40+
const exmodp2Secret = exmodp2.computeSecret(modp2.getPublicKey())
41+
.toString('hex');
42+
assert.strictEqual(modp2Secret, exmodp2Secret);
43+
}
Collapse file
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict';
2+
const common = require('../common');
3+
if (!common.hasCrypto)
4+
common.skip('missing crypto');
5+
6+
const assert = require('assert');
7+
const crypto = require('crypto');
8+
9+
const alice = crypto.createDiffieHellmanGroup('modp5');
10+
const bob = crypto.createDiffieHellmanGroup('modp5');
11+
alice.generateKeys();
12+
bob.generateKeys();
13+
const aSecret = alice.computeSecret(bob.getPublicKey()).toString('hex');
14+
const bSecret = bob.computeSecret(alice.getPublicKey()).toString('hex');
15+
assert.strictEqual(aSecret, bSecret);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.