1use crate::{cbb_to_buffer, parse_with_cbs, scoped, sealed, Buffer, FfiSlice};
23use alloc::{fmt::Debug, vec::Vec};
24use core::ptr::{null, null_mut};
25
26pub trait Curve: Debug + Sync + Send + sealed::Sealed {
33 fn group() -> Group;
35
36 #[doc(hidden)]
39 fn hash(data: &[u8]) -> Vec<u8>;
40}
41
42#[derive(Debug)]
44pub struct P256;
45
46impl sealed::Sealed for P256 {}
47
48impl Curve for P256 {
49 fn group() -> Group {
50 Group::P256
51 }
52
53 fn hash(data: &[u8]) -> Vec<u8> {
54 crate::digest::Sha256::hash(data).to_vec()
55 }
56}
57
58#[derive(Debug)]
60pub struct P384;
61
62impl sealed::Sealed for P384 {}
63
64impl Curve for P384 {
65 fn group() -> Group {
66 Group::P384
67 }
68
69 fn hash(data: &[u8]) -> Vec<u8> {
70 crate::digest::Sha384::hash(data).to_vec()
71 }
72}
73
74#[derive(Copy, Clone, Eq, PartialEq, Debug)]
75#[doc(hidden)]
76pub enum Group {
77 P256,
78 P384,
79}
80
81impl Group {
82 fn as_ffi_ptr(self) -> *const bssl_sys::EC_GROUP {
83 match self {
86 Group::P256 => unsafe { bssl_sys::EC_group_p256() },
87 Group::P384 => unsafe { bssl_sys::EC_group_p384() },
88 }
89 }
90
91 fn as_evp_pkey_alg(self) -> *const bssl_sys::EVP_PKEY_ALG {
92 match self {
95 Group::P256 => unsafe { bssl_sys::EVP_pkey_ec_p256() },
96 Group::P384 => unsafe { bssl_sys::EVP_pkey_ec_p384() },
97 }
98 }
99}
100
101pub(crate) struct Point {
103 group: *const bssl_sys::EC_GROUP,
104 point: *mut bssl_sys::EC_POINT,
105}
106
107impl Point {
108 fn new(group: Group) -> Self {
111 let group = group.as_ffi_ptr();
112 let point = unsafe { bssl_sys::EC_POINT_new(group) };
114 assert!(!point.is_null());
117 Self { group, point }
118 }
119
120 unsafe fn from_scalar(group: Group, scalar: *const bssl_sys::BIGNUM) -> Option<Self> {
125 let point = Self::new(group);
126 let result = unsafe {
129 bssl_sys::EC_POINT_mul(
130 point.group,
131 point.point,
132 scalar,
133 null(),
134 null(),
135 null_mut(),
136 )
137 };
138 if result != 1 {
139 return None;
140 }
141 if 1 == unsafe { bssl_sys::EC_POINT_is_at_infinity(point.group, point.point) } {
142 return None;
143 }
144 Some(point)
145 }
146
147 unsafe fn clone_from_ptr(
149 group: *const bssl_sys::EC_GROUP,
150 point: *const bssl_sys::EC_POINT,
151 ) -> Point {
152 assert_eq!(0, unsafe {
153 bssl_sys::EC_POINT_is_at_infinity(group, point)
154 });
155
156 let new_point = unsafe { bssl_sys::EC_POINT_dup(point, group) };
158 assert!(!new_point.is_null());
161
162 Self {
163 group,
164 point: new_point,
165 }
166 }
167
168 pub fn as_ffi_ptr(&self) -> *const bssl_sys::EC_POINT {
169 self.point
170 }
171
172 fn from_x962(group: Group, x962: &[u8]) -> Option<Self> {
173 let point = Self::new(group);
174 let result = unsafe {
177 bssl_sys::EC_POINT_oct2point(
178 point.group,
179 point.point,
180 x962.as_ffi_ptr(),
181 x962.len(),
182 null_mut(),
183 )
184 };
185 if result == 1 {
186 assert_eq!(0, unsafe {
190 bssl_sys::EC_POINT_is_at_infinity(point.group, point.point)
191 });
192 Some(point)
193 } else {
194 None
195 }
196 }
197
198 pub fn from_x962_uncompressed(group: Group, x962: &[u8]) -> Option<Self> {
203 const UNCOMPRESSED: u8 =
204 bssl_sys::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED as u8;
205 if x962.first()? != &UNCOMPRESSED {
206 return None;
207 }
208
209 Self::from_x962(group, x962)
210 }
211
212 pub fn to_x962_uncompressed(&self) -> Buffer {
213 unsafe {
216 to_x962(
217 self.group,
218 self.point,
219 bssl_sys::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED,
220 )
221 }
222 }
223
224 pub fn from_x962_compressed(group: Group, x962: &[u8]) -> Option<Self> {
225 let first_byte = *x962.first()?;
228 if first_byte != 2 && first_byte != 3 {
229 return None;
230 }
231
232 Self::from_x962(group, x962)
233 }
234
235 pub fn to_x962_compressed(&self) -> Buffer {
238 unsafe {
241 to_x962(
242 self.group,
243 self.point,
244 bssl_sys::point_conversion_form_t::POINT_CONVERSION_COMPRESSED,
245 )
246 }
247 }
248
249 pub fn from_der_subject_public_key_info(group: Group, spki: &[u8]) -> Option<Self> {
250 let alg = group.as_evp_pkey_alg();
251 let mut pkey =
252 scoped::EvpPkey::from_der_subject_public_key_info(spki, core::slice::from_ref(&alg))?;
253 let ec_key = unsafe { bssl_sys::EVP_PKEY_get0_EC_KEY(pkey.as_ffi_ptr()) };
254 assert!(!ec_key.is_null());
256 let parsed_group = unsafe { bssl_sys::EC_KEY_get0_group(ec_key) };
257 assert!(parsed_group == group.as_ffi_ptr());
259 let point = unsafe { bssl_sys::EC_KEY_get0_public_key(ec_key) };
260 assert!(!point.is_null());
262 Some(unsafe { Self::clone_from_ptr(parsed_group, point) })
264 }
265
266 pub fn with_point_as_ec_key<F, T>(&self, func: F) -> T
268 where
269 F: FnOnce(*mut bssl_sys::EC_KEY) -> T,
270 {
271 let mut ec_key = scoped::EcKey::new();
272 assert_eq!(1, unsafe {
275 bssl_sys::EC_KEY_set_group(ec_key.as_ffi_ptr(), self.group)
276 });
277 assert_eq!(1, unsafe {
280 bssl_sys::EC_KEY_set_public_key(ec_key.as_ffi_ptr(), self.point)
281 });
282 func(ec_key.as_ffi_ptr())
283 }
284
285 pub fn to_der_subject_public_key_info(&self) -> Buffer {
286 self.with_point_as_ec_key(|ec_key| unsafe { to_der_subject_public_key_info(ec_key) })
288 }
289}
290
291unsafe impl Sync for Point {}
301unsafe impl Send for Point {}
302
303impl Drop for Point {
304 fn drop(&mut self) {
305 unsafe { bssl_sys::EC_POINT_free(self.point) }
308 }
309}
310
311pub(crate) struct Key(*mut bssl_sys::EC_KEY);
315
316impl Key {
317 fn new(group: Group) -> Self {
320 let key = unsafe { bssl_sys::EC_KEY_new() };
321 assert!(!key.is_null());
324
325 assert_eq!(1, unsafe {
327 bssl_sys::EC_KEY_set_group(key, group.as_ffi_ptr())
328 });
329
330 Self(key)
331 }
332
333 pub fn as_ffi_ptr(&self) -> *const bssl_sys::EC_KEY {
334 self.0
335 }
336
337 pub fn generate(group: Group) -> Self {
339 let key = Self::new(group);
340 assert_eq!(1, unsafe { bssl_sys::EC_KEY_generate_key(key.0) });
343 key
345 }
346
347 pub fn from_big_endian(group: Group, scalar: &[u8]) -> Option<Self> {
351 let key = Self::new(group);
352 let result = unsafe { bssl_sys::EC_KEY_oct2priv(key.0, scalar.as_ffi_ptr(), scalar.len()) };
354 if result != 1 {
355 return None;
356 }
357
358 let scalar = unsafe { bssl_sys::EC_KEY_get0_private_key(key.0) };
367 assert!(!scalar.is_null());
368
369 let point = unsafe { Point::from_scalar(group, scalar)? };
371 let result = unsafe { bssl_sys::EC_KEY_set_public_key(key.0, point.point) };
374 assert_eq!(result, 1);
378
379 Some(key)
380 }
381
382 pub fn to_big_endian(&self) -> Buffer {
383 let mut ptr: *mut u8 = null_mut();
384 unsafe {
387 let len = bssl_sys::EC_KEY_priv2buf(self.0, &mut ptr);
388 assert!(len != 0);
389 Buffer::new(ptr, len)
390 }
391 }
392
393 pub fn from_der_ec_private_key(group: Group, der: &[u8]) -> Option<Self> {
397 let key = parse_with_cbs(
398 der,
399 |key| unsafe { bssl_sys::EC_KEY_free(key) },
402 |cbs| unsafe { bssl_sys::EC_KEY_parse_private_key(cbs, group.as_ffi_ptr()) },
405 )?;
406 Some(Self(key))
407 }
408
409 pub fn from_der_ec_private_key_with_curve_names(der: &[u8]) -> Option<Self> {
416 let key = parse_with_cbs(
417 der,
418 |key| unsafe { bssl_sys::EC_KEY_free(key) },
421 |cbs| unsafe { bssl_sys::EC_KEY_parse_private_key(cbs, null()) },
423 )?;
424 let key = Self(key);
425 if key.get_group().is_none() {
426 None
427 } else {
428 Some(key)
429 }
430 }
431
432 pub fn to_der_ec_private_key(&self) -> Buffer {
438 cbb_to_buffer(64, |cbb| unsafe {
439 assert_eq!(1, bssl_sys::EC_KEY_marshal_private_key(cbb, self.0, 0));
442 })
443 }
444
445 pub fn from_der_private_key_info(group: Group, der: &[u8]) -> Option<Self> {
447 let alg = group.as_evp_pkey_alg();
448 let pkey = scoped::EvpPkey::from_der_private_key_info(der, core::slice::from_ref(&alg))?;
449 let ec_key = Self::from_evp_pkey(pkey)?;
451 (ec_key.get_group()? == group).then_some(ec_key)
453 }
454
455 pub(crate) fn from_evp_pkey(mut pkey: scoped::EvpPkey) -> Option<Self> {
457 let ec_key = unsafe { bssl_sys::EVP_PKEY_get1_EC_KEY(pkey.as_ffi_ptr()) };
458 if ec_key.is_null() {
459 return None;
460 }
461 Some(Self(ec_key))
464 }
465
466 pub(crate) fn get_group(&self) -> Option<Group> {
467 let id = unsafe { bssl_sys::EC_KEY_get0_group(self.0) };
469 if id == Group::P256.as_ffi_ptr() {
470 Some(Group::P256)
471 } else if id == Group::P384.as_ffi_ptr() {
472 Some(Group::P384)
473 } else {
474 None
475 }
476 }
477
478 pub fn to_der_private_key_info(&self) -> Buffer {
480 let mut pkey = scoped::EvpPkey::new();
481 assert_eq!(1, unsafe {
485 bssl_sys::EVP_PKEY_set1_EC_KEY(pkey.as_ffi_ptr(), self.0)
486 });
487 cbb_to_buffer(64, |cbb| unsafe {
488 assert_eq!(1, bssl_sys::EVP_marshal_private_key(cbb, pkey.as_ffi_ptr()));
491 })
492 }
493
494 pub fn to_point(&self) -> Point {
495 let group = unsafe { bssl_sys::EC_KEY_get0_group(self.0) };
497 let point = unsafe { bssl_sys::EC_KEY_get0_public_key(self.0) };
498 assert!(!point.is_null());
500 unsafe { Point::clone_from_ptr(group, point) }
503 }
504
505 pub fn to_x962_uncompressed(&self) -> Buffer {
506 let group = unsafe { bssl_sys::EC_KEY_get0_group(self.0) };
508 let point = unsafe { bssl_sys::EC_KEY_get0_public_key(self.0) };
509 unsafe {
512 to_x962(
513 group,
514 point,
515 bssl_sys::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED,
516 )
517 }
518 }
519
520 pub fn to_x962_compressed(&self) -> Buffer {
523 let group = unsafe { bssl_sys::EC_KEY_get0_group(self.0) };
525 let point = unsafe { bssl_sys::EC_KEY_get0_public_key(self.0) };
526 unsafe {
529 to_x962(
530 group,
531 point,
532 bssl_sys::point_conversion_form_t::POINT_CONVERSION_COMPRESSED,
533 )
534 }
535 }
536
537 pub fn to_der_subject_public_key_info(&self) -> Buffer {
538 unsafe { to_der_subject_public_key_info(self.0) }
540 }
541}
542
543unsafe impl Sync for Key {}
554unsafe impl Send for Key {}
555
556impl Drop for Key {
557 fn drop(&mut self) {
558 unsafe { bssl_sys::EC_KEY_free(self.0) }
561 }
562}
563
564impl Clone for Key {
565 fn clone(&self) -> Self {
566 unsafe {
567 bssl_sys::EC_KEY_up_ref(self.0);
568 }
569 Self(self.0)
570 }
571}
572
573unsafe fn to_x962(
578 group: *const bssl_sys::EC_GROUP,
579 point: *const bssl_sys::EC_POINT,
580 form: bssl_sys::point_conversion_form_t,
581) -> Buffer {
582 cbb_to_buffer(
583 if form == bssl_sys::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED {
585 1 + 32 + 32
586 } else {
587 1 + 32
588 },
589 |cbb| unsafe {
590 let result =
592 bssl_sys::EC_POINT_point2cbb(cbb, group, point, form, null_mut());
593 assert_eq!(result, 1);
596 },
597 )
598}
599
600unsafe fn to_der_subject_public_key_info(ec_key: *mut bssl_sys::EC_KEY) -> Buffer {
601 let mut pkey = scoped::EvpPkey::new();
602 assert_eq!(1, unsafe {
604 bssl_sys::EVP_PKEY_set1_EC_KEY(pkey.as_ffi_ptr(), ec_key)
605 });
606 cbb_to_buffer(
607 65,
609 |cbb| unsafe {
610 assert_eq!(1, bssl_sys::EVP_marshal_public_key(cbb, pkey.as_ffi_ptr()));
613 },
614 )
615}
616
617#[cfg(test)]
618mod test {
619 use super::*;
620
621 #[derive(PartialEq)]
622 enum Corruption {
623 ShouldBeDetected,
624 DontTest,
625 }
626
627 fn test_point_format<Serialize, Parse>(
628 group: Group,
629 serialize_func: Serialize,
630 parse_func: Parse,
631 corruption: Corruption,
632 ) where
633 Serialize: FnOnce(&Point) -> Buffer,
634 Parse: Fn(&[u8]) -> Option<Point>,
635 {
636 let key = Key::generate(group);
637 let point = key.to_point();
638
639 let mut vec = serialize_func(&point).as_ref().to_vec();
640 let point2 = parse_func(vec.as_slice()).unwrap();
641 assert_eq!(
642 point.to_x962_uncompressed().as_ref(),
643 point2.to_x962_uncompressed().as_ref()
644 );
645
646 assert!(parse_func(&vec.as_slice()[0..16]).is_none());
647
648 vec[0] ^= 64;
650 assert!(parse_func(vec.as_slice()).is_none());
651 vec[0] ^= 64;
652
653 if corruption == Corruption::ShouldBeDetected {
654 vec[11] ^= 1;
655 assert!(parse_func(vec.as_slice()).is_none());
656 vec[11] ^= 1;
657 }
658
659 assert!(parse_func(b"").is_none());
660 }
661
662 #[test]
663 fn x962() {
664 let x962 = b"\x04\x74\xcf\x69\xcb\xd1\x2b\x75\x07\x42\x85\xcf\x69\x6f\xc2\x56\x4b\x90\xe7\xeb\xbc\xd0\xe7\x20\x36\x86\x66\xbe\xcc\x94\x75\xa2\xa4\x4c\x2a\xf8\xa2\x56\xb8\x92\xb7\x7d\x17\xba\x97\x93\xbb\xf2\x9f\x52\x26\x7d\x90\xf9\x2c\x37\x26\x02\xbb\x4e\xd1\x89\x7c\xad\x54";
665 assert!(Point::from_x962_uncompressed(Group::P256, x962).is_some());
666
667 test_point_format(
668 Group::P256,
669 |point| point.to_x962_uncompressed(),
670 |buf| Point::from_x962_uncompressed(Group::P256, buf),
671 Corruption::ShouldBeDetected,
672 );
673
674 test_point_format(
675 Group::P384,
676 |point| point.to_x962_uncompressed(),
677 |buf| Point::from_x962_uncompressed(Group::P384, buf),
678 Corruption::ShouldBeDetected,
679 );
680
681 test_point_format(
682 Group::P256,
683 |point| point.to_x962_compressed(),
684 |buf| Point::from_x962_compressed(Group::P256, buf),
685 Corruption::DontTest,
689 );
690
691 test_point_format(
692 Group::P384,
693 |point| point.to_x962_compressed(),
694 |buf| Point::from_x962_compressed(Group::P384, buf),
695 Corruption::DontTest,
699 );
700 }
701
702 #[test]
703 fn x962_crossing_formats() {
704 let point = Key::generate(Group::P256).to_point();
705 let uncompressed = point.to_x962_uncompressed();
706 let compressed = point.to_x962_compressed();
707
708 assert!(Point::from_x962_uncompressed(Group::P256, compressed.as_ref()).is_none());
711 assert!(Point::from_x962_compressed(Group::P256, uncompressed.as_ref()).is_none());
712 }
713
714 #[test]
715 fn x962_infinity_not_accepted() {
716 let infinity = &[0];
718 assert!(Point::from_x962_uncompressed(Group::P256, infinity).is_none());
719 assert!(Point::from_x962_compressed(Group::P256, infinity).is_none());
720 }
721
722 #[test]
723 fn x962_empty() {
724 let empty = b"";
727 assert!(Point::from_x962_uncompressed(Group::P256, empty).is_none());
728 assert!(Point::from_x962_compressed(Group::P256, empty).is_none());
729 }
730
731 #[test]
732 fn spki() {
733 test_point_format(
734 Group::P256,
735 |point| point.to_der_subject_public_key_info(),
736 |buf| Point::from_der_subject_public_key_info(Group::P256, buf),
737 Corruption::ShouldBeDetected,
738 );
739
740 test_point_format(
741 Group::P384,
742 |point| point.to_der_subject_public_key_info(),
743 |buf| Point::from_der_subject_public_key_info(Group::P384, buf),
744 Corruption::ShouldBeDetected,
745 );
746 }
747
748 fn test_key_format<Serialize, Parse>(group: Group, serialize_func: Serialize, parse_func: Parse)
749 where
750 Serialize: FnOnce(&Key) -> Buffer,
751 Parse: Fn(&[u8]) -> Option<Key>,
752 {
753 let key = Key::generate(group);
754 assert_eq!(key.get_group().unwrap(), group);
755
756 let vec = serialize_func(&key).as_ref().to_vec();
757 let key2 = parse_func(vec.as_slice()).unwrap();
758 assert_eq!(
759 key.to_x962_uncompressed().as_ref(),
760 key2.to_x962_uncompressed().as_ref()
761 );
762 assert_eq!(key.get_group(), key2.get_group());
763
764 assert!(parse_func(&vec.as_slice()[0..16]).is_none());
765 assert!(parse_func(b"").is_none());
766 }
767
768 #[test]
769 fn der_ec_private_key() {
770 for group in [Group::P256, Group::P384] {
771 test_key_format(
772 group,
773 |key| key.to_der_ec_private_key(),
774 |buf| Key::from_der_ec_private_key(group, buf),
775 );
776 test_key_format(
777 group,
778 |key| key.to_der_ec_private_key(),
779 |buf| Key::from_der_ec_private_key_with_curve_names(buf),
780 );
781 }
782 }
783
784 #[test]
785 fn der_private_key_info() {
786 for group in [Group::P256, Group::P384] {
787 test_key_format(
788 group,
789 |key| key.to_der_private_key_info(),
790 |buf| Key::from_der_private_key_info(group, buf),
791 );
792 }
793 }
794
795 #[test]
796 fn big_endian() {
797 for group in [Group::P256, Group::P384] {
798 test_key_format(
799 group,
800 |key| key.to_big_endian(),
801 |buf| Key::from_big_endian(group, buf),
802 );
803 }
804 }
805}