@@ -185,126 +185,141 @@ const bad_dh = crypto.createDiffieHellman(p, 'hex');
185185assert . 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- } , / ^ T y p e E r r o r : B a d f o r m a t : 1 0 $ / ) ;
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+ } , / ^ T y p e E r r o r : B a d f o r m a t : 1 0 $ / ) ;
217218
218- assert . throws ( ( ) => {
219- ecdh2 . computeSecret ( key3 , 'latin1' , 'buffer ') ;
220- } , / ^ E r r o r : F a i l e d t o t r a n s l a t e B u f f e r t o a E C _ P O I N T $ / ) ;
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+ } , / ^ E r r o r : F a i l e d t o t r a n s l a t e B u f f e r t o a E C _ P O I N T $ / ) ;
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- } , / ^ E r r o r : F a i l e d t o c o n v e r t B u f f e r t o E C _ P O I N T $ / ) ;
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+ } , / ^ E r r o r : F a i l e d t o c o n v e r t B u f f e r t o E C _ P O I N T $ / ) ;
234236
235- // Verify errors are thrown when retrieving keys from an uninitialized object.
236- assert . throws ( ( ) => {
237- ecdh5 . getPublicKey ( ) ;
238- } , / ^ E r r o r : F a i l e d t o g e t E C D H p u b l i c k e y $ / ) ;
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- } , / ^ E r r o r : F a i l e d t o g e t E C D H p r i v a t e k e y $ / ) ;
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- } , / ^ E r r o r : I n v a l i d k e y p a i r $ / ) ;
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- } , / ^ E r r o r : P r i v a t e k e y i s n o t v a l i d f o r s p e c i f i e d c u r v e \. $ / ) ;
305- // Verify object state did not change.
242+ ecdh5 . getPublicKey ( ) ;
243+ } , / ^ E r r o r : F a i l e d t o g e t E C D H p u b l i c k e y $ / ) ;
244+
245+ assert . throws ( ( ) => {
246+ ecdh5 . getPrivateKey ( ) ;
247+ } , / ^ E r r o r : F a i l e d t o g e t E C D H p r i v a t e k e y $ / ) ;
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+ } , / ^ E r r o r : I n v a l i d k e y p a i r $ / ) ;
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+ } , / ^ E r r o r : P r i v a t e k e y i s n o t v a l i d f o r s p e c i f i e d c u r v e \. $ / ) ;
319+ // Verify object state did not change.
320+ assert . strictEqual ( ecdh5 . getPrivateKey ( 'hex' ) , cafebabeKey ) ;
321+ } ) ;
322+ }
308323
309324// invalid test: curve argument is undefined
310325assert . throws ( ( ) => {
0 commit comments