1 //! Elliptic Curve
2 //!
3 //! Cryptography relies on the difficulty of solving mathematical problems, such as the factor
4 //! of large integers composed of two large prime numbers and the discrete logarithm of a
5 //! random elliptic curve.  This module provides low-level features of the latter.
6 //! Elliptic Curve protocols can provide the same security with smaller keys.
7 //!
8 //! There are 2 forms of elliptic curves, `Fp` and `F2^m`.  These curves use irreducible
9 //! trinomial or pentanomial.  Being a generic interface to a wide range of algorithms,
10 //! the curves are generally referenced by [`EcGroup`].  There are many built-in groups
11 //! found in [`Nid`].
12 //!
13 //! OpenSSL Wiki explains the fields and curves in detail at [Elliptic Curve Cryptography].
14 //!
15 //! [`EcGroup`]: struct.EcGroup.html
16 //! [`Nid`]: ../nid/struct.Nid.html
17 //! [Elliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography
18 use cfg_if::cfg_if;
19 use foreign_types::{ForeignType, ForeignTypeRef};
20 use libc::c_int;
21 use std::fmt;
22 use std::ptr;
23 
24 use crate::bn::{BigNum, BigNumContextRef, BigNumRef};
25 use crate::error::ErrorStack;
26 use crate::nid::Nid;
27 use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public};
28 use crate::util::ForeignTypeRefExt;
29 use crate::{cvt, cvt_n, cvt_p, init};
30 use openssl_macros::corresponds;
31 
32 cfg_if! {
33     if #[cfg(not(boringssl))] {
34         use std::ffi::CString;
35         use crate::string::OpensslString;
36     }
37 }
38 
39 /// Compressed or Uncompressed conversion
40 ///
41 /// Conversion from the binary value of the point on the curve is performed in one of
42 /// compressed, uncompressed, or hybrid conversions.  The default is compressed, except
43 /// for binary curves.
44 ///
45 /// Further documentation is available in the [X9.62] standard.
46 ///
47 /// [X9.62]: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.202.2977&rep=rep1&type=pdf
48 #[derive(Copy, Clone)]
49 pub struct PointConversionForm(ffi::point_conversion_form_t);
50 
51 impl PointConversionForm {
52     /// Compressed conversion from point value.
53     pub const COMPRESSED: PointConversionForm =
54         PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED);
55 
56     /// Uncompressed conversion from point value.
57     pub const UNCOMPRESSED: PointConversionForm =
58         PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED);
59 
60     /// Performs both compressed and uncompressed conversions.
61     pub const HYBRID: PointConversionForm =
62         PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID);
63 }
64 
65 /// Named Curve or Explicit
66 ///
67 /// This type acts as a boolean as to whether the `EcGroup` is named or explicit.
68 #[derive(Copy, Clone, Debug, PartialEq)]
69 pub struct Asn1Flag(c_int);
70 
71 impl Asn1Flag {
72     /// Curve defined using polynomial parameters
73     ///
74     /// Most applications use a named EC_GROUP curve, however, support
75     /// is included to explicitly define the curve used to calculate keys
76     /// This information would need to be known by both endpoint to make communication
77     /// effective.
78     ///
79     /// OPENSSL_EC_EXPLICIT_CURVE, but that was only added in 1.1.
80     /// Man page documents that 0 can be used in older versions.
81     ///
82     /// OpenSSL documentation at [`EC_GROUP`]
83     ///
84     /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/crypto/EC_GROUP_get_seed_len.html
85     pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0);
86 
87     /// Standard Curves
88     ///
89     /// Curves that make up the typical encryption use cases.  The collection of curves
90     /// are well known but extensible.
91     ///
92     /// OpenSSL documentation at [`EC_GROUP`]
93     ///
94     /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/man3/EC_GROUP_order_bits.html
95     pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE);
96 }
97 
98 foreign_type_and_impl_send_sync! {
99     type CType = ffi::EC_GROUP;
100     fn drop = ffi::EC_GROUP_free;
101 
102     /// Describes the curve
103     ///
104     /// A curve can be of the named curve type.  These curves can be discovered
105     /// using openssl binary `openssl ecparam -list_curves`.  Other operations
106     /// are available in the [wiki].  These named curves are available in the
107     /// [`Nid`] module.
108     ///
109     /// Curves can also be generated using prime field parameters or a binary field.
110     ///
111     /// Prime fields use the formula `y^2 mod p = x^3 + ax + b mod p`.  Binary
112     /// fields use the formula `y^2 + xy = x^3 + ax^2 + b`.  Named curves have
113     /// assured security.  To prevent accidental vulnerabilities, they should
114     /// be preferred.
115     ///
116     /// [wiki]: https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations
117     /// [`Nid`]: ../nid/index.html
118     pub struct EcGroup;
119     /// Reference to [`EcGroup`]
120     ///
121     /// [`EcGroup`]: struct.EcGroup.html
122     pub struct EcGroupRef;
123 }
124 
125 impl EcGroup {
126     /// Returns the group of a standard named curve.
127     ///
128     /// # Examples
129     ///
130     /// ```
131     /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
132     /// use openssl::nid::Nid;
133     /// use openssl::ec::{EcGroup, EcKey};
134     ///
135     /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve
136     /// let group = EcGroup::from_curve_name(nid)?;
137     /// let key = EcKey::generate(&group)?;
138     /// # Ok(()) }
139     /// ```
140     #[corresponds(EC_GROUP_new_by_curve_name)]
from_curve_name(nid: Nid) -> Result<EcGroup, ErrorStack>141     pub fn from_curve_name(nid: Nid) -> Result<EcGroup, ErrorStack> {
142         unsafe {
143             init();
144             cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup)
145         }
146     }
147 
148     /// Returns the group for given parameters
149     #[corresponds(EC_GROUP_new_curve_GFp)]
from_components( p: BigNum, a: BigNum, b: BigNum, ctx: &mut BigNumContextRef, ) -> Result<EcGroup, ErrorStack>150     pub fn from_components(
151         p: BigNum,
152         a: BigNum,
153         b: BigNum,
154         ctx: &mut BigNumContextRef,
155     ) -> Result<EcGroup, ErrorStack> {
156         unsafe {
157             cvt_p(ffi::EC_GROUP_new_curve_GFp(
158                 p.as_ptr(),
159                 a.as_ptr(),
160                 b.as_ptr(),
161                 ctx.as_ptr(),
162             ))
163             .map(EcGroup)
164         }
165     }
166 }
167 
168 impl EcGroupRef {
169     /// Places the components of a curve over a prime field in the provided `BigNum`s.
170     /// The components make up the formula `y^2 mod p = x^3 + ax + b mod p`.
171     #[corresponds(EC_GROUP_get_curve_GFp)]
components_gfp( &self, p: &mut BigNumRef, a: &mut BigNumRef, b: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>172     pub fn components_gfp(
173         &self,
174         p: &mut BigNumRef,
175         a: &mut BigNumRef,
176         b: &mut BigNumRef,
177         ctx: &mut BigNumContextRef,
178     ) -> Result<(), ErrorStack> {
179         unsafe {
180             cvt(ffi::EC_GROUP_get_curve_GFp(
181                 self.as_ptr(),
182                 p.as_ptr(),
183                 a.as_ptr(),
184                 b.as_ptr(),
185                 ctx.as_ptr(),
186             ))
187             .map(|_| ())
188         }
189     }
190 
191     /// Places the components of a curve over a binary field in the provided `BigNum`s.
192     /// The components make up the formula `y^2 + xy = x^3 + ax^2 + b`.
193     ///
194     /// In this form `p` relates to the irreducible polynomial.  Each bit represents
195     /// a term in the polynomial.  It will be set to 3 `1`s or 5 `1`s depending on
196     /// using a trinomial or pentanomial.
197     #[corresponds(EC_GROUP_get_curve_GF2m)]
198     #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
199     #[cfg(not(boringssl))]
components_gf2m( &self, p: &mut BigNumRef, a: &mut BigNumRef, b: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>200     pub fn components_gf2m(
201         &self,
202         p: &mut BigNumRef,
203         a: &mut BigNumRef,
204         b: &mut BigNumRef,
205         ctx: &mut BigNumContextRef,
206     ) -> Result<(), ErrorStack> {
207         unsafe {
208             cvt(ffi::EC_GROUP_get_curve_GF2m(
209                 self.as_ptr(),
210                 p.as_ptr(),
211                 a.as_ptr(),
212                 b.as_ptr(),
213                 ctx.as_ptr(),
214             ))
215             .map(|_| ())
216         }
217     }
218 
219     /// Places the cofactor of the group in the provided `BigNum`.
220     #[corresponds(EC_GROUP_get_cofactor)]
cofactor( &self, cofactor: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>221     pub fn cofactor(
222         &self,
223         cofactor: &mut BigNumRef,
224         ctx: &mut BigNumContextRef,
225     ) -> Result<(), ErrorStack> {
226         unsafe {
227             cvt(ffi::EC_GROUP_get_cofactor(
228                 self.as_ptr(),
229                 cofactor.as_ptr(),
230                 ctx.as_ptr(),
231             ))
232             .map(|_| ())
233         }
234     }
235 
236     /// Returns the degree of the curve.
237     #[corresponds(EC_GROUP_get_degree)]
degree(&self) -> u32238     pub fn degree(&self) -> u32 {
239         unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 }
240     }
241 
242     /// Returns the number of bits in the group order.
243     #[corresponds(EC_GROUP_order_bits)]
244     #[cfg(ossl110)]
order_bits(&self) -> u32245     pub fn order_bits(&self) -> u32 {
246         unsafe { ffi::EC_GROUP_order_bits(self.as_ptr()) as u32 }
247     }
248 
249     /// Returns the generator for the given curve as an [`EcPoint`].
250     #[corresponds(EC_GROUP_get0_generator)]
generator(&self) -> &EcPointRef251     pub fn generator(&self) -> &EcPointRef {
252         unsafe {
253             let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr());
254             EcPointRef::from_const_ptr(ptr)
255         }
256     }
257 
258     /// Sets the generator point for the given curve
259     #[corresponds(EC_GROUP_set_generator)]
set_generator( &mut self, generator: EcPoint, order: BigNum, cofactor: BigNum, ) -> Result<(), ErrorStack>260     pub fn set_generator(
261         &mut self,
262         generator: EcPoint,
263         order: BigNum,
264         cofactor: BigNum,
265     ) -> Result<(), ErrorStack> {
266         unsafe {
267             cvt(ffi::EC_GROUP_set_generator(
268                 self.as_ptr(),
269                 generator.as_ptr(),
270                 order.as_ptr(),
271                 cofactor.as_ptr(),
272             ))
273             .map(|_| ())
274         }
275     }
276 
277     /// Places the order of the curve in the provided `BigNum`.
278     #[corresponds(EC_GROUP_get_order)]
order( &self, order: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>279     pub fn order(
280         &self,
281         order: &mut BigNumRef,
282         ctx: &mut BigNumContextRef,
283     ) -> Result<(), ErrorStack> {
284         unsafe {
285             cvt(ffi::EC_GROUP_get_order(
286                 self.as_ptr(),
287                 order.as_ptr(),
288                 ctx.as_ptr(),
289             ))
290             .map(|_| ())
291         }
292     }
293 
294     /// Sets the flag determining if the group corresponds to a named curve or must be explicitly
295     /// parameterized.
296     ///
297     /// This defaults to `EXPLICIT_CURVE` in OpenSSL 1.0.1 and 1.0.2, but `NAMED_CURVE` in OpenSSL
298     /// 1.1.0.
299     #[corresponds(EC_GROUP_set_asn1_flag)]
set_asn1_flag(&mut self, flag: Asn1Flag)300     pub fn set_asn1_flag(&mut self, flag: Asn1Flag) {
301         unsafe {
302             ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0);
303         }
304     }
305 
306     /// Gets the flag determining if the group corresponds to a named curve.
307     #[corresponds(EC_GROUP_get_asn1_flag)]
asn1_flag(&self) -> Asn1Flag308     pub fn asn1_flag(&self) -> Asn1Flag {
309         unsafe { Asn1Flag(ffi::EC_GROUP_get_asn1_flag(self.as_ptr())) }
310     }
311 
312     /// Returns the name of the curve, if a name is associated.
313     #[corresponds(EC_GROUP_get_curve_name)]
curve_name(&self) -> Option<Nid>314     pub fn curve_name(&self) -> Option<Nid> {
315         let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) };
316         if nid > 0 {
317             Some(Nid::from_raw(nid))
318         } else {
319             None
320         }
321     }
322 }
323 
324 foreign_type_and_impl_send_sync! {
325     type CType = ffi::EC_POINT;
326     fn drop = ffi::EC_POINT_free;
327 
328     /// Represents a point on the curve
329     pub struct EcPoint;
330     /// A reference a borrowed [`EcPoint`].
331     pub struct EcPointRef;
332 }
333 
334 impl EcPointRef {
335     /// Computes `a + b`, storing the result in `self`.
336     #[corresponds(EC_POINT_add)]
add( &mut self, group: &EcGroupRef, a: &EcPointRef, b: &EcPointRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>337     pub fn add(
338         &mut self,
339         group: &EcGroupRef,
340         a: &EcPointRef,
341         b: &EcPointRef,
342         ctx: &mut BigNumContextRef,
343     ) -> Result<(), ErrorStack> {
344         unsafe {
345             cvt(ffi::EC_POINT_add(
346                 group.as_ptr(),
347                 self.as_ptr(),
348                 a.as_ptr(),
349                 b.as_ptr(),
350                 ctx.as_ptr(),
351             ))
352             .map(|_| ())
353         }
354     }
355 
356     /// Computes `q * m`, storing the result in `self`.
357     #[corresponds(EC_POINT_mul)]
mul( &mut self, group: &EcGroupRef, q: &EcPointRef, m: &BigNumRef, ctx: &BigNumContextRef, ) -> Result<(), ErrorStack>358     pub fn mul(
359         &mut self,
360         group: &EcGroupRef,
361         q: &EcPointRef,
362         m: &BigNumRef,
363         // FIXME should be &mut
364         ctx: &BigNumContextRef,
365     ) -> Result<(), ErrorStack> {
366         unsafe {
367             cvt(ffi::EC_POINT_mul(
368                 group.as_ptr(),
369                 self.as_ptr(),
370                 ptr::null(),
371                 q.as_ptr(),
372                 m.as_ptr(),
373                 ctx.as_ptr(),
374             ))
375             .map(|_| ())
376         }
377     }
378 
379     /// Computes `generator * n`, storing the result in `self`.
380     #[corresponds(EC_POINT_mul)]
mul_generator( &mut self, group: &EcGroupRef, n: &BigNumRef, ctx: &BigNumContextRef, ) -> Result<(), ErrorStack>381     pub fn mul_generator(
382         &mut self,
383         group: &EcGroupRef,
384         n: &BigNumRef,
385         // FIXME should be &mut
386         ctx: &BigNumContextRef,
387     ) -> Result<(), ErrorStack> {
388         unsafe {
389             cvt(ffi::EC_POINT_mul(
390                 group.as_ptr(),
391                 self.as_ptr(),
392                 n.as_ptr(),
393                 ptr::null(),
394                 ptr::null(),
395                 ctx.as_ptr(),
396             ))
397             .map(|_| ())
398         }
399     }
400 
401     /// Computes `generator * n + q * m`, storing the result in `self`.
402     #[corresponds(EC_POINT_mul)]
mul_full( &mut self, group: &EcGroupRef, n: &BigNumRef, q: &EcPointRef, m: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>403     pub fn mul_full(
404         &mut self,
405         group: &EcGroupRef,
406         n: &BigNumRef,
407         q: &EcPointRef,
408         m: &BigNumRef,
409         ctx: &mut BigNumContextRef,
410     ) -> Result<(), ErrorStack> {
411         unsafe {
412             cvt(ffi::EC_POINT_mul(
413                 group.as_ptr(),
414                 self.as_ptr(),
415                 n.as_ptr(),
416                 q.as_ptr(),
417                 m.as_ptr(),
418                 ctx.as_ptr(),
419             ))
420             .map(|_| ())
421         }
422     }
423 
424     /// Inverts `self`.
425     #[corresponds(EC_POINT_invert)]
426     // FIXME should be mutable
invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack>427     pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> {
428         unsafe {
429             cvt(ffi::EC_POINT_invert(
430                 group.as_ptr(),
431                 self.as_ptr(),
432                 ctx.as_ptr(),
433             ))
434             .map(|_| ())
435         }
436     }
437 
438     /// Serializes the point to a binary representation.
439     #[corresponds(EC_POINT_point2oct)]
to_bytes( &self, group: &EcGroupRef, form: PointConversionForm, ctx: &mut BigNumContextRef, ) -> Result<Vec<u8>, ErrorStack>440     pub fn to_bytes(
441         &self,
442         group: &EcGroupRef,
443         form: PointConversionForm,
444         ctx: &mut BigNumContextRef,
445     ) -> Result<Vec<u8>, ErrorStack> {
446         unsafe {
447             let len = ffi::EC_POINT_point2oct(
448                 group.as_ptr(),
449                 self.as_ptr(),
450                 form.0,
451                 ptr::null_mut(),
452                 0,
453                 ctx.as_ptr(),
454             );
455             if len == 0 {
456                 return Err(ErrorStack::get());
457             }
458             let mut buf = vec![0; len];
459             let len = ffi::EC_POINT_point2oct(
460                 group.as_ptr(),
461                 self.as_ptr(),
462                 form.0,
463                 buf.as_mut_ptr(),
464                 len,
465                 ctx.as_ptr(),
466             );
467             if len == 0 {
468                 Err(ErrorStack::get())
469             } else {
470                 Ok(buf)
471             }
472         }
473     }
474 
475     /// Serializes the point to a hexadecimal string representation.
476     #[corresponds(EC_POINT_point2hex)]
477     #[cfg(not(boringssl))]
to_hex_str( &self, group: &EcGroupRef, form: PointConversionForm, ctx: &mut BigNumContextRef, ) -> Result<OpensslString, ErrorStack>478     pub fn to_hex_str(
479         &self,
480         group: &EcGroupRef,
481         form: PointConversionForm,
482         ctx: &mut BigNumContextRef,
483     ) -> Result<OpensslString, ErrorStack> {
484         unsafe {
485             let buf = cvt_p(ffi::EC_POINT_point2hex(
486                 group.as_ptr(),
487                 self.as_ptr(),
488                 form.0,
489                 ctx.as_ptr(),
490             ))?;
491             Ok(OpensslString::from_ptr(buf))
492         }
493     }
494 
495     /// Creates a new point on the specified curve with the same value.
496     #[corresponds(EC_POINT_dup)]
to_owned(&self, group: &EcGroupRef) -> Result<EcPoint, ErrorStack>497     pub fn to_owned(&self, group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
498         unsafe { cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(EcPoint) }
499     }
500 
501     /// Determines if this point is equal to another.
502     #[corresponds(EC_POINT_cmp)]
eq( &self, group: &EcGroupRef, other: &EcPointRef, ctx: &mut BigNumContextRef, ) -> Result<bool, ErrorStack>503     pub fn eq(
504         &self,
505         group: &EcGroupRef,
506         other: &EcPointRef,
507         ctx: &mut BigNumContextRef,
508     ) -> Result<bool, ErrorStack> {
509         unsafe {
510             let res = cvt_n(ffi::EC_POINT_cmp(
511                 group.as_ptr(),
512                 self.as_ptr(),
513                 other.as_ptr(),
514                 ctx.as_ptr(),
515             ))?;
516             Ok(res == 0)
517         }
518     }
519 
520     /// Places affine coordinates of a curve over a prime field in the provided
521     /// `x` and `y` `BigNum`s.
522     #[corresponds(EC_POINT_get_affine_coordinates)]
523     #[cfg(any(ossl111, boringssl, libressl350))]
affine_coordinates( &self, group: &EcGroupRef, x: &mut BigNumRef, y: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>524     pub fn affine_coordinates(
525         &self,
526         group: &EcGroupRef,
527         x: &mut BigNumRef,
528         y: &mut BigNumRef,
529         ctx: &mut BigNumContextRef,
530     ) -> Result<(), ErrorStack> {
531         unsafe {
532             cvt(ffi::EC_POINT_get_affine_coordinates(
533                 group.as_ptr(),
534                 self.as_ptr(),
535                 x.as_ptr(),
536                 y.as_ptr(),
537                 ctx.as_ptr(),
538             ))
539             .map(|_| ())
540         }
541     }
542 
543     /// Places affine coordinates of a curve over a prime field in the provided
544     /// `x` and `y` `BigNum`s
545     #[corresponds(EC_POINT_get_affine_coordinates_GFp)]
affine_coordinates_gfp( &self, group: &EcGroupRef, x: &mut BigNumRef, y: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>546     pub fn affine_coordinates_gfp(
547         &self,
548         group: &EcGroupRef,
549         x: &mut BigNumRef,
550         y: &mut BigNumRef,
551         ctx: &mut BigNumContextRef,
552     ) -> Result<(), ErrorStack> {
553         unsafe {
554             cvt(ffi::EC_POINT_get_affine_coordinates_GFp(
555                 group.as_ptr(),
556                 self.as_ptr(),
557                 x.as_ptr(),
558                 y.as_ptr(),
559                 ctx.as_ptr(),
560             ))
561             .map(|_| ())
562         }
563     }
564 
565     /// Sets affine coordinates of a curve over a prime field using the provided
566     /// `x` and `y` `BigNum`s
567     #[corresponds(EC_POINT_set_affine_coordinates_GFp)]
set_affine_coordinates_gfp( &mut self, group: &EcGroupRef, x: &BigNumRef, y: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>568     pub fn set_affine_coordinates_gfp(
569         &mut self,
570         group: &EcGroupRef,
571         x: &BigNumRef,
572         y: &BigNumRef,
573         ctx: &mut BigNumContextRef,
574     ) -> Result<(), ErrorStack> {
575         unsafe {
576             cvt(ffi::EC_POINT_set_affine_coordinates_GFp(
577                 group.as_ptr(),
578                 self.as_ptr(),
579                 x.as_ptr(),
580                 y.as_ptr(),
581                 ctx.as_ptr(),
582             ))
583             .map(|_| ())
584         }
585     }
586 
587     /// Places affine coordinates of a curve over a binary field in the provided
588     /// `x` and `y` `BigNum`s
589     #[corresponds(EC_POINT_get_affine_coordinates_GF2m)]
590     #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
591     #[cfg(not(boringssl))]
affine_coordinates_gf2m( &self, group: &EcGroupRef, x: &mut BigNumRef, y: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>592     pub fn affine_coordinates_gf2m(
593         &self,
594         group: &EcGroupRef,
595         x: &mut BigNumRef,
596         y: &mut BigNumRef,
597         ctx: &mut BigNumContextRef,
598     ) -> Result<(), ErrorStack> {
599         unsafe {
600             cvt(ffi::EC_POINT_get_affine_coordinates_GF2m(
601                 group.as_ptr(),
602                 self.as_ptr(),
603                 x.as_ptr(),
604                 y.as_ptr(),
605                 ctx.as_ptr(),
606             ))
607             .map(|_| ())
608         }
609     }
610 
611     /// Checks if point is infinity
612     #[corresponds(EC_POINT_is_at_infinity)]
is_infinity(&self, group: &EcGroupRef) -> bool613     pub fn is_infinity(&self, group: &EcGroupRef) -> bool {
614         unsafe {
615             let res = ffi::EC_POINT_is_at_infinity(group.as_ptr(), self.as_ptr());
616             res == 1
617         }
618     }
619 
620     /// Checks if point is on a given curve
621     #[corresponds(EC_POINT_is_on_curve)]
is_on_curve( &self, group: &EcGroupRef, ctx: &mut BigNumContextRef, ) -> Result<bool, ErrorStack>622     pub fn is_on_curve(
623         &self,
624         group: &EcGroupRef,
625         ctx: &mut BigNumContextRef,
626     ) -> Result<bool, ErrorStack> {
627         unsafe {
628             let res = cvt_n(ffi::EC_POINT_is_on_curve(
629                 group.as_ptr(),
630                 self.as_ptr(),
631                 ctx.as_ptr(),
632             ))?;
633             Ok(res == 1)
634         }
635     }
636 }
637 
638 impl EcPoint {
639     /// Creates a new point on the specified curve.
640     #[corresponds(EC_POINT_new)]
new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack>641     pub fn new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
642         unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) }
643     }
644 
645     /// Creates point from a binary representation
646     #[corresponds(EC_POINT_oct2point)]
from_bytes( group: &EcGroupRef, buf: &[u8], ctx: &mut BigNumContextRef, ) -> Result<EcPoint, ErrorStack>647     pub fn from_bytes(
648         group: &EcGroupRef,
649         buf: &[u8],
650         ctx: &mut BigNumContextRef,
651     ) -> Result<EcPoint, ErrorStack> {
652         let point = EcPoint::new(group)?;
653         unsafe {
654             cvt(ffi::EC_POINT_oct2point(
655                 group.as_ptr(),
656                 point.as_ptr(),
657                 buf.as_ptr(),
658                 buf.len(),
659                 ctx.as_ptr(),
660             ))?;
661         }
662         Ok(point)
663     }
664 
665     /// Creates point from a hexadecimal string representation
666     #[corresponds(EC_POINT_hex2point)]
667     #[cfg(not(boringssl))]
from_hex_str( group: &EcGroupRef, s: &str, ctx: &mut BigNumContextRef, ) -> Result<EcPoint, ErrorStack>668     pub fn from_hex_str(
669         group: &EcGroupRef,
670         s: &str,
671         ctx: &mut BigNumContextRef,
672     ) -> Result<EcPoint, ErrorStack> {
673         let point = EcPoint::new(group)?;
674         unsafe {
675             let c_str = CString::new(s.as_bytes()).unwrap();
676             cvt_p(ffi::EC_POINT_hex2point(
677                 group.as_ptr(),
678                 c_str.as_ptr() as *const _,
679                 point.as_ptr(),
680                 ctx.as_ptr(),
681             ))?;
682         }
683         Ok(point)
684     }
685 }
686 
687 generic_foreign_type_and_impl_send_sync! {
688     type CType = ffi::EC_KEY;
689     fn drop = ffi::EC_KEY_free;
690 
691     /// Public and optional private key on the given curve.
692     pub struct EcKey<T>;
693     /// A reference to an [`EcKey`].
694     pub struct EcKeyRef<T>;
695 }
696 
697 impl<T> EcKeyRef<T>
698 where
699     T: HasPrivate,
700 {
701     private_key_to_pem! {
702         /// Serializes the private key to a PEM-encoded ECPrivateKey structure.
703         ///
704         /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`.
705         #[corresponds(PEM_write_bio_ECPrivateKey)]
706         private_key_to_pem,
707         /// Serializes the private key to a PEM-encoded encrypted ECPrivateKey structure.
708         ///
709         /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`.
710         #[corresponds(PEM_write_bio_ECPrivateKey)]
711         private_key_to_pem_passphrase,
712         ffi::PEM_write_bio_ECPrivateKey
713     }
714 
715     to_der! {
716         /// Serializes the private key into a DER-encoded ECPrivateKey structure.
717         #[corresponds(i2d_ECPrivateKey)]
718         private_key_to_der,
719         ffi::i2d_ECPrivateKey
720     }
721 
722     /// Returns the private key value.
723     #[corresponds(EC_KEY_get0_private_key)]
private_key(&self) -> &BigNumRef724     pub fn private_key(&self) -> &BigNumRef {
725         unsafe {
726             let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr());
727             BigNumRef::from_const_ptr(ptr)
728         }
729     }
730 }
731 
732 impl<T> EcKeyRef<T>
733 where
734     T: HasPublic,
735 {
736     /// Returns the public key.
737     #[corresponds(EC_KEY_get0_public_key)]
public_key(&self) -> &EcPointRef738     pub fn public_key(&self) -> &EcPointRef {
739         unsafe {
740             let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr());
741             EcPointRef::from_const_ptr(ptr)
742         }
743     }
744 
745     to_pem! {
746         /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure.
747         ///
748         /// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
749         #[corresponds(PEM_write_bio_EC_PUBKEY)]
750         public_key_to_pem,
751         ffi::PEM_write_bio_EC_PUBKEY
752     }
753 
754     to_der! {
755         /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
756         #[corresponds(i2d_EC_PUBKEY)]
757         public_key_to_der,
758         ffi::i2d_EC_PUBKEY
759     }
760 }
761 
762 impl<T> EcKeyRef<T>
763 where
764     T: HasParams,
765 {
766     /// Returns the key's group.
767     #[corresponds(EC_KEY_get0_group)]
group(&self) -> &EcGroupRef768     pub fn group(&self) -> &EcGroupRef {
769         unsafe {
770             let ptr = ffi::EC_KEY_get0_group(self.as_ptr());
771             EcGroupRef::from_const_ptr(ptr)
772         }
773     }
774 
775     /// Checks the key for validity.
776     #[corresponds(EC_KEY_check_key)]
check_key(&self) -> Result<(), ErrorStack>777     pub fn check_key(&self) -> Result<(), ErrorStack> {
778         unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) }
779     }
780 }
781 
782 impl<T> ToOwned for EcKeyRef<T> {
783     type Owned = EcKey<T>;
784 
to_owned(&self) -> EcKey<T>785     fn to_owned(&self) -> EcKey<T> {
786         unsafe {
787             let r = ffi::EC_KEY_up_ref(self.as_ptr());
788             assert!(r == 1);
789             EcKey::from_ptr(self.as_ptr())
790         }
791     }
792 }
793 
794 impl EcKey<Params> {
795     /// Constructs an `EcKey` corresponding to a known curve.
796     ///
797     /// It will not have an associated public or private key. This kind of key is primarily useful
798     /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`.
799     #[corresponds(EC_KEY_new_by_curve_name)]
from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack>800     pub fn from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack> {
801         unsafe {
802             init();
803             cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p))
804         }
805     }
806 
807     /// Constructs an `EcKey` corresponding to a curve.
808     #[corresponds(EC_KEY_set_group)]
from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack>809     pub fn from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack> {
810         unsafe {
811             cvt_p(ffi::EC_KEY_new())
812                 .map(|p| EcKey::from_ptr(p))
813                 .and_then(|key| {
814                     cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
815                 })
816         }
817     }
818 }
819 
820 impl EcKey<Public> {
821     /// Constructs an `EcKey` from the specified group with the associated [`EcPoint`]: `public_key`.
822     ///
823     /// This will only have the associated `public_key`.
824     ///
825     /// # Example
826     ///
827     /// ```
828     /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
829     /// use openssl::bn::BigNumContext;
830     /// use openssl::ec::*;
831     /// use openssl::nid::Nid;
832     /// use openssl::pkey::PKey;
833     ///
834     /// let group = EcGroup::from_curve_name(Nid::SECP384R1)?;
835     /// let mut ctx = BigNumContext::new()?;
836     ///
837     /// // get bytes from somewhere
838     /// let public_key = // ...
839     /// # EcKey::generate(&group)?.public_key().to_bytes(&group,
840     /// # PointConversionForm::COMPRESSED, &mut ctx)?;
841     ///
842     /// // create an EcKey from the binary form of a EcPoint
843     /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx)?;
844     /// let key = EcKey::from_public_key(&group, &point)?;
845     /// key.check_key()?;
846     /// # Ok(()) }
847     /// ```
848     #[corresponds(EC_KEY_set_public_key)]
from_public_key( group: &EcGroupRef, public_key: &EcPointRef, ) -> Result<EcKey<Public>, ErrorStack>849     pub fn from_public_key(
850         group: &EcGroupRef,
851         public_key: &EcPointRef,
852     ) -> Result<EcKey<Public>, ErrorStack> {
853         unsafe {
854             cvt_p(ffi::EC_KEY_new())
855                 .map(|p| EcKey::from_ptr(p))
856                 .and_then(|key| {
857                     cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
858                 })
859                 .and_then(|key| {
860                     cvt(ffi::EC_KEY_set_public_key(
861                         key.as_ptr(),
862                         public_key.as_ptr(),
863                     ))
864                     .map(|_| key)
865                 })
866         }
867     }
868 
869     /// Constructs a public key from its affine coordinates.
870     #[corresponds(EC_KEY_set_public_key_affine_coordinates)]
from_public_key_affine_coordinates( group: &EcGroupRef, x: &BigNumRef, y: &BigNumRef, ) -> Result<EcKey<Public>, ErrorStack>871     pub fn from_public_key_affine_coordinates(
872         group: &EcGroupRef,
873         x: &BigNumRef,
874         y: &BigNumRef,
875     ) -> Result<EcKey<Public>, ErrorStack> {
876         unsafe {
877             cvt_p(ffi::EC_KEY_new())
878                 .map(|p| EcKey::from_ptr(p))
879                 .and_then(|key| {
880                     cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
881                 })
882                 .and_then(|key| {
883                     cvt(ffi::EC_KEY_set_public_key_affine_coordinates(
884                         key.as_ptr(),
885                         x.as_ptr(),
886                         y.as_ptr(),
887                     ))
888                     .map(|_| key)
889                 })
890         }
891     }
892 
893     from_pem! {
894         /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a EC key.
895         ///
896         /// The input should have a header of `-----BEGIN PUBLIC KEY-----`.
897         #[corresponds(PEM_read_bio_EC_PUBKEY)]
898         public_key_from_pem,
899         EcKey<Public>,
900         ffi::PEM_read_bio_EC_PUBKEY
901     }
902 
903     from_der! {
904         /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a EC key.
905         #[corresponds(d2i_EC_PUBKEY)]
906         public_key_from_der,
907         EcKey<Public>,
908         ffi::d2i_EC_PUBKEY
909     }
910 }
911 
912 impl EcKey<Private> {
913     /// Generates a new public/private key pair on the specified curve.
914     ///
915     /// # Examples
916     ///
917     /// ```
918     /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
919     /// use openssl::bn::BigNumContext;
920     /// use openssl::nid::Nid;
921     /// use openssl::ec::{EcGroup, EcKey, PointConversionForm};
922     ///
923     /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve
924     /// let group = EcGroup::from_curve_name(nid)?;
925     /// let key = EcKey::generate(&group)?;
926     ///
927     /// let mut ctx = BigNumContext::new()?;
928     ///
929     /// let public_key = &key.public_key().to_bytes(
930     ///     &group,
931     ///     PointConversionForm::COMPRESSED,
932     ///     &mut ctx,
933     /// )?;
934     /// assert_eq!(public_key.len(), 33);
935     /// assert_ne!(public_key[0], 0x04);
936     ///
937     /// let private_key = key.private_key().to_vec();
938     /// assert!(private_key.len() >= 31);
939     /// # Ok(()) }
940     /// ```
941     #[corresponds(EC_KEY_generate_key)]
generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack>942     pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> {
943         unsafe {
944             cvt_p(ffi::EC_KEY_new())
945                 .map(|p| EcKey::from_ptr(p))
946                 .and_then(|key| {
947                     cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
948                 })
949                 .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key))
950         }
951     }
952 
953     /// Constructs an public/private key pair given a curve, a private key and a public key point.
954     #[corresponds(EC_KEY_set_private_key)]
from_private_components( group: &EcGroupRef, private_number: &BigNumRef, public_key: &EcPointRef, ) -> Result<EcKey<Private>, ErrorStack>955     pub fn from_private_components(
956         group: &EcGroupRef,
957         private_number: &BigNumRef,
958         public_key: &EcPointRef,
959     ) -> Result<EcKey<Private>, ErrorStack> {
960         unsafe {
961             cvt_p(ffi::EC_KEY_new())
962                 .map(|p| EcKey::from_ptr(p))
963                 .and_then(|key| {
964                     cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
965                 })
966                 .and_then(|key| {
967                     cvt(ffi::EC_KEY_set_private_key(
968                         key.as_ptr(),
969                         private_number.as_ptr(),
970                     ))
971                     .map(|_| key)
972                 })
973                 .and_then(|key| {
974                     cvt(ffi::EC_KEY_set_public_key(
975                         key.as_ptr(),
976                         public_key.as_ptr(),
977                     ))
978                     .map(|_| key)
979                 })
980         }
981     }
982 
983     private_key_from_pem! {
984         /// Deserializes a private key from a PEM-encoded ECPrivateKey structure.
985         ///
986         /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
987         #[corresponds(PEM_read_bio_ECPrivateKey)]
988         private_key_from_pem,
989 
990         /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure.
991         ///
992         /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
993         #[corresponds(PEM_read_bio_ECPrivateKey)]
994         private_key_from_pem_passphrase,
995 
996         /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure.
997         ///
998         /// The callback should fill the password into the provided buffer and return its length.
999         ///
1000         /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
1001         #[corresponds(PEM_read_bio_ECPrivateKey)]
1002         private_key_from_pem_callback,
1003         EcKey<Private>,
1004         ffi::PEM_read_bio_ECPrivateKey
1005     }
1006 
1007     from_der! {
1008         /// Decodes a DER-encoded elliptic curve private key structure.
1009         #[corresponds(d2i_ECPrivateKey)]
1010         private_key_from_der,
1011         EcKey<Private>,
1012         ffi::d2i_ECPrivateKey
1013     }
1014 
1015     /// Decodes a DER-encoded elliptic curve private key structure for the specified curve.
1016     #[corresponds(EC_KEY_parse_private_key)]
1017     #[cfg(boringssl)]
private_key_from_der_for_group( der: &[u8], group: &EcGroupRef, ) -> Result<EcKey<Private>, ErrorStack>1018     pub fn private_key_from_der_for_group(
1019         der: &[u8],
1020         group: &EcGroupRef,
1021     ) -> Result<EcKey<Private>, ErrorStack> {
1022         unsafe {
1023             let mut cbs = ffi::CBS {
1024                 data: der.as_ptr(),
1025                 len: der.len(),
1026             };
1027             cvt_p(ffi::EC_KEY_parse_private_key(
1028                 &mut cbs as *mut ffi::CBS,
1029                 group.as_ptr(),
1030             ))
1031             .map(|p| EcKey::from_ptr(p))
1032         }
1033     }
1034 }
1035 
1036 impl<T> Clone for EcKey<T> {
clone(&self) -> EcKey<T>1037     fn clone(&self) -> EcKey<T> {
1038         (**self).to_owned()
1039     }
1040 }
1041 
1042 impl<T> fmt::Debug for EcKey<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1043     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1044         write!(f, "EcKey")
1045     }
1046 }
1047 
1048 #[cfg(test)]
1049 mod test {
1050     use hex::FromHex;
1051 
1052     use super::*;
1053     use crate::bn::{BigNum, BigNumContext};
1054     use crate::nid::Nid;
1055 
1056     #[test]
key_new_by_curve_name()1057     fn key_new_by_curve_name() {
1058         EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1059     }
1060 
1061     #[test]
generate()1062     fn generate() {
1063         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1064         EcKey::generate(&group).unwrap();
1065     }
1066 
1067     #[test]
ec_group_from_components()1068     fn ec_group_from_components() {
1069         // parameters are from secp256r1
1070         let p = BigNum::from_hex_str(
1071             "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1072         )
1073         .unwrap();
1074         let a = BigNum::from_hex_str(
1075             "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1076         )
1077         .unwrap();
1078         let b = BigNum::from_hex_str(
1079             "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1080         )
1081         .unwrap();
1082         let mut ctx = BigNumContext::new().unwrap();
1083 
1084         let _curve = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1085     }
1086 
1087     #[test]
ec_point_set_affine()1088     fn ec_point_set_affine() {
1089         // parameters are from secp256r1
1090         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1091         let mut ctx = BigNumContext::new().unwrap();
1092         let mut gen_point = EcPoint::new(&group).unwrap();
1093         let gen_x = BigNum::from_hex_str(
1094             "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1095         )
1096         .unwrap();
1097         let gen_y = BigNum::from_hex_str(
1098             "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1099         )
1100         .unwrap();
1101         gen_point
1102             .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx)
1103             .unwrap();
1104         assert!(gen_point.is_on_curve(&group, &mut ctx).unwrap());
1105     }
1106 
1107     #[test]
ec_group_set_generator()1108     fn ec_group_set_generator() {
1109         // parameters are from secp256r1
1110         let mut ctx = BigNumContext::new().unwrap();
1111         let p = BigNum::from_hex_str(
1112             "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1113         )
1114         .unwrap();
1115         let a = BigNum::from_hex_str(
1116             "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1117         )
1118         .unwrap();
1119         let b = BigNum::from_hex_str(
1120             "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1121         )
1122         .unwrap();
1123 
1124         let mut group = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1125 
1126         let mut gen_point = EcPoint::new(&group).unwrap();
1127         let gen_x = BigNum::from_hex_str(
1128             "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1129         )
1130         .unwrap();
1131         let gen_y = BigNum::from_hex_str(
1132             "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1133         )
1134         .unwrap();
1135         gen_point
1136             .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx)
1137             .unwrap();
1138 
1139         let order = BigNum::from_hex_str(
1140             "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
1141         )
1142         .unwrap();
1143         let cofactor = BigNum::from_hex_str("01").unwrap();
1144         group.set_generator(gen_point, order, cofactor).unwrap();
1145         let mut constructed_order = BigNum::new().unwrap();
1146         group.order(&mut constructed_order, &mut ctx).unwrap();
1147 
1148         let named_group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1149         let mut named_order = BigNum::new().unwrap();
1150         named_group.order(&mut named_order, &mut ctx).unwrap();
1151 
1152         assert_eq!(
1153             constructed_order.ucmp(&named_order),
1154             std::cmp::Ordering::Equal
1155         );
1156     }
1157 
1158     #[test]
cofactor()1159     fn cofactor() {
1160         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1161         let mut ctx = BigNumContext::new().unwrap();
1162         let mut cofactor = BigNum::new().unwrap();
1163         group.cofactor(&mut cofactor, &mut ctx).unwrap();
1164         let one = BigNum::from_u32(1).unwrap();
1165         assert_eq!(cofactor, one);
1166     }
1167 
1168     #[test]
1169     #[allow(clippy::redundant_clone)]
dup()1170     fn dup() {
1171         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1172         let key = EcKey::generate(&group).unwrap();
1173         drop(key.clone());
1174     }
1175 
1176     #[test]
point_new()1177     fn point_new() {
1178         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1179         EcPoint::new(&group).unwrap();
1180     }
1181 
1182     #[test]
point_bytes()1183     fn point_bytes() {
1184         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1185         let key = EcKey::generate(&group).unwrap();
1186         let point = key.public_key();
1187         let mut ctx = BigNumContext::new().unwrap();
1188         let bytes = point
1189             .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1190             .unwrap();
1191         let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1192         assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1193     }
1194 
1195     #[test]
1196     #[cfg(not(boringssl))]
point_hex_str()1197     fn point_hex_str() {
1198         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1199         let key = EcKey::generate(&group).unwrap();
1200         let point = key.public_key();
1201         let mut ctx = BigNumContext::new().unwrap();
1202         let hex = point
1203             .to_hex_str(&group, PointConversionForm::COMPRESSED, &mut ctx)
1204             .unwrap();
1205         let point2 = EcPoint::from_hex_str(&group, &hex, &mut ctx).unwrap();
1206         assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1207     }
1208 
1209     #[test]
point_owned()1210     fn point_owned() {
1211         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1212         let key = EcKey::generate(&group).unwrap();
1213         let point = key.public_key();
1214         let owned = point.to_owned(&group).unwrap();
1215         let mut ctx = BigNumContext::new().unwrap();
1216         assert!(owned.eq(&group, point, &mut ctx).unwrap());
1217     }
1218 
1219     #[test]
mul_generator()1220     fn mul_generator() {
1221         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1222         let key = EcKey::generate(&group).unwrap();
1223         let mut ctx = BigNumContext::new().unwrap();
1224         let mut public_key = EcPoint::new(&group).unwrap();
1225         public_key
1226             .mul_generator(&group, key.private_key(), &ctx)
1227             .unwrap();
1228         assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap());
1229     }
1230 
1231     #[test]
generator()1232     fn generator() {
1233         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1234         let gen = group.generator();
1235         let one = BigNum::from_u32(1).unwrap();
1236         let mut ctx = BigNumContext::new().unwrap();
1237         let mut ecp = EcPoint::new(&group).unwrap();
1238         ecp.mul_generator(&group, &one, &ctx).unwrap();
1239         assert!(ecp.eq(&group, gen, &mut ctx).unwrap());
1240     }
1241 
1242     #[test]
key_from_public_key()1243     fn key_from_public_key() {
1244         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1245         let key = EcKey::generate(&group).unwrap();
1246         let mut ctx = BigNumContext::new().unwrap();
1247         let bytes = key
1248             .public_key()
1249             .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1250             .unwrap();
1251 
1252         drop(key);
1253         let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1254         let ec_key = EcKey::from_public_key(&group, &public_key).unwrap();
1255         assert!(ec_key.check_key().is_ok());
1256     }
1257 
1258     #[test]
key_from_private_components()1259     fn key_from_private_components() {
1260         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1261         let key = EcKey::generate(&group).unwrap();
1262 
1263         let dup_key =
1264             EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap();
1265         dup_key.check_key().unwrap();
1266 
1267         assert!(key.private_key() == dup_key.private_key());
1268     }
1269 
1270     #[test]
key_from_affine_coordinates()1271     fn key_from_affine_coordinates() {
1272         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1273         let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1274             .unwrap();
1275         let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1276             .unwrap();
1277 
1278         let xbn = BigNum::from_slice(&x).unwrap();
1279         let ybn = BigNum::from_slice(&y).unwrap();
1280 
1281         let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1282         assert!(ec_key.check_key().is_ok());
1283     }
1284 
1285     #[cfg(any(ossl111, boringssl, libressl350))]
1286     #[test]
get_affine_coordinates()1287     fn get_affine_coordinates() {
1288         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1289         let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1290             .unwrap();
1291         let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1292             .unwrap();
1293 
1294         let xbn = BigNum::from_slice(&x).unwrap();
1295         let ybn = BigNum::from_slice(&y).unwrap();
1296 
1297         let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1298 
1299         let mut xbn2 = BigNum::new().unwrap();
1300         let mut ybn2 = BigNum::new().unwrap();
1301         let mut ctx = BigNumContext::new().unwrap();
1302         let ec_key_pk = ec_key.public_key();
1303         ec_key_pk
1304             .affine_coordinates(&group, &mut xbn2, &mut ybn2, &mut ctx)
1305             .unwrap();
1306         assert_eq!(xbn2, xbn);
1307         assert_eq!(ybn2, ybn);
1308     }
1309 
1310     #[test]
get_affine_coordinates_gfp()1311     fn get_affine_coordinates_gfp() {
1312         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1313         let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1314             .unwrap();
1315         let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1316             .unwrap();
1317 
1318         let xbn = BigNum::from_slice(&x).unwrap();
1319         let ybn = BigNum::from_slice(&y).unwrap();
1320 
1321         let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1322 
1323         let mut xbn2 = BigNum::new().unwrap();
1324         let mut ybn2 = BigNum::new().unwrap();
1325         let mut ctx = BigNumContext::new().unwrap();
1326         let ec_key_pk = ec_key.public_key();
1327         ec_key_pk
1328             .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx)
1329             .unwrap();
1330         assert_eq!(xbn2, xbn);
1331         assert_eq!(ybn2, ybn);
1332     }
1333 
1334     #[test]
is_infinity()1335     fn is_infinity() {
1336         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1337         let mut ctx = BigNumContext::new().unwrap();
1338         let g = group.generator();
1339         assert!(!g.is_infinity(&group));
1340 
1341         let mut order = BigNum::new().unwrap();
1342         group.order(&mut order, &mut ctx).unwrap();
1343         let mut inf = EcPoint::new(&group).unwrap();
1344         inf.mul_generator(&group, &order, &ctx).unwrap();
1345         assert!(inf.is_infinity(&group));
1346     }
1347 
1348     #[test]
1349     #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
is_on_curve()1350     fn is_on_curve() {
1351         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1352         let mut ctx = BigNumContext::new().unwrap();
1353         let g = group.generator();
1354         assert!(g.is_on_curve(&group, &mut ctx).unwrap());
1355 
1356         let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap();
1357         assert!(!g.is_on_curve(&group2, &mut ctx).unwrap());
1358     }
1359 
1360     #[test]
1361     #[cfg(any(boringssl, ossl111, libressl350))]
asn1_flag()1362     fn asn1_flag() {
1363         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1364         let flag = group.asn1_flag();
1365         assert_eq!(flag, Asn1Flag::NAMED_CURVE);
1366     }
1367 }
1368