@@ -161,146 +161,157 @@ const bad_dh = crypto.createDiffieHellman(p, 'hex');
161161assert . 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- } , / ^ T y p e E r r o r : B a d f o r m a t : 1 0 $ / ) ;
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+ } , / ^ T y p e E r r o r : B a d f o r m a t : 1 0 $ / ) ;
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- } , / ^ 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 $ / ) ;
199+ assert . throws ( ( ) => {
200+ ecdh2 . computeSecret ( key3 , 'latin1' , 'buffer' ) ;
201+ } , / ^ 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 $ / ) ;
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- } , / ^ 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 $ / ) ;
209+ assert . throws ( ( ) => {
210+ ecdh4 . setPublicKey ( ecdh3 . getPublicKey ( ) ) ;
211+ } , / ^ 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 $ / ) ;
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- } , / ^ 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 $ / ) ;
216+ // Verify errors are thrown when retrieving keys from an uninitialized object.
217+ assert . throws ( ( ) => {
218+ ecdh5 . getPublicKey ( ) ;
219+ } , / ^ 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 $ / ) ;
215220
216- assert . throws ( ( ) => {
217- ecdh5 . getPrivateKey ( ) ;
218- } , / ^ 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 $ / ) ;
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- } , / ^ E r r o r : I n v a l i d k e y p a i r $ / ) ;
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- } , / ^ 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 .$ / ) ;
281- // Verify object state did not change.
222+ ecdh5 . getPrivateKey ( ) ;
223+ } , / ^ 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 $ / ) ;
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- } , / ^ 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 $ / ) ;
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+ } , / ^ E r r o r : I n v a l i d k e y p a i r $ / ) ;
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+ } , / ^ 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 .$ / ) ;
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+ } , / ^ 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 $ / ) ;
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
306317assert . throws ( ( ) => {
0 commit comments