Skip to main content

bssl_crypto/
ec.rs

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