1 // Copyright 2023 The BoringSSL Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Definitions of NIST elliptic curves.
16 //!
17 //! If you're looking for curve25519, see the `x25519` and `ed25519` modules.
18 
19 // This module is substantially internal-only and is only public for the
20 // [`Curve`] trait, which is shared by ECDH and ECDSA.
21 
22 use crate::{cbb_to_buffer, parse_with_cbs, scoped, sealed, Buffer, FfiSlice};
23 use alloc::{fmt::Debug, vec::Vec};
24 use core::ptr::{null, null_mut};
25 
26 /// An elliptic curve.
27 pub trait Curve: Debug {
28     #[doc(hidden)]
group(_: sealed::Sealed) -> Group29     fn group(_: sealed::Sealed) -> Group;
30 
31     /// Hash `data` using a hash function suitable for the curve. (I.e.
32     /// SHA-256 for P-256 and SHA-384 for P-384.)
33     #[doc(hidden)]
hash(data: &[u8]) -> Vec<u8>34     fn hash(data: &[u8]) -> Vec<u8>;
35 }
36 
37 /// The NIST P-256 curve, also called secp256r1.
38 #[derive(Debug)]
39 pub struct P256;
40 
41 impl Curve for P256 {
group(_: sealed::Sealed) -> Group42     fn group(_: sealed::Sealed) -> Group {
43         Group::P256
44     }
45 
hash(data: &[u8]) -> Vec<u8>46     fn hash(data: &[u8]) -> Vec<u8> {
47         crate::digest::Sha256::hash(data).to_vec()
48     }
49 }
50 
51 /// The NIST P-384 curve, also called secp384r1.
52 #[derive(Debug)]
53 pub struct P384;
54 
55 impl Curve for P384 {
group(_: sealed::Sealed) -> Group56     fn group(_: sealed::Sealed) -> Group {
57         Group::P384
58     }
59 
hash(data: &[u8]) -> Vec<u8>60     fn hash(data: &[u8]) -> Vec<u8> {
61         crate::digest::Sha384::hash(data).to_vec()
62     }
63 }
64 
65 #[derive(Copy, Clone)]
66 #[doc(hidden)]
67 pub enum Group {
68     P256,
69     P384,
70 }
71 
72 impl Group {
as_ffi_ptr(self) -> *const bssl_sys::EC_GROUP73     fn as_ffi_ptr(self) -> *const bssl_sys::EC_GROUP {
74         // Safety: `group` is an address-space constant. These functions
75         // cannot fail and no resources need to be released in the future.
76         match self {
77             Group::P256 => unsafe { bssl_sys::EC_group_p256() },
78             Group::P384 => unsafe { bssl_sys::EC_group_p384() },
79         }
80     }
81 }
82 
83 /// Point is a valid, finite point on some curve.
84 pub(crate) struct Point {
85     group: *const bssl_sys::EC_GROUP,
86     point: *mut bssl_sys::EC_POINT,
87 }
88 
89 impl Point {
90     /// Construct an uninitialized curve point. This is not public and all
91     /// callers must ensure that the point is initialized before being returned.
new(group: Group) -> Self92     fn new(group: Group) -> Self {
93         let group = group.as_ffi_ptr();
94         // Safety: `group` is valid because it was constructed just above.
95         let point = unsafe { bssl_sys::EC_POINT_new(group) };
96         // `EC_POINT_new` only fails if out of memory, which is not a case that
97         // is handled short of panicking.
98         assert!(!point.is_null());
99         Self { group, point }
100     }
101 
102     /// Construct a point by multipling the curve's base point by the given
103     /// scalar.
104     ///
105     /// Safety: `scalar` must be a valid pointer.
from_scalar(group: Group, scalar: *const bssl_sys::BIGNUM) -> Option<Self>106     unsafe fn from_scalar(group: Group, scalar: *const bssl_sys::BIGNUM) -> Option<Self> {
107         let point = Self::new(group);
108         // Safety: the members of `point` are valid by construction. `scalar`
109         // is assumed to be valid.
110         let result = unsafe {
111             bssl_sys::EC_POINT_mul(
112                 point.group,
113                 point.point,
114                 scalar,
115                 /*q=*/ null(),
116                 /*m=*/ null(),
117                 /*ctx=*/ null_mut(),
118             )
119         };
120         if result != 1 {
121             return None;
122         }
123         if 1 == unsafe { bssl_sys::EC_POINT_is_at_infinity(point.group, point.point) } {
124             return None;
125         }
126         Some(point)
127     }
128 
129     /// Duplicate the given finite point.
clone_from_ptr( group: *const bssl_sys::EC_GROUP, point: *const bssl_sys::EC_POINT, ) -> Point130     unsafe fn clone_from_ptr(
131         group: *const bssl_sys::EC_GROUP,
132         point: *const bssl_sys::EC_POINT,
133     ) -> Point {
134         assert_eq!(0, unsafe {
135             bssl_sys::EC_POINT_is_at_infinity(group, point)
136         });
137 
138         // Safety: we assume that the caller is passing valid pointers
139         let new_point = unsafe { bssl_sys::EC_POINT_dup(point, group) };
140         // `EC_POINT_dup` only fails if out of memory, which is not a case that
141         // is handled short of panicking.
142         assert!(!new_point.is_null());
143 
144         Self {
145             group,
146             point: new_point,
147         }
148     }
149 
as_ffi_ptr(&self) -> *const bssl_sys::EC_POINT150     pub fn as_ffi_ptr(&self) -> *const bssl_sys::EC_POINT {
151         self.point
152     }
153 
154     /// Create a new point from an uncompressed X9.62 representation.
155     ///
156     /// (X9.62 is the standard representation of an elliptic-curve point that
157     /// starts with an 0x04 byte.)
from_x962_uncompressed(group: Group, x962: &[u8]) -> Option<Self>158     pub fn from_x962_uncompressed(group: Group, x962: &[u8]) -> Option<Self> {
159         const UNCOMPRESSED: u8 =
160             bssl_sys::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED as u8;
161         if x962.first()? != &UNCOMPRESSED {
162             return None;
163         }
164 
165         let point = Self::new(group);
166         // Safety: `point` is valid by construction. `x962` is a valid memory
167         // buffer.
168         let result = unsafe {
169             bssl_sys::EC_POINT_oct2point(
170                 point.group,
171                 point.point,
172                 x962.as_ffi_ptr(),
173                 x962.len(),
174                 /*bn_ctx=*/ null_mut(),
175             )
176         };
177         if result == 1 {
178             // X9.62 format cannot represent the point at infinity, so this
179             // should be moot, but `Point` must never contain infinity.
180             assert_eq!(0, unsafe {
181                 bssl_sys::EC_POINT_is_at_infinity(point.group, point.point)
182             });
183             Some(point)
184         } else {
185             None
186         }
187     }
188 
to_x962_uncompressed(&self) -> Buffer189     pub fn to_x962_uncompressed(&self) -> Buffer {
190         // Safety: arguments are valid, `EC_KEY` ensures that the the group is
191         // correct for the point, and a `Point` is always finite.
192         unsafe { to_x962_uncompressed(self.group, self.point) }
193     }
194 
from_der_subject_public_key_info(group: Group, spki: &[u8]) -> Option<Self>195     pub fn from_der_subject_public_key_info(group: Group, spki: &[u8]) -> Option<Self> {
196         let mut pkey = scoped::EvpPkey::from_ptr(parse_with_cbs(
197             spki,
198             // Safety: if called, `pkey` is the non-null result of `EVP_parse_public_key`.
199             |pkey| unsafe { bssl_sys::EVP_PKEY_free(pkey) },
200             // Safety: `cbs` is a valid pointer in this context.
201             |cbs| unsafe { bssl_sys::EVP_parse_public_key(cbs) },
202         )?);
203         let ec_key = unsafe { bssl_sys::EVP_PKEY_get0_EC_KEY(pkey.as_ffi_ptr()) };
204         if ec_key.is_null() {
205             // Not an ECC key.
206             return None;
207         }
208         let parsed_group = unsafe { bssl_sys::EC_KEY_get0_group(ec_key) };
209         if parsed_group != group.as_ffi_ptr() {
210             // ECC key for a different curve.
211             return None;
212         }
213         let point = unsafe { bssl_sys::EC_KEY_get0_public_key(ec_key) };
214         if point.is_null() {
215             return None;
216         }
217         // Safety: `ec_key` is still owned by `pkey` and doesn't need to be freed.
218         Some(unsafe { Self::clone_from_ptr(parsed_group, point) })
219     }
220 
221     /// Calls `func` with an `EC_KEY` that contains a copy of this point.
with_point_as_ec_key<F, T>(&self, func: F) -> T where F: FnOnce(*mut bssl_sys::EC_KEY) -> T,222     pub fn with_point_as_ec_key<F, T>(&self, func: F) -> T
223     where
224         F: FnOnce(*mut bssl_sys::EC_KEY) -> T,
225     {
226         let mut ec_key = scoped::EcKey::new();
227         // Safety: `self.group` is always valid by construction and this doesn't
228         // pass ownership.
229         assert_eq!(1, unsafe {
230             bssl_sys::EC_KEY_set_group(ec_key.as_ffi_ptr(), self.group)
231         });
232         // Safety: `self.point` is always valid by construction and this doesn't
233         // pass ownership.
234         assert_eq!(1, unsafe {
235             bssl_sys::EC_KEY_set_public_key(ec_key.as_ffi_ptr(), self.point)
236         });
237         func(ec_key.as_ffi_ptr())
238     }
239 
to_der_subject_public_key_info(&self) -> Buffer240     pub fn to_der_subject_public_key_info(&self) -> Buffer {
241         // Safety: `ec_key` is a valid pointer in this context.
242         self.with_point_as_ec_key(|ec_key| unsafe { to_der_subject_public_key_info(ec_key) })
243     }
244 }
245 
246 // Safety:
247 //
248 // An `EC_POINT` can be used concurrently from multiple threads so long as no
249 // mutating operations are performed. The mutating operations used here are
250 // `EC_POINT_mul` and `EC_POINT_oct2point` (which can be observed by setting
251 // `point` to be `*const` in the struct and seeing what errors trigger.
252 //
253 // Both those operations are done internally, however, before a `Point` is
254 // returned. So, after construction, callers cannot mutate the `EC_POINT`.
255 unsafe impl Sync for Point {}
256 unsafe impl Send for Point {}
257 
258 impl Drop for Point {
drop(&mut self)259     fn drop(&mut self) {
260         // Safety: `self.point` must be valid because only valid `Point`s can
261         // be constructed. `self.group` does not need to be freed.
262         unsafe { bssl_sys::EC_POINT_free(self.point) }
263     }
264 }
265 
266 /// Key holds both a public and private key. While BoringSSL allows an `EC_KEY`
267 /// to also be a) empty, b) holding only a private scalar, or c) holding only
268 // a public key, those cases are never exposed as a `Key`.
269 pub(crate) struct Key(*mut bssl_sys::EC_KEY);
270 
271 impl Key {
272     /// Construct an uninitialized key. This is not public and all
273     /// callers must ensure that the key is initialized before being returned.
new(group: Group) -> Self274     fn new(group: Group) -> Self {
275         let key = unsafe { bssl_sys::EC_KEY_new() };
276         // `EC_KEY_new` only fails if out of memory, which is not a case that
277         // is handled short of panicking.
278         assert!(!key.is_null());
279 
280         // Setting the group on a fresh `EC_KEY` never fails.
281         assert_eq!(1, unsafe {
282             bssl_sys::EC_KEY_set_group(key, group.as_ffi_ptr())
283         });
284 
285         Self(key)
286     }
287 
as_ffi_ptr(&self) -> *const bssl_sys::EC_KEY288     pub fn as_ffi_ptr(&self) -> *const bssl_sys::EC_KEY {
289         self.0
290     }
291 
292     /// Generate a random private key.
generate(group: Group) -> Self293     pub fn generate(group: Group) -> Self {
294         let key = Self::new(group);
295         // Generation only fails if out of memory, which is only handled by
296         // panicking.
297         assert_eq!(1, unsafe { bssl_sys::EC_KEY_generate_key(key.0) });
298         // `EC_KEY_generate_key` is documented as also setting the public key.
299         key
300     }
301 
302     /// Construct a private key from a big-endian representation of the private
303     /// scalar. The scalar must be zero padded to the correct length for the
304     /// curve.
from_big_endian(group: Group, scalar: &[u8]) -> Option<Self>305     pub fn from_big_endian(group: Group, scalar: &[u8]) -> Option<Self> {
306         let key = Self::new(group);
307         // Safety: `key.0` is always valid by construction.
308         let result = unsafe { bssl_sys::EC_KEY_oct2priv(key.0, scalar.as_ffi_ptr(), scalar.len()) };
309         if result != 1 {
310             return None;
311         }
312 
313         // BoringSSL allows an `EC_KEY` to have a private scalar without a
314         // public point, but `Key` is never exposed in that state.
315 
316         // Safety: `key.0` is valid by construction. The returned value is
317         // still owned the `EC_KEY`.
318         let scalar = unsafe { bssl_sys::EC_KEY_get0_private_key(key.0) };
319         assert!(!scalar.is_null());
320 
321         // Safety: `scalar` is a valid pointer.
322         let point = unsafe { Point::from_scalar(group, scalar)? };
323         // Safety: `key.0` is valid by construction, as is `point.point`. The
324         // point is copied into the `EC_KEY` so ownership isn't being moved.
325         let result = unsafe { bssl_sys::EC_KEY_set_public_key(key.0, point.point) };
326         // Setting the public key should only fail if out of memory, which this
327         // crate doesn't handle, or if the groups don't match, which is
328         // impossible.
329         assert_eq!(result, 1);
330 
331         Some(key)
332     }
333 
to_big_endian(&self) -> Buffer334     pub fn to_big_endian(&self) -> Buffer {
335         let mut ptr: *mut u8 = null_mut();
336         // Safety: `self.0` is valid by construction. If this returns non-zero
337         // then ptr holds ownership of a buffer.
338         unsafe {
339             let len = bssl_sys::EC_KEY_priv2buf(self.0, &mut ptr);
340             assert!(len != 0);
341             Buffer::new(ptr, len)
342         }
343     }
344 
345     /// Parses an ECPrivateKey structure (from RFC 5915).
from_der_ec_private_key(group: Group, der: &[u8]) -> Option<Self>346     pub fn from_der_ec_private_key(group: Group, der: &[u8]) -> Option<Self> {
347         let key = parse_with_cbs(
348             der,
349             // Safety: in this context, `key` is the non-null result of
350             // `EC_KEY_parse_private_key`.
351             |key| unsafe { bssl_sys::EC_KEY_free(key) },
352             // Safety: `cbs` is valid per `parse_with_cbs` and `group` always
353             // returns a valid pointer.
354             |cbs| unsafe { bssl_sys::EC_KEY_parse_private_key(cbs, group.as_ffi_ptr()) },
355         )?;
356         Some(Self(key))
357     }
358 
359     /// Serializes this private key as an ECPrivateKey structure from RFC 5915.
to_der_ec_private_key(&self) -> Buffer360     pub fn to_der_ec_private_key(&self) -> Buffer {
361         cbb_to_buffer(64, |cbb| unsafe {
362             // Safety: the `EC_KEY` is always valid so `EC_KEY_marshal_private_key`
363             // should only fail if out of memory, which this crate doesn't handle.
364             assert_eq!(
365                 1,
366                 bssl_sys::EC_KEY_marshal_private_key(
367                     cbb,
368                     self.0,
369                     bssl_sys::EC_PKEY_NO_PARAMETERS as u32
370                 )
371             );
372         })
373     }
374 
375     /// Parses a PrivateKeyInfo structure (from RFC 5208).
from_der_private_key_info(group: Group, der: &[u8]) -> Option<Self>376     pub fn from_der_private_key_info(group: Group, der: &[u8]) -> Option<Self> {
377         let mut pkey = scoped::EvpPkey::from_ptr(parse_with_cbs(
378             der,
379             // Safety: in this context, `pkey` is the non-null result of
380             // `EVP_parse_private_key`.
381             |pkey| unsafe { bssl_sys::EVP_PKEY_free(pkey) },
382             // Safety: `cbs` is valid per `parse_with_cbs`.
383             |cbs| unsafe { bssl_sys::EVP_parse_private_key(cbs) },
384         )?);
385         let ec_key = unsafe { bssl_sys::EVP_PKEY_get1_EC_KEY(pkey.as_ffi_ptr()) };
386         if ec_key.is_null() {
387             return None;
388         }
389         // Safety: `ec_key` is now owned by this function.
390         let parsed_group = unsafe { bssl_sys::EC_KEY_get0_group(ec_key) };
391         if parsed_group == group.as_ffi_ptr() {
392             // Safety: parsing an EC_KEY always set the public key. It should
393             // be impossible for the public key to be infinity, but double-check.
394             let is_infinite = unsafe {
395                 bssl_sys::EC_POINT_is_at_infinity(
396                     bssl_sys::EC_KEY_get0_group(ec_key),
397                     bssl_sys::EC_KEY_get0_public_key(ec_key),
398                 )
399             };
400             if is_infinite == 0 {
401                 // Safety: `EVP_PKEY_get1_EC_KEY` returned ownership, which we can move
402                 // into the returned object.
403                 return Some(Self(ec_key));
404             }
405         }
406         unsafe { bssl_sys::EC_KEY_free(ec_key) };
407         None
408     }
409 
410     /// Serializes this private key as a PrivateKeyInfo structure from RFC 5208.
to_der_private_key_info(&self) -> Buffer411     pub fn to_der_private_key_info(&self) -> Buffer {
412         let mut pkey = scoped::EvpPkey::new();
413         // Safety: `pkey` was just allocated above; the `EC_KEY` is valid by
414         // construction. This call takes a reference to the `EC_KEY` and so
415         // hasn't stolen ownership from `self`.
416         assert_eq!(1, unsafe {
417             bssl_sys::EVP_PKEY_set1_EC_KEY(pkey.as_ffi_ptr(), self.0)
418         });
419         cbb_to_buffer(64, |cbb| unsafe {
420             // `EVP_marshal_private_key` should always return one because this
421             // key is valid by construction.
422             assert_eq!(1, bssl_sys::EVP_marshal_private_key(cbb, pkey.as_ffi_ptr()));
423         })
424     }
425 
to_point(&self) -> Point426     pub fn to_point(&self) -> Point {
427         // Safety: `self.0` is valid by construction.
428         let group = unsafe { bssl_sys::EC_KEY_get0_group(self.0) };
429         let point = unsafe { bssl_sys::EC_KEY_get0_public_key(self.0) };
430         // A `Key` is never constructed without a public key.
431         assert!(!point.is_null());
432         // Safety: pointers are valid and `clone_from_ptr` doesn't take
433         // ownership.
434         unsafe { Point::clone_from_ptr(group, point) }
435     }
436 
to_x962_uncompressed(&self) -> Buffer437     pub fn to_x962_uncompressed(&self) -> Buffer {
438         // Safety: `self.0` is valid by construction.
439         let group = unsafe { bssl_sys::EC_KEY_get0_group(self.0) };
440         let point = unsafe { bssl_sys::EC_KEY_get0_public_key(self.0) };
441         // Safety: arguments are valid, `EC_KEY` ensures that the the group is
442         // correct for the point, and a `Key` always holds a finite public point.
443         unsafe { to_x962_uncompressed(group, point) }
444     }
445 
to_der_subject_public_key_info(&self) -> Buffer446     pub fn to_der_subject_public_key_info(&self) -> Buffer {
447         // Safety: `self.0` is always valid by construction.
448         unsafe { to_der_subject_public_key_info(self.0) }
449     }
450 }
451 
452 // Safety:
453 //
454 // An `EC_KEY` is safe to use from multiple threads so long as no mutating
455 // operations are performed. (Reference count changes don't count as mutating.)
456 // The mutating operations used here are:
457 //   * EC_KEY_generate_key
458 //   * EC_KEY_oct2priv
459 //   * EC_KEY_set_public_key
460 // But those are all done internally, before a `Key` is returned. So, once
461 // constructed, callers cannot mutate the `EC_KEY`.
462 unsafe impl Sync for Key {}
463 unsafe impl Send for Key {}
464 
465 impl Drop for Key {
drop(&mut self)466     fn drop(&mut self) {
467         // Safety: `self.0` must be valid because only valid `Key`s can
468         // be constructed.
469         unsafe { bssl_sys::EC_KEY_free(self.0) }
470     }
471 }
472 
473 /// Serialize a finite point to uncompressed X9.62 format.
474 ///
475 /// Callers must ensure that the arguments are valid, that the point has the
476 /// specified group, and that the point is finite.
to_x962_uncompressed( group: *const bssl_sys::EC_GROUP, point: *const bssl_sys::EC_POINT, ) -> Buffer477 unsafe fn to_x962_uncompressed(
478     group: *const bssl_sys::EC_GROUP,
479     point: *const bssl_sys::EC_POINT,
480 ) -> Buffer {
481     cbb_to_buffer(65, |cbb| unsafe {
482         // Safety: the caller must ensure that the arguments are valid.
483         let result = bssl_sys::EC_POINT_point2cbb(
484             cbb,
485             group,
486             point,
487             bssl_sys::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED,
488             /*bn_ctx=*/ null_mut(),
489         );
490         // The public key is always finite, so `EC_POINT_point2cbb` only fails
491         // if out of memory, which isn't handled by this crate.
492         assert_eq!(result, 1);
493     })
494 }
495 
to_der_subject_public_key_info(ec_key: *mut bssl_sys::EC_KEY) -> Buffer496 unsafe fn to_der_subject_public_key_info(ec_key: *mut bssl_sys::EC_KEY) -> Buffer {
497     let mut pkey = scoped::EvpPkey::new();
498     // Safety: this takes a reference to `ec_key` and so doesn't steal ownership.
499     assert_eq!(1, unsafe {
500         bssl_sys::EVP_PKEY_set1_EC_KEY(pkey.as_ffi_ptr(), ec_key)
501     });
502     cbb_to_buffer(65, |cbb| unsafe {
503         // The arguments are valid so this will only fail if out of memory,
504         // which this crate doesn't handle.
505         assert_eq!(1, bssl_sys::EVP_marshal_public_key(cbb, pkey.as_ffi_ptr()));
506     })
507 }
508 
509 #[cfg(test)]
510 mod test {
511     use super::*;
512 
test_point_format<Serialize, Parse>(serialize_func: Serialize, parse_func: Parse) where Serialize: FnOnce(&Point) -> Buffer, Parse: Fn(&[u8]) -> Option<Point>,513     fn test_point_format<Serialize, Parse>(serialize_func: Serialize, parse_func: Parse)
514     where
515         Serialize: FnOnce(&Point) -> Buffer,
516         Parse: Fn(&[u8]) -> Option<Point>,
517     {
518         let key = Key::generate(Group::P256);
519         let point = key.to_point();
520 
521         let mut vec = serialize_func(&point).as_ref().to_vec();
522         let point2 = parse_func(vec.as_slice()).unwrap();
523         assert_eq!(
524             point.to_x962_uncompressed().as_ref(),
525             point2.to_x962_uncompressed().as_ref()
526         );
527 
528         assert!(parse_func(&vec.as_slice()[0..16]).is_none());
529 
530         vec[10] ^= 1;
531         assert!(parse_func(vec.as_slice()).is_none());
532         vec[10] ^= 1;
533 
534         assert!(parse_func(b"").is_none());
535     }
536 
537     #[test]
x962()538     fn x962() {
539         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";
540         assert!(Point::from_x962_uncompressed(Group::P256, x962).is_some());
541 
542         test_point_format(
543             |point| point.to_x962_uncompressed(),
544             |buf| Point::from_x962_uncompressed(Group::P256, buf),
545         );
546     }
547 
548     #[test]
spki()549     fn spki() {
550         test_point_format(
551             |point| point.to_der_subject_public_key_info(),
552             |buf| Point::from_der_subject_public_key_info(Group::P256, buf),
553         );
554     }
555 
test_key_format<Serialize, Parse>(serialize_func: Serialize, parse_func: Parse) where Serialize: FnOnce(&Key) -> Buffer, Parse: Fn(&[u8]) -> Option<Key>,556     fn test_key_format<Serialize, Parse>(serialize_func: Serialize, parse_func: Parse)
557     where
558         Serialize: FnOnce(&Key) -> Buffer,
559         Parse: Fn(&[u8]) -> Option<Key>,
560     {
561         let key = Key::generate(Group::P256);
562 
563         let vec = serialize_func(&key).as_ref().to_vec();
564         let key2 = parse_func(vec.as_slice()).unwrap();
565         assert_eq!(
566             key.to_x962_uncompressed().as_ref(),
567             key2.to_x962_uncompressed().as_ref()
568         );
569 
570         assert!(parse_func(&vec.as_slice()[0..16]).is_none());
571         assert!(parse_func(b"").is_none());
572     }
573 
574     #[test]
der_ec_private_key()575     fn der_ec_private_key() {
576         test_key_format(
577             |key| key.to_der_ec_private_key(),
578             |buf| Key::from_der_ec_private_key(Group::P256, buf),
579         );
580     }
581 
582     #[test]
der_private_key_info()583     fn der_private_key_info() {
584         test_key_format(
585             |key| key.to_der_private_key_info(),
586             |buf| Key::from_der_private_key_info(Group::P256, buf),
587         );
588     }
589 
590     #[test]
big_endian()591     fn big_endian() {
592         test_key_format(
593             |key| key.to_big_endian(),
594             |buf| Key::from_big_endian(Group::P256, buf),
595         );
596     }
597 }
598