Skip to main content

bssl_crypto/
ec.rs

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
22use crate::{cbb_to_buffer, parse_with_cbs, scoped, sealed, Buffer, FfiSlice};
23use alloc::{fmt::Debug, vec::Vec};
24use core::ptr::{null, null_mut};
25
26/// An elliptic curve.
27///
28/// ## Safety
29/// The current EC implementation are thread-safe.
30/// Implementers should make sure that further additions to the curve family
31/// should respect thread-safety, too.
32pub trait Curve: Debug + Sync + Send + sealed::Sealed {
33    /// Return the underlying [`Group`] of the curve
34    fn group() -> Group;
35
36    /// Hash `data` using a hash function suitable for the curve. (I.e.
37    /// SHA-256 for P-256 and SHA-384 for P-384.)
38    #[doc(hidden)]
39    fn hash(data: &[u8]) -> Vec<u8>;
40}
41
42/// The NIST P-256 curve, also called secp256r1.
43#[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/// The NIST P-384 curve, also called secp384r1.
59#[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        // Safety: These functions cannot fail and no resources need to be
84        // released in the future.
85        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        // Safety: These functions cannot fail and no resources need to be
93        // released in the future.
94        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
101/// Point is a valid, finite point on some curve.
102pub(crate) struct Point {
103    group: *const bssl_sys::EC_GROUP,
104    point: *mut bssl_sys::EC_POINT,
105}
106
107impl Point {
108    /// Construct an uninitialized curve point. This is not public and all
109    /// callers must ensure that the point is initialized before being returned.
110    fn new(group: Group) -> Self {
111        let group = group.as_ffi_ptr();
112        // Safety: `group` is valid because it was constructed just above.
113        let point = unsafe { bssl_sys::EC_POINT_new(group) };
114        // `EC_POINT_new` only fails if out of memory, which is not a case that
115        // is handled short of panicking.
116        assert!(!point.is_null());
117        Self { group, point }
118    }
119
120    /// Construct a point by multiplying the curve's base point by the given
121    /// scalar.
122    ///
123    /// Safety: `scalar` must be a valid pointer.
124    unsafe fn from_scalar(group: Group, scalar: *const bssl_sys::BIGNUM) -> Option<Self> {
125        let point = Self::new(group);
126        // Safety: the members of `point` are valid by construction. `scalar`
127        // is assumed to be valid.
128        let result = unsafe {
129            bssl_sys::EC_POINT_mul(
130                point.group,
131                point.point,
132                scalar,
133                /*q=*/ null(),
134                /*m=*/ null(),
135                /*ctx=*/ 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    /// Duplicate the given finite point.
148    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        // Safety: we assume that the caller is passing valid pointers
157        let new_point = unsafe { bssl_sys::EC_POINT_dup(point, group) };
158        // `EC_POINT_dup` only fails if out of memory, which is not a case that
159        // is handled short of panicking.
160        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        // Safety: `point` is valid by construction. `x962` is a valid memory
175        // buffer.
176        let result = unsafe {
177            bssl_sys::EC_POINT_oct2point(
178                point.group,
179                point.point,
180                x962.as_ffi_ptr(),
181                x962.len(),
182                /*bn_ctx=*/ null_mut(),
183            )
184        };
185        if result == 1 {
186            // The X9.62 encoding of the point at infinity is 0x00, but
187            // BoringSSL will never parse it. So this should be moot,
188            // but `Point` must never contain infinity.
189            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    /// Create a new point from an uncompressed X9.62 representation.
199    ///
200    /// (X9.62 is the standard representation of an elliptic-curve point that
201    /// starts with an 0x04 byte.)
202    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        // Safety: arguments are valid, `EC_KEY` ensures that the group is
214        // correct for the point, and a `Point` is always finite.
215        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        // The first byte of the compressed format can be either 0x02 or 0x03,
226        // to indicate whether the y coordinate of the point is even or odd.
227        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    /// WARNING: compressed form is rarely used and is not as well supported as
236    /// the uncompressed form.
237    pub fn to_x962_compressed(&self) -> Buffer {
238        // Safety: arguments are valid, `EC_KEY` ensures that the group is
239        // correct for the point, and a `Point` is always finite.
240        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        // We only passed in one allowed algorithm, an EC algorithm.
255        assert!(!ec_key.is_null());
256        let parsed_group = unsafe { bssl_sys::EC_KEY_get0_group(ec_key) };
257        // We only passed in one allowed algorithm, this EC group.
258        assert!(parsed_group == group.as_ffi_ptr());
259        let point = unsafe { bssl_sys::EC_KEY_get0_public_key(ec_key) };
260        // A valid EC SPKI cannot be missing the public key.
261        assert!(!point.is_null());
262        // Safety: `ec_key` is still owned by `pkey` and doesn't need to be freed.
263        Some(unsafe { Self::clone_from_ptr(parsed_group, point) })
264    }
265
266    /// Calls `func` with an `EC_KEY` that contains a copy of this point.
267    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        // Safety: `self.group` is always valid by construction and this doesn't
273        // pass ownership.
274        assert_eq!(1, unsafe {
275            bssl_sys::EC_KEY_set_group(ec_key.as_ffi_ptr(), self.group)
276        });
277        // Safety: `self.point` is always valid by construction and this doesn't
278        // pass ownership.
279        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        // Safety: `ec_key` is a valid pointer in this context.
287        self.with_point_as_ec_key(|ec_key| unsafe { to_der_subject_public_key_info(ec_key) })
288    }
289}
290
291// Safety:
292//
293// An `EC_POINT` can be used concurrently from multiple threads so long as no
294// mutating operations are performed. The mutating operations used here are
295// `EC_POINT_mul` and `EC_POINT_oct2point`, which can be observed by setting
296// `point` to be `*const` in the struct and seeing what errors trigger.
297//
298// Both those operations are done internally, however, before a `Point` is
299// returned. So, after construction, callers cannot mutate the `EC_POINT`.
300unsafe impl Sync for Point {}
301unsafe impl Send for Point {}
302
303impl Drop for Point {
304    fn drop(&mut self) {
305        // Safety: `self.point` must be valid because only valid `Point`s can
306        // be constructed. `self.group` does not need to be freed.
307        unsafe { bssl_sys::EC_POINT_free(self.point) }
308    }
309}
310
311/// Key holds both a public and private key. While BoringSSL allows an `EC_KEY`
312/// to also be a) empty, b) holding only a private scalar, or c) holding only
313// a public key, those cases are never exposed as a `Key`.
314pub(crate) struct Key(*mut bssl_sys::EC_KEY);
315
316impl Key {
317    /// Construct an uninitialized key. This is not public and all
318    /// callers must ensure that the key is initialized before being returned.
319    fn new(group: Group) -> Self {
320        let key = unsafe { bssl_sys::EC_KEY_new() };
321        // `EC_KEY_new` only fails if out of memory, which is not a case that
322        // is handled short of panicking.
323        assert!(!key.is_null());
324
325        // Setting the group on a fresh `EC_KEY` never fails.
326        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    /// Generate a random private key.
338    pub fn generate(group: Group) -> Self {
339        let key = Self::new(group);
340        // Generation only fails if out of memory, which is only handled by
341        // panicking.
342        assert_eq!(1, unsafe { bssl_sys::EC_KEY_generate_key(key.0) });
343        // `EC_KEY_generate_key` is documented as also setting the public key.
344        key
345    }
346
347    /// Construct a private key from a big-endian representation of the private
348    /// scalar. The scalar must be zero padded to the correct length for the
349    /// curve.
350    pub fn from_big_endian(group: Group, scalar: &[u8]) -> Option<Self> {
351        let key = Self::new(group);
352        // Safety: `key.0` is always valid by construction.
353        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        // BoringSSL allows an `EC_KEY` to have a private scalar without a
359        // public point, but `Key` is never exposed in that state.
360        //
361        // TODO(crbug.com/42290404): `EC_KEY_oct2priv` should fill in the public
362        // key.
363
364        // Safety: `key.0` is valid by construction. The returned value is
365        // still owned the `EC_KEY`.
366        let scalar = unsafe { bssl_sys::EC_KEY_get0_private_key(key.0) };
367        assert!(!scalar.is_null());
368
369        // Safety: `scalar` is a valid pointer.
370        let point = unsafe { Point::from_scalar(group, scalar)? };
371        // Safety: `key.0` is valid by construction, as is `point.point`. The
372        // point is copied into the `EC_KEY` so ownership isn't being moved.
373        let result = unsafe { bssl_sys::EC_KEY_set_public_key(key.0, point.point) };
374        // Setting the public key should only fail if out of memory, which this
375        // crate doesn't handle, or if the groups don't match, which is
376        // impossible.
377        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        // Safety: `self.0` is valid by construction. If this returns non-zero
385        // then ptr holds ownership of a buffer.
386        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    /// Parses an ECPrivateKey structure from [RFC 5915].
394    ///
395    /// [RFC 5915]: <https://datatracker.ietf.org/doc/html/rfc5915>
396    pub fn from_der_ec_private_key(group: Group, der: &[u8]) -> Option<Self> {
397        let key = parse_with_cbs(
398            der,
399            // Safety: in this context, `key` is the non-null result of
400            // `EC_KEY_parse_private_key`.
401            |key| unsafe { bssl_sys::EC_KEY_free(key) },
402            // Safety: `cbs` is valid per `parse_with_cbs` and `group` always
403            // returns a valid pointer.
404            |cbs| unsafe { bssl_sys::EC_KEY_parse_private_key(cbs, group.as_ffi_ptr()) },
405        )?;
406        Some(Self(key))
407    }
408
409    /// Parses an ECPrivateKey structure from [RFC 5915], whose curve is specified by
410    /// the `ECParameters`.
411    ///
412    /// Unless the curve group is one of the variants of [`Group`], this method returns [`None`].
413    ///
414    /// [RFC 5915]: <https://datatracker.ietf.org/doc/html/rfc5915>
415    pub fn from_der_ec_private_key_with_curve_names(der: &[u8]) -> Option<Self> {
416        let key = parse_with_cbs(
417            der,
418            // Safety: in this context, `key` is the non-null result of
419            // `EC_KEY_parse_private_key`.
420            |key| unsafe { bssl_sys::EC_KEY_free(key) },
421            // Safety: `cbs` is valid per `parse_with_cbs`.
422            |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    /// Serializes this private key as an ECPrivateKey structure from [RFC 5915].
433    ///
434    /// This method also **serialise** known curve names as `ECParameters`.
435    ///
436    /// [RFC 5915]: <https://datatracker.ietf.org/doc/html/rfc5915>
437    pub fn to_der_ec_private_key(&self) -> Buffer {
438        cbb_to_buffer(64, |cbb| unsafe {
439            // Safety: the `EC_KEY` is always valid so `EC_KEY_marshal_private_key`
440            // should only fail if out of memory, which this crate doesn't handle.
441            assert_eq!(1, bssl_sys::EC_KEY_marshal_private_key(cbb, self.0, 0));
442        })
443    }
444
445    /// Parses a PrivateKeyInfo structure (from RFC 5208).
446    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        // Safety: the pkey is not aliased
450        let ec_key = Self::from_evp_pkey(pkey)?;
451        // We only passed in one allowed algorithm, this EC group.
452        (ec_key.get_group()? == group).then_some(ec_key)
453    }
454
455    // Safety: the pkey must not be aliased via `as_ffi_ptr`
456    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        // Safety: `EVP_PKEY_get1_EC_KEY` returned owned key, which we can move
462        // into the returned object and whose lifetime is independent of the EVP pkey.
463        Some(Self(ec_key))
464    }
465
466    pub(crate) fn get_group(&self) -> Option<Group> {
467        // Safety: we own the `EC_KEY`
468        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    /// Serializes this private key as a PrivateKeyInfo structure from RFC 5208.
479    pub fn to_der_private_key_info(&self) -> Buffer {
480        let mut pkey = scoped::EvpPkey::new();
481        // Safety: `pkey` was just allocated above; the `EC_KEY` is valid by
482        // construction. This call takes a reference to the `EC_KEY` and so
483        // hasn't stolen ownership from `self`.
484        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            // `EVP_marshal_private_key` should always return one because this
489            // key is valid by construction.
490            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        // Safety: `self.0` is valid by construction.
496        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        // A `Key` is never constructed without a public key.
499        assert!(!point.is_null());
500        // Safety: pointers are valid and `clone_from_ptr` doesn't take
501        // ownership.
502        unsafe { Point::clone_from_ptr(group, point) }
503    }
504
505    pub fn to_x962_uncompressed(&self) -> Buffer {
506        // Safety: `self.0` is valid by construction.
507        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        // Safety: arguments are valid, `EC_KEY` ensures that the group is
510        // correct for the point, and a `Key` always holds a finite public point.
511        unsafe {
512            to_x962(
513                group,
514                point,
515                bssl_sys::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED,
516            )
517        }
518    }
519
520    /// WARNING: compressed form is rarely used and is not as well supported as
521    /// the uncompressed form.
522    pub fn to_x962_compressed(&self) -> Buffer {
523        // Safety: `self.0` is valid by construction.
524        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        // Safety: arguments are valid, `EC_KEY` ensures that the group is
527        // correct for the point, and a `Key` always holds a finite public point.
528        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        // Safety: `self.0` is always valid by construction.
539        unsafe { to_der_subject_public_key_info(self.0) }
540    }
541}
542
543// Safety:
544//
545// An `EC_KEY` is safe to use from multiple threads so long as no mutating
546// operations are performed. (Reference count changes don't count as mutating.)
547// The mutating operations used here are:
548//   * EC_KEY_generate_key
549//   * EC_KEY_oct2priv
550//   * EC_KEY_set_public_key
551// But those are all done internally, before a `Key` is returned. So, once
552// constructed, callers cannot mutate the `EC_KEY`.
553unsafe impl Sync for Key {}
554unsafe impl Send for Key {}
555
556impl Drop for Key {
557    fn drop(&mut self) {
558        // Safety: `self.0` must be valid because only valid `Key`s can
559        // be constructed.
560        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
573/// Serialize a finite point to X9.62 format.
574///
575/// Callers must ensure that the arguments are valid, that the point has the
576/// specified group, and that the point is finite.
577unsafe 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        // This length is just a hint and is tuned for P-256's output length.
584        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            // Safety: the caller must ensure that the arguments are valid.
591            let result =
592                bssl_sys::EC_POINT_point2cbb(cbb, group, point, form, /*bn_ctx=*/ null_mut());
593            // The public key is always finite, so `EC_POINT_point2cbb` only fails
594            // if out of memory, which isn't handled by this crate.
595            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    // Safety: this takes a reference to `ec_key` and so doesn't steal ownership.
603    assert_eq!(1, unsafe {
604        bssl_sys::EVP_PKEY_set1_EC_KEY(pkey.as_ffi_ptr(), ec_key)
605    });
606    cbb_to_buffer(
607        // This length is just a hint and is tuned for P-256's output length.
608        65,
609        |cbb| unsafe {
610            // The arguments are valid so this will only fail if out of memory,
611            // which this crate doesn't handle.
612            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        // Messing with the first byte should always cause an error.
649        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            // Flipping a bit in a compressed point has a reasonable chance of
686            // producing another valid point, so we can't run a bit-flip test
687            // in this case.
688            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            // Flipping a bit in a compressed point has a reasonable chance of
696            // producing another valid point, so we can't run a bit-flip test
697            // in this case.
698            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        // Compressed points won't be accepted by the uncompressed function and
709        // vice-versa.
710        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        // 0x00 is the X9.62 encoding of the point at infinity.
717        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        // The X9.62 functions look at the first byte to check the type. They
725        // must handle the case of an empty input correctly.
726        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}