Skip to main content

rama_boring/
ec.rs

1//! Elliptic Curve
2//!
3//! Cryptology 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 eliptic 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 cuves 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 [Eliptic Curve Cryptography].
14//!
15//! [`EcGroup`]: struct.EcGroup.html
16//! [`Nid`]: ../nid/struct.Nid.html
17//! [Eliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography
18use crate::ffi;
19use crate::libc_types::c_int;
20use foreign_types::{ForeignType, ForeignTypeRef};
21use openssl_macros::corresponds;
22use std::fmt;
23use std::ptr;
24
25use crate::bn::{BigNumContextRef, BigNumRef};
26use crate::error::ErrorStack;
27use crate::nid::Nid;
28use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public};
29use crate::{cvt, cvt_n, cvt_p, init};
30
31/// Compressed or Uncompressed conversion
32///
33/// Conversion from the binary value of the point on the curve is performed in one of
34/// compressed, uncompressed, or hybrid conversions.  The default is compressed, except
35/// for binary curves.
36///
37/// Further documentation is available in the [X9.62] standard.
38///
39/// [X9.62]: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.202.2977&rep=rep1&type=pdf
40#[derive(Copy, Clone)]
41pub struct PointConversionForm(ffi::point_conversion_form_t);
42
43impl PointConversionForm {
44    /// Compressed conversion from point value.
45    pub const COMPRESSED: PointConversionForm =
46        PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED);
47
48    /// Uncompressed conversion from point value.
49    pub const UNCOMPRESSED: PointConversionForm =
50        PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED);
51
52    /// Performs both compressed and uncompressed conversions.
53    pub const HYBRID: PointConversionForm =
54        PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID);
55}
56
57/// Named Curve or Explicit
58///
59/// This type acts as a boolean as to whether the `EcGroup` is named or explicit.
60#[derive(Copy, Clone)]
61pub struct Asn1Flag(c_int);
62
63impl Asn1Flag {
64    /// Curve defined using polynomial parameters
65    ///
66    /// Most applications use a named EC_GROUP curve, however, support
67    /// is included to explicitly define the curve used to calculate keys
68    /// This information would need to be known by both endpoint to make communication
69    /// effective.
70    ///
71    /// OPENSSL_EC_EXPLICIT_CURVE, but that was only added in 1.1.
72    /// Man page documents that 0 can be used in older versions.
73    ///
74    /// OpenSSL documentation at [`EC_GROUP`]
75    ///
76    /// [`EC_GROUP`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_seed_len.html
77    pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0);
78
79    /// Standard Curves
80    ///
81    /// Curves that make up the typical encryption use cases.  The collection of curves
82    /// are well known but extensible.
83    ///
84    /// OpenSSL documentation at [`EC_GROUP`]
85    ///
86    /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/man3/EC_GROUP_order_bits.html
87    pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE);
88}
89
90foreign_type_and_impl_send_sync! {
91    type CType = ffi::EC_GROUP;
92    fn drop = ffi::EC_GROUP_free;
93
94    /// Describes the curve
95    ///
96    /// A curve can be of the named curve type.  These curves can be discovered
97    /// using openssl binary `openssl ecparam -list_curves`.  Other operations
98    /// are available in the [wiki].  These named curves are available in the
99    /// [`Nid`] module.
100    ///
101    /// Curves can also be generated using prime field parameters or a binary field.
102    ///
103    /// Prime fields use the formula `y^2 mod p = x^3 + ax + b mod p`.  Binary
104    /// fields use the formula `y^2 + xy = x^3 + ax^2 + b`.  Named curves have
105    /// assured security.  To prevent accidental vulnerabilities, they should
106    /// be preferred.
107    ///
108    /// [wiki]: https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations
109    /// [`Nid`]: ../nid/index.html
110    pub struct EcGroup;
111}
112
113impl EcGroup {
114    /// Returns the group of a standard named curve.
115    #[corresponds(EC_GROUP_new)]
116    pub fn from_curve_name(nid: Nid) -> Result<EcGroup, ErrorStack> {
117        unsafe {
118            init();
119            cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(|p| EcGroup::from_ptr(p))
120        }
121    }
122}
123
124impl EcGroupRef {
125    /// Places the components of a curve over a prime field in the provided `BigNum`s.
126    /// The components make up the formula `y^2 mod p = x^3 + ax + b mod p`.
127    ///
128    /// OpenSSL documentation available at [`EC_GROUP_get_curve_GFp`]
129    ///
130    /// [`EC_GROUP_get_curve_GFp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_curve_GFp.html
131    pub fn components_gfp(
132        &self,
133        p: &mut BigNumRef,
134        a: &mut BigNumRef,
135        b: &mut BigNumRef,
136        ctx: &mut BigNumContextRef,
137    ) -> Result<(), ErrorStack> {
138        unsafe {
139            cvt(ffi::EC_GROUP_get_curve_GFp(
140                self.as_ptr(),
141                p.as_ptr(),
142                a.as_ptr(),
143                b.as_ptr(),
144                ctx.as_ptr(),
145            ))
146        }
147    }
148
149    /// Places the cofactor of the group in the provided `BigNum`.
150    #[corresponds(EC_GROUP_get_cofactor)]
151    pub fn cofactor(
152        &self,
153        cofactor: &mut BigNumRef,
154        ctx: &mut BigNumContextRef,
155    ) -> Result<(), ErrorStack> {
156        unsafe {
157            cvt(ffi::EC_GROUP_get_cofactor(
158                self.as_ptr(),
159                cofactor.as_ptr(),
160                ctx.as_ptr(),
161            ))
162        }
163    }
164
165    /// Returns the degree of the curve.
166    #[corresponds(EC_GROUP_get_degree)]
167    #[allow(clippy::unnecessary_cast)]
168    #[must_use]
169    pub fn degree(&self) -> u32 {
170        unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 }
171    }
172
173    /// Returns the number of bits in the group order.
174    #[corresponds(EC_GROUP_order_bits)]
175    #[must_use]
176    pub fn order_bits(&self) -> u32 {
177        unsafe { ffi::EC_GROUP_order_bits(self.as_ptr()) as u32 }
178    }
179
180    /// Returns the generator for the given curve as a [`EcPoint`].
181    #[corresponds(EC_GROUP_get0_generator)]
182    #[must_use]
183    pub fn generator(&self) -> &EcPointRef {
184        unsafe {
185            let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr());
186            EcPointRef::from_ptr(ptr as *mut _)
187        }
188    }
189
190    /// Places the order of the curve in the provided `BigNum`.
191    #[corresponds(EC_GROUP_get_order)]
192    pub fn order(
193        &self,
194        order: &mut BigNumRef,
195        ctx: &mut BigNumContextRef,
196    ) -> Result<(), ErrorStack> {
197        unsafe {
198            cvt(ffi::EC_GROUP_get_order(
199                self.as_ptr(),
200                order.as_ptr(),
201                ctx.as_ptr(),
202            ))
203        }
204    }
205
206    /// Sets the flag determining if the group corresponds to a named curve or must be explicitly
207    /// parameterized.
208    ///
209    /// This defaults to `EXPLICIT_CURVE` in OpenSSL 1.0.1 and 1.0.2, but `NAMED_CURVE` in OpenSSL
210    /// 1.1.0.
211    pub fn set_asn1_flag(&mut self, flag: Asn1Flag) {
212        unsafe {
213            ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0);
214        }
215    }
216
217    /// Returns the name of the curve, if a name is associated.
218    #[corresponds(EC_GROUP_get_curve_name)]
219    #[must_use]
220    pub fn curve_name(&self) -> Option<Nid> {
221        let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) };
222        if nid > 0 {
223            Some(Nid::from_raw(nid))
224        } else {
225            None
226        }
227    }
228}
229
230foreign_type_and_impl_send_sync! {
231    type CType = ffi::EC_POINT;
232    fn drop = ffi::EC_POINT_free;
233
234    /// Represents a point on the curve
235    ///
236    /// OpenSSL documentation at [`EC_POINT_new`]
237    ///
238    /// [`EC_POINT_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_new.html
239    pub struct EcPoint;
240}
241
242impl EcPointRef {
243    /// Computes `a + b`, storing the result in `self`.
244    #[corresponds(EC_POINT_add)]
245    pub fn add(
246        &mut self,
247        group: &EcGroupRef,
248        a: &EcPointRef,
249        b: &EcPointRef,
250        ctx: &mut BigNumContextRef,
251    ) -> Result<(), ErrorStack> {
252        unsafe {
253            cvt(ffi::EC_POINT_add(
254                group.as_ptr(),
255                self.as_ptr(),
256                a.as_ptr(),
257                b.as_ptr(),
258                ctx.as_ptr(),
259            ))
260        }
261    }
262
263    /// Computes `q * m`, storing the result in `self`.
264    #[corresponds(EC_POINT_mul)]
265    pub fn mul(
266        &mut self,
267        group: &EcGroupRef,
268        q: &EcPointRef,
269        m: &BigNumRef,
270        ctx: &mut BigNumContextRef,
271    ) -> Result<(), ErrorStack> {
272        unsafe {
273            cvt(ffi::EC_POINT_mul(
274                group.as_ptr(),
275                self.as_ptr(),
276                ptr::null(),
277                q.as_ptr(),
278                m.as_ptr(),
279                ctx.as_ptr(),
280            ))
281        }
282    }
283
284    /// Computes `generator * n`, storing the result in `self`.
285    pub fn mul_generator(
286        &mut self,
287        group: &EcGroupRef,
288        n: &BigNumRef,
289        ctx: &mut BigNumContextRef,
290    ) -> Result<(), ErrorStack> {
291        unsafe {
292            cvt(ffi::EC_POINT_mul(
293                group.as_ptr(),
294                self.as_ptr(),
295                n.as_ptr(),
296                ptr::null(),
297                ptr::null(),
298                ctx.as_ptr(),
299            ))
300        }
301    }
302
303    /// Computes `generator * n + q * m`, storing the result in `self`.
304    pub fn mul_full(
305        &mut self,
306        group: &EcGroupRef,
307        n: &BigNumRef,
308        q: &EcPointRef,
309        m: &BigNumRef,
310        ctx: &mut BigNumContextRef,
311    ) -> Result<(), ErrorStack> {
312        unsafe {
313            cvt(ffi::EC_POINT_mul(
314                group.as_ptr(),
315                self.as_ptr(),
316                n.as_ptr(),
317                q.as_ptr(),
318                m.as_ptr(),
319                ctx.as_ptr(),
320            ))
321        }
322    }
323
324    /// Inverts `self`.
325    #[corresponds(EC_POINT_invert)]
326    pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> {
327        unsafe {
328            cvt(ffi::EC_POINT_invert(
329                group.as_ptr(),
330                self.as_ptr(),
331                ctx.as_ptr(),
332            ))
333        }
334    }
335
336    /// Serializes the point to a binary representation.
337    #[corresponds(EC_POINT_point2oct)]
338    pub fn to_bytes(
339        &self,
340        group: &EcGroupRef,
341        form: PointConversionForm,
342        ctx: &mut BigNumContextRef,
343    ) -> Result<Vec<u8>, ErrorStack> {
344        unsafe {
345            let len = ffi::EC_POINT_point2oct(
346                group.as_ptr(),
347                self.as_ptr(),
348                form.0,
349                ptr::null_mut(),
350                0,
351                ctx.as_ptr(),
352            );
353            if len == 0 {
354                return Err(ErrorStack::get());
355            }
356            let mut buf = vec![0; len];
357            let len = ffi::EC_POINT_point2oct(
358                group.as_ptr(),
359                self.as_ptr(),
360                form.0,
361                buf.as_mut_ptr(),
362                len,
363                ctx.as_ptr(),
364            );
365            if len == 0 {
366                Err(ErrorStack::get())
367            } else {
368                Ok(buf)
369            }
370        }
371    }
372
373    /// Creates a new point on the specified curve with the same value.
374    #[corresponds(EC_POINT_dup)]
375    pub fn to_owned(&self, group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
376        unsafe {
377            cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(|p| EcPoint::from_ptr(p))
378        }
379    }
380
381    /// Determines if this point is equal to another.
382    ///
383    /// OpenSSL doucmentation at [`EC_POINT_cmp`]
384    ///
385    /// [`EC_POINT_cmp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_cmp.html
386    pub fn eq(
387        &self,
388        group: &EcGroupRef,
389        other: &EcPointRef,
390        ctx: &mut BigNumContextRef,
391    ) -> Result<bool, ErrorStack> {
392        unsafe {
393            let res = cvt_n(ffi::EC_POINT_cmp(
394                group.as_ptr(),
395                self.as_ptr(),
396                other.as_ptr(),
397                ctx.as_ptr(),
398            ))?;
399            Ok(res == 0)
400        }
401    }
402
403    /// Place affine coordinates of a curve over a prime field in the provided
404    /// `x` and `y` `BigNum`s
405    #[corresponds(EC_POINT_get_affine_coordinates_GFp)]
406    pub fn affine_coordinates_gfp(
407        &self,
408        group: &EcGroupRef,
409        x: &mut BigNumRef,
410        y: &mut BigNumRef,
411        ctx: &mut BigNumContextRef,
412    ) -> Result<(), ErrorStack> {
413        unsafe {
414            cvt(ffi::EC_POINT_get_affine_coordinates_GFp(
415                group.as_ptr(),
416                self.as_ptr(),
417                x.as_ptr(),
418                y.as_ptr(),
419                ctx.as_ptr(),
420            ))
421        }
422    }
423}
424
425impl EcPoint {
426    /// Creates a new point on the specified curve.
427    #[corresponds(EC_POINT_new)]
428    pub fn new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
429        unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(|p| EcPoint::from_ptr(p)) }
430    }
431
432    /// Creates point from a binary representation
433    #[corresponds(EC_POINT_oct2point)]
434    pub fn from_bytes(
435        group: &EcGroupRef,
436        buf: &[u8],
437        ctx: &mut BigNumContextRef,
438    ) -> Result<EcPoint, ErrorStack> {
439        let point = EcPoint::new(group)?;
440        unsafe {
441            cvt(ffi::EC_POINT_oct2point(
442                group.as_ptr(),
443                point.as_ptr(),
444                buf.as_ptr(),
445                buf.len(),
446                ctx.as_ptr(),
447            ))?;
448        }
449        Ok(point)
450    }
451}
452
453generic_foreign_type_and_impl_send_sync! {
454    type CType = ffi::EC_KEY;
455    fn drop = ffi::EC_KEY_free;
456
457    /// Public and optional Private key on the given curve
458    ///
459    pub struct EcKey<T>;
460
461    /// Reference to [`EcKey`]
462    ///
463    /// [`EcKey`]: struct.EcKey.html
464    pub struct EcKeyRef<T>;
465}
466
467impl<T> EcKeyRef<T>
468where
469    T: HasPrivate,
470{
471    private_key_to_pem! {
472        /// Serializes the private key to a PEM-encoded ECPrivateKey structure.
473        ///
474        /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`.
475        #[corresponds(PEM_write_bio_ECPrivateKey)]
476        private_key_to_pem,
477        /// Serializes the private key to a PEM-encoded encrypted ECPrivateKey structure.
478        ///
479        /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`.
480        #[corresponds(PEM_write_bio_ECPrivateKey)]
481        private_key_to_pem_passphrase,
482        ffi::PEM_write_bio_ECPrivateKey
483    }
484
485    to_der! {
486        /// Serializes the private key into a DER-encoded ECPrivateKey structure.
487        #[corresponds(i2d_ECPrivateKey)]
488        private_key_to_der,
489        ffi::i2d_ECPrivateKey
490    }
491
492    /// Return [`EcPoint`] associated with the private key
493    #[corresponds(EC_KEY_get0_private_key)]
494    #[must_use]
495    pub fn private_key(&self) -> &BigNumRef {
496        unsafe {
497            let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr());
498            BigNumRef::from_ptr(ptr.cast_mut())
499        }
500    }
501}
502
503impl<T> EcKeyRef<T>
504where
505    T: HasPublic,
506{
507    /// Returns the public key.
508    #[corresponds(EC_KEY_get0_public_key)]
509    #[must_use]
510    pub fn public_key(&self) -> &EcPointRef {
511        unsafe {
512            let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr());
513            EcPointRef::from_ptr(ptr.cast_mut())
514        }
515    }
516
517    to_pem! {
518        /// Serialies the public key into a PEM-encoded SubjectPublicKeyInfo structure.
519        ///
520        /// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
521        #[corresponds(PEM_write_bio_EC_PUBKEY)]
522        public_key_to_pem,
523        ffi::PEM_write_bio_EC_PUBKEY
524    }
525
526    to_der! {
527        /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
528        #[corresponds(i2d_EC_PUBKEY)]
529        public_key_to_der,
530        ffi::i2d_EC_PUBKEY
531    }
532}
533
534impl<T> EcKeyRef<T>
535where
536    T: HasParams,
537{
538    /// Return [`EcGroup`] of the `EcKey`
539    #[corresponds(EC_KEY_get0_group)]
540    #[must_use]
541    pub fn group(&self) -> &EcGroupRef {
542        unsafe {
543            let ptr = ffi::EC_KEY_get0_group(self.as_ptr());
544            EcGroupRef::from_ptr(ptr.cast_mut())
545        }
546    }
547
548    /// Checks the key for validity.
549    #[corresponds(EC_KEY_check_key)]
550    pub fn check_key(&self) -> Result<(), ErrorStack> {
551        unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())) }
552    }
553}
554
555impl<T> ToOwned for EcKeyRef<T> {
556    type Owned = EcKey<T>;
557
558    fn to_owned(&self) -> EcKey<T> {
559        unsafe {
560            let r = ffi::EC_KEY_up_ref(self.as_ptr());
561            assert!(r == 1);
562            EcKey::from_ptr(self.as_ptr())
563        }
564    }
565}
566
567impl EcKey<Params> {
568    /// Constructs an `EcKey` corresponding to a known curve.
569    ///
570    /// It will not have an associated public or private key. This kind of key is primarily useful
571    /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`.
572    #[corresponds(EC_KEY_new_by_curve_name)]
573    pub fn from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack> {
574        unsafe {
575            init();
576            cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p))
577        }
578    }
579
580    /// Constructs an `EcKey` corresponding to a curve.
581    #[corresponds(EC_KEY_set_group)]
582    pub fn from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack> {
583        unsafe {
584            cvt_p(ffi::EC_KEY_new())
585                .map(|p| EcKey::from_ptr(p))
586                .and_then(|key| {
587                    cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
588                })
589        }
590    }
591}
592
593impl EcKey<Public> {
594    /// Constructs an `EcKey` from the specified group with the associated `EcPoint`, public_key.
595    ///
596    /// This will only have the associated public_key.
597    ///
598    /// # Example
599    ///
600    /// ```no_run
601    /// use rama_boring::bn::BigNumContext;
602    /// use rama_boring::ec::*;
603    /// use rama_boring::nid::Nid;
604    /// use rama_boring::pkey::PKey;
605    ///
606    /// // get bytes from somewhere, i.e. this will not produce a valid key
607    /// let public_key: Vec<u8> = vec![];
608    ///
609    /// // create an EcKey from the binary form of a EcPoint
610    /// let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
611    /// let mut ctx = BigNumContext::new().unwrap();
612    /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx).unwrap();
613    /// let key = EcKey::from_public_key(&group, &point);
614    /// ```
615    pub fn from_public_key(
616        group: &EcGroupRef,
617        public_key: &EcPointRef,
618    ) -> Result<EcKey<Public>, ErrorStack> {
619        unsafe {
620            cvt_p(ffi::EC_KEY_new())
621                .map(|p| EcKey::from_ptr(p))
622                .and_then(|key| {
623                    cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
624                })
625                .and_then(|key| {
626                    cvt(ffi::EC_KEY_set_public_key(
627                        key.as_ptr(),
628                        public_key.as_ptr(),
629                    ))
630                    .map(|_| key)
631                })
632        }
633    }
634
635    /// Constructs a public key from its affine coordinates.
636    pub fn from_public_key_affine_coordinates(
637        group: &EcGroupRef,
638        x: &BigNumRef,
639        y: &BigNumRef,
640    ) -> Result<EcKey<Public>, ErrorStack> {
641        unsafe {
642            cvt_p(ffi::EC_KEY_new())
643                .map(|p| EcKey::from_ptr(p))
644                .and_then(|key| {
645                    cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
646                })
647                .and_then(|key| {
648                    cvt(ffi::EC_KEY_set_public_key_affine_coordinates(
649                        key.as_ptr(),
650                        x.as_ptr(),
651                        y.as_ptr(),
652                    ))
653                    .map(|_| key)
654                })
655        }
656    }
657
658    from_pem! {
659        /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a EC key.
660        ///
661        /// The input should have a header of `-----BEGIN PUBLIC KEY-----`.
662        #[corresponds(PEM_read_bio_EC_PUBKEY)]
663        public_key_from_pem,
664        EcKey<Public>,
665        ffi::PEM_read_bio_EC_PUBKEY
666    }
667
668    from_der! {
669        /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a EC key.
670        #[corresponds(d2i_EC_PUBKEY)]
671        public_key_from_der,
672        EcKey<Public>,
673        ffi::d2i_EC_PUBKEY,
674        crate::libc_types::c_long
675    }
676}
677
678impl EcKey<Private> {
679    /// Generates a new public/private key pair on the specified curve.
680    pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> {
681        unsafe {
682            cvt_p(ffi::EC_KEY_new())
683                .map(|p| EcKey::from_ptr(p))
684                .and_then(|key| {
685                    cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
686                })
687                .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key))
688        }
689    }
690
691    /// Constructs an public/private key pair given a curve, a private key and a public key point.
692    pub fn from_private_components(
693        group: &EcGroupRef,
694        private_number: &BigNumRef,
695        public_key: &EcPointRef,
696    ) -> Result<EcKey<Private>, ErrorStack> {
697        unsafe {
698            cvt_p(ffi::EC_KEY_new())
699                .map(|p| EcKey::from_ptr(p))
700                .and_then(|key| {
701                    cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
702                })
703                .and_then(|key| {
704                    cvt(ffi::EC_KEY_set_private_key(
705                        key.as_ptr(),
706                        private_number.as_ptr(),
707                    ))
708                    .map(|_| key)
709                })
710                .and_then(|key| {
711                    cvt(ffi::EC_KEY_set_public_key(
712                        key.as_ptr(),
713                        public_key.as_ptr(),
714                    ))
715                    .map(|_| key)
716                })
717        }
718    }
719
720    private_key_from_pem! {
721        /// Deserializes a private key from a PEM-encoded ECPrivateKey structure.
722        ///
723        /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
724        #[corresponds(PEM_read_bio_ECPrivateKey)]
725        private_key_from_pem,
726
727        /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure.
728        ///
729        /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
730        #[corresponds(PEM_read_bio_ECPrivateKey)]
731        private_key_from_pem_passphrase,
732
733        /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure.
734        ///
735        /// The callback should fill the password into the provided buffer and return its length.
736        ///
737        /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
738        #[corresponds(PEM_read_bio_ECPrivateKey)]
739        private_key_from_pem_callback,
740        EcKey<Private>,
741        ffi::PEM_read_bio_ECPrivateKey
742    }
743
744    from_der! {
745        /// Decodes a DER-encoded elliptic curve private key structure.
746        #[corresponds(d2i_ECPrivateKey)]
747        private_key_from_der,
748        EcKey<Private>,
749        ffi::d2i_ECPrivateKey,
750        crate::libc_types::c_long
751    }
752}
753
754impl<T> Clone for EcKey<T> {
755    fn clone(&self) -> EcKey<T> {
756        (**self).to_owned()
757    }
758}
759
760impl<T> fmt::Debug for EcKey<T> {
761    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
762        write!(f, "EcKey")
763    }
764}
765
766#[cfg(test)]
767mod test {
768    use hex::FromHex;
769
770    use super::*;
771    use crate::bn::{BigNum, BigNumContext};
772    use crate::nid::Nid;
773
774    #[test]
775    fn key_new_by_curve_name() {
776        EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
777    }
778
779    #[test]
780    fn generate() {
781        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
782        EcKey::generate(&group).unwrap();
783    }
784
785    #[test]
786    fn cofactor() {
787        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
788        let mut ctx = BigNumContext::new().unwrap();
789        let mut cofactor = BigNum::new().unwrap();
790        group.cofactor(&mut cofactor, &mut ctx).unwrap();
791        let one = BigNum::from_u32(1).unwrap();
792        assert_eq!(cofactor, one);
793    }
794
795    #[test]
796    #[allow(clippy::redundant_clone)]
797    fn dup() {
798        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
799        let key = EcKey::generate(&group).unwrap();
800        drop(key.clone());
801    }
802
803    #[test]
804    fn point_new() {
805        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
806        EcPoint::new(&group).unwrap();
807    }
808
809    #[test]
810    fn point_bytes() {
811        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
812        let key = EcKey::generate(&group).unwrap();
813        let point = key.public_key();
814        let mut ctx = BigNumContext::new().unwrap();
815        let bytes = point
816            .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
817            .unwrap();
818        let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
819        assert!(point.eq(&group, &point2, &mut ctx).unwrap());
820    }
821
822    #[test]
823    fn point_owned() {
824        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
825        let key = EcKey::generate(&group).unwrap();
826        let point = key.public_key();
827        let owned = point.to_owned(&group).unwrap();
828        let mut ctx = BigNumContext::new().unwrap();
829        assert!(owned.eq(&group, point, &mut ctx).unwrap());
830    }
831
832    #[test]
833    fn mul_generator() {
834        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
835        let key = EcKey::generate(&group).unwrap();
836        let mut ctx = BigNumContext::new().unwrap();
837        let mut public_key = EcPoint::new(&group).unwrap();
838        public_key
839            .mul_generator(&group, key.private_key(), &mut ctx)
840            .unwrap();
841        assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap());
842    }
843
844    #[test]
845    fn generator() {
846        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
847        let generator = group.generator();
848        let one = BigNum::from_u32(1).unwrap();
849        let mut ctx = BigNumContext::new().unwrap();
850        let mut ecp = EcPoint::new(&group).unwrap();
851        ecp.mul_generator(&group, &one, &mut ctx).unwrap();
852        assert!(ecp.eq(&group, generator, &mut ctx).unwrap());
853    }
854
855    #[test]
856    fn key_from_public_key() {
857        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
858        let key = EcKey::generate(&group).unwrap();
859        let mut ctx = BigNumContext::new().unwrap();
860        let bytes = key
861            .public_key()
862            .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
863            .unwrap();
864
865        drop(key);
866        let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
867        let ec_key = EcKey::from_public_key(&group, &public_key).unwrap();
868        assert!(ec_key.check_key().is_ok());
869    }
870
871    #[test]
872    fn key_from_private_components() {
873        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
874        let key = EcKey::generate(&group).unwrap();
875
876        let dup_key =
877            EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap();
878        dup_key.check_key().unwrap();
879
880        assert!(key.private_key() == dup_key.private_key());
881    }
882
883    #[test]
884    fn key_from_affine_coordinates() {
885        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
886        let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
887            .unwrap();
888        let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
889            .unwrap();
890
891        let xbn = BigNum::from_slice(&x).unwrap();
892        let ybn = BigNum::from_slice(&y).unwrap();
893
894        let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
895        assert!(ec_key.check_key().is_ok());
896    }
897
898    #[test]
899    fn get_affine_coordinates() {
900        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
901        let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
902            .unwrap();
903        let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
904            .unwrap();
905
906        let xbn = BigNum::from_slice(&x).unwrap();
907        let ybn = BigNum::from_slice(&y).unwrap();
908
909        let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
910
911        let mut xbn2 = BigNum::new().unwrap();
912        let mut ybn2 = BigNum::new().unwrap();
913        let mut ctx = BigNumContext::new().unwrap();
914        let ec_key_pk = ec_key.public_key();
915        ec_key_pk
916            .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx)
917            .unwrap();
918        assert_eq!(xbn2, xbn);
919        assert_eq!(ybn2, ybn);
920    }
921}