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 use crate::symm::Cipher;
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 test_password_callback_oversize_return_is_rejected() {
1116 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1121 let key = EcKey::generate(&group).unwrap();
1122 let encrypted = key
1123 .private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"correct-pw")
1124 .unwrap();
1125
1126 let result = EcKey::private_key_from_pem_callback(&encrypted, |buf| {
1127 buf[..10].copy_from_slice(b"correct-pw");
1128 Ok(buf.len() * 10)
1129 });
1130 assert!(result.is_err());
1131 }
1132
1133 #[test]
1134 fn ec_group_from_components() {
1135 let p = BigNum::from_hex_str(
1137 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1138 )
1139 .unwrap();
1140 let a = BigNum::from_hex_str(
1141 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1142 )
1143 .unwrap();
1144 let b = BigNum::from_hex_str(
1145 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1146 )
1147 .unwrap();
1148 let mut ctx = BigNumContext::new().unwrap();
1149
1150 let _curve = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1151 }
1152
1153 fn set_affine_coords_test(
1154 set_affine_coords: fn(
1155 &mut EcPointRef,
1156 &EcGroupRef,
1157 &BigNumRef,
1158 &BigNumRef,
1159 &mut BigNumContextRef,
1160 ) -> Result<(), ErrorStack>,
1161 ) {
1162 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1164 let mut ctx = BigNumContext::new().unwrap();
1165 let mut gen_point = EcPoint::new(&group).unwrap();
1166 let gen_x = BigNum::from_hex_str(
1167 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1168 )
1169 .unwrap();
1170 let gen_y = BigNum::from_hex_str(
1171 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1172 )
1173 .unwrap();
1174 set_affine_coords(&mut gen_point, &group, &gen_x, &gen_y, &mut ctx).unwrap();
1175
1176 assert!(gen_point.is_on_curve(&group, &mut ctx).unwrap());
1177 }
1178
1179 #[test]
1180 fn ec_point_set_affine_gfp() {
1181 set_affine_coords_test(EcPointRef::set_affine_coordinates_gfp)
1182 }
1183
1184 #[test]
1185 #[cfg(any(ossl111, boringssl, libressl, awslc))]
1186 fn ec_point_set_affine() {
1187 set_affine_coords_test(EcPointRef::set_affine_coordinates)
1188 }
1189
1190 #[test]
1191 fn ec_group_set_generator() {
1192 let mut ctx = BigNumContext::new().unwrap();
1194 let p = BigNum::from_hex_str(
1195 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
1196 )
1197 .unwrap();
1198 let a = BigNum::from_hex_str(
1199 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
1200 )
1201 .unwrap();
1202 let b = BigNum::from_hex_str(
1203 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
1204 )
1205 .unwrap();
1206
1207 let mut group = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1208
1209 let mut gen_point = EcPoint::new(&group).unwrap();
1210 let gen_x = BigNum::from_hex_str(
1211 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
1212 )
1213 .unwrap();
1214 let gen_y = BigNum::from_hex_str(
1215 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
1216 )
1217 .unwrap();
1218 gen_point
1219 .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx)
1220 .unwrap();
1221
1222 let order = BigNum::from_hex_str(
1223 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
1224 )
1225 .unwrap();
1226 let cofactor = BigNum::from_hex_str("01").unwrap();
1227 group.set_generator(gen_point, order, cofactor).unwrap();
1228 let mut constructed_order = BigNum::new().unwrap();
1229 group.order(&mut constructed_order, &mut ctx).unwrap();
1230
1231 let named_group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1232 let mut named_order = BigNum::new().unwrap();
1233 named_group.order(&mut named_order, &mut ctx).unwrap();
1234
1235 assert_eq!(
1236 constructed_order.ucmp(&named_order),
1237 std::cmp::Ordering::Equal
1238 );
1239 }
1240
1241 #[test]
1242 fn cofactor() {
1243 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1244 let mut ctx = BigNumContext::new().unwrap();
1245 let mut cofactor = BigNum::new().unwrap();
1246 group.cofactor(&mut cofactor, &mut ctx).unwrap();
1247 let one = BigNum::from_u32(1).unwrap();
1248 assert_eq!(cofactor, one);
1249 }
1250
1251 #[test]
1252 #[allow(clippy::redundant_clone)]
1253 fn dup() {
1254 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1255 let key = EcKey::generate(&group).unwrap();
1256 drop(key.clone());
1257 }
1258
1259 #[test]
1260 fn point_new() {
1261 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1262 EcPoint::new(&group).unwrap();
1263 }
1264
1265 #[test]
1266 fn point_bytes() {
1267 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1268 let key = EcKey::generate(&group).unwrap();
1269 let point = key.public_key();
1270 let mut ctx = BigNumContext::new().unwrap();
1271 let bytes = point
1272 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1273 .unwrap();
1274 let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1275 assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1276 }
1277
1278 #[test]
1279 #[cfg(not(any(boringssl, awslc)))]
1280 fn point_hex_str() {
1281 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1282 let key = EcKey::generate(&group).unwrap();
1283 let point = key.public_key();
1284 let mut ctx = BigNumContext::new().unwrap();
1285 let hex = point
1286 .to_hex_str(&group, PointConversionForm::COMPRESSED, &mut ctx)
1287 .unwrap();
1288 let point2 = EcPoint::from_hex_str(&group, &hex, &mut ctx).unwrap();
1289 assert!(point.eq(&group, &point2, &mut ctx).unwrap());
1290 }
1291
1292 #[test]
1293 fn point_owned() {
1294 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1295 let key = EcKey::generate(&group).unwrap();
1296 let point = key.public_key();
1297 let owned = point.to_owned(&group).unwrap();
1298 let mut ctx = BigNumContext::new().unwrap();
1299 assert!(owned.eq(&group, point, &mut ctx).unwrap());
1300 }
1301
1302 #[test]
1303 fn mul_generator() {
1304 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1305 let key = EcKey::generate(&group).unwrap();
1306 let mut ctx = BigNumContext::new().unwrap();
1307 let mut public_key = EcPoint::new(&group).unwrap();
1308 public_key
1309 .mul_generator(&group, key.private_key(), &ctx)
1310 .unwrap();
1311 assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap());
1312 }
1313
1314 #[test]
1315 fn generator() {
1316 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1317 let gen = group.generator();
1318 let one = BigNum::from_u32(1).unwrap();
1319 let mut ctx = BigNumContext::new().unwrap();
1320 let mut ecp = EcPoint::new(&group).unwrap();
1321 ecp.mul_generator(&group, &one, &ctx).unwrap();
1322 assert!(ecp.eq(&group, gen, &mut ctx).unwrap());
1323 }
1324
1325 #[test]
1326 fn key_from_public_key() {
1327 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1328 let key = EcKey::generate(&group).unwrap();
1329 let mut ctx = BigNumContext::new().unwrap();
1330 let bytes = key
1331 .public_key()
1332 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx)
1333 .unwrap();
1334
1335 drop(key);
1336 let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
1337 let ec_key = EcKey::from_public_key(&group, &public_key).unwrap();
1338 assert!(ec_key.check_key().is_ok());
1339 }
1340
1341 #[test]
1342 fn key_from_private_components() {
1343 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1344 let key = EcKey::generate(&group).unwrap();
1345
1346 let dup_key =
1347 EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap();
1348 dup_key.check_key().unwrap();
1349
1350 assert!(key.private_key() == dup_key.private_key());
1351 }
1352
1353 #[test]
1354 fn key_from_affine_coordinates() {
1355 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1356 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1357 .unwrap();
1358 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1359 .unwrap();
1360
1361 let xbn = BigNum::from_slice(&x).unwrap();
1362 let ybn = BigNum::from_slice(&y).unwrap();
1363
1364 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1365 assert!(ec_key.check_key().is_ok());
1366 }
1367
1368 #[cfg(any(ossl111, boringssl, libressl, awslc))]
1369 #[test]
1370 fn get_affine_coordinates() {
1371 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1372 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1373 .unwrap();
1374 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1375 .unwrap();
1376
1377 let xbn = BigNum::from_slice(&x).unwrap();
1378 let ybn = BigNum::from_slice(&y).unwrap();
1379
1380 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1381
1382 let mut xbn2 = BigNum::new().unwrap();
1383 let mut ybn2 = BigNum::new().unwrap();
1384 let mut ctx = BigNumContext::new().unwrap();
1385 let ec_key_pk = ec_key.public_key();
1386 ec_key_pk
1387 .affine_coordinates(&group, &mut xbn2, &mut ybn2, &mut ctx)
1388 .unwrap();
1389 assert_eq!(xbn2, xbn);
1390 assert_eq!(ybn2, ybn);
1391 }
1392
1393 #[test]
1394 fn get_affine_coordinates_gfp() {
1395 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1396 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1397 .unwrap();
1398 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1399 .unwrap();
1400
1401 let xbn = BigNum::from_slice(&x).unwrap();
1402 let ybn = BigNum::from_slice(&y).unwrap();
1403
1404 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap();
1405
1406 let mut xbn2 = BigNum::new().unwrap();
1407 let mut ybn2 = BigNum::new().unwrap();
1408 let mut ctx = BigNumContext::new().unwrap();
1409 let ec_key_pk = ec_key.public_key();
1410 ec_key_pk
1411 .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx)
1412 .unwrap();
1413 assert_eq!(xbn2, xbn);
1414 assert_eq!(ybn2, ybn);
1415 }
1416
1417 #[test]
1418 fn is_infinity() {
1419 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1420 let mut ctx = BigNumContext::new().unwrap();
1421 let g = group.generator();
1422 assert!(!g.is_infinity(&group));
1423
1424 let mut order = BigNum::new().unwrap();
1425 group.order(&mut order, &mut ctx).unwrap();
1426 let mut inf = EcPoint::new(&group).unwrap();
1427 inf.mul_generator(&group, &order, &ctx).unwrap();
1428 assert!(inf.is_infinity(&group));
1429 }
1430
1431 #[test]
1432 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
1433 fn is_on_curve() {
1434 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1435 let mut ctx = BigNumContext::new().unwrap();
1436 let g = group.generator();
1437 assert!(g.is_on_curve(&group, &mut ctx).unwrap());
1438
1439 let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap();
1440 assert!(!g.is_on_curve(&group2, &mut ctx).unwrap());
1441 }
1442
1443 #[test]
1444 #[cfg(any(ossl111, boringssl, libressl, awslc))]
1445 fn asn1_flag() {
1446 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
1447 let flag = group.asn1_flag();
1448 assert_eq!(flag, Asn1Flag::NAMED_CURVE);
1449 }
1450
1451 #[test]
1452 fn test_debug_standard_group() {
1453 let group = EcGroup::from_curve_name(Nid::SECP521R1).unwrap();
1454
1455 assert_eq!(
1456 format!("{:?}", group),
1457 "EcGroup { curve_name: \"secp521r1\" }"
1458 );
1459 }
1460
1461 #[test]
1462 fn test_debug_custom_group() {
1463 let mut p = BigNum::new().unwrap();
1464 let mut a = BigNum::new().unwrap();
1465 let mut b = BigNum::new().unwrap();
1466 let mut ctx = BigNumContext::new().unwrap();
1467
1468 EcGroup::from_curve_name(Nid::SECP521R1)
1469 .unwrap()
1470 .components_gfp(&mut p, &mut a, &mut b, &mut ctx)
1471 .unwrap();
1472
1473 let group = EcGroup::from_components(p, a, b, &mut ctx).unwrap();
1475
1476 assert_eq!(
1477 format!("{:?}", group),
1478 "EcGroup { p: \"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", a: \"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC\", b: \"51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00\" }"
1479 );
1480 }
1481}