aws_lc_rs/ec/
encoding.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0 OR ISC
3
4use crate::aws_lc::{EVP_PKEY, EVP_PKEY_EC};
5use crate::ec::encoding::sec1::parse_sec1_public_point;
6use crate::ec::validate_ec_evp_key;
7
8use crate::error::KeyRejected;
9use crate::ptr::LcPtr;
10
11// [SEC 1](https://secg.org/sec1-v2.pdf)
12//
13// SEC 1: Elliptic Curve Cryptography, Version 2.0
14pub(crate) mod sec1 {
15    use crate::aws_lc::{
16        point_conversion_form_t, BN_bn2cbb_padded, EC_GROUP_get_curve_name, EC_KEY_get0_group,
17        EC_KEY_get0_private_key, EC_KEY_get0_public_key, EC_KEY_new, EC_KEY_set_group,
18        EC_KEY_set_private_key, EC_KEY_set_public_key, EC_POINT_mul, EC_POINT_new,
19        EC_POINT_oct2point, EC_POINT_point2cbb, EVP_PKEY_assign_EC_KEY, EVP_PKEY_get0_EC_KEY,
20        EVP_PKEY_new, NID_X9_62_prime256v1, NID_secp256k1, NID_secp384r1, NID_secp521r1, BIGNUM,
21        EC_GROUP, EC_POINT, EVP_PKEY,
22    };
23    use crate::cbb::LcCBB;
24    use crate::ec::{
25        compressed_public_key_size_bytes, ec_group_from_nid, uncompressed_public_key_size_bytes,
26        validate_ec_evp_key, KeyRejected,
27    };
28    use crate::error::Unspecified;
29    use crate::ptr::{ConstPointer, DetachableLcPtr, LcPtr};
30    use std::ptr::{null, null_mut};
31
32    pub(crate) fn parse_sec1_public_point(
33        key_bytes: &[u8],
34        expected_curve_nid: i32,
35    ) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
36        let ec_group = ec_group_from_nid(expected_curve_nid)?;
37        let mut ec_point = LcPtr::new(unsafe { EC_POINT_new(ec_group.as_const_ptr()) })?;
38
39        if 1 != unsafe {
40            EC_POINT_oct2point(
41                ec_group.as_const_ptr(),
42                ec_point.as_mut_ptr(),
43                key_bytes.as_ptr(),
44                key_bytes.len(),
45                null_mut(),
46            )
47        } {
48            return Err(KeyRejected::invalid_encoding());
49        }
50        from_ec_public_point(&ec_group, &ec_point)
51    }
52
53    #[inline]
54    fn from_ec_public_point(
55        ec_group: &ConstPointer<EC_GROUP>,
56        public_ec_point: &LcPtr<EC_POINT>,
57    ) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
58        let nid = unsafe { EC_GROUP_get_curve_name(ec_group.as_const_ptr()) };
59        let mut ec_key = DetachableLcPtr::new(unsafe { EC_KEY_new() })?;
60        if 1 != unsafe { EC_KEY_set_group(ec_key.as_mut_ptr(), ec_group.as_const_ptr()) } {
61            return Err(KeyRejected::unexpected_error());
62        }
63        if 1 != unsafe {
64            EC_KEY_set_public_key(ec_key.as_mut_ptr(), public_ec_point.as_const_ptr())
65        } {
66            return Err(KeyRejected::inconsistent_components());
67        }
68
69        let mut pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
70
71        if 1 != unsafe { EVP_PKEY_assign_EC_KEY(pkey.as_mut_ptr(), ec_key.as_mut_ptr()) } {
72            return Err(KeyRejected::unexpected_error());
73        }
74
75        ec_key.detach();
76
77        validate_ec_evp_key(&pkey.as_const(), nid)?;
78
79        Ok(pkey)
80    }
81
82    pub(crate) fn parse_sec1_private_bn(
83        priv_key: &[u8],
84        nid: i32,
85    ) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
86        let ec_group = ec_group_from_nid(nid)?;
87        let priv_key = LcPtr::<BIGNUM>::try_from(priv_key)?;
88
89        let pkey = from_ec_private_bn(&ec_group, &priv_key.as_const())?;
90
91        Ok(pkey)
92    }
93
94    fn from_ec_private_bn(
95        ec_group: &ConstPointer<EC_GROUP>,
96        private_big_num: &ConstPointer<BIGNUM>,
97    ) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
98        let mut ec_key = DetachableLcPtr::new(unsafe { EC_KEY_new() })?;
99        if 1 != unsafe { EC_KEY_set_group(ec_key.as_mut_ptr(), ec_group.as_const_ptr()) } {
100            return Err(KeyRejected::unexpected_error());
101        }
102        if 1 != unsafe {
103            EC_KEY_set_private_key(ec_key.as_mut_ptr(), private_big_num.as_const_ptr())
104        } {
105            return Err(KeyRejected::invalid_encoding());
106        }
107        let mut pub_key = LcPtr::new(unsafe { EC_POINT_new(ec_group.as_const_ptr()) })?;
108        if 1 != unsafe {
109            EC_POINT_mul(
110                ec_group.as_const_ptr(),
111                pub_key.as_mut_ptr(),
112                private_big_num.as_const_ptr(),
113                null(),
114                null(),
115                null_mut(),
116            )
117        } {
118            return Err(KeyRejected::unexpected_error());
119        }
120        if 1 != unsafe { EC_KEY_set_public_key(ec_key.as_mut_ptr(), pub_key.as_const_ptr()) } {
121            return Err(KeyRejected::unexpected_error());
122        }
123        let expected_curve_nid = unsafe { EC_GROUP_get_curve_name(ec_group.as_const_ptr()) };
124
125        let mut pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
126
127        if 1 != unsafe { EVP_PKEY_assign_EC_KEY(pkey.as_mut_ptr(), ec_key.as_mut_ptr()) } {
128            return Err(KeyRejected::unexpected_error());
129        }
130        ec_key.detach();
131
132        // Validate the EC_KEY before returning it.
133        validate_ec_evp_key(&pkey.as_const(), expected_curve_nid)?;
134
135        Ok(pkey)
136    }
137    pub(crate) fn marshal_sec1_public_point(
138        evp_pkey: &LcPtr<EVP_PKEY>,
139        compressed: bool,
140    ) -> Result<Vec<u8>, Unspecified> {
141        let pub_key_size = if compressed {
142            compressed_public_key_size_bytes(evp_pkey.as_const().key_size_bits())
143        } else {
144            uncompressed_public_key_size_bytes(evp_pkey.as_const().key_size_bits())
145        };
146        let mut cbb = LcCBB::new(pub_key_size);
147        marshal_sec1_public_point_into_cbb(&mut cbb, evp_pkey, compressed)?;
148        cbb.into_vec()
149    }
150
151    pub(crate) fn marshal_sec1_public_point_into_buffer(
152        buffer: &mut [u8],
153        evp_pkey: &LcPtr<EVP_PKEY>,
154        compressed: bool,
155    ) -> Result<usize, Unspecified> {
156        let mut cbb = LcCBB::new_from_slice(buffer);
157        marshal_sec1_public_point_into_cbb(&mut cbb, evp_pkey, compressed)?;
158        cbb.finish()
159    }
160
161    fn marshal_sec1_public_point_into_cbb(
162        cbb: &mut LcCBB,
163        evp_pkey: &LcPtr<EVP_PKEY>,
164        compressed: bool,
165    ) -> Result<(), Unspecified> {
166        let ec_key = evp_pkey.project_const_lifetime(unsafe {
167            |evp_pkey| EVP_PKEY_get0_EC_KEY(evp_pkey.as_const_ptr())
168        })?;
169        let ec_group = ec_key
170            .project_const_lifetime(unsafe { |ec_key| EC_KEY_get0_group(ec_key.as_const_ptr()) })?;
171        let ec_point = ec_key.project_const_lifetime(unsafe {
172            |ec_key| EC_KEY_get0_public_key(ec_key.as_const_ptr())
173        })?;
174
175        let point_conversion_form = if compressed {
176            point_conversion_form_t::POINT_CONVERSION_COMPRESSED
177        } else {
178            point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED
179        };
180
181        if 1 != unsafe {
182            EC_POINT_point2cbb(
183                cbb.as_mut_ptr(),
184                ec_group.as_const_ptr(),
185                ec_point.as_const_ptr(),
186                point_conversion_form,
187                null_mut(),
188            )
189        } {
190            return Err(Unspecified);
191        }
192        Ok(())
193    }
194
195    pub(crate) fn marshal_sec1_private_key(
196        evp_pkey: &LcPtr<EVP_PKEY>,
197    ) -> Result<Vec<u8>, Unspecified> {
198        let ec_key = evp_pkey.project_const_lifetime(unsafe {
199            |evp_pkey| EVP_PKEY_get0_EC_KEY(evp_pkey.as_const_ptr())
200        })?;
201        let ec_group = ec_key
202            .project_const_lifetime(unsafe { |ec_key| EC_KEY_get0_group(ec_key.as_const_ptr()) })?;
203        let nid = unsafe { EC_GROUP_get_curve_name(ec_group.as_const_ptr()) };
204        #[allow(non_upper_case_globals)]
205        let key_size: usize = match nid {
206            NID_X9_62_prime256v1 | NID_secp256k1 => Ok(32usize),
207            NID_secp384r1 => Ok(48usize),
208            NID_secp521r1 => Ok(66usize),
209            _ => Err(Unspecified),
210        }?;
211        let private_bn = ec_key.project_const_lifetime(unsafe {
212            |ec_key| EC_KEY_get0_private_key(ec_key.as_const_ptr())
213        })?;
214
215        let mut cbb = LcCBB::new(key_size);
216        if 1 != unsafe { BN_bn2cbb_padded(cbb.as_mut_ptr(), key_size, private_bn.as_const_ptr()) } {
217            return Err(Unspecified);
218        }
219        cbb.into_vec()
220    }
221}
222
223pub(crate) mod rfc5915 {
224    use crate::aws_lc::{
225        EC_KEY_get_enc_flags, EC_KEY_marshal_private_key, EC_KEY_parse_private_key,
226        EVP_PKEY_get0_EC_KEY, EVP_PKEY_new, EVP_PKEY_set1_EC_KEY, EVP_PKEY,
227    };
228    use crate::cbb::LcCBB;
229    use crate::cbs::build_CBS;
230    use crate::ec::ec_group_from_nid;
231    use crate::error::{KeyRejected, Unspecified};
232    use crate::ptr::LcPtr;
233
234    pub(crate) fn parse_rfc5915_private_key(
235        key_bytes: &[u8],
236        expected_curve_nid: i32,
237    ) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
238        let ec_group = ec_group_from_nid(expected_curve_nid)?;
239        let mut cbs = build_CBS(key_bytes);
240        let mut ec_key =
241            LcPtr::new(unsafe { EC_KEY_parse_private_key(&mut cbs, ec_group.as_const_ptr()) })?;
242        let mut evp_pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
243        if 1 != unsafe { EVP_PKEY_set1_EC_KEY(evp_pkey.as_mut_ptr(), ec_key.as_mut_ptr()) } {
244            return Err(KeyRejected::unexpected_error());
245        }
246        Ok(evp_pkey)
247    }
248
249    pub(crate) fn marshal_rfc5915_private_key(
250        evp_pkey: &LcPtr<EVP_PKEY>,
251    ) -> Result<Vec<u8>, Unspecified> {
252        let ec_key = evp_pkey.project_const_lifetime(unsafe {
253            |evp_pkey| EVP_PKEY_get0_EC_KEY(evp_pkey.as_const_ptr())
254        })?;
255        let mut cbb = LcCBB::new(evp_pkey.as_const().key_size_bytes());
256        let enc_flags = unsafe { EC_KEY_get_enc_flags(ec_key.as_const_ptr()) };
257        if 1 != unsafe {
258            EC_KEY_marshal_private_key(cbb.as_mut_ptr(), ec_key.as_const_ptr(), enc_flags)
259        } {
260            return Err(Unspecified);
261        }
262        cbb.into_vec()
263    }
264}
265
266pub(crate) fn parse_ec_public_key(
267    key_bytes: &[u8],
268    expected_curve_nid: i32,
269) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
270    LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_EC)
271        .or(parse_sec1_public_point(key_bytes, expected_curve_nid))
272        .and_then(|key| validate_ec_evp_key(&key.as_const(), expected_curve_nid).map(|()| key))
273}