Coverage Report

Created: 2026-07-25 06:08

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