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) })?;
38
39        if 1 != unsafe {
40            EC_POINT_oct2point(
41                *ec_group,
42                *ec_point.as_mut(),
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) };
59        let ec_key = DetachableLcPtr::new(unsafe { EC_KEY_new() })?;
60        if 1 != unsafe { EC_KEY_set_group(*ec_key, **ec_group) } {
61            return Err(KeyRejected::unexpected_error());
62        }
63        if 1 != unsafe { EC_KEY_set_public_key(*ec_key, *public_ec_point.as_const()) } {
64            return Err(KeyRejected::inconsistent_components());
65        }
66
67        let mut pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
68
69        if 1 != unsafe { EVP_PKEY_assign_EC_KEY(*pkey.as_mut(), *ec_key) } {
70            return Err(KeyRejected::unexpected_error());
71        }
72
73        ec_key.detach();
74
75        validate_ec_evp_key(&pkey.as_const(), nid)?;
76
77        Ok(pkey)
78    }
79
80    pub(crate) fn parse_sec1_private_bn(
81        priv_key: &[u8],
82        nid: i32,
83    ) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
84        let ec_group = ec_group_from_nid(nid)?;
85        let priv_key = LcPtr::<BIGNUM>::try_from(priv_key)?;
86
87        let pkey = from_ec_private_bn(&ec_group, &priv_key.as_const())?;
88
89        Ok(pkey)
90    }
91
92    fn from_ec_private_bn(
93        ec_group: &ConstPointer<EC_GROUP>,
94        private_big_num: &ConstPointer<BIGNUM>,
95    ) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
96        let ec_key = DetachableLcPtr::new(unsafe { EC_KEY_new() })?;
97        if 1 != unsafe { EC_KEY_set_group(*ec_key, **ec_group) } {
98            return Err(KeyRejected::unexpected_error());
99        }
100        if 1 != unsafe { EC_KEY_set_private_key(*ec_key, **private_big_num) } {
101            return Err(KeyRejected::invalid_encoding());
102        }
103        let mut pub_key = LcPtr::new(unsafe { EC_POINT_new(**ec_group) })?;
104        if 1 != unsafe {
105            EC_POINT_mul(
106                **ec_group,
107                *pub_key.as_mut(),
108                **private_big_num,
109                null(),
110                null(),
111                null_mut(),
112            )
113        } {
114            return Err(KeyRejected::unexpected_error());
115        }
116        if 1 != unsafe { EC_KEY_set_public_key(*ec_key, *pub_key.as_const()) } {
117            return Err(KeyRejected::unexpected_error());
118        }
119        let expected_curve_nid = unsafe { EC_GROUP_get_curve_name(**ec_group) };
120
121        let mut pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
122
123        if 1 != unsafe { EVP_PKEY_assign_EC_KEY(*pkey.as_mut(), *ec_key) } {
124            return Err(KeyRejected::unexpected_error());
125        }
126        ec_key.detach();
127
128        // Validate the EC_KEY before returning it.
129        validate_ec_evp_key(&pkey.as_const(), expected_curve_nid)?;
130
131        Ok(pkey)
132    }
133    pub(crate) fn marshal_sec1_public_point(
134        evp_pkey: &LcPtr<EVP_PKEY>,
135        compressed: bool,
136    ) -> Result<Vec<u8>, Unspecified> {
137        let pub_key_size = if compressed {
138            compressed_public_key_size_bytes(evp_pkey.as_const().key_size_bits())
139        } else {
140            uncompressed_public_key_size_bytes(evp_pkey.as_const().key_size_bits())
141        };
142        let mut cbb = LcCBB::new(pub_key_size);
143        marshal_sec1_public_point_into_cbb(&mut cbb, evp_pkey, compressed)?;
144        cbb.into_vec()
145    }
146
147    pub(crate) fn marshal_sec1_public_point_into_buffer(
148        buffer: &mut [u8],
149        evp_pkey: &LcPtr<EVP_PKEY>,
150        compressed: bool,
151    ) -> Result<usize, Unspecified> {
152        let mut cbb = LcCBB::new_from_slice(buffer);
153        marshal_sec1_public_point_into_cbb(&mut cbb, evp_pkey, compressed)?;
154        cbb.finish()
155    }
156
157    fn marshal_sec1_public_point_into_cbb(
158        cbb: &mut LcCBB,
159        evp_pkey: &LcPtr<EVP_PKEY>,
160        compressed: bool,
161    ) -> Result<(), Unspecified> {
162        let ec_key = evp_pkey.project_const_lifetime(unsafe {
163            |evp_pkey| EVP_PKEY_get0_EC_KEY(*evp_pkey.as_const())
164        })?;
165        let ec_group =
166            ec_key.project_const_lifetime(unsafe { |ec_key| EC_KEY_get0_group(**ec_key) })?;
167        let ec_point =
168            ec_key.project_const_lifetime(unsafe { |ec_key| EC_KEY_get0_public_key(**ec_key) })?;
169
170        let point_conversion_form = if compressed {
171            point_conversion_form_t::POINT_CONVERSION_COMPRESSED
172        } else {
173            point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED
174        };
175
176        if 1 != unsafe {
177            EC_POINT_point2cbb(
178                cbb.as_mut_ptr(),
179                *ec_group,
180                *ec_point,
181                point_conversion_form,
182                null_mut(),
183            )
184        } {
185            return Err(Unspecified);
186        }
187        Ok(())
188    }
189
190    pub(crate) fn marshal_sec1_private_key(
191        evp_pkey: &LcPtr<EVP_PKEY>,
192    ) -> Result<Vec<u8>, Unspecified> {
193        let ec_key = evp_pkey.project_const_lifetime(unsafe {
194            |evp_pkey| EVP_PKEY_get0_EC_KEY(*evp_pkey.as_const())
195        })?;
196        let ec_group =
197            ec_key.project_const_lifetime(unsafe { |ec_key| EC_KEY_get0_group(**ec_key) })?;
198        let nid = unsafe { EC_GROUP_get_curve_name(*ec_group) };
199        #[allow(non_upper_case_globals)]
200        let key_size: usize = match nid {
201            NID_X9_62_prime256v1 | NID_secp256k1 => Ok(32usize),
202            NID_secp384r1 => Ok(48usize),
203            NID_secp521r1 => Ok(66usize),
204            _ => Err(Unspecified),
205        }?;
206        let private_bn =
207            ec_key.project_const_lifetime(unsafe { |ec_key| EC_KEY_get0_private_key(**ec_key) })?;
208
209        let mut cbb = LcCBB::new(key_size);
210        if 1 != unsafe { BN_bn2cbb_padded(cbb.as_mut_ptr(), key_size, *private_bn) } {
211            return Err(Unspecified);
212        }
213        cbb.into_vec()
214    }
215}
216
217pub(crate) mod rfc5915 {
218    use crate::aws_lc::{
219        EC_KEY_get_enc_flags, EC_KEY_marshal_private_key, EC_KEY_parse_private_key,
220        EVP_PKEY_get0_EC_KEY, EVP_PKEY_new, EVP_PKEY_set1_EC_KEY, EVP_PKEY,
221    };
222    use crate::cbb::LcCBB;
223    use crate::cbs::build_CBS;
224    use crate::ec::ec_group_from_nid;
225    use crate::error::{KeyRejected, Unspecified};
226    use crate::ptr::LcPtr;
227
228    pub(crate) fn parse_rfc5915_private_key(
229        key_bytes: &[u8],
230        expected_curve_nid: i32,
231    ) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
232        let ec_group = ec_group_from_nid(expected_curve_nid)?;
233        let mut cbs = build_CBS(key_bytes);
234        let mut ec_key = LcPtr::new(unsafe { EC_KEY_parse_private_key(&mut cbs, *ec_group) })?;
235        let mut evp_pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
236        if 1 != unsafe { EVP_PKEY_set1_EC_KEY(*evp_pkey.as_mut(), *ec_key.as_mut()) } {
237            return Err(KeyRejected::unexpected_error());
238        }
239        Ok(evp_pkey)
240    }
241
242    pub(crate) fn marshal_rfc5915_private_key(
243        evp_pkey: &LcPtr<EVP_PKEY>,
244    ) -> Result<Vec<u8>, Unspecified> {
245        let ec_key = evp_pkey.project_const_lifetime(unsafe {
246            |evp_pkey| EVP_PKEY_get0_EC_KEY(*evp_pkey.as_const())
247        })?;
248        let mut cbb = LcCBB::new(evp_pkey.as_const().key_size_bytes());
249        let enc_flags = unsafe { EC_KEY_get_enc_flags(*ec_key) };
250        if 1 != unsafe { EC_KEY_marshal_private_key(cbb.as_mut_ptr(), *ec_key, enc_flags) } {
251            return Err(Unspecified);
252        }
253        cbb.into_vec()
254    }
255}
256
257pub(crate) fn parse_ec_public_key(
258    key_bytes: &[u8],
259    expected_curve_nid: i32,
260) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
261    LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_EC)
262        .or(parse_sec1_public_point(key_bytes, expected_curve_nid))
263        .and_then(|key| validate_ec_evp_key(&key.as_const(), expected_curve_nid).map(|()| key))
264}