1use cfg_if::cfg_if;
19use foreign_types::{ForeignType, ForeignTypeRef};
20use libc::c_int;
21use std::fmt;
22use std::ptr;
23
24use crate::bn::{BigNum, BigNumContext, BigNumContextRef, BigNumRef};
25use crate::error::ErrorStack;
26use crate::nid::Nid;
27use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public};
28use crate::util::ForeignTypeRefExt;
29use crate::{cvt, cvt_n, cvt_p, init};
30use openssl_macros::corresponds;
31
32cfg_if! {
33 if #[cfg(not(any(boringssl, awslc)))] {
34 use std::ffi::CString;
35 use crate::string::OpensslString;
36 }
37}
38
39#[derive(Copy, Clone)]
49pub struct PointConversionForm(ffi::point_conversion_form_t);
50
51impl PointConversionForm {
52 pub const COMPRESSED: PointConversionForm =
54 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED);
55
56 pub const UNCOMPRESSED: PointConversionForm =
58 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED);
59
60 pub const HYBRID: PointConversionForm =
62 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID);
63}
64
65#[derive(Copy, Clone, Debug, PartialEq)]
69pub struct Asn1Flag(c_int);
70
71impl Asn1Flag {
72 pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0);
86
87 pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE);
96}
97
98foreign_type_and_impl_send_sync! {
99 type CType = ffi::EC_GROUP;
100 fn drop = ffi::EC_GROUP_free;
101
102 pub struct EcGroup;
119 pub struct EcGroupRef;
123}
124
125impl EcGroup {
126 #[corresponds(EC_GROUP_new_by_curve_name)]
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 #[corresponds(EC_GROUP_new_curve_GFp)]
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
168impl fmt::Debug for EcGroup {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
170 self.as_ref().fmt(f)
171 }
172}
173
174impl EcGroupRef {
175 #[corresponds(EC_GROUP_get_curve_GFp)]
178 pub fn components_gfp(
179 &self,
180 p: &mut BigNumRef,
181 a: &mut BigNumRef,
182 b: &mut BigNumRef,
183 ctx: &mut BigNumContextRef,
184 ) -> Result<(), ErrorStack> {
185 unsafe {
186 cvt(ffi::EC_GROUP_get_curve_GFp(
187 self.as_ptr(),
188 p.as_ptr(),
189 a.as_ptr(),
190 b.as_ptr(),
191 ctx.as_ptr(),
192 ))
193 .map(|_| ())
194 }
195 }
196
197 #[corresponds(EC_GROUP_get_curve_GF2m)]
204 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
205 pub fn components_gf2m(
206 &self,
207 p: &mut BigNumRef,
208 a: &mut BigNumRef,
209 b: &mut BigNumRef,
210 ctx: &mut BigNumContextRef,
211 ) -> Result<(), ErrorStack> {
212 unsafe {
213 cvt(ffi::EC_GROUP_get_curve_GF2m(
214 self.as_ptr(),
215 p.as_ptr(),
216 a.as_ptr(),
217 b.as_ptr(),
218 ctx.as_ptr(),
219 ))
220 .map(|_| ())
221 }
222 }
223
224 #[corresponds(EC_GROUP_get_cofactor)]
226 pub fn cofactor(
227 &self,
228 cofactor: &mut BigNumRef,
229 ctx: &mut BigNumContextRef,
230 ) -> Result<(), ErrorStack> {
231 unsafe {
232 cvt(ffi::EC_GROUP_get_cofactor(
233 self.as_ptr(),
234 cofactor.as_ptr(),
235 ctx.as_ptr(),
236 ))
237 .map(|_| ())
238 }
239 }
240
241 #[corresponds(EC_GROUP_get_degree)]
243 pub fn degree(&self) -> u32 {
244 unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 }
245 }
246
247 #[corresponds(EC_GROUP_order_bits)]
249 #[cfg(any(ossl110, libressl, awslc, boringssl))]
250 pub fn order_bits(&self) -> u32 {
251 unsafe { ffi::EC_GROUP_order_bits(self.as_ptr()) as u32 }
252 }
253
254 #[corresponds(EC_GROUP_get0_generator)]
256 pub fn generator(&self) -> &EcPointRef {
257 unsafe {
258 let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr());
259 EcPointRef::from_const_ptr(ptr)
260 }
261 }
262
263 #[corresponds(EC_GROUP_set_generator)]
265 pub fn set_generator(
266 &mut self,
267 generator: EcPoint,
268 order: BigNum,
269 cofactor: BigNum,
270 ) -> Result<(), ErrorStack> {
271 unsafe {
272 cvt(ffi::EC_GROUP_set_generator(
273 self.as_ptr(),
274 generator.as_ptr(),
275 order.as_ptr(),
276 cofactor.as_ptr(),
277 ))
278 .map(|_| ())
279 }
280 }
281
282 #[corresponds(EC_GROUP_get_order)]
284 pub fn order(
285 &self,
286 order: &mut BigNumRef,
287 ctx: &mut BigNumContextRef,
288 ) -> Result<(), ErrorStack> {
289 unsafe {
290 cvt(ffi::EC_GROUP_get_order(
291 self.as_ptr(),
292 order.as_ptr(),
293 ctx.as_ptr(),
294 ))
295 .map(|_| ())
296 }
297 }
298
299 #[corresponds(EC_GROUP_set_asn1_flag)]
305 pub fn set_asn1_flag(&mut self, flag: Asn1Flag) {
306 unsafe {
307 ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0);
308 }
309 }
310
311 #[corresponds(EC_GROUP_get_asn1_flag)]
313 pub fn asn1_flag(&self) -> Asn1Flag {
314 unsafe { Asn1Flag(ffi::EC_GROUP_get_asn1_flag(self.as_ptr())) }
315 }
316
317 #[corresponds(EC_GROUP_get_curve_name)]
319 pub fn curve_name(&self) -> Option<Nid> {
320 let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) };
321 if nid > 0 {
322 Some(Nid::from_raw(nid))
323 } else {
324 None
325 }
326 }
327}
328
329impl fmt::Debug for EcGroupRef {
330 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
331 if let Some(curve_name) = self.curve_name() {
332 if let Ok(name) = curve_name.short_name() {
333 f.debug_struct("EcGroup")
334 .field("curve_name", &name)
335 .finish()
336 } else {
337 f.debug_struct("EcGroup")
338 .field("curve", &curve_name)
339 .finish()
340 }
341 } else {
342 if let Ok(mut p) = BigNum::new() {
344 if let Ok(mut a) = BigNum::new() {
345 if let Ok(mut b) = BigNum::new() {
346 if let Ok(mut ctx) = BigNumContext::new() {
347 if self
348 .components_gfp(&mut p, &mut a, &mut b, &mut ctx)
349 .is_ok()
350 {
351 return f
353 .debug_struct("EcGroup")
354 .field("p", &format!("{:X}", p))
355 .field("a", &format!("{:X}", a))
356 .field("b", &format!("{:X}", b))
357 .finish();
358 }
359 }
360 }
361 }
362 }
363
364 f.debug_struct("EcGroup").finish()
365 }
366 }
367}
368
369foreign_type_and_impl_send_sync! {
370 type CType = ffi::EC_POINT;
371 fn drop = ffi::EC_POINT_free;
372
373 pub struct EcPoint;
375 pub struct EcPointRef;
377}
378
379impl EcPointRef {
380 #[corresponds(EC_POINT_add)]
382 pub fn add(
383 &mut self,
384 group: &EcGroupRef,
385 a: &EcPointRef,
386 b: &EcPointRef,
387 ctx: &mut BigNumContextRef,
388 ) -> Result<(), ErrorStack> {
389 unsafe {
390 cvt(ffi::EC_POINT_add(
391 group.as_ptr(),
392 self.as_ptr(),
393 a.as_ptr(),
394 b.as_ptr(),
395 ctx.as_ptr(),
396 ))
397 .map(|_| ())
398 }
399 }
400
401 #[corresponds(EC_POINT_mul)]
403 pub fn mul(
404 &mut self,
405 group: &EcGroupRef,
406 q: &EcPointRef,
407 m: &BigNumRef,
408 ctx: &BigNumContextRef,
410 ) -> Result<(), ErrorStack> {
411 unsafe {
412 cvt(ffi::EC_POINT_mul(
413 group.as_ptr(),
414 self.as_ptr(),
415 ptr::null(),
416 q.as_ptr(),
417 m.as_ptr(),
418 ctx.as_ptr(),
419 ))
420 .map(|_| ())
421 }
422 }
423
424 #[corresponds(EC_POINT_mul)]
426 pub fn mul_generator(
427 &mut self,
428 group: &EcGroupRef,
429 n: &BigNumRef,
430 ctx: &BigNumContextRef,
432 ) -> Result<(), ErrorStack> {
433 unsafe {
434 cvt(ffi::EC_POINT_mul(
435 group.as_ptr(),
436 self.as_ptr(),
437 n.as_ptr(),
438 ptr::null(),
439 ptr::null(),
440 ctx.as_ptr(),
441 ))
442 .map(|_| ())
443 }
444 }
445
446 #[corresponds(EC_POINT_mul)]
448 pub fn mul_full(
449 &mut self,
450 group: &EcGroupRef,
451 n: &BigNumRef,
452 q: &EcPointRef,
453 m: &BigNumRef,
454 ctx: &mut BigNumContextRef,
455 ) -> Result<(), ErrorStack> {
456 unsafe {
457 cvt(ffi::EC_POINT_mul(
458 group.as_ptr(),
459 self.as_ptr(),
460 n.as_ptr(),
461 q.as_ptr(),
462 m.as_ptr(),
463 ctx.as_ptr(),
464 ))
465 .map(|_| ())
466 }
467 }
468
469 #[corresponds(EC_POINT_invert)]
471 pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> {
473 unsafe {
474 cvt(ffi::EC_POINT_invert(
475 group.as_ptr(),
476 self.as_ptr(),
477 ctx.as_ptr(),
478 ))
479 .map(|_| ())
480 }
481 }
482
483 #[corresponds(EC_POINT_point2oct)]
485 pub fn to_bytes(
486 &self,
487 group: &EcGroupRef,
488 form: PointConversionForm,
489 ctx: &mut BigNumContextRef,
490 ) -> Result<Vec<u8>, ErrorStack> {
491 unsafe {
492 let len = ffi::EC_POINT_point2oct(
493 group.as_ptr(),
494 self.as_ptr(),
495 form.0,
496 ptr::null_mut(),
497 0,
498 ctx.as_ptr(),
499 );
500 if len == 0 {
501 return Err(ErrorStack::get());
502 }
503 let mut buf = vec![0; len];
504 let len = ffi::EC_POINT_point2oct(
505 group.as_ptr(),
506 self.as_ptr(),
507 form.0,
508 buf.as_mut_ptr(),
509 len,
510 ctx.as_ptr(),
511 );
512 if len == 0 {
513 Err(ErrorStack::get())
514 } else {
515 Ok(buf)
516 }
517 }
518 }
519
520 #[corresponds(EC_POINT_point2hex)]
522 #[cfg(not(any(boringssl, awslc)))]
523 pub fn to_hex_str(
524 &self,
525 group: &EcGroupRef,
526 form: PointConversionForm,
527 ctx: &mut BigNumContextRef,
528 ) -> Result<OpensslString, ErrorStack> {
529 unsafe {
530 let buf = cvt_p(ffi::EC_POINT_point2hex(
531 group.as_ptr(),
532 self.as_ptr(),
533 form.0,
534 ctx.as_ptr(),
535 ))?;
536 Ok(OpensslString::from_ptr(buf))
537 }
538 }
539
540 #[corresponds(EC_POINT_dup)]
542 pub fn to_owned(&self, group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
543 unsafe { cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(EcPoint) }
544 }
545
546 #[corresponds(EC_POINT_cmp)]
548 pub fn eq(
549 &self,
550 group: &EcGroupRef,
551 other: &EcPointRef,
552 ctx: &mut BigNumContextRef,
553 ) -> Result<bool, ErrorStack> {
554 unsafe {
555 let res = cvt_n(ffi::EC_POINT_cmp(
556 group.as_ptr(),
557 self.as_ptr(),
558 other.as_ptr(),
559 ctx.as_ptr(),
560 ))?;
561 Ok(res == 0)
562 }
563 }
564
565 #[corresponds(EC_POINT_get_affine_coordinates)]
568 #[cfg(any(ossl111, boringssl, libressl, awslc))]
569 pub fn affine_coordinates(
570 &self,
571 group: &EcGroupRef,
572 x: &mut BigNumRef,
573 y: &mut BigNumRef,
574 ctx: &mut BigNumContextRef,
575 ) -> Result<(), ErrorStack> {
576 unsafe {
577 cvt(ffi::EC_POINT_get_affine_coordinates(
578 group.as_ptr(),
579 self.as_ptr(),
580 x.as_ptr(),
581 y.as_ptr(),
582 ctx.as_ptr(),
583 ))
584 .map(|_| ())
585 }
586 }
587
588 #[corresponds(EC_POINT_get_affine_coordinates_GFp)]
591 pub fn affine_coordinates_gfp(
592 &self,
593 group: &EcGroupRef,
594 x: &mut BigNumRef,
595 y: &mut BigNumRef,
596 ctx: &mut BigNumContextRef,
597 ) -> Result<(), ErrorStack> {
598 unsafe {
599 cvt(ffi::EC_POINT_get_affine_coordinates_GFp(
600 group.as_ptr(),
601 self.as_ptr(),
602 x.as_ptr(),
603 y.as_ptr(),
604 ctx.as_ptr(),
605 ))
606 .map(|_| ())
607 }
608 }
609
610 #[corresponds(EC_POINT_set_affine_coordinates)]
613 #[cfg(any(ossl111, boringssl, libressl, awslc))]
614 pub fn set_affine_coordinates(
615 &mut self,
616 group: &EcGroupRef,
617 x: &BigNumRef,
618 y: &BigNumRef,
619 ctx: &mut BigNumContextRef,
620 ) -> Result<(), ErrorStack> {
621 unsafe {
622 cvt(ffi::EC_POINT_set_affine_coordinates(
623 group.as_ptr(),
624 self.as_ptr(),
625 x.as_ptr(),
626 y.as_ptr(),
627 ctx.as_ptr(),
628 ))
629 .map(|_| ())
630 }
631 }
632
633 #[corresponds(EC_POINT_set_affine_coordinates_GFp)]
636 pub fn set_affine_coordinates_gfp(
637 &mut self,
638 group: &EcGroupRef,
639 x: &BigNumRef,
640 y: &BigNumRef,
641 ctx: &mut BigNumContextRef,
642 ) -> Result<(), ErrorStack> {
643 unsafe {
644 cvt(ffi::EC_POINT_set_affine_coordinates_GFp(
645 group.as_ptr(),
646 self.as_ptr(),
647 x.as_ptr(),
648 y.as_ptr(),
649 ctx.as_ptr(),
650 ))
651 .map(|_| ())
652 }
653 }
654
655 #[corresponds(EC_POINT_get_affine_coordinates_GF2m)]
658 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
659 pub fn affine_coordinates_gf2m(
660 &self,
661 group: &EcGroupRef,
662 x: &mut BigNumRef,
663 y: &mut BigNumRef,
664 ctx: &mut BigNumContextRef,
665 ) -> Result<(), ErrorStack> {
666 unsafe {
667 cvt(ffi::EC_POINT_get_affine_coordinates_GF2m(
668 group.as_ptr(),
669 self.as_ptr(),
670 x.as_ptr(),
671 y.as_ptr(),
672 ctx.as_ptr(),
673 ))
674 .map(|_| ())
675 }
676 }
677
678 #[corresponds(EC_POINT_is_at_infinity)]
680 pub fn is_infinity(&self, group: &EcGroupRef) -> bool {
681 unsafe {
682 let res = ffi::EC_POINT_is_at_infinity(group.as_ptr(), self.as_ptr());
683 res == 1
684 }
685 }
686
687 #[corresponds(EC_POINT_is_on_curve)]
689 pub fn is_on_curve(
690 &self,
691 group: &EcGroupRef,
692 ctx: &mut BigNumContextRef,
693 ) -> Result<bool, ErrorStack> {
694 unsafe {
695 let res = cvt_n(ffi::EC_POINT_is_on_curve(
696 group.as_ptr(),
697 self.as_ptr(),
698 ctx.as_ptr(),
699 ))?;
700 Ok(res == 1)
701 }
702 }
703}
704
705impl EcPoint {
706 #[corresponds(EC_POINT_new)]
708 pub fn new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
709 unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) }
710 }
711
712 #[corresponds(EC_POINT_oct2point)]
714 pub fn from_bytes(
715 group: &EcGroupRef,
716 buf: &[u8],
717 ctx: &mut BigNumContextRef,
718 ) -> Result<EcPoint, ErrorStack> {
719 let point = EcPoint::new(group)?;
720 unsafe {
721 cvt(ffi::EC_POINT_oct2point(
722 group.as_ptr(),
723 point.as_ptr(),
724 buf.as_ptr(),
725 buf.len(),
726 ctx.as_ptr(),
727 ))?;
728 }
729 Ok(point)
730 }
731
732 #[corresponds(EC_POINT_hex2point)]
734 #[cfg(not(any(boringssl, awslc)))]
735 pub fn from_hex_str(
736 group: &EcGroupRef,
737 s: &str,
738 ctx: &mut BigNumContextRef,
739 ) -> Result<EcPoint, ErrorStack> {
740 let point = EcPoint::new(group)?;
741 unsafe {
742 let c_str = CString::new(s.as_bytes()).unwrap();
743 cvt_p(ffi::EC_POINT_hex2point(
744 group.as_ptr(),
745 c_str.as_ptr() as *const _,
746 point.as_ptr(),
747 ctx.as_ptr(),
748 ))?;
749 }
750 Ok(point)
751 }
752}
753
754generic_foreign_type_and_impl_send_sync! {
755 type CType = ffi::EC_KEY;
756 fn drop = ffi::EC_KEY_free;
757
758 pub struct EcKey<T>;
760 pub struct EcKeyRef<T>;
762}
763
764impl<T> EcKeyRef<T>
765where
766 T: HasPrivate,
767{
768 private_key_to_pem! {
769 #[corresponds(PEM_write_bio_ECPrivateKey)]
773 private_key_to_pem,
774 #[corresponds(PEM_write_bio_ECPrivateKey)]
778 private_key_to_pem_passphrase,
779 ffi::PEM_write_bio_ECPrivateKey
780 }
781
782 to_der! {
783 #[corresponds(i2d_ECPrivateKey)]
785 private_key_to_der,
786 ffi::i2d_ECPrivateKey
787 }
788
789 #[corresponds(EC_KEY_get0_private_key)]
791 pub fn private_key(&self) -> &BigNumRef {
792 unsafe {
793 let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr());
794 BigNumRef::from_const_ptr(ptr)
795 }
796 }
797}
798
799impl<T> EcKeyRef<T>
800where
801 T: HasPublic,
802{
803 #[corresponds(EC_KEY_get0_public_key)]
805 pub fn public_key(&self) -> &EcPointRef {
806 unsafe {
807 let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr());
808 EcPointRef::from_const_ptr(ptr)
809 }
810 }
811
812 to_pem! {
813 #[corresponds(PEM_write_bio_EC_PUBKEY)]
817 public_key_to_pem,
818 ffi::PEM_write_bio_EC_PUBKEY
819 }
820
821 to_der! {
822 #[corresponds(i2d_EC_PUBKEY)]
824 public_key_to_der,
825 ffi::i2d_EC_PUBKEY
826 }
827}
828
829impl<T> EcKeyRef<T>
830where
831 T: HasParams,
832{
833 #[corresponds(EC_KEY_get0_group)]
835 pub fn group(&self) -> &EcGroupRef {
836 unsafe {
837 let ptr = ffi::EC_KEY_get0_group(self.as_ptr());
838 EcGroupRef::from_const_ptr(ptr)
839 }
840 }
841
842 #[corresponds(EC_KEY_check_key)]
844 pub fn check_key(&self) -> Result<(), ErrorStack> {
845 unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) }
846 }
847}
848
849impl<T> ToOwned for EcKeyRef<T> {
850 type Owned = EcKey<T>;
851
852 fn to_owned(&self) -> EcKey<T> {
853 unsafe {
854 let r = ffi::EC_KEY_up_ref(self.as_ptr());
855 assert!(r == 1);
856 EcKey::from_ptr(self.as_ptr())
857 }
858 }
859}
860
861impl EcKey<Params> {
862 #[corresponds(EC_KEY_new_by_curve_name)]
867 pub fn from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack> {
868 unsafe {
869 init();
870 cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p))
871 }
872 }
873
874 #[corresponds(EC_KEY_set_group)]
876 pub fn from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack> {
877 unsafe {
878 cvt_p(ffi::EC_KEY_new())
879 .map(|p| EcKey::from_ptr(p))
880 .and_then(|key| {
881 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
882 })
883 }
884 }
885}
886
887impl EcKey<Public> {
888 #[corresponds(EC_KEY_set_public_key)]
916 pub fn from_public_key(
917 group: &EcGroupRef,
918 public_key: &EcPointRef,
919 ) -> Result<EcKey<Public>, ErrorStack> {
920 unsafe {
921 cvt_p(ffi::EC_KEY_new())
922 .map(|p| EcKey::from_ptr(p))
923 .and_then(|key| {
924 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
925 })
926 .and_then(|key| {
927 cvt(ffi::EC_KEY_set_public_key(
928 key.as_ptr(),
929 public_key.as_ptr(),
930 ))
931 .map(|_| key)
932 })
933 }
934 }
935
936 #[corresponds(EC_KEY_set_public_key_affine_coordinates)]
938 pub fn from_public_key_affine_coordinates(
939 group: &EcGroupRef,
940 x: &BigNumRef,
941 y: &BigNumRef,
942 ) -> Result<EcKey<Public>, 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| {
950 cvt(ffi::EC_KEY_set_public_key_affine_coordinates(
951 key.as_ptr(),
952 x.as_ptr(),
953 y.as_ptr(),
954 ))
955 .map(|_| key)
956 })
957 }
958 }
959
960 from_pem! {
961 #[corresponds(PEM_read_bio_EC_PUBKEY)]
965 public_key_from_pem,
966 EcKey<Public>,
967 ffi::PEM_read_bio_EC_PUBKEY
968 }
969
970 from_der! {
971 #[corresponds(d2i_EC_PUBKEY)]
973 public_key_from_der,
974 EcKey<Public>,
975 ffi::d2i_EC_PUBKEY
976 }
977}
978
979impl EcKey<Private> {
980 #[corresponds(EC_KEY_generate_key)]
1009 pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> {
1010 unsafe {
1011 cvt_p(ffi::EC_KEY_new())
1012 .map(|p| EcKey::from_ptr(p))
1013 .and_then(|key| {
1014 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
1015 })
1016 .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key))
1017 }
1018 }
1019
1020 #[corresponds(EC_KEY_set_private_key)]
1022 pub fn from_private_components(
1023 group: &EcGroupRef,
1024 private_number: &BigNumRef,
1025 public_key: &EcPointRef,
1026 ) -> Result<EcKey<Private>, ErrorStack> {
1027 unsafe {
1028 cvt_p(ffi::EC_KEY_new())
1029 .map(|p| EcKey::from_ptr(p))
1030 .and_then(|key| {
1031 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
1032 })
1033 .and_then(|key| {
1034 cvt(ffi::EC_KEY_set_private_key(
1035 key.as_ptr(),
1036 private_number.as_ptr(),
1037 ))
1038 .map(|_| key)
1039 })
1040 .and_then(|key| {
1041 cvt(ffi::EC_KEY_set_public_key(
1042 key.as_ptr(),
1043 public_key.as_ptr(),
1044 ))
1045 .map(|_| key)
1046 })
1047 }
1048 }
1049
1050 private_key_from_pem! {
1051 #[corresponds(PEM_read_bio_ECPrivateKey)]
1055 private_key_from_pem,
1056
1057 #[corresponds(PEM_read_bio_ECPrivateKey)]
1061 private_key_from_pem_passphrase,
1062
1063 #[corresponds(PEM_read_bio_ECPrivateKey)]
1069 private_key_from_pem_callback,
1070 EcKey<Private>,
1071 ffi::PEM_read_bio_ECPrivateKey
1072 }
1073
1074 from_der! {
1075 #[corresponds(d2i_ECPrivateKey)]
1077 private_key_from_der,
1078 EcKey<Private>,
1079 ffi::d2i_ECPrivateKey
1080 }
1081}
1082
1083impl<T> Clone for EcKey<T> {
1084 fn clone(&self) -> EcKey<T> {
1085 (**self).to_owned()
1086 }
1087}
1088
1089impl<T> fmt::Debug for EcKey<T> {
1090 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1091 write!(f, "EcKey")
1092 }
1093}
1094
1095#[cfg(test)]
1096mod test {
1097 use hex::FromHex;
1098
1099 use super::*;
1100 use crate::bn::{BigNum, BigNumContext};
1101 use crate::nid::Nid;
1102
1103 #[test]
1104 fn key_new_by_curve_name() {
1105 EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1106 }
1107
1108 #[test]
1109 fn generate() {
1110 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1111 EcKey::generate(&group).unwrap();
1112 }
1113
1114 #[test]
1115 fn ec_group_from_components() {
1116 let p = BigNum::from_hex_str(
1118 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1119 )
1120 .unwrap();
1121 let a = BigNum::from_hex_str(
1122 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1123 )
1124 .unwrap();
1125 let b = BigNum::from_hex_str(
1126 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1127 )
1128 .unwrap();
1129 let mut ctx = BigNumContext::new().unwrap();
1130
1131 let _curve = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1132 }
1133
1134 fn set_affine_coords_test(
1135 set_affine_coords: fn(
1136 &mut EcPointRef,
1137 &EcGroupRef,
1138 &BigNumRef,
1139 &BigNumRef,
1140 &mut BigNumContextRef,
1141 ) -> Result<(), ErrorStack>,
1142 ) {
1143 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1145 let mut ctx = BigNumContext::new().unwrap();
1146 let mut gen_point = EcPoint::new(&group).unwrap();
1147 let gen_x = BigNum::from_hex_str(
1148 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1149 )
1150 .unwrap();
1151 let gen_y = BigNum::from_hex_str(
1152 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1153 )
1154 .unwrap();
1155 set_affine_coords(&mut gen_point, &group, &gen_x, &gen_y, &mut ctx).unwrap();
1156
1157 assert!(gen_point.is_on_curve(&group, &mut ctx).unwrap());
1158 }
1159
1160 #[test]
1161 fn ec_point_set_affine_gfp() {
1162 set_affine_coords_test(EcPointRef::set_affine_coordinates_gfp)
1163 }
1164
1165 #[test]
1166 #[cfg(any(ossl111, boringssl, libressl, awslc))]
1167 fn ec_point_set_affine() {
1168 set_affine_coords_test(EcPointRef::set_affine_coordinates)
1169 }
1170
1171 #[test]
1172 fn ec_group_set_generator() {
1173 let mut ctx = BigNumContext::new().unwrap();
1175 let p = BigNum::from_hex_str(
1176 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1177 )
1178 .unwrap();
1179 let a = BigNum::from_hex_str(
1180 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1181 )
1182 .unwrap();
1183 let b = BigNum::from_hex_str(
1184 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1185 )
1186 .unwrap();
1187
1188 let mut group = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1189
1190 let mut gen_point = EcPoint::new(&group).unwrap();
1191 let gen_x = BigNum::from_hex_str(
1192 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1193 )
1194 .unwrap();
1195 let gen_y = BigNum::from_hex_str(
1196 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1197 )
1198 .unwrap();
1199 gen_point
1200 .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx)
1201 .unwrap();
1202
1203 let order = BigNum::from_hex_str(
1204 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
1205 )
1206 .unwrap();
1207 let cofactor = BigNum::from_hex_str("01").unwrap();
1208 group.set_generator(gen_point, order, cofactor).unwrap();
1209 let mut constructed_order = BigNum::new().unwrap();
1210 group.order(&mut constructed_order, &mut ctx).unwrap();
1211
1212 let named_group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1213 let mut named_order = BigNum::new().unwrap();
1214 named_group.order(&mut named_order, &mut ctx).unwrap();
1215
1216 assert_eq!(
1217 constructed_order.ucmp(&named_order),
1218 std::cmp::Ordering::Equal
1219 );
1220 }
1221
1222 #[test]
1223 fn cofactor() {
1224 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1225 let mut ctx = BigNumContext::new().unwrap();
1226 let mut cofactor = BigNum::new().unwrap();
1227 group.cofactor(&mut cofactor, &mut ctx).unwrap();
1228 let one = BigNum::from_u32(1).unwrap();
1229 assert_eq!(cofactor, one);
1230 }
1231
1232 #[test]
1233 #[allow(clippy::redundant_clone)]
1234 fn dup() {
1235 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1236 let key = EcKey::generate(&group).unwrap();
1237 drop(key.clone());
1238 }
1239
1240 #[test]
1241 fn point_new() {
1242 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1243 EcPoint::new(&group).unwrap();
1244 }
1245
1246 #[test]
1247 fn point_bytes() {
1248 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1249 let key = EcKey::generate(&group).unwrap();
1250 let point = key.public_key();
1251 let mut ctx = BigNumContext::new().unwrap();
1252 let bytes = point
1253 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1254 .unwrap();
1255 let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1256 assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1257 }
1258
1259 #[test]
1260 #[cfg(not(any(boringssl, awslc)))]
1261 fn point_hex_str() {
1262 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1263 let key = EcKey::generate(&group).unwrap();
1264 let point = key.public_key();
1265 let mut ctx = BigNumContext::new().unwrap();
1266 let hex = point
1267 .to_hex_str(&group, PointConversionForm::COMPRESSED, &mut ctx)
1268 .unwrap();
1269 let point2 = EcPoint::from_hex_str(&group, &hex, &mut ctx).unwrap();
1270 assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1271 }
1272
1273 #[test]
1274 fn point_owned() {
1275 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1276 let key = EcKey::generate(&group).unwrap();
1277 let point = key.public_key();
1278 let owned = point.to_owned(&group).unwrap();
1279 let mut ctx = BigNumContext::new().unwrap();
1280 assert!(owned.eq(&group, point, &mut ctx).unwrap());
1281 }
1282
1283 #[test]
1284 fn mul_generator() {
1285 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1286 let key = EcKey::generate(&group).unwrap();
1287 let mut ctx = BigNumContext::new().unwrap();
1288 let mut public_key = EcPoint::new(&group).unwrap();
1289 public_key
1290 .mul_generator(&group, key.private_key(), &ctx)
1291 .unwrap();
1292 assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap());
1293 }
1294
1295 #[test]
1296 fn generator() {
1297 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1298 let gen = group.generator();
1299 let one = BigNum::from_u32(1).unwrap();
1300 let mut ctx = BigNumContext::new().unwrap();
1301 let mut ecp = EcPoint::new(&group).unwrap();
1302 ecp.mul_generator(&group, &one, &ctx).unwrap();
1303 assert!(ecp.eq(&group, gen, &mut ctx).unwrap());
1304 }
1305
1306 #[test]
1307 fn key_from_public_key() {
1308 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1309 let key = EcKey::generate(&group).unwrap();
1310 let mut ctx = BigNumContext::new().unwrap();
1311 let bytes = key
1312 .public_key()
1313 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1314 .unwrap();
1315
1316 drop(key);
1317 let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1318 let ec_key = EcKey::from_public_key(&group, &public_key).unwrap();
1319 assert!(ec_key.check_key().is_ok());
1320 }
1321
1322 #[test]
1323 fn key_from_private_components() {
1324 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1325 let key = EcKey::generate(&group).unwrap();
1326
1327 let dup_key =
1328 EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap();
1329 dup_key.check_key().unwrap();
1330
1331 assert!(key.private_key() == dup_key.private_key());
1332 }
1333
1334 #[test]
1335 fn key_from_affine_coordinates() {
1336 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1337 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1338 .unwrap();
1339 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1340 .unwrap();
1341
1342 let xbn = BigNum::from_slice(&x).unwrap();
1343 let ybn = BigNum::from_slice(&y).unwrap();
1344
1345 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1346 assert!(ec_key.check_key().is_ok());
1347 }
1348
1349 #[cfg(any(ossl111, boringssl, libressl, awslc))]
1350 #[test]
1351 fn get_affine_coordinates() {
1352 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1353 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1354 .unwrap();
1355 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1356 .unwrap();
1357
1358 let xbn = BigNum::from_slice(&x).unwrap();
1359 let ybn = BigNum::from_slice(&y).unwrap();
1360
1361 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1362
1363 let mut xbn2 = BigNum::new().unwrap();
1364 let mut ybn2 = BigNum::new().unwrap();
1365 let mut ctx = BigNumContext::new().unwrap();
1366 let ec_key_pk = ec_key.public_key();
1367 ec_key_pk
1368 .affine_coordinates(&group, &mut xbn2, &mut ybn2, &mut ctx)
1369 .unwrap();
1370 assert_eq!(xbn2, xbn);
1371 assert_eq!(ybn2, ybn);
1372 }
1373
1374 #[test]
1375 fn get_affine_coordinates_gfp() {
1376 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1377 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1378 .unwrap();
1379 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1380 .unwrap();
1381
1382 let xbn = BigNum::from_slice(&x).unwrap();
1383 let ybn = BigNum::from_slice(&y).unwrap();
1384
1385 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1386
1387 let mut xbn2 = BigNum::new().unwrap();
1388 let mut ybn2 = BigNum::new().unwrap();
1389 let mut ctx = BigNumContext::new().unwrap();
1390 let ec_key_pk = ec_key.public_key();
1391 ec_key_pk
1392 .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx)
1393 .unwrap();
1394 assert_eq!(xbn2, xbn);
1395 assert_eq!(ybn2, ybn);
1396 }
1397
1398 #[test]
1399 fn is_infinity() {
1400 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1401 let mut ctx = BigNumContext::new().unwrap();
1402 let g = group.generator();
1403 assert!(!g.is_infinity(&group));
1404
1405 let mut order = BigNum::new().unwrap();
1406 group.order(&mut order, &mut ctx).unwrap();
1407 let mut inf = EcPoint::new(&group).unwrap();
1408 inf.mul_generator(&group, &order, &ctx).unwrap();
1409 assert!(inf.is_infinity(&group));
1410 }
1411
1412 #[test]
1413 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
1414 fn is_on_curve() {
1415 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1416 let mut ctx = BigNumContext::new().unwrap();
1417 let g = group.generator();
1418 assert!(g.is_on_curve(&group, &mut ctx).unwrap());
1419
1420 let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap();
1421 assert!(!g.is_on_curve(&group2, &mut ctx).unwrap());
1422 }
1423
1424 #[test]
1425 #[cfg(any(boringssl, ossl111, libressl, awslc))]
1426 fn asn1_flag() {
1427 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1428 let flag = group.asn1_flag();
1429 assert_eq!(flag, Asn1Flag::NAMED_CURVE);
1430 }
1431
1432 #[test]
1433 fn test_debug_standard_group() {
1434 let group = EcGroup::from_curve_name(Nid::SECP521R1).unwrap();
1435
1436 assert_eq!(
1437 format!("{:?}", group),
1438 "EcGroup { curve_name: \"secp521r1\" }"
1439 );
1440 }
1441
1442 #[test]
1443 fn test_debug_custom_group() {
1444 let mut p = BigNum::new().unwrap();
1445 let mut a = BigNum::new().unwrap();
1446 let mut b = BigNum::new().unwrap();
1447 let mut ctx = BigNumContext::new().unwrap();
1448
1449 EcGroup::from_curve_name(Nid::SECP521R1)
1450 .unwrap()
1451 .components_gfp(&mut p, &mut a, &mut b, &mut ctx)
1452 .unwrap();
1453
1454 let group = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1456
1457 assert_eq!(
1458 format!("{:?}", group),
1459 "EcGroup { p: \"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", a: \"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC\", b: \"51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00\" }"
1460 );
1461 }
1462}