Skip to content

Commit ac400a7

Browse files
Qantas94HeavyMylesBorins
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.
1 parent 47e7020 commit ac400a7

File tree

1 file changed

+138
-127
lines changed

1 file changed

+138
-127
lines changed

Diff for: test/parallel/test-crypto-dh.js

+138-127
Original file line numberDiff line numberDiff line change
@@ -161,146 +161,157 @@ const bad_dh = crypto.createDiffieHellman(p, 'hex');
161161
assert.strictEqual(bad_dh.verifyError, DH_NOT_SUITABLE_GENERATOR);
162162

163163

164-
// Test ECDH
165-
const ecdh1 = crypto.createECDH('prime256v1');
166-
const ecdh2 = crypto.createECDH('prime256v1');
167-
key1 = ecdh1.generateKeys();
168-
key2 = ecdh2.generateKeys('hex');
169-
secret1 = ecdh1.computeSecret(key2, 'hex', 'base64');
170-
secret2 = ecdh2.computeSecret(key1, 'latin1', 'buffer');
171-
172-
assert.strictEqual(secret1, secret2.toString('base64'));
164+
const availableCurves = new Set(crypto.getCurves());
173165

174166
// Oakley curves do not clean up ERR stack, it was causing unexpected failure
175167
// when accessing other OpenSSL APIs afterwards.
176-
crypto.createECDH('Oakley-EC2N-3');
177-
crypto.createHash('sha256');
178-
179-
// Point formats
180-
assert.strictEqual(ecdh1.getPublicKey('buffer', 'uncompressed')[0], 4);
181-
let firstByte = ecdh1.getPublicKey('buffer', 'compressed')[0];
182-
assert(firstByte === 2 || firstByte === 3);
183-
firstByte = ecdh1.getPublicKey('buffer', 'hybrid')[0];
184-
assert(firstByte === 6 || firstByte === 7);
185-
// format value should be string
186-
assert.throws(() => {
187-
ecdh1.getPublicKey('buffer', 10);
188-
}, /^TypeError: Bad format: 10$/);
168+
if (availableCurves.has('Oakley-EC2N-3')) {
169+
crypto.createECDH('Oakley-EC2N-3');
170+
crypto.createHash('sha256');
171+
}
172+
173+
// Test ECDH
174+
if (availableCurves.has('prime256v1') && availableCurves.has('secp256k1')) {
175+
const ecdh1 = crypto.createECDH('prime256v1');
176+
const ecdh2 = crypto.createECDH('prime256v1');
177+
key1 = ecdh1.generateKeys();
178+
key2 = ecdh2.generateKeys('hex');
179+
secret1 = ecdh1.computeSecret(key2, 'hex', 'base64');
180+
secret2 = ecdh2.computeSecret(key1, 'latin1', 'buffer');
181+
182+
assert.strictEqual(secret1, secret2.toString('base64'));
183+
184+
// Point formats
185+
assert.strictEqual(ecdh1.getPublicKey('buffer', 'uncompressed')[0], 4);
186+
let firstByte = ecdh1.getPublicKey('buffer', 'compressed')[0];
187+
assert(firstByte === 2 || firstByte === 3);
188+
firstByte = ecdh1.getPublicKey('buffer', 'hybrid')[0];
189+
assert(firstByte === 6 || firstByte === 7);
190+
// format value should be string
191+
assert.throws(() => {
192+
ecdh1.getPublicKey('buffer', 10);
193+
}, /^TypeError: Bad format: 10$/);
189194

190-
// ECDH should check that point is on curve
191-
const ecdh3 = crypto.createECDH('secp256k1');
192-
const key3 = ecdh3.generateKeys();
195+
// ECDH should check that point is on curve
196+
const ecdh3 = crypto.createECDH('secp256k1');
197+
const key3 = ecdh3.generateKeys();
193198

194-
assert.throws(() => {
195-
ecdh2.computeSecret(key3, 'latin1', 'buffer');
196-
}, /^Error: Failed to translate Buffer to a EC_POINT$/);
199+
assert.throws(() => {
200+
ecdh2.computeSecret(key3, 'latin1', 'buffer');
201+
}, /^Error: Failed to translate Buffer to a EC_POINT$/);
197202

198-
// ECDH should allow .setPrivateKey()/.setPublicKey()
199-
const ecdh4 = crypto.createECDH('prime256v1');
203+
// ECDH should allow .setPrivateKey()/.setPublicKey()
204+
const ecdh4 = crypto.createECDH('prime256v1');
200205

201-
ecdh4.setPrivateKey(ecdh1.getPrivateKey());
202-
ecdh4.setPublicKey(ecdh1.getPublicKey());
206+
ecdh4.setPrivateKey(ecdh1.getPrivateKey());
207+
ecdh4.setPublicKey(ecdh1.getPublicKey());
203208

204-
assert.throws(() => {
205-
ecdh4.setPublicKey(ecdh3.getPublicKey());
206-
}, /^Error: Failed to convert Buffer to EC_POINT$/);
209+
assert.throws(() => {
210+
ecdh4.setPublicKey(ecdh3.getPublicKey());
211+
}, /^Error: Failed to convert Buffer to EC_POINT$/);
207212

208-
// Verify that we can use ECDH without having to use newly generated keys.
209-
const ecdh5 = crypto.createECDH('secp256k1');
213+
// Verify that we can use ECDH without having to use newly generated keys.
214+
const ecdh5 = crypto.createECDH('secp256k1');
210215

211-
// Verify errors are thrown when retrieving keys from an uninitialized object.
212-
assert.throws(() => {
213-
ecdh5.getPublicKey();
214-
}, /^Error: Failed to get ECDH public key$/);
216+
// Verify errors are thrown when retrieving keys from an uninitialized object.
217+
assert.throws(() => {
218+
ecdh5.getPublicKey();
219+
}, /^Error: Failed to get ECDH public key$/);
215220

216-
assert.throws(() => {
217-
ecdh5.getPrivateKey();
218-
}, /^Error: Failed to get ECDH private key$/);
219-
220-
// A valid private key for the secp256k1 curve.
221-
const cafebabeKey = 'cafebabe'.repeat(8);
222-
// Associated compressed and uncompressed public keys (points).
223-
const cafebabePubPtComp =
224-
'03672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3';
225-
const cafebabePubPtUnComp =
226-
'04672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3' +
227-
'2e02c7f93d13dc2732b760ca377a5897b9dd41a1c1b29dc0442fdce6d0a04d1d';
228-
ecdh5.setPrivateKey(cafebabeKey, 'hex');
229-
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
230-
// Show that the public point (key) is generated while setting the private key.
231-
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
232-
233-
// Compressed and uncompressed public points/keys for other party's private key
234-
// 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
235-
const peerPubPtComp =
236-
'02c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae';
237-
const peerPubPtUnComp =
238-
'04c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae' +
239-
'b651944a574a362082a77e3f2b5d9223eb54d7f2f76846522bf75f3bedb8178e';
240-
241-
const sharedSecret =
242-
'1da220b5329bbe8bfd19ceef5a5898593f411a6f12ea40f2a8eead9a5cf59970';
243-
244-
assert.strictEqual(ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'),
245-
sharedSecret);
246-
assert.strictEqual(ecdh5.computeSecret(peerPubPtUnComp, 'hex', 'hex'),
247-
sharedSecret);
248-
249-
// Verify that we still have the same key pair as before the computation.
250-
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
251-
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
252-
253-
// Verify setting and getting compressed and non-compressed serializations.
254-
ecdh5.setPublicKey(cafebabePubPtComp, 'hex');
255-
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
256-
assert.strictEqual(ecdh5.getPublicKey('hex', 'compressed'), cafebabePubPtComp);
257-
ecdh5.setPublicKey(cafebabePubPtUnComp, 'hex');
258-
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
259-
assert.strictEqual(ecdh5.getPublicKey('hex', 'compressed'), cafebabePubPtComp);
260-
261-
// Show why allowing the public key to be set on this type does not make sense.
262-
ecdh5.setPublicKey(peerPubPtComp, 'hex');
263-
assert.strictEqual(ecdh5.getPublicKey('hex'), peerPubPtUnComp);
264-
assert.throws(() => {
265-
// Error because the public key does not match the private key anymore.
266-
ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex');
267-
}, /^Error: Invalid key pair$/);
268-
269-
// Set to a valid key to show that later attempts to set an invalid key are
270-
// rejected.
271-
ecdh5.setPrivateKey(cafebabeKey, 'hex');
272-
273-
[ // Some invalid private keys for the secp256k1 curve.
274-
'0000000000000000000000000000000000000000000000000000000000000000',
275-
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141',
276-
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
277-
].forEach((element) => {
278221
assert.throws(() => {
279-
ecdh5.setPrivateKey(element, 'hex');
280-
}, /^Error: Private key is not valid for specified curve.$/);
281-
// Verify object state did not change.
222+
ecdh5.getPrivateKey();
223+
}, /^Error: Failed to get ECDH private key$/);
224+
225+
// A valid private key for the secp256k1 curve.
226+
const cafebabeKey = 'cafebabe'.repeat(8);
227+
// Associated compressed and uncompressed public keys (points).
228+
const cafebabePubPtComp =
229+
'03672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3';
230+
const cafebabePubPtUnComp =
231+
'04672a31bfc59d3f04548ec9b7daeeba2f61814e8ccc40448045007f5479f693a3' +
232+
'2e02c7f93d13dc2732b760ca377a5897b9dd41a1c1b29dc0442fdce6d0a04d1d';
233+
ecdh5.setPrivateKey(cafebabeKey, 'hex');
282234
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
283-
});
284-
285-
// Use of invalid keys was not cleaning up ERR stack, and was causing
286-
// unexpected failure in subsequent signing operations.
287-
const ecdh6 = crypto.createECDH('prime256v1');
288-
const invalidKey = Buffer.alloc(65);
289-
invalidKey.fill('\0');
290-
ecdh6.generateKeys();
291-
assert.throws(() => {
292-
ecdh6.computeSecret(invalidKey);
293-
}, /^Error: Failed to translate Buffer to a EC_POINT$/);
294-
// Check that signing operations are not impacted by the above error.
295-
const ecPrivateKey =
296-
'-----BEGIN EC PRIVATE KEY-----\n' +
297-
'MHcCAQEEIF+jnWY1D5kbVYDNvxxo/Y+ku2uJPDwS0r/VuPZQrjjVoAoGCCqGSM49\n' +
298-
'AwEHoUQDQgAEurOxfSxmqIRYzJVagdZfMMSjRNNhB8i3mXyIMq704m2m52FdfKZ2\n' +
299-
'pQhByd5eyj3lgZ7m7jbchtdgyOF8Io/1ng==\n' +
300-
'-----END EC PRIVATE KEY-----';
301-
assert.doesNotThrow(() => {
302-
crypto.createSign('SHA256').sign(ecPrivateKey);
303-
});
235+
// Show that the public point (key) is generated while setting the
236+
// private key.
237+
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
238+
239+
// Compressed and uncompressed public points/keys for other party's
240+
// private key.
241+
// 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
242+
const peerPubPtComp =
243+
'02c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae';
244+
const peerPubPtUnComp =
245+
'04c6b754b20826eb925e052ee2c25285b162b51fdca732bcf67e39d647fb6830ae' +
246+
'b651944a574a362082a77e3f2b5d9223eb54d7f2f76846522bf75f3bedb8178e';
247+
248+
const sharedSecret =
249+
'1da220b5329bbe8bfd19ceef5a5898593f411a6f12ea40f2a8eead9a5cf59970';
250+
251+
assert.strictEqual(ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex'),
252+
sharedSecret);
253+
assert.strictEqual(ecdh5.computeSecret(peerPubPtUnComp, 'hex', 'hex'),
254+
sharedSecret);
255+
256+
// Verify that we still have the same key pair as before the computation.
257+
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
258+
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
259+
260+
// Verify setting and getting compressed and non-compressed serializations.
261+
ecdh5.setPublicKey(cafebabePubPtComp, 'hex');
262+
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
263+
assert.strictEqual(ecdh5.getPublicKey('hex', 'compressed'),
264+
cafebabePubPtComp);
265+
ecdh5.setPublicKey(cafebabePubPtUnComp, 'hex');
266+
assert.strictEqual(ecdh5.getPublicKey('hex'), cafebabePubPtUnComp);
267+
assert.strictEqual(ecdh5.getPublicKey('hex', 'compressed'),
268+
cafebabePubPtComp);
269+
270+
// Show why allowing the public key to be set on this type
271+
// does not make sense.
272+
ecdh5.setPublicKey(peerPubPtComp, 'hex');
273+
assert.strictEqual(ecdh5.getPublicKey('hex'), peerPubPtUnComp);
274+
assert.throws(() => {
275+
// Error because the public key does not match the private key anymore.
276+
ecdh5.computeSecret(peerPubPtComp, 'hex', 'hex');
277+
}, /^Error: Invalid key pair$/);
278+
279+
// Set to a valid key to show that later attempts to set an invalid key are
280+
// rejected.
281+
ecdh5.setPrivateKey(cafebabeKey, 'hex');
282+
283+
[ // Some invalid private keys for the secp256k1 curve.
284+
'0000000000000000000000000000000000000000000000000000000000000000',
285+
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141',
286+
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
287+
].forEach((element) => {
288+
assert.throws(() => {
289+
ecdh5.setPrivateKey(element, 'hex');
290+
}, /^Error: Private key is not valid for specified curve.$/);
291+
// Verify object state did not change.
292+
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
293+
});
294+
295+
// Use of invalid keys was not cleaning up ERR stack, and was causing
296+
// unexpected failure in subsequent signing operations.
297+
const ecdh6 = crypto.createECDH('prime256v1');
298+
const invalidKey = Buffer.alloc(65);
299+
invalidKey.fill('\0');
300+
ecdh6.generateKeys();
301+
assert.throws(() => {
302+
ecdh6.computeSecret(invalidKey);
303+
}, /^Error: Failed to translate Buffer to a EC_POINT$/);
304+
// Check that signing operations are not impacted by the above error.
305+
const ecPrivateKey =
306+
'-----BEGIN EC PRIVATE KEY-----\n' +
307+
'MHcCAQEEIF+jnWY1D5kbVYDNvxxo/Y+ku2uJPDwS0r/VuPZQrjjVoAoGCCqGSM49\n' +
308+
'AwEHoUQDQgAEurOxfSxmqIRYzJVagdZfMMSjRNNhB8i3mXyIMq704m2m52FdfKZ2\n' +
309+
'pQhByd5eyj3lgZ7m7jbchtdgyOF8Io/1ng==\n' +
310+
'-----END EC PRIVATE KEY-----';
311+
assert.doesNotThrow(() => {
312+
crypto.createSign('SHA256').sign(ecPrivateKey);
313+
});
314+
}
304315

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

0 commit comments

Comments
 (0)