Skip to content

Commit 2555780

Browse files
Qantas94Heavyaddaleax
authored andcommitted
test: check curve algorithm is supported
parallel/test-crypto-dh.js assumes particular curve algorithms (e.g. Oakley-EC2N-3) are supported, though this may not necessarily be the case if Node.js was built with a system version of OpenSSL. PR-URL: #12265 Reviewed-By: Ben Noordhuis <[email protected]>
1 parent b2a12ee commit 2555780

File tree

1 file changed

+122
-107
lines changed

1 file changed

+122
-107
lines changed

test/parallel/test-crypto-dh.js

+122-107
Original file line numberDiff line numberDiff line change
@@ -185,126 +185,141 @@ const bad_dh = crypto.createDiffieHellman(p, 'hex');
185185
assert.strictEqual(bad_dh.verifyError, DH_NOT_SUITABLE_GENERATOR);
186186

187187

188-
// Test ECDH
189-
const ecdh1 = crypto.createECDH('prime256v1');
190-
const ecdh2 = crypto.createECDH('prime256v1');
191-
key1 = ecdh1.generateKeys();
192-
key2 = ecdh2.generateKeys('hex');
193-
secret1 = ecdh1.computeSecret(key2, 'hex', 'base64');
194-
secret2 = ecdh2.computeSecret(key1, 'latin1', 'buffer');
195-
196-
assert.strictEqual(secret1, secret2.toString('base64'));
188+
const availableCurves = new Set(crypto.getCurves());
197189

198190
// Oakley curves do not clean up ERR stack, it was causing unexpected failure
199191
// when accessing other OpenSSL APIs afterwards.
200-
crypto.createECDH('Oakley-EC2N-3');
201-
crypto.createHash('sha256');
202-
203-
// Point formats
204-
assert.strictEqual(ecdh1.getPublicKey('buffer', 'uncompressed')[0], 4);
205-
let firstByte = ecdh1.getPublicKey('buffer', 'compressed')[0];
206-
assert(firstByte === 2 || firstByte === 3);
207-
firstByte = ecdh1.getPublicKey('buffer', 'hybrid')[0];
208-
assert(firstByte === 6 || firstByte === 7);
209-
// format value should be string
210-
assert.throws(() => {
211-
ecdh1.getPublicKey('buffer', 10);
212-
}, /^TypeError: Bad format: 10$/);
192+
if (availableCurves.has('Oakley-EC2N-3')) {
193+
crypto.createECDH('Oakley-EC2N-3');
194+
crypto.createHash('sha256');
195+
}
213196

214-
// ECDH should check that point is on curve
215-
const ecdh3 = crypto.createECDH('secp256k1');
216-
const key3 = ecdh3.generateKeys();
197+
// Test ECDH
198+
if (availableCurves.has('prime256v1') && availableCurves.has('secp256k1')) {
199+
const ecdh1 = crypto.createECDH('prime256v1');
200+
const ecdh2 = crypto.createECDH('prime256v1');
201+
key1 = ecdh1.generateKeys();
202+
key2 = ecdh2.generateKeys('hex');
203+
secret1 = ecdh1.computeSecret(key2, 'hex', 'base64');
204+
secret2 = ecdh2.computeSecret(key1, 'latin1', 'buffer');
205+
206+
assert.strictEqual(secret1, secret2.toString('base64'));
207+
208+
// Point formats
209+
assert.strictEqual(ecdh1.getPublicKey('buffer', 'uncompressed')[0], 4);
210+
let firstByte = ecdh1.getPublicKey('buffer', 'compressed')[0];
211+
assert(firstByte === 2 || firstByte === 3);
212+
firstByte = ecdh1.getPublicKey('buffer', 'hybrid')[0];
213+
assert(firstByte === 6 || firstByte === 7);
214+
// format value should be string
215+
assert.throws(() => {
216+
ecdh1.getPublicKey('buffer', 10);
217+
}, /^TypeError: Bad format: 10$/);
217218

218-
assert.throws(() => {
219-
ecdh2.computeSecret(key3, 'latin1', 'buffer');
220-
}, /^Error: Failed to translate Buffer to a EC_POINT$/);
219+
// ECDH should check that point is on curve
220+
const ecdh3 = crypto.createECDH('secp256k1');
221+
const key3 = ecdh3.generateKeys();
221222

222-
// ECDH should allow .setPrivateKey()/.setPublicKey()
223-
const ecdh4 = crypto.createECDH('prime256v1');
223+
assert.throws(() => {
224+
ecdh2.computeSecret(key3, 'latin1', 'buffer');
225+
}, /^Error: Failed to translate Buffer to a EC_POINT$/);
224226

225-
ecdh4.setPrivateKey(ecdh1.getPrivateKey());
226-
ecdh4.setPublicKey(ecdh1.getPublicKey());
227+
// ECDH should allow .setPrivateKey()/.setPublicKey()
228+
const ecdh4 = crypto.createECDH('prime256v1');
227229

228-
assert.throws(() => {
229-
ecdh4.setPublicKey(ecdh3.getPublicKey());
230-
}, /^Error: Failed to convert Buffer to EC_POINT$/);
230+
ecdh4.setPrivateKey(ecdh1.getPrivateKey());
231+
ecdh4.setPublicKey(ecdh1.getPublicKey());
231232

232-
// Verify that we can use ECDH without having to use newly generated keys.
233-
const ecdh5 = crypto.createECDH('secp256k1');
233+
assert.throws(() => {
234+
ecdh4.setPublicKey(ecdh3.getPublicKey());
235+
}, /^Error: Failed to convert Buffer to EC_POINT$/);
234236

235-
// Verify errors are thrown when retrieving keys from an uninitialized object.
236-
assert.throws(() => {
237-
ecdh5.getPublicKey();
238-
}, /^Error: Failed to get ECDH public key$/);
237+
// Verify that we can use ECDH without having to use newly generated keys.
238+
const ecdh5 = crypto.createECDH('secp256k1');
239239

240-
assert.throws(() => {
241-
ecdh5.getPrivateKey();
242-
}, /^Error: Failed to get ECDH private key$/);
243-
244-
// A valid private key for the secp256k1 curve.
245-
const cafebabeKey = 'cafebabe'.repeat(8);
246-
// Associated compressed and uncompressed public keys (points).
247-
const cafebabePubPtComp =
248-
'03672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3';
249-
const cafebabePubPtUnComp =
250-
'04672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3' +
251-
'2e02c7f93d13dc2732b760ca377a5897b9dd41a1c1b29dc0442fdce6d0a04d1d';
252-
ecdh5.setPrivateKey(cafebabeKey, 'hex');
253-
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
254-
// Show that the public point (key) is generated while setting the private key.
255-
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
256-
257-
// Compressed and uncompressed public points/keys for other party's private key
258-
// 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
259-
const peerPubPtComp =
260-
'02c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae';
261-
const peerPubPtUnComp =
262-
'04c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae' +
263-
'b651944a574a362082a77e3f2b5d9223eb54d7f2f76846522bf75f3bedb8178e';
264-
265-
const sharedSecret =
266-
'1da220b5329bbe8bfd19ceef5a5898593f411a6f12ea40f2a8eead9a5cf59970';
267-
268-
assert.strictEqual(ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'),
269-
sharedSecret);
270-
assert.strictEqual(ecdh5.computeSecret(peerPubPtUnComp, 'hex', 'hex'),
271-
sharedSecret);
272-
273-
// Verify that we still have the same key pair as before the computation.
274-
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
275-
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
276-
277-
// Verify setting and getting compressed and non-compressed serializations.
278-
ecdh5.setPublicKey(cafebabePubPtComp, 'hex');
279-
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
280-
assert.strictEqual(ecdh5.getPublicKey('hex', 'compressed'), cafebabePubPtComp);
281-
ecdh5.setPublicKey(cafebabePubPtUnComp, 'hex');
282-
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
283-
assert.strictEqual(ecdh5.getPublicKey('hex', 'compressed'), cafebabePubPtComp);
284-
285-
// Show why allowing the public key to be set on this type does not make sense.
286-
ecdh5.setPublicKey(peerPubPtComp, 'hex');
287-
assert.strictEqual(ecdh5.getPublicKey('hex'), peerPubPtUnComp);
288-
assert.throws(() => {
289-
// Error because the public key does not match the private key anymore.
290-
ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex');
291-
}, /^Error: Invalid key pair$/);
292-
293-
// Set to a valid key to show that later attempts to set an invalid key are
294-
// rejected.
295-
ecdh5.setPrivateKey(cafebabeKey, 'hex');
296-
297-
[ // Some invalid private keys for the secp256k1 curve.
298-
'0000000000000000000000000000000000000000000000000000000000000000',
299-
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141',
300-
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
301-
].forEach((element) => {
240+
// Verify errors are thrown when retrieving keys from an uninitialized object.
302241
assert.throws(() => {
303-
ecdh5.setPrivateKey(element, 'hex');
304-
}, /^Error: Private key is not valid for specified curve\.$/);
305-
// Verify object state did not change.
242+
ecdh5.getPublicKey();
243+
}, /^Error: Failed to get ECDH public key$/);
244+
245+
assert.throws(() => {
246+
ecdh5.getPrivateKey();
247+
}, /^Error: Failed to get ECDH private key$/);
248+
249+
// A valid private key for the secp256k1 curve.
250+
const cafebabeKey = 'cafebabe'.repeat(8);
251+
// Associated compressed and uncompressed public keys (points).
252+
const cafebabePubPtComp =
253+
'03672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3';
254+
const cafebabePubPtUnComp =
255+
'04672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3' +
256+
'2e02c7f93d13dc2732b760ca377a5897b9dd41a1c1b29dc0442fdce6d0a04d1d';
257+
ecdh5.setPrivateKey(cafebabeKey, 'hex');
258+
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
259+
// Show that the public point (key) is generated while setting the
260+
// private key.
261+
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
262+
263+
// Compressed and uncompressed public points/keys for other party's
264+
// private key.
265+
// 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
266+
const peerPubPtComp =
267+
'02c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae';
268+
const peerPubPtUnComp =
269+
'04c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae' +
270+
'b651944a574a362082a77e3f2b5d9223eb54d7f2f76846522bf75f3bedb8178e';
271+
272+
const sharedSecret =
273+
'1da220b5329bbe8bfd19ceef5a5898593f411a6f12ea40f2a8eead9a5cf59970';
274+
275+
assert.strictEqual(ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'),
276+
sharedSecret);
277+
assert.strictEqual(ecdh5.computeSecret(peerPubPtUnComp, 'hex', 'hex'),
278+
sharedSecret);
279+
280+
// Verify that we still have the same key pair as before the computation.
306281
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
307-
});
282+
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
283+
284+
// Verify setting and getting compressed and non-compressed serializations.
285+
ecdh5.setPublicKey(cafebabePubPtComp, 'hex');
286+
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
287+
assert.strictEqual(
288+
ecdh5.getPublicKey('hex', 'compressed'),
289+
cafebabePubPtComp
290+
);
291+
ecdh5.setPublicKey(cafebabePubPtUnComp, 'hex');
292+
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
293+
assert.strictEqual(
294+
ecdh5.getPublicKey('hex', 'compressed'),
295+
cafebabePubPtComp
296+
);
297+
298+
// Show why allowing the public key to be set on this type
299+
// does not make sense.
300+
ecdh5.setPublicKey(peerPubPtComp, 'hex');
301+
assert.strictEqual(ecdh5.getPublicKey('hex'), peerPubPtUnComp);
302+
assert.throws(() => {
303+
// Error because the public key does not match the private key anymore.
304+
ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex');
305+
}, /^Error: Invalid key pair$/);
306+
307+
// Set to a valid key to show that later attempts to set an invalid key are
308+
// rejected.
309+
ecdh5.setPrivateKey(cafebabeKey, 'hex');
310+
311+
[ // Some invalid private keys for the secp256k1 curve.
312+
'0000000000000000000000000000000000000000000000000000000000000000',
313+
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141',
314+
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
315+
].forEach((element) => {
316+
assert.throws(() => {
317+
ecdh5.setPrivateKey(element, 'hex');
318+
}, /^Error: Private key is not valid for specified curve\.$/);
319+
// Verify object state did not change.
320+
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
321+
});
322+
}
308323

309324
// invalid test: curve argument is undefined
310325
assert.throws(() => {

0 commit comments

Comments
 (0)