blob: 9eb5e5cf8d9f7a9bc7e83dd2a3f4229ddbbf76dc [file] [log] [blame]
Alice Wang7b2ab942023-09-12 13:04:42 +00001// Copyright 2023, The Android Open Source Project
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// http://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//! Contains struct and functions that wraps the API related to EC_KEY in
16//! BoringSSL.
17
Alice Wangb3fcf632023-09-26 08:32:55 +000018use crate::cbb::CbbFixed;
Alice Wang000595b2023-10-02 13:46:45 +000019use crate::cbs::Cbs;
Alice Wangdd29c5d2023-12-07 09:56:23 +000020use crate::util::{check_int_result, to_call_failed_error};
Alice Wang0271ee02023-11-15 15:03:42 +000021use alloc::vec;
Alice Wang7b2ab942023-09-12 13:04:42 +000022use alloc::vec::Vec;
Alice Wangb3fcf632023-09-26 08:32:55 +000023use bssl_avf_error::{ApiName, Error, Result};
Maurice Lam0322b8c2023-12-18 22:13:48 +000024use bssl_sys::{
Alan Stokesb2f52fb2024-05-09 10:12:55 +010025 i2d_ECDSA_SIG, BN_bin2bn, BN_bn2bin_padded, BN_clear_free, BN_new, CBB_flush, CBB_len,
26 ECDSA_SIG_free, ECDSA_SIG_new, ECDSA_SIG_set0, ECDSA_sign, ECDSA_size, ECDSA_verify,
27 EC_GROUP_get_curve_name, EC_GROUP_new_by_curve_name, EC_KEY_check_key, EC_KEY_free,
28 EC_KEY_generate_key, EC_KEY_get0_group, EC_KEY_get0_public_key, EC_KEY_marshal_private_key,
29 EC_KEY_new_by_curve_name, EC_KEY_parse_private_key, EC_KEY_set_public_key_affine_coordinates,
30 EC_POINT_get_affine_coordinates, NID_X9_62_prime256v1, NID_secp384r1, BIGNUM, ECDSA_SIG,
31 EC_GROUP, EC_KEY, EC_POINT,
Alan Stokesb1f64ee2023-09-25 10:38:13 +010032};
Alice Wangdd29c5d2023-12-07 09:56:23 +000033use cbor_util::{get_label_value, get_label_value_as_bytes};
Alice Wang9bd98092023-11-10 14:08:12 +000034use ciborium::Value;
Alan Stokesb2f52fb2024-05-09 10:12:55 +010035use core::mem;
Alice Wanga78d3f02023-09-13 12:39:16 +000036use core::ptr::{self, NonNull};
Alice Wang9bd98092023-11-10 14:08:12 +000037use coset::{
38 iana::{self, EnumI64},
Alice Wangbe7a4b12023-12-01 11:53:36 +000039 CborSerializable, CoseKey, CoseKeyBuilder, KeyType, Label,
Alice Wang9bd98092023-11-10 14:08:12 +000040};
41use log::error;
Alice Wang7b2ab942023-09-12 13:04:42 +000042use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
43
Alice Wang9bd98092023-11-10 14:08:12 +000044const ES256_ALGO: iana::Algorithm = iana::Algorithm::ES256;
45const P256_CURVE: iana::EllipticCurve = iana::EllipticCurve::P_256;
Alice Wang306c8e22023-11-29 12:40:43 +000046const P384_CURVE: iana::EllipticCurve = iana::EllipticCurve::P_384;
Alice Wanga78d3f02023-09-13 12:39:16 +000047const P256_AFFINE_COORDINATE_SIZE: usize = 32;
Alice Wang306c8e22023-11-29 12:40:43 +000048const P384_AFFINE_COORDINATE_SIZE: usize = 48;
Alice Wang7b2ab942023-09-12 13:04:42 +000049
50/// Wrapper of an `EC_KEY` object, representing a public or private EC key.
Alice Wang600ea5b2023-11-17 15:12:16 +000051pub struct EcKey(pub(crate) NonNull<EC_KEY>);
Alice Wang7b2ab942023-09-12 13:04:42 +000052
53impl Drop for EcKey {
54 fn drop(&mut self) {
55 // SAFETY: It is safe because the key has been allocated by BoringSSL and isn't
56 // used after this.
57 unsafe { EC_KEY_free(self.0.as_ptr()) }
58 }
59}
60
61impl EcKey {
62 /// Creates a new EC P-256 key pair.
63 pub fn new_p256() -> Result<Self> {
64 // SAFETY: The returned pointer is checked below.
Alan Stokesb1f64ee2023-09-25 10:38:13 +010065 let ec_key = unsafe {
66 EC_KEY_new_by_curve_name(NID_X9_62_prime256v1) // EC P-256 CURVE Nid
67 };
Alice Wang9bd98092023-11-10 14:08:12 +000068 NonNull::new(ec_key)
Alice Wangc8f88f52023-09-25 14:02:17 +000069 .map(Self)
Alice Wangf6e02272024-03-20 10:11:30 +000070 .ok_or_else(|| to_call_failed_error(ApiName::EC_KEY_new_by_curve_name))
Alice Wang9bd98092023-11-10 14:08:12 +000071 }
72
Alice Wang306c8e22023-11-29 12:40:43 +000073 /// Creates a new EC P-384 key pair.
74 pub fn new_p384() -> Result<Self> {
75 // SAFETY: The returned pointer is checked below.
76 let ec_key = unsafe {
77 EC_KEY_new_by_curve_name(NID_secp384r1) // EC P-384 CURVE Nid
78 };
79 NonNull::new(ec_key)
80 .map(Self)
Alice Wangf6e02272024-03-20 10:11:30 +000081 .ok_or_else(|| to_call_failed_error(ApiName::EC_KEY_new_by_curve_name))
Alice Wang306c8e22023-11-29 12:40:43 +000082 }
83
Alice Wang9bd98092023-11-10 14:08:12 +000084 /// Constructs an `EcKey` instance from the provided COSE_Key encoded public key slice.
Alice Wangbe7a4b12023-12-01 11:53:36 +000085 pub fn from_cose_public_key_slice(cose_key: &[u8]) -> Result<Self> {
Alice Wang9bd98092023-11-10 14:08:12 +000086 let cose_key = CoseKey::from_slice(cose_key).map_err(|e| {
87 error!("Failed to deserialize COSE_Key: {e:?}");
88 Error::CoseKeyDecodingFailed
89 })?;
Alice Wangbe7a4b12023-12-01 11:53:36 +000090 Self::from_cose_public_key(&cose_key)
91 }
92
93 /// Constructs an `EcKey` instance from the provided `COSE_Key`.
94 ///
95 /// The lifetime of the returned `EcKey` is not tied to the lifetime of the `cose_key`,
96 /// because the affine coordinates stored in the `cose_key` are copied into the `EcKey`.
97 ///
98 /// Currently, only the EC P-256 and P-384 curves are supported.
99 pub fn from_cose_public_key(cose_key: &CoseKey) -> Result<Self> {
100 if cose_key.kty != KeyType::Assigned(iana::KeyType::EC2) {
101 error!("Only EC2 keys are supported. Key type in the COSE Key: {:?}", cose_key.kty);
102 return Err(Error::Unimplemented);
103 }
Alice Wang306c8e22023-11-29 12:40:43 +0000104 let ec_key =
Alice Wangbe7a4b12023-12-01 11:53:36 +0000105 match get_label_value(cose_key, Label::Int(iana::Ec2KeyParameter::Crv.to_i64()))? {
Alice Wang306c8e22023-11-29 12:40:43 +0000106 crv if crv == &Value::from(P256_CURVE.to_i64()) => EcKey::new_p256()?,
107 crv if crv == &Value::from(P384_CURVE.to_i64()) => EcKey::new_p384()?,
108 crv => {
109 error!(
110 "Only EC P-256 and P-384 curves are supported. \
111 Curve type in the COSE Key: {crv:?}"
112 );
113 return Err(Error::Unimplemented);
114 }
115 };
Alice Wangbe7a4b12023-12-01 11:53:36 +0000116 let x = get_label_value_as_bytes(cose_key, Label::Int(iana::Ec2KeyParameter::X.to_i64()))?;
117 let y = get_label_value_as_bytes(cose_key, Label::Int(iana::Ec2KeyParameter::Y.to_i64()))?;
Alice Wang9bd98092023-11-10 14:08:12 +0000118
Alice Wang306c8e22023-11-29 12:40:43 +0000119 let group = ec_key.ec_group()?;
120 group.check_affine_coordinate_size(x)?;
121 group.check_affine_coordinate_size(y)?;
Alice Wang9bd98092023-11-10 14:08:12 +0000122
123 let x = BigNum::from_slice(x)?;
124 let y = BigNum::from_slice(y)?;
125
Alice Wang9bd98092023-11-10 14:08:12 +0000126 // SAFETY: All the parameters are checked non-null and initialized.
127 // The function only reads the coordinates x and y within their bounds.
128 let ret = unsafe {
129 EC_KEY_set_public_key_affine_coordinates(ec_key.0.as_ptr(), x.as_ref(), y.as_ref())
130 };
131 check_int_result(ret, ApiName::EC_KEY_set_public_key_affine_coordinates)?;
Alice Wangf061e472023-11-21 08:17:16 +0000132 ec_key.check_key()?;
Alice Wang7b2ab942023-09-12 13:04:42 +0000133 Ok(ec_key)
134 }
135
Alice Wang000595b2023-10-02 13:46:45 +0000136 /// Performs several checks on the key. See BoringSSL doc for more details:
137 ///
138 /// https://commondatastorage.googleapis.com/chromium-boringssl-docs/ec_key.h.html#EC_KEY_check_key
139 pub fn check_key(&self) -> Result<()> {
140 // SAFETY: This function only reads the `EC_KEY` pointer, the non-null check is performed
141 // within the function.
142 let ret = unsafe { EC_KEY_check_key(self.0.as_ptr()) };
143 check_int_result(ret, ApiName::EC_KEY_check_key)
144 }
145
Alice Wang0271ee02023-11-15 15:03:42 +0000146 /// Verifies the DER-encoded ECDSA `signature` of the `digest` with the current `EcKey`.
147 ///
148 /// Returns Ok(()) if the verification succeeds, otherwise an error will be returned.
Alan Stokesb2f52fb2024-05-09 10:12:55 +0100149 pub fn ecdsa_verify_der(&self, signature: &[u8], digest: &[u8]) -> Result<()> {
Alice Wang0271ee02023-11-15 15:03:42 +0000150 // The `type` argument should be 0 as required in the BoringSSL spec.
151 const TYPE: i32 = 0;
152
153 // SAFETY: This function only reads the given data within its bounds.
154 // The `EC_KEY` passed to this function has been initialized and checked non-null.
155 let ret = unsafe {
156 ECDSA_verify(
157 TYPE,
158 digest.as_ptr(),
159 digest.len(),
160 signature.as_ptr(),
161 signature.len(),
162 self.0.as_ptr(),
163 )
164 };
165 check_int_result(ret, ApiName::ECDSA_verify)
Alice Wang9bd98092023-11-10 14:08:12 +0000166 }
167
Alan Stokesb2f52fb2024-05-09 10:12:55 +0100168 /// Verifies the NIST-encoded (R | S) ECDSA `signature` of the `digest` with the current
169 /// `EcKey`.
170 ///
171 /// Returns Ok(()) if the verification succeeds, otherwise an error will be returned.
172 pub fn ecdsa_verify_nist(&self, signature: &[u8], digest: &[u8]) -> Result<()> {
173 let signature = ec_cose_signature_to_der(signature)?;
174 self.ecdsa_verify_der(&signature, digest)
175 }
176
Alice Wang0271ee02023-11-15 15:03:42 +0000177 /// Signs the `digest` with the current `EcKey` using ECDSA.
Alice Wang9bd98092023-11-10 14:08:12 +0000178 ///
179 /// Returns the DER-encoded ECDSA signature.
Alice Wang0271ee02023-11-15 15:03:42 +0000180 pub fn ecdsa_sign(&self, digest: &[u8]) -> Result<Vec<u8>> {
181 // The `type` argument should be 0 as required in the BoringSSL spec.
182 const TYPE: i32 = 0;
183
184 let mut signature = vec![0u8; self.ecdsa_size()?];
185 let mut signature_len = 0;
186 // SAFETY: This function only reads the given data within its bounds.
187 // The `EC_KEY` passed to this function has been initialized and checked non-null.
188 let ret = unsafe {
189 ECDSA_sign(
190 TYPE,
191 digest.as_ptr(),
192 digest.len(),
193 signature.as_mut_ptr(),
194 &mut signature_len,
195 self.0.as_ptr(),
196 )
197 };
198 check_int_result(ret, ApiName::ECDSA_sign)?;
199 if signature.len() < (signature_len as usize) {
200 Err(to_call_failed_error(ApiName::ECDSA_sign))
201 } else {
202 signature.truncate(signature_len as usize);
203 Ok(signature)
204 }
205 }
206
207 /// Returns the maximum size of an ECDSA signature using the current `EcKey`.
208 fn ecdsa_size(&self) -> Result<usize> {
209 // SAFETY: This function only reads the `EC_KEY` that has been initialized
210 // and checked non-null when this instance is created.
211 let size = unsafe { ECDSA_size(self.0.as_ptr()) };
212 if size == 0 {
213 Err(to_call_failed_error(ApiName::ECDSA_size))
214 } else {
215 Ok(size)
216 }
Alice Wang9bd98092023-11-10 14:08:12 +0000217 }
218
Alice Wang7b2ab942023-09-12 13:04:42 +0000219 /// Generates a random, private key, calculates the corresponding public key and stores both
220 /// in the `EC_KEY`.
Alice Wang9bd98092023-11-10 14:08:12 +0000221 pub fn generate_key(&mut self) -> Result<()> {
Alice Wang7b2ab942023-09-12 13:04:42 +0000222 // SAFETY: The non-null pointer is created with `EC_KEY_new_by_curve_name` and should
223 // point to a valid `EC_KEY`.
224 // The randomness is provided by `getentropy()` in `vmbase`.
225 let ret = unsafe { EC_KEY_generate_key(self.0.as_ptr()) };
Alice Wangc8f88f52023-09-25 14:02:17 +0000226 check_int_result(ret, ApiName::EC_KEY_generate_key)
Alice Wang7b2ab942023-09-12 13:04:42 +0000227 }
228
Alice Wanga78d3f02023-09-13 12:39:16 +0000229 /// Returns the `CoseKey` for the public key.
230 pub fn cose_public_key(&self) -> Result<CoseKey> {
Alice Wanga78d3f02023-09-13 12:39:16 +0000231 let (x, y) = self.public_key_coordinates()?;
Alice Wang306c8e22023-11-29 12:40:43 +0000232 let curve = self.ec_group()?.coset_curve()?;
233 let key = CoseKeyBuilder::new_ec2_pub_key(curve, x, y).algorithm(ES256_ALGO).build();
Alice Wanga78d3f02023-09-13 12:39:16 +0000234 Ok(key)
235 }
236
237 /// Returns the x and y coordinates of the public key.
Alice Wang306c8e22023-11-29 12:40:43 +0000238 fn public_key_coordinates(&self) -> Result<(Vec<u8>, Vec<u8>)> {
Alice Wanga78d3f02023-09-13 12:39:16 +0000239 let ec_group = self.ec_group()?;
240 let ec_point = self.public_key_ec_point()?;
241 let mut x = BigNum::new()?;
242 let mut y = BigNum::new()?;
243 let ctx = ptr::null_mut();
244 // SAFETY: All the parameters are checked non-null and initialized when needed.
245 // The last parameter `ctx` is generated when needed inside the function.
246 let ret = unsafe {
Alice Wang306c8e22023-11-29 12:40:43 +0000247 EC_POINT_get_affine_coordinates(
248 ec_group.as_ref(),
249 ec_point,
250 x.as_mut_ptr(),
251 y.as_mut_ptr(),
252 ctx,
253 )
Alice Wanga78d3f02023-09-13 12:39:16 +0000254 };
Alice Wangc8f88f52023-09-25 14:02:17 +0000255 check_int_result(ret, ApiName::EC_POINT_get_affine_coordinates)?;
Alice Wang306c8e22023-11-29 12:40:43 +0000256 let len = ec_group.affine_coordinate_size()?;
257 Ok((x.to_padded_vec(len)?, y.to_padded_vec(len)?))
Alice Wanga78d3f02023-09-13 12:39:16 +0000258 }
259
260 /// Returns a pointer to the public key point inside `EC_KEY`. The memory region pointed
261 /// by the pointer is owned by the `EC_KEY`.
262 fn public_key_ec_point(&self) -> Result<*const EC_POINT> {
263 let ec_point =
264 // SAFETY: It is safe since the key pair has been generated and stored in the
265 // `EC_KEY` pointer.
266 unsafe { EC_KEY_get0_public_key(self.0.as_ptr()) };
267 if ec_point.is_null() {
Alice Wang47287e72023-09-29 13:14:33 +0000268 Err(to_call_failed_error(ApiName::EC_KEY_get0_public_key))
Alice Wanga78d3f02023-09-13 12:39:16 +0000269 } else {
270 Ok(ec_point)
271 }
272 }
273
274 /// Returns a pointer to the `EC_GROUP` object inside `EC_KEY`. The memory region pointed
275 /// by the pointer is owned by the `EC_KEY`.
Alice Wang306c8e22023-11-29 12:40:43 +0000276 fn ec_group(&self) -> Result<EcGroup<'_>> {
Alice Wanga78d3f02023-09-13 12:39:16 +0000277 let group =
278 // SAFETY: It is safe since the key pair has been generated and stored in the
279 // `EC_KEY` pointer.
280 unsafe { EC_KEY_get0_group(self.0.as_ptr()) };
281 if group.is_null() {
Alice Wang47287e72023-09-29 13:14:33 +0000282 Err(to_call_failed_error(ApiName::EC_KEY_get0_group))
Alice Wanga78d3f02023-09-13 12:39:16 +0000283 } else {
Alice Wang306c8e22023-11-29 12:40:43 +0000284 // SAFETY: The pointer should be valid and points to an initialized `EC_GROUP`
285 // since it is read from a valid `EC_KEY`.
286 Ok(EcGroup(unsafe { &*group }))
Alice Wanga78d3f02023-09-13 12:39:16 +0000287 }
288 }
Alice Wang7b2ab942023-09-12 13:04:42 +0000289
Alice Wang000595b2023-10-02 13:46:45 +0000290 /// Constructs an `EcKey` instance from the provided DER-encoded ECPrivateKey slice.
291 ///
292 /// Currently, only the EC P-256 curve is supported.
293 pub fn from_ec_private_key(der_encoded_ec_private_key: &[u8]) -> Result<Self> {
294 // SAFETY: This function only returns a pointer to a static object, and the
295 // return is checked below.
296 let ec_group = unsafe {
297 EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1) // EC P-256 CURVE Nid
298 };
299 if ec_group.is_null() {
300 return Err(to_call_failed_error(ApiName::EC_GROUP_new_by_curve_name));
301 }
302 let mut cbs = Cbs::new(der_encoded_ec_private_key);
303 // SAFETY: The function only reads bytes from the buffer managed by the valid `CBS`
304 // object, and the returned EC_KEY is checked.
305 let ec_key = unsafe { EC_KEY_parse_private_key(cbs.as_mut(), ec_group) };
306
307 let ec_key = NonNull::new(ec_key)
308 .map(Self)
Alice Wangf6e02272024-03-20 10:11:30 +0000309 .ok_or_else(|| to_call_failed_error(ApiName::EC_KEY_parse_private_key))?;
Alice Wang000595b2023-10-02 13:46:45 +0000310 ec_key.check_key()?;
311 Ok(ec_key)
312 }
313
Alice Wang7b2ab942023-09-12 13:04:42 +0000314 /// Returns the DER-encoded ECPrivateKey structure described in RFC 5915 Section 3:
315 ///
316 /// https://datatracker.ietf.org/doc/html/rfc5915#section-3
Alice Wang000595b2023-10-02 13:46:45 +0000317 pub fn ec_private_key(&self) -> Result<ZVec> {
Alice Wang7b2ab942023-09-12 13:04:42 +0000318 const CAPACITY: usize = 256;
319 let mut buf = Zeroizing::new([0u8; CAPACITY]);
Alan Stokesb1f64ee2023-09-25 10:38:13 +0100320 let mut cbb = CbbFixed::new(buf.as_mut());
Alice Wang7b2ab942023-09-12 13:04:42 +0000321 let enc_flags = 0;
322 let ret =
323 // SAFETY: The function only write bytes to the buffer managed by the valid `CBB`
324 // object, and the key has been allocated by BoringSSL.
Alan Stokesb1f64ee2023-09-25 10:38:13 +0100325 unsafe { EC_KEY_marshal_private_key(cbb.as_mut(), self.0.as_ptr(), enc_flags) };
Alice Wang7b2ab942023-09-12 13:04:42 +0000326
Alice Wangc8f88f52023-09-25 14:02:17 +0000327 check_int_result(ret, ApiName::EC_KEY_marshal_private_key)?;
Alice Wang7b2ab942023-09-12 13:04:42 +0000328 // SAFETY: This is safe because the CBB pointer is a valid pointer initialized with
329 // `CBB_init_fixed()`.
Alice Wangc8f88f52023-09-25 14:02:17 +0000330 check_int_result(unsafe { CBB_flush(cbb.as_mut()) }, ApiName::CBB_flush)?;
Alice Wang7b2ab942023-09-12 13:04:42 +0000331 // SAFETY: This is safe because the CBB pointer is initialized with `CBB_init_fixed()`,
332 // and it has been flushed, thus it has no active children.
Alan Stokesb1f64ee2023-09-25 10:38:13 +0100333 let len = unsafe { CBB_len(cbb.as_ref()) };
Alice Wangf6e02272024-03-20 10:11:30 +0000334 Ok(buf.get(0..len).ok_or_else(|| to_call_failed_error(ApiName::CBB_len))?.to_vec().into())
Alice Wang7b2ab942023-09-12 13:04:42 +0000335 }
336}
337
Alan Stokesb2f52fb2024-05-09 10:12:55 +0100338/// Convert a R | S format NIST signature to a DER-encoded form.
339fn ec_cose_signature_to_der(signature: &[u8]) -> Result<Vec<u8>> {
340 let mut ec_sig = EcSignature::new()?;
341 ec_sig.load_from_nist(signature)?;
342 ec_sig.to_der()
343}
344
345/// Wrapper for an `ECDSA_SIG` object representing an EC signature.
346struct EcSignature(NonNull<ECDSA_SIG>);
347
348impl EcSignature {
349 /// Allocate a signature object.
350 fn new() -> Result<Self> {
351 // SAFETY: We take ownership of the returned pointer if it is non-null.
352 let signature = unsafe { ECDSA_SIG_new() };
353
354 let signature =
355 NonNull::new(signature).ok_or_else(|| to_call_failed_error(ApiName::ECDSA_SIG_new))?;
356 Ok(Self(signature))
357 }
358
359 /// Populate the signature parameters from a NIST encoding (R | S).
360 fn load_from_nist(&mut self, signature: &[u8]) -> Result<()> {
361 let coord_bytes = signature.len() / 2;
362 if signature.len() != 2 * coord_bytes {
363 return Err(Error::InternalError);
364 }
365 let mut r = BigNum::from_slice(&signature[..coord_bytes])?;
366 let mut s = BigNum::from_slice(&signature[coord_bytes..])?;
367
368 check_int_result(
369 // SAFETY: The ECDSA_SIG was properly allocated and not yet freed. We have ownership
370 // of the two BigNums and they are not null.
371 unsafe { ECDSA_SIG_set0(self.0.as_mut(), r.as_mut_ptr(), s.as_mut_ptr()) },
372 ApiName::ECDSA_SIG_set0,
373 )?;
374
375 // On success, the ECDSA_SIG has taken ownership of the BigNums.
376 mem::forget(r);
377 mem::forget(s);
378
379 Ok(())
380 }
381
382 /// Return the signature encoded as DER.
383 fn to_der(&self) -> Result<Vec<u8>> {
384 // SAFETY: The ECDSA_SIG was properly allocated and not yet freed. Null is a valid
385 // value for `outp`; no output is written.
386 let len = unsafe { i2d_ECDSA_SIG(self.0.as_ptr(), ptr::null_mut()) };
387 if len < 0 {
388 return Err(to_call_failed_error(ApiName::i2d_ECDSA_SIG));
389 }
390
391 let mut buf = vec![0; len.try_into().map_err(|_| Error::InternalError)?];
392 let outp = &mut buf.as_mut_ptr();
393 // SAFETY: The ECDSA_SIG was properly allocated and not yet freed. `outp` is a non-null
394 // pointer to a mutable buffer of the right size to which the result will be written.
395 let final_len = unsafe { i2d_ECDSA_SIG(self.0.as_ptr(), outp) };
396 if final_len < 0 {
397 return Err(to_call_failed_error(ApiName::i2d_ECDSA_SIG));
398 }
399 // The input hasn't changed, so the length of the output shouldn't have. If it has we
400 // already have potentially undefined behavior so panic.
401 assert_eq!(
402 len, final_len,
403 "i2d_ECDSA_SIG returned inconsistent lengths: {len}, {final_len}"
404 );
405
406 Ok(buf)
407 }
408}
409
410impl Drop for EcSignature {
411 fn drop(&mut self) {
412 // SAFETY: The pointer was allocated by `ECDSA_SIG_new`.
413 unsafe { ECDSA_SIG_free(self.0.as_mut()) };
414 }
415}
416
Alice Wang306c8e22023-11-29 12:40:43 +0000417/// Wrapper of an `EC_GROUP` reference.
418struct EcGroup<'a>(&'a EC_GROUP);
419
420impl<'a> EcGroup<'a> {
421 /// Returns the NID that identifies the EC group of the key.
422 fn curve_nid(&self) -> i32 {
423 // SAFETY: It is safe since the inner pointer is valid and points to an initialized
424 // instance of `EC_GROUP`.
425 unsafe { EC_GROUP_get_curve_name(self.as_ref()) }
426 }
427
428 fn coset_curve(&self) -> Result<iana::EllipticCurve> {
429 #[allow(non_upper_case_globals)]
430 match self.curve_nid() {
431 NID_X9_62_prime256v1 => Ok(P256_CURVE),
432 NID_secp384r1 => Ok(P384_CURVE),
433 name => {
434 error!("Unsupported curve NID: {}", name);
435 Err(Error::Unimplemented)
436 }
437 }
438 }
439
440 fn affine_coordinate_size(&self) -> Result<usize> {
441 #[allow(non_upper_case_globals)]
442 match self.curve_nid() {
443 NID_X9_62_prime256v1 => Ok(P256_AFFINE_COORDINATE_SIZE),
444 NID_secp384r1 => Ok(P384_AFFINE_COORDINATE_SIZE),
445 name => {
446 error!("Unsupported curve NID: {}", name);
447 Err(Error::Unimplemented)
448 }
449 }
450 }
451
452 fn check_affine_coordinate_size(&self, coordinate: &[u8]) -> Result<()> {
453 let expected_len = self.affine_coordinate_size()?;
454 if expected_len == coordinate.len() {
455 Ok(())
456 } else {
457 error!(
458 "The size of the affine coordinate '{}' does not match the expected size '{}'",
459 coordinate.len(),
460 expected_len
461 );
462 Err(Error::CoseKeyDecodingFailed)
463 }
464 }
465}
466
467impl<'a> AsRef<EC_GROUP> for EcGroup<'a> {
468 fn as_ref(&self) -> &EC_GROUP {
469 self.0
Alice Wang9bd98092023-11-10 14:08:12 +0000470 }
471}
472
Alice Wang7b2ab942023-09-12 13:04:42 +0000473/// A u8 vector that is zeroed when dropped.
474#[derive(Zeroize, ZeroizeOnDrop)]
475pub struct ZVec(Vec<u8>);
476
477impl ZVec {
478 /// Extracts a slice containing the entire vector.
479 pub fn as_slice(&self) -> &[u8] {
480 &self.0[..]
481 }
482}
483
484impl From<Vec<u8>> for ZVec {
485 fn from(v: Vec<u8>) -> Self {
486 Self(v)
487 }
488}
489
Alice Wanga78d3f02023-09-13 12:39:16 +0000490struct BigNum(NonNull<BIGNUM>);
491
492impl Drop for BigNum {
493 fn drop(&mut self) {
494 // SAFETY: The pointer has been created with `BN_new`.
495 unsafe { BN_clear_free(self.as_mut_ptr()) }
496 }
497}
498
499impl BigNum {
Alice Wang9bd98092023-11-10 14:08:12 +0000500 fn from_slice(x: &[u8]) -> Result<Self> {
501 // SAFETY: The function reads `x` within its bounds, and the returned
502 // pointer is checked below.
503 let bn = unsafe { BN_bin2bn(x.as_ptr(), x.len(), ptr::null_mut()) };
Alice Wangf6e02272024-03-20 10:11:30 +0000504 NonNull::new(bn).map(Self).ok_or_else(|| to_call_failed_error(ApiName::BN_bin2bn))
Alice Wang9bd98092023-11-10 14:08:12 +0000505 }
506
Alice Wanga78d3f02023-09-13 12:39:16 +0000507 fn new() -> Result<Self> {
508 // SAFETY: The returned pointer is checked below.
509 let bn = unsafe { BN_new() };
Alice Wangf6e02272024-03-20 10:11:30 +0000510 NonNull::new(bn).map(Self).ok_or_else(|| to_call_failed_error(ApiName::BN_new))
Alice Wanga78d3f02023-09-13 12:39:16 +0000511 }
512
Alice Wang306c8e22023-11-29 12:40:43 +0000513 /// Converts the `BigNum` to a big-endian integer. The integer is padded with leading zeros up
514 /// to size `len`. The conversion fails if `len` is smaller than the size of the integer.
515 fn to_padded_vec(&self, len: usize) -> Result<Vec<u8>> {
516 let mut num = vec![0u8; len];
517 // SAFETY: The `BIGNUM` pointer has been created with `BN_new`.
518 let ret = unsafe { BN_bn2bin_padded(num.as_mut_ptr(), num.len(), self.0.as_ptr()) };
519 check_int_result(ret, ApiName::BN_bn2bin_padded)?;
520 Ok(num)
521 }
522
Alice Wanga78d3f02023-09-13 12:39:16 +0000523 fn as_mut_ptr(&mut self) -> *mut BIGNUM {
524 self.0.as_ptr()
525 }
526}
527
Alice Wang9bd98092023-11-10 14:08:12 +0000528impl AsRef<BIGNUM> for BigNum {
529 fn as_ref(&self) -> &BIGNUM {
530 // SAFETY: The pointer is valid and points to an initialized instance of `BIGNUM`
531 // when the instance was created.
532 unsafe { self.0.as_ref() }
533 }
534}