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