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, 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 EcGroupRef {
169 #[corresponds(EC_GROUP_get_curve_GFp)]
172 pub fn components_gfp(
173 &self,
174 p: &mut BigNumRef,
175 a: &mut BigNumRef,
176 b: &mut BigNumRef,
177 ctx: &mut BigNumContextRef,
178 ) -> Result<(), ErrorStack> {
179 unsafe {
180 cvt(ffi::EC_GROUP_get_curve_GFp(
181 self.as_ptr(),
182 p.as_ptr(),
183 a.as_ptr(),
184 b.as_ptr(),
185 ctx.as_ptr(),
186 ))
187 .map(|_| ())
188 }
189 }
190
191 #[corresponds(EC_GROUP_get_curve_GF2m)]
198 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
199 pub fn components_gf2m(
200 &self,
201 p: &mut BigNumRef,
202 a: &mut BigNumRef,
203 b: &mut BigNumRef,
204 ctx: &mut BigNumContextRef,
205 ) -> Result<(), ErrorStack> {
206 unsafe {
207 cvt(ffi::EC_GROUP_get_curve_GF2m(
208 self.as_ptr(),
209 p.as_ptr(),
210 a.as_ptr(),
211 b.as_ptr(),
212 ctx.as_ptr(),
213 ))
214 .map(|_| ())
215 }
216 }
217
218 #[corresponds(EC_GROUP_get_cofactor)]
220 pub fn cofactor(
221 &self,
222 cofactor: &mut BigNumRef,
223 ctx: &mut BigNumContextRef,
224 ) -> Result<(), ErrorStack> {
225 unsafe {
226 cvt(ffi::EC_GROUP_get_cofactor(
227 self.as_ptr(),
228 cofactor.as_ptr(),
229 ctx.as_ptr(),
230 ))
231 .map(|_| ())
232 }
233 }
234
235 #[corresponds(EC_GROUP_get_degree)]
237 pub fn degree(&self) -> u32 {
238 unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 }
239 }
240
241 #[corresponds(EC_GROUP_order_bits)]
243 #[cfg(any(ossl110, libressl, awslc, boringssl))]
244 pub fn order_bits(&self) -> u32 {
245 unsafe { ffi::EC_GROUP_order_bits(self.as_ptr()) as u32 }
246 }
247
248 #[corresponds(EC_GROUP_get0_generator)]
250 pub fn generator(&self) -> &EcPointRef {
251 unsafe {
252 let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr());
253 EcPointRef::from_const_ptr(ptr)
254 }
255 }
256
257 #[corresponds(EC_GROUP_set_generator)]
259 pub fn set_generator(
260 &mut self,
261 generator: EcPoint,
262 order: BigNum,
263 cofactor: BigNum,
264 ) -> Result<(), ErrorStack> {
265 unsafe {
266 cvt(ffi::EC_GROUP_set_generator(
267 self.as_ptr(),
268 generator.as_ptr(),
269 order.as_ptr(),
270 cofactor.as_ptr(),
271 ))
272 .map(|_| ())
273 }
274 }
275
276 #[corresponds(EC_GROUP_get_order)]
278 pub fn order(
279 &self,
280 order: &mut BigNumRef,
281 ctx: &mut BigNumContextRef,
282 ) -> Result<(), ErrorStack> {
283 unsafe {
284 cvt(ffi::EC_GROUP_get_order(
285 self.as_ptr(),
286 order.as_ptr(),
287 ctx.as_ptr(),
288 ))
289 .map(|_| ())
290 }
291 }
292
293 #[corresponds(EC_GROUP_set_asn1_flag)]
299 pub fn set_asn1_flag(&mut self, flag: Asn1Flag) {
300 unsafe {
301 ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0);
302 }
303 }
304
305 #[corresponds(EC_GROUP_get_asn1_flag)]
307 pub fn asn1_flag(&self) -> Asn1Flag {
308 unsafe { Asn1Flag(ffi::EC_GROUP_get_asn1_flag(self.as_ptr())) }
309 }
310
311 #[corresponds(EC_GROUP_get_curve_name)]
313 pub fn curve_name(&self) -> Option<Nid> {
314 let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) };
315 if nid > 0 {
316 Some(Nid::from_raw(nid))
317 } else {
318 None
319 }
320 }
321}
322
323foreign_type_and_impl_send_sync! {
324 type CType = ffi::EC_POINT;
325 fn drop = ffi::EC_POINT_free;
326
327 pub struct EcPoint;
329 pub struct EcPointRef;
331}
332
333impl EcPointRef {
334 #[corresponds(EC_POINT_add)]
336 pub fn add(
337 &mut self,
338 group: &EcGroupRef,
339 a: &EcPointRef,
340 b: &EcPointRef,
341 ctx: &mut BigNumContextRef,
342 ) -> Result<(), ErrorStack> {
343 unsafe {
344 cvt(ffi::EC_POINT_add(
345 group.as_ptr(),
346 self.as_ptr(),
347 a.as_ptr(),
348 b.as_ptr(),
349 ctx.as_ptr(),
350 ))
351 .map(|_| ())
352 }
353 }
354
355 #[corresponds(EC_POINT_mul)]
357 pub fn mul(
358 &mut self,
359 group: &EcGroupRef,
360 q: &EcPointRef,
361 m: &BigNumRef,
362 ctx: &BigNumContextRef,
364 ) -> Result<(), ErrorStack> {
365 unsafe {
366 cvt(ffi::EC_POINT_mul(
367 group.as_ptr(),
368 self.as_ptr(),
369 ptr::null(),
370 q.as_ptr(),
371 m.as_ptr(),
372 ctx.as_ptr(),
373 ))
374 .map(|_| ())
375 }
376 }
377
378 #[corresponds(EC_POINT_mul)]
380 pub fn mul_generator(
381 &mut self,
382 group: &EcGroupRef,
383 n: &BigNumRef,
384 ctx: &BigNumContextRef,
386 ) -> Result<(), ErrorStack> {
387 unsafe {
388 cvt(ffi::EC_POINT_mul(
389 group.as_ptr(),
390 self.as_ptr(),
391 n.as_ptr(),
392 ptr::null(),
393 ptr::null(),
394 ctx.as_ptr(),
395 ))
396 .map(|_| ())
397 }
398 }
399
400 #[corresponds(EC_POINT_mul)]
402 pub fn mul_full(
403 &mut self,
404 group: &EcGroupRef,
405 n: &BigNumRef,
406 q: &EcPointRef,
407 m: &BigNumRef,
408 ctx: &mut BigNumContextRef,
409 ) -> Result<(), ErrorStack> {
410 unsafe {
411 cvt(ffi::EC_POINT_mul(
412 group.as_ptr(),
413 self.as_ptr(),
414 n.as_ptr(),
415 q.as_ptr(),
416 m.as_ptr(),
417 ctx.as_ptr(),
418 ))
419 .map(|_| ())
420 }
421 }
422
423 #[corresponds(EC_POINT_invert)]
425 pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> {
427 unsafe {
428 cvt(ffi::EC_POINT_invert(
429 group.as_ptr(),
430 self.as_ptr(),
431 ctx.as_ptr(),
432 ))
433 .map(|_| ())
434 }
435 }
436
437 #[corresponds(EC_POINT_point2oct)]
439 pub fn to_bytes(
440 &self,
441 group: &EcGroupRef,
442 form: PointConversionForm,
443 ctx: &mut BigNumContextRef,
444 ) -> Result<Vec<u8>, ErrorStack> {
445 unsafe {
446 let len = ffi::EC_POINT_point2oct(
447 group.as_ptr(),
448 self.as_ptr(),
449 form.0,
450 ptr::null_mut(),
451 0,
452 ctx.as_ptr(),
453 );
454 if len == 0 {
455 return Err(ErrorStack::get());
456 }
457 let mut buf = vec![0; len];
458 let len = ffi::EC_POINT_point2oct(
459 group.as_ptr(),
460 self.as_ptr(),
461 form.0,
462 buf.as_mut_ptr(),
463 len,
464 ctx.as_ptr(),
465 );
466 if len == 0 {
467 Err(ErrorStack::get())
468 } else {
469 Ok(buf)
470 }
471 }
472 }
473
474 #[corresponds(EC_POINT_point2hex)]
476 #[cfg(not(any(boringssl, awslc)))]
477 pub fn to_hex_str(
478 &self,
479 group: &EcGroupRef,
480 form: PointConversionForm,
481 ctx: &mut BigNumContextRef,
482 ) -> Result<OpensslString, ErrorStack> {
483 unsafe {
484 let buf = cvt_p(ffi::EC_POINT_point2hex(
485 group.as_ptr(),
486 self.as_ptr(),
487 form.0,
488 ctx.as_ptr(),
489 ))?;
490 Ok(OpensslString::from_ptr(buf))
491 }
492 }
493
494 #[corresponds(EC_POINT_dup)]
496 pub fn to_owned(&self, group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
497 unsafe { cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(EcPoint) }
498 }
499
500 #[corresponds(EC_POINT_cmp)]
502 pub fn eq(
503 &self,
504 group: &EcGroupRef,
505 other: &EcPointRef,
506 ctx: &mut BigNumContextRef,
507 ) -> Result<bool, ErrorStack> {
508 unsafe {
509 let res = cvt_n(ffi::EC_POINT_cmp(
510 group.as_ptr(),
511 self.as_ptr(),
512 other.as_ptr(),
513 ctx.as_ptr(),
514 ))?;
515 Ok(res == 0)
516 }
517 }
518
519 #[corresponds(EC_POINT_get_affine_coordinates)]
522 #[cfg(any(ossl111, boringssl, libressl, awslc))]
523 pub fn affine_coordinates(
524 &self,
525 group: &EcGroupRef,
526 x: &mut BigNumRef,
527 y: &mut BigNumRef,
528 ctx: &mut BigNumContextRef,
529 ) -> Result<(), ErrorStack> {
530 unsafe {
531 cvt(ffi::EC_POINT_get_affine_coordinates(
532 group.as_ptr(),
533 self.as_ptr(),
534 x.as_ptr(),
535 y.as_ptr(),
536 ctx.as_ptr(),
537 ))
538 .map(|_| ())
539 }
540 }
541
542 #[corresponds(EC_POINT_get_affine_coordinates_GFp)]
545 pub fn affine_coordinates_gfp(
546 &self,
547 group: &EcGroupRef,
548 x: &mut BigNumRef,
549 y: &mut BigNumRef,
550 ctx: &mut BigNumContextRef,
551 ) -> Result<(), ErrorStack> {
552 unsafe {
553 cvt(ffi::EC_POINT_get_affine_coordinates_GFp(
554 group.as_ptr(),
555 self.as_ptr(),
556 x.as_ptr(),
557 y.as_ptr(),
558 ctx.as_ptr(),
559 ))
560 .map(|_| ())
561 }
562 }
563
564 #[corresponds(EC_POINT_set_affine_coordinates)]
567 #[cfg(any(ossl111, boringssl, libressl, awslc))]
568 pub fn set_affine_coordinates(
569 &mut self,
570 group: &EcGroupRef,
571 x: &BigNumRef,
572 y: &BigNumRef,
573 ctx: &mut BigNumContextRef,
574 ) -> Result<(), ErrorStack> {
575 unsafe {
576 cvt(ffi::EC_POINT_set_affine_coordinates(
577 group.as_ptr(),
578 self.as_ptr(),
579 x.as_ptr(),
580 y.as_ptr(),
581 ctx.as_ptr(),
582 ))
583 .map(|_| ())
584 }
585 }
586
587 #[corresponds(EC_POINT_set_affine_coordinates_GFp)]
590 pub fn set_affine_coordinates_gfp(
591 &mut self,
592 group: &EcGroupRef,
593 x: &BigNumRef,
594 y: &BigNumRef,
595 ctx: &mut BigNumContextRef,
596 ) -> Result<(), ErrorStack> {
597 unsafe {
598 cvt(ffi::EC_POINT_set_affine_coordinates_GFp(
599 group.as_ptr(),
600 self.as_ptr(),
601 x.as_ptr(),
602 y.as_ptr(),
603 ctx.as_ptr(),
604 ))
605 .map(|_| ())
606 }
607 }
608
609 #[corresponds(EC_POINT_get_affine_coordinates_GF2m)]
612 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
613 pub fn affine_coordinates_gf2m(
614 &self,
615 group: &EcGroupRef,
616 x: &mut BigNumRef,
617 y: &mut BigNumRef,
618 ctx: &mut BigNumContextRef,
619 ) -> Result<(), ErrorStack> {
620 unsafe {
621 cvt(ffi::EC_POINT_get_affine_coordinates_GF2m(
622 group.as_ptr(),
623 self.as_ptr(),
624 x.as_ptr(),
625 y.as_ptr(),
626 ctx.as_ptr(),
627 ))
628 .map(|_| ())
629 }
630 }
631
632 #[corresponds(EC_POINT_is_at_infinity)]
634 pub fn is_infinity(&self, group: &EcGroupRef) -> bool {
635 unsafe {
636 let res = ffi::EC_POINT_is_at_infinity(group.as_ptr(), self.as_ptr());
637 res == 1
638 }
639 }
640
641 #[corresponds(EC_POINT_is_on_curve)]
643 pub fn is_on_curve(
644 &self,
645 group: &EcGroupRef,
646 ctx: &mut BigNumContextRef,
647 ) -> Result<bool, ErrorStack> {
648 unsafe {
649 let res = cvt_n(ffi::EC_POINT_is_on_curve(
650 group.as_ptr(),
651 self.as_ptr(),
652 ctx.as_ptr(),
653 ))?;
654 Ok(res == 1)
655 }
656 }
657}
658
659impl EcPoint {
660 #[corresponds(EC_POINT_new)]
662 pub fn new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack> {
663 unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) }
664 }
665
666 #[corresponds(EC_POINT_oct2point)]
668 pub fn from_bytes(
669 group: &EcGroupRef,
670 buf: &[u8],
671 ctx: &mut BigNumContextRef,
672 ) -> Result<EcPoint, ErrorStack> {
673 let point = EcPoint::new(group)?;
674 unsafe {
675 cvt(ffi::EC_POINT_oct2point(
676 group.as_ptr(),
677 point.as_ptr(),
678 buf.as_ptr(),
679 buf.len(),
680 ctx.as_ptr(),
681 ))?;
682 }
683 Ok(point)
684 }
685
686 #[corresponds(EC_POINT_hex2point)]
688 #[cfg(not(any(boringssl, awslc)))]
689 pub fn from_hex_str(
690 group: &EcGroupRef,
691 s: &str,
692 ctx: &mut BigNumContextRef,
693 ) -> Result<EcPoint, ErrorStack> {
694 let point = EcPoint::new(group)?;
695 unsafe {
696 let c_str = CString::new(s.as_bytes()).unwrap();
697 cvt_p(ffi::EC_POINT_hex2point(
698 group.as_ptr(),
699 c_str.as_ptr() as *const _,
700 point.as_ptr(),
701 ctx.as_ptr(),
702 ))?;
703 }
704 Ok(point)
705 }
706}
707
708generic_foreign_type_and_impl_send_sync! {
709 type CType = ffi::EC_KEY;
710 fn drop = ffi::EC_KEY_free;
711
712 pub struct EcKey<T>;
714 pub struct EcKeyRef<T>;
716}
717
718impl<T> EcKeyRef<T>
719where
720 T: HasPrivate,
721{
722 private_key_to_pem! {
723 #[corresponds(PEM_write_bio_ECPrivateKey)]
727 private_key_to_pem,
728 #[corresponds(PEM_write_bio_ECPrivateKey)]
732 private_key_to_pem_passphrase,
733 ffi::PEM_write_bio_ECPrivateKey
734 }
735
736 to_der! {
737 #[corresponds(i2d_ECPrivateKey)]
739 private_key_to_der,
740 ffi::i2d_ECPrivateKey
741 }
742
743 #[corresponds(EC_KEY_get0_private_key)]
745 pub fn private_key(&self) -> &BigNumRef {
746 unsafe {
747 let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr());
748 BigNumRef::from_const_ptr(ptr)
749 }
750 }
751}
752
753impl<T> EcKeyRef<T>
754where
755 T: HasPublic,
756{
757 #[corresponds(EC_KEY_get0_public_key)]
759 pub fn public_key(&self) -> &EcPointRef {
760 unsafe {
761 let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr());
762 EcPointRef::from_const_ptr(ptr)
763 }
764 }
765
766 to_pem! {
767 #[corresponds(PEM_write_bio_EC_PUBKEY)]
771 public_key_to_pem,
772 ffi::PEM_write_bio_EC_PUBKEY
773 }
774
775 to_der! {
776 #[corresponds(i2d_EC_PUBKEY)]
778 public_key_to_der,
779 ffi::i2d_EC_PUBKEY
780 }
781}
782
783impl<T> EcKeyRef<T>
784where
785 T: HasParams,
786{
787 #[corresponds(EC_KEY_get0_group)]
789 pub fn group(&self) -> &EcGroupRef {
790 unsafe {
791 let ptr = ffi::EC_KEY_get0_group(self.as_ptr());
792 EcGroupRef::from_const_ptr(ptr)
793 }
794 }
795
796 #[corresponds(EC_KEY_check_key)]
798 pub fn check_key(&self) -> Result<(), ErrorStack> {
799 unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) }
800 }
801}
802
803impl<T> ToOwned for EcKeyRef<T> {
804 type Owned = EcKey<T>;
805
806 fn to_owned(&self) -> EcKey<T> {
807 unsafe {
808 let r = ffi::EC_KEY_up_ref(self.as_ptr());
809 assert!(r == 1);
810 EcKey::from_ptr(self.as_ptr())
811 }
812 }
813}
814
815impl EcKey<Params> {
816 #[corresponds(EC_KEY_new_by_curve_name)]
821 pub fn from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack> {
822 unsafe {
823 init();
824 cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p))
825 }
826 }
827
828 #[corresponds(EC_KEY_set_group)]
830 pub fn from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack> {
831 unsafe {
832 cvt_p(ffi::EC_KEY_new())
833 .map(|p| EcKey::from_ptr(p))
834 .and_then(|key| {
835 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
836 })
837 }
838 }
839}
840
841impl EcKey<Public> {
842 #[corresponds(EC_KEY_set_public_key)]
870 pub fn from_public_key(
871 group: &EcGroupRef,
872 public_key: &EcPointRef,
873 ) -> Result<EcKey<Public>, ErrorStack> {
874 unsafe {
875 cvt_p(ffi::EC_KEY_new())
876 .map(|p| EcKey::from_ptr(p))
877 .and_then(|key| {
878 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
879 })
880 .and_then(|key| {
881 cvt(ffi::EC_KEY_set_public_key(
882 key.as_ptr(),
883 public_key.as_ptr(),
884 ))
885 .map(|_| key)
886 })
887 }
888 }
889
890 #[corresponds(EC_KEY_set_public_key_affine_coordinates)]
892 pub fn from_public_key_affine_coordinates(
893 group: &EcGroupRef,
894 x: &BigNumRef,
895 y: &BigNumRef,
896 ) -> Result<EcKey<Public>, ErrorStack> {
897 unsafe {
898 cvt_p(ffi::EC_KEY_new())
899 .map(|p| EcKey::from_ptr(p))
900 .and_then(|key| {
901 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
902 })
903 .and_then(|key| {
904 cvt(ffi::EC_KEY_set_public_key_affine_coordinates(
905 key.as_ptr(),
906 x.as_ptr(),
907 y.as_ptr(),
908 ))
909 .map(|_| key)
910 })
911 }
912 }
913
914 from_pem! {
915 #[corresponds(PEM_read_bio_EC_PUBKEY)]
919 public_key_from_pem,
920 EcKey<Public>,
921 ffi::PEM_read_bio_EC_PUBKEY
922 }
923
924 from_der! {
925 #[corresponds(d2i_EC_PUBKEY)]
927 public_key_from_der,
928 EcKey<Public>,
929 ffi::d2i_EC_PUBKEY
930 }
931}
932
933impl EcKey<Private> {
934 #[corresponds(EC_KEY_generate_key)]
963 pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> {
964 unsafe {
965 cvt_p(ffi::EC_KEY_new())
966 .map(|p| EcKey::from_ptr(p))
967 .and_then(|key| {
968 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
969 })
970 .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key))
971 }
972 }
973
974 #[corresponds(EC_KEY_set_private_key)]
976 pub fn from_private_components(
977 group: &EcGroupRef,
978 private_number: &BigNumRef,
979 public_key: &EcPointRef,
980 ) -> Result<EcKey<Private>, ErrorStack> {
981 unsafe {
982 cvt_p(ffi::EC_KEY_new())
983 .map(|p| EcKey::from_ptr(p))
984 .and_then(|key| {
985 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key)
986 })
987 .and_then(|key| {
988 cvt(ffi::EC_KEY_set_private_key(
989 key.as_ptr(),
990 private_number.as_ptr(),
991 ))
992 .map(|_| key)
993 })
994 .and_then(|key| {
995 cvt(ffi::EC_KEY_set_public_key(
996 key.as_ptr(),
997 public_key.as_ptr(),
998 ))
999 .map(|_| key)
1000 })
1001 }
1002 }
1003
1004 private_key_from_pem! {
1005 #[corresponds(PEM_read_bio_ECPrivateKey)]
1009 private_key_from_pem,
1010
1011 #[corresponds(PEM_read_bio_ECPrivateKey)]
1015 private_key_from_pem_passphrase,
1016
1017 #[corresponds(PEM_read_bio_ECPrivateKey)]
1023 private_key_from_pem_callback,
1024 EcKey<Private>,
1025 ffi::PEM_read_bio_ECPrivateKey
1026 }
1027
1028 from_der! {
1029 #[corresponds(d2i_ECPrivateKey)]
1031 private_key_from_der,
1032 EcKey<Private>,
1033 ffi::d2i_ECPrivateKey
1034 }
1035}
1036
1037impl<T> Clone for EcKey<T> {
1038 fn clone(&self) -> EcKey<T> {
1039 (**self).to_owned()
1040 }
1041}
1042
1043impl<T> fmt::Debug for EcKey<T> {
1044 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1045 write!(f, "EcKey")
1046 }
1047}
1048
1049#[cfg(test)]
1050mod test {
1051 use hex::FromHex;
1052
1053 use super::*;
1054 use crate::bn::{BigNum, BigNumContext};
1055 use crate::nid::Nid;
1056
1057 #[test]
1058 fn key_new_by_curve_name() {
1059 EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1060 }
1061
1062 #[test]
1063 fn generate() {
1064 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1065 EcKey::generate(&group).unwrap();
1066 }
1067
1068 #[test]
1069 fn ec_group_from_components() {
1070 let p = BigNum::from_hex_str(
1072 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1073 )
1074 .unwrap();
1075 let a = BigNum::from_hex_str(
1076 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1077 )
1078 .unwrap();
1079 let b = BigNum::from_hex_str(
1080 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1081 )
1082 .unwrap();
1083 let mut ctx = BigNumContext::new().unwrap();
1084
1085 let _curve = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1086 }
1087
1088 fn set_affine_coords_test(
1089 set_affine_coords: fn(
1090 &mut EcPointRef,
1091 &EcGroupRef,
1092 &BigNumRef,
1093 &BigNumRef,
1094 &mut BigNumContextRef,
1095 ) -> Result<(), ErrorStack>,
1096 ) {
1097 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1099 let mut ctx = BigNumContext::new().unwrap();
1100 let mut gen_point = EcPoint::new(&group).unwrap();
1101 let gen_x = BigNum::from_hex_str(
1102 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1103 )
1104 .unwrap();
1105 let gen_y = BigNum::from_hex_str(
1106 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1107 )
1108 .unwrap();
1109 set_affine_coords(&mut gen_point, &group, &gen_x, &gen_y, &mut ctx).unwrap();
1110
1111 assert!(gen_point.is_on_curve(&group, &mut ctx).unwrap());
1112 }
1113
1114 #[test]
1115 fn ec_point_set_affine_gfp() {
1116 set_affine_coords_test(EcPointRef::set_affine_coordinates_gfp)
1117 }
1118
1119 #[test]
1120 #[cfg(any(ossl111, boringssl, libressl, awslc))]
1121 fn ec_point_set_affine() {
1122 set_affine_coords_test(EcPointRef::set_affine_coordinates)
1123 }
1124
1125 #[test]
1126 fn ec_group_set_generator() {
1127 let mut ctx = BigNumContext::new().unwrap();
1129 let p = BigNum::from_hex_str(
1130 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1131 )
1132 .unwrap();
1133 let a = BigNum::from_hex_str(
1134 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1135 )
1136 .unwrap();
1137 let b = BigNum::from_hex_str(
1138 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1139 )
1140 .unwrap();
1141
1142 let mut group = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1143
1144 let mut gen_point = EcPoint::new(&group).unwrap();
1145 let gen_x = BigNum::from_hex_str(
1146 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1147 )
1148 .unwrap();
1149 let gen_y = BigNum::from_hex_str(
1150 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1151 )
1152 .unwrap();
1153 gen_point
1154 .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx)
1155 .unwrap();
1156
1157 let order = BigNum::from_hex_str(
1158 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
1159 )
1160 .unwrap();
1161 let cofactor = BigNum::from_hex_str("01").unwrap();
1162 group.set_generator(gen_point, order, cofactor).unwrap();
1163 let mut constructed_order = BigNum::new().unwrap();
1164 group.order(&mut constructed_order, &mut ctx).unwrap();
1165
1166 let named_group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1167 let mut named_order = BigNum::new().unwrap();
1168 named_group.order(&mut named_order, &mut ctx).unwrap();
1169
1170 assert_eq!(
1171 constructed_order.ucmp(&named_order),
1172 std::cmp::Ordering::Equal
1173 );
1174 }
1175
1176 #[test]
1177 fn cofactor() {
1178 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1179 let mut ctx = BigNumContext::new().unwrap();
1180 let mut cofactor = BigNum::new().unwrap();
1181 group.cofactor(&mut cofactor, &mut ctx).unwrap();
1182 let one = BigNum::from_u32(1).unwrap();
1183 assert_eq!(cofactor, one);
1184 }
1185
1186 #[test]
1187 #[allow(clippy::redundant_clone)]
1188 fn dup() {
1189 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1190 let key = EcKey::generate(&group).unwrap();
1191 drop(key.clone());
1192 }
1193
1194 #[test]
1195 fn point_new() {
1196 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1197 EcPoint::new(&group).unwrap();
1198 }
1199
1200 #[test]
1201 fn point_bytes() {
1202 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1203 let key = EcKey::generate(&group).unwrap();
1204 let point = key.public_key();
1205 let mut ctx = BigNumContext::new().unwrap();
1206 let bytes = point
1207 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1208 .unwrap();
1209 let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1210 assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1211 }
1212
1213 #[test]
1214 #[cfg(not(any(boringssl, awslc)))]
1215 fn point_hex_str() {
1216 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1217 let key = EcKey::generate(&group).unwrap();
1218 let point = key.public_key();
1219 let mut ctx = BigNumContext::new().unwrap();
1220 let hex = point
1221 .to_hex_str(&group, PointConversionForm::COMPRESSED, &mut ctx)
1222 .unwrap();
1223 let point2 = EcPoint::from_hex_str(&group, &hex, &mut ctx).unwrap();
1224 assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1225 }
1226
1227 #[test]
1228 fn point_owned() {
1229 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1230 let key = EcKey::generate(&group).unwrap();
1231 let point = key.public_key();
1232 let owned = point.to_owned(&group).unwrap();
1233 let mut ctx = BigNumContext::new().unwrap();
1234 assert!(owned.eq(&group, point, &mut ctx).unwrap());
1235 }
1236
1237 #[test]
1238 fn mul_generator() {
1239 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1240 let key = EcKey::generate(&group).unwrap();
1241 let mut ctx = BigNumContext::new().unwrap();
1242 let mut public_key = EcPoint::new(&group).unwrap();
1243 public_key
1244 .mul_generator(&group, key.private_key(), &ctx)
1245 .unwrap();
1246 assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap());
1247 }
1248
1249 #[test]
1250 fn generator() {
1251 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1252 let gen = group.generator();
1253 let one = BigNum::from_u32(1).unwrap();
1254 let mut ctx = BigNumContext::new().unwrap();
1255 let mut ecp = EcPoint::new(&group).unwrap();
1256 ecp.mul_generator(&group, &one, &ctx).unwrap();
1257 assert!(ecp.eq(&group, gen, &mut ctx).unwrap());
1258 }
1259
1260 #[test]
1261 fn key_from_public_key() {
1262 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1263 let key = EcKey::generate(&group).unwrap();
1264 let mut ctx = BigNumContext::new().unwrap();
1265 let bytes = key
1266 .public_key()
1267 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1268 .unwrap();
1269
1270 drop(key);
1271 let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1272 let ec_key = EcKey::from_public_key(&group, &public_key).unwrap();
1273 assert!(ec_key.check_key().is_ok());
1274 }
1275
1276 #[test]
1277 fn key_from_private_components() {
1278 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1279 let key = EcKey::generate(&group).unwrap();
1280
1281 let dup_key =
1282 EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap();
1283 dup_key.check_key().unwrap();
1284
1285 assert!(key.private_key() == dup_key.private_key());
1286 }
1287
1288 #[test]
1289 fn key_from_affine_coordinates() {
1290 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1291 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1292 .unwrap();
1293 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1294 .unwrap();
1295
1296 let xbn = BigNum::from_slice(&x).unwrap();
1297 let ybn = BigNum::from_slice(&y).unwrap();
1298
1299 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1300 assert!(ec_key.check_key().is_ok());
1301 }
1302
1303 #[cfg(any(ossl111, boringssl, libressl, awslc))]
1304 #[test]
1305 fn get_affine_coordinates() {
1306 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1307 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1308 .unwrap();
1309 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1310 .unwrap();
1311
1312 let xbn = BigNum::from_slice(&x).unwrap();
1313 let ybn = BigNum::from_slice(&y).unwrap();
1314
1315 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1316
1317 let mut xbn2 = BigNum::new().unwrap();
1318 let mut ybn2 = BigNum::new().unwrap();
1319 let mut ctx = BigNumContext::new().unwrap();
1320 let ec_key_pk = ec_key.public_key();
1321 ec_key_pk
1322 .affine_coordinates(&group, &mut xbn2, &mut ybn2, &mut ctx)
1323 .unwrap();
1324 assert_eq!(xbn2, xbn);
1325 assert_eq!(ybn2, ybn);
1326 }
1327
1328 #[test]
1329 fn get_affine_coordinates_gfp() {
1330 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1331 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1332 .unwrap();
1333 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1334 .unwrap();
1335
1336 let xbn = BigNum::from_slice(&x).unwrap();
1337 let ybn = BigNum::from_slice(&y).unwrap();
1338
1339 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1340
1341 let mut xbn2 = BigNum::new().unwrap();
1342 let mut ybn2 = BigNum::new().unwrap();
1343 let mut ctx = BigNumContext::new().unwrap();
1344 let ec_key_pk = ec_key.public_key();
1345 ec_key_pk
1346 .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx)
1347 .unwrap();
1348 assert_eq!(xbn2, xbn);
1349 assert_eq!(ybn2, ybn);
1350 }
1351
1352 #[test]
1353 fn is_infinity() {
1354 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1355 let mut ctx = BigNumContext::new().unwrap();
1356 let g = group.generator();
1357 assert!(!g.is_infinity(&group));
1358
1359 let mut order = BigNum::new().unwrap();
1360 group.order(&mut order, &mut ctx).unwrap();
1361 let mut inf = EcPoint::new(&group).unwrap();
1362 inf.mul_generator(&group, &order, &ctx).unwrap();
1363 assert!(inf.is_infinity(&group));
1364 }
1365
1366 #[test]
1367 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
1368 fn is_on_curve() {
1369 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1370 let mut ctx = BigNumContext::new().unwrap();
1371 let g = group.generator();
1372 assert!(g.is_on_curve(&group, &mut ctx).unwrap());
1373
1374 let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap();
1375 assert!(!g.is_on_curve(&group2, &mut ctx).unwrap());
1376 }
1377
1378 #[test]
1379 #[cfg(any(boringssl, ossl111, libressl, awslc))]
1380 fn asn1_flag() {
1381 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1382 let flag = group.asn1_flag();
1383 assert_eq!(flag, Asn1Flag::NAMED_CURVE);
1384 }
1385}