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