1 // 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
18 use crate::cbb::CbbFixed;
19 use crate::cbs::Cbs;
20 use crate::util::{check_int_result, to_call_failed_error};
21 use alloc::vec;
22 use alloc::vec::Vec;
23 use bssl_avf_error::{ApiName, Error, Result};
24 use bssl_sys::{
25 i2d_ECDSA_SIG, BN_bin2bn, BN_bn2bin_padded, BN_clear_free, BN_new, CBB_flush, CBB_len,
26 ECDSA_SIG_free, ECDSA_SIG_from_bytes, ECDSA_SIG_get0_r, ECDSA_SIG_get0_s, ECDSA_SIG_new,
27 ECDSA_SIG_set0, ECDSA_sign, ECDSA_size, ECDSA_verify, EC_GROUP_get_curve_name,
28 EC_GROUP_new_by_curve_name, EC_KEY_check_key, EC_KEY_free, EC_KEY_generate_key,
29 EC_KEY_get0_group, EC_KEY_get0_public_key, EC_KEY_marshal_private_key,
30 EC_KEY_new_by_curve_name, EC_KEY_parse_private_key, EC_KEY_set_public_key_affine_coordinates,
31 EC_POINT_get_affine_coordinates, NID_X9_62_prime256v1, NID_secp384r1, BIGNUM, ECDSA_SIG,
32 EC_GROUP, EC_KEY, EC_POINT,
33 };
34 use cbor_util::{get_label_value, get_label_value_as_bytes};
35 use ciborium::Value;
36 use core::mem;
37 use core::ptr::{self, NonNull};
38 use coset::{
39 iana::{self, EnumI64},
40 CborSerializable, CoseKey, CoseKeyBuilder, KeyType, Label,
41 };
42 use log::error;
43 use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
44
45 const ES256_ALGO: iana::Algorithm = iana::Algorithm::ES256;
46 const P256_CURVE: iana::EllipticCurve = iana::EllipticCurve::P_256;
47 const P384_CURVE: iana::EllipticCurve = iana::EllipticCurve::P_384;
48 const P256_AFFINE_COORDINATE_SIZE: usize = 32;
49 const P384_AFFINE_COORDINATE_SIZE: usize = 48;
50
51 /// Wrapper of an `EC_KEY` object, representing a public or private EC key.
52 pub struct EcKey(pub(crate) NonNull<EC_KEY>);
53
54 impl Drop for EcKey {
drop(&mut self)55 fn drop(&mut self) {
56 // SAFETY: It is safe because the key has been allocated by BoringSSL and isn't
57 // used after this.
58 unsafe { EC_KEY_free(self.0.as_ptr()) }
59 }
60 }
61
62 impl EcKey {
63 /// Creates a new EC P-256 key pair.
new_p256() -> Result<Self>64 pub fn new_p256() -> Result<Self> {
65 // SAFETY: The returned pointer is checked below.
66 let ec_key = unsafe {
67 EC_KEY_new_by_curve_name(NID_X9_62_prime256v1) // EC P-256 CURVE Nid
68 };
69 NonNull::new(ec_key)
70 .map(Self)
71 .ok_or_else(|| to_call_failed_error(ApiName::EC_KEY_new_by_curve_name))
72 }
73
74 /// Creates a new EC P-384 key pair.
new_p384() -> Result<Self>75 pub fn new_p384() -> Result<Self> {
76 // SAFETY: The returned pointer is checked below.
77 let ec_key = unsafe {
78 EC_KEY_new_by_curve_name(NID_secp384r1) // EC P-384 CURVE Nid
79 };
80 NonNull::new(ec_key)
81 .map(Self)
82 .ok_or_else(|| to_call_failed_error(ApiName::EC_KEY_new_by_curve_name))
83 }
84
85 /// Constructs an `EcKey` instance from the provided COSE_Key encoded public key slice.
from_cose_public_key_slice(cose_key: &[u8]) -> Result<Self>86 pub fn from_cose_public_key_slice(cose_key: &[u8]) -> Result<Self> {
87 let cose_key = CoseKey::from_slice(cose_key).map_err(|e| {
88 error!("Failed to deserialize COSE_Key: {e:?}");
89 Error::CoseKeyDecodingFailed
90 })?;
91 Self::from_cose_public_key(&cose_key)
92 }
93
94 /// Constructs an `EcKey` instance from the provided `COSE_Key`.
95 ///
96 /// The lifetime of the returned `EcKey` is not tied to the lifetime of the `cose_key`,
97 /// because the affine coordinates stored in the `cose_key` are copied into the `EcKey`.
98 ///
99 /// Currently, only the EC P-256 and P-384 curves are supported.
from_cose_public_key(cose_key: &CoseKey) -> Result<Self>100 pub fn from_cose_public_key(cose_key: &CoseKey) -> Result<Self> {
101 if cose_key.kty != KeyType::Assigned(iana::KeyType::EC2) {
102 error!("Only EC2 keys are supported. Key type in the COSE Key: {:?}", cose_key.kty);
103 return Err(Error::Unimplemented);
104 }
105 let ec_key =
106 match get_label_value(cose_key, Label::Int(iana::Ec2KeyParameter::Crv.to_i64()))? {
107 crv if crv == &Value::from(P256_CURVE.to_i64()) => EcKey::new_p256()?,
108 crv if crv == &Value::from(P384_CURVE.to_i64()) => EcKey::new_p384()?,
109 crv => {
110 error!(
111 "Only EC P-256 and P-384 curves are supported. \
112 Curve type in the COSE Key: {crv:?}"
113 );
114 return Err(Error::Unimplemented);
115 }
116 };
117 let x = get_label_value_as_bytes(cose_key, Label::Int(iana::Ec2KeyParameter::X.to_i64()))?;
118 let y = get_label_value_as_bytes(cose_key, Label::Int(iana::Ec2KeyParameter::Y.to_i64()))?;
119
120 let group = ec_key.ec_group()?;
121 group.check_affine_coordinate_size(x)?;
122 group.check_affine_coordinate_size(y)?;
123
124 let x = BigNum::from_slice(x)?;
125 let y = BigNum::from_slice(y)?;
126
127 // SAFETY: All the parameters are checked non-null and initialized.
128 // The function only reads the coordinates x and y within their bounds.
129 let ret = unsafe {
130 EC_KEY_set_public_key_affine_coordinates(ec_key.0.as_ptr(), x.as_ref(), y.as_ref())
131 };
132 check_int_result(ret, ApiName::EC_KEY_set_public_key_affine_coordinates)?;
133 ec_key.check_key()?;
134 Ok(ec_key)
135 }
136
137 /// Performs several checks on the key. See BoringSSL doc for more details:
138 ///
139 /// https://commondatastorage.googleapis.com/chromium-boringssl-docs/ec_key.h.html#EC_KEY_check_key
check_key(&self) -> Result<()>140 pub fn check_key(&self) -> Result<()> {
141 // SAFETY: This function only reads the `EC_KEY` pointer, the non-null check is performed
142 // within the function.
143 let ret = unsafe { EC_KEY_check_key(self.0.as_ptr()) };
144 check_int_result(ret, ApiName::EC_KEY_check_key)
145 }
146
147 /// Verifies the DER-encoded ECDSA `signature` of the `digest` with the current `EcKey`.
148 ///
149 /// Returns Ok(()) if the verification succeeds, otherwise an error will be returned.
ecdsa_verify_der(&self, signature: &[u8], digest: &[u8]) -> Result<()>150 pub fn ecdsa_verify_der(&self, signature: &[u8], digest: &[u8]) -> Result<()> {
151 // The `type` argument should be 0 as required in the BoringSSL spec.
152 const TYPE: i32 = 0;
153
154 // SAFETY: This function only reads the given data within its bounds.
155 // The `EC_KEY` passed to this function has been initialized and checked non-null.
156 let ret = unsafe {
157 ECDSA_verify(
158 TYPE,
159 digest.as_ptr(),
160 digest.len(),
161 signature.as_ptr(),
162 signature.len(),
163 self.0.as_ptr(),
164 )
165 };
166 check_int_result(ret, ApiName::ECDSA_verify)
167 }
168
169 /// Verifies the COSE-encoded (R | S, see RFC8152) ECDSA `signature` of the `digest` with the
170 /// current `EcKey`.
171 ///
172 /// Returns Ok(()) if the verification succeeds, otherwise an error will be returned.
ecdsa_verify_cose(&self, signature: &[u8], digest: &[u8]) -> Result<()>173 pub fn ecdsa_verify_cose(&self, signature: &[u8], digest: &[u8]) -> Result<()> {
174 let signature = ec_cose_signature_to_der(signature)?;
175 self.ecdsa_verify_der(&signature, digest)
176 }
177
178 /// Signs the `digest` with the current `EcKey` using ECDSA.
179 ///
180 /// Returns the DER-encoded ECDSA signature.
ecdsa_sign_der(&self, digest: &[u8]) -> Result<Vec<u8>>181 pub fn ecdsa_sign_der(&self, digest: &[u8]) -> Result<Vec<u8>> {
182 // The `type` argument should be 0 as required in the BoringSSL spec.
183 const TYPE: i32 = 0;
184
185 let mut signature = vec![0u8; self.ecdsa_size()?];
186 let mut signature_len = 0;
187 // SAFETY: This function only reads the given data within its bounds.
188 // The `EC_KEY` passed to this function has been initialized and checked non-null.
189 let ret = unsafe {
190 ECDSA_sign(
191 TYPE,
192 digest.as_ptr(),
193 digest.len(),
194 signature.as_mut_ptr(),
195 &mut signature_len,
196 self.0.as_ptr(),
197 )
198 };
199 check_int_result(ret, ApiName::ECDSA_sign)?;
200 if signature.len() < (signature_len as usize) {
201 Err(to_call_failed_error(ApiName::ECDSA_sign))
202 } else {
203 signature.truncate(signature_len as usize);
204 Ok(signature)
205 }
206 }
207
208 /// Signs the `digest` with the current `EcKey` using ECDSA.
209 ///
210 /// Returns the COSE-encoded (R | S, see RFC8152) ECDSA signature.
ecdsa_sign_cose(&self, digest: &[u8]) -> Result<Vec<u8>>211 pub fn ecdsa_sign_cose(&self, digest: &[u8]) -> Result<Vec<u8>> {
212 let signature = self.ecdsa_sign_der(digest)?;
213 let coord_bytes = self.ec_group()?.affine_coordinate_size()?;
214 ec_der_signature_to_cose(&signature, coord_bytes)
215 }
216
217 /// Returns the maximum size of an ECDSA signature using the current `EcKey`.
ecdsa_size(&self) -> Result<usize>218 fn ecdsa_size(&self) -> Result<usize> {
219 // SAFETY: This function only reads the `EC_KEY` that has been initialized
220 // and checked non-null when this instance is created.
221 let size = unsafe { ECDSA_size(self.0.as_ptr()) };
222 if size == 0 {
223 Err(to_call_failed_error(ApiName::ECDSA_size))
224 } else {
225 Ok(size)
226 }
227 }
228
229 /// Generates a random, private key, calculates the corresponding public key and stores both
230 /// in the `EC_KEY`.
generate_key(&mut self) -> Result<()>231 pub fn generate_key(&mut self) -> Result<()> {
232 // SAFETY: The non-null pointer is created with `EC_KEY_new_by_curve_name` and should
233 // point to a valid `EC_KEY`.
234 // The randomness is provided by `getentropy()` in `vmbase`.
235 let ret = unsafe { EC_KEY_generate_key(self.0.as_ptr()) };
236 check_int_result(ret, ApiName::EC_KEY_generate_key)
237 }
238
239 /// Returns the `CoseKey` for the public key.
cose_public_key(&self) -> Result<CoseKey>240 pub fn cose_public_key(&self) -> Result<CoseKey> {
241 let (x, y) = self.public_key_coordinates()?;
242 let curve = self.ec_group()?.coset_curve()?;
243 let key = CoseKeyBuilder::new_ec2_pub_key(curve, x, y).algorithm(ES256_ALGO).build();
244 Ok(key)
245 }
246
247 /// Returns the x and y coordinates of the public key.
public_key_coordinates(&self) -> Result<(Vec<u8>, Vec<u8>)>248 fn public_key_coordinates(&self) -> Result<(Vec<u8>, Vec<u8>)> {
249 let ec_group = self.ec_group()?;
250 let ec_point = self.public_key_ec_point()?;
251 let mut x = BigNum::new()?;
252 let mut y = BigNum::new()?;
253 let ctx = ptr::null_mut();
254 // SAFETY: All the parameters are checked non-null and initialized when needed.
255 // The last parameter `ctx` is generated when needed inside the function.
256 let ret = unsafe {
257 EC_POINT_get_affine_coordinates(
258 ec_group.as_ref(),
259 ec_point,
260 x.as_mut_ptr(),
261 y.as_mut_ptr(),
262 ctx,
263 )
264 };
265 check_int_result(ret, ApiName::EC_POINT_get_affine_coordinates)?;
266 let len = ec_group.affine_coordinate_size()?;
267 Ok((x.to_padded_vec(len)?, y.to_padded_vec(len)?))
268 }
269
270 /// Returns a pointer to the public key point inside `EC_KEY`. The memory region pointed
271 /// by the pointer is owned by the `EC_KEY`.
public_key_ec_point(&self) -> Result<*const EC_POINT>272 fn public_key_ec_point(&self) -> Result<*const EC_POINT> {
273 let ec_point =
274 // SAFETY: It is safe since the key pair has been generated and stored in the
275 // `EC_KEY` pointer.
276 unsafe { EC_KEY_get0_public_key(self.0.as_ptr()) };
277 if ec_point.is_null() {
278 Err(to_call_failed_error(ApiName::EC_KEY_get0_public_key))
279 } else {
280 Ok(ec_point)
281 }
282 }
283
284 /// Returns a pointer to the `EC_GROUP` object inside `EC_KEY`. The memory region pointed
285 /// by the pointer is owned by the `EC_KEY`.
ec_group(&self) -> Result<EcGroup<'_>>286 fn ec_group(&self) -> Result<EcGroup<'_>> {
287 let group =
288 // SAFETY: It is safe since the key pair has been generated and stored in the
289 // `EC_KEY` pointer.
290 unsafe { EC_KEY_get0_group(self.0.as_ptr()) };
291 if group.is_null() {
292 Err(to_call_failed_error(ApiName::EC_KEY_get0_group))
293 } else {
294 // SAFETY: The pointer should be valid and points to an initialized `EC_GROUP`
295 // since it is read from a valid `EC_KEY`.
296 Ok(EcGroup(unsafe { &*group }))
297 }
298 }
299
300 /// Constructs an `EcKey` instance from the provided DER-encoded ECPrivateKey slice.
301 ///
302 /// Currently, only the EC P-256 curve is supported.
from_ec_private_key(der_encoded_ec_private_key: &[u8]) -> Result<Self>303 pub fn from_ec_private_key(der_encoded_ec_private_key: &[u8]) -> Result<Self> {
304 // SAFETY: This function only returns a pointer to a static object, and the
305 // return is checked below.
306 let ec_group = unsafe {
307 EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1) // EC P-256 CURVE Nid
308 };
309 if ec_group.is_null() {
310 return Err(to_call_failed_error(ApiName::EC_GROUP_new_by_curve_name));
311 }
312 let mut cbs = Cbs::new(der_encoded_ec_private_key);
313 // SAFETY: The function only reads bytes from the buffer managed by the valid `CBS`
314 // object, and the returned EC_KEY is checked.
315 let ec_key = unsafe { EC_KEY_parse_private_key(cbs.as_mut(), ec_group) };
316
317 let ec_key = NonNull::new(ec_key)
318 .map(Self)
319 .ok_or_else(|| to_call_failed_error(ApiName::EC_KEY_parse_private_key))?;
320 ec_key.check_key()?;
321 Ok(ec_key)
322 }
323
324 /// Returns the DER-encoded ECPrivateKey structure described in RFC 5915 Section 3:
325 ///
326 /// https://datatracker.ietf.org/doc/html/rfc5915#section-3
ec_private_key(&self) -> Result<ZVec>327 pub fn ec_private_key(&self) -> Result<ZVec> {
328 const CAPACITY: usize = 256;
329 let mut buf = Zeroizing::new([0u8; CAPACITY]);
330 let mut cbb = CbbFixed::new(buf.as_mut());
331 let enc_flags = 0;
332 let ret =
333 // SAFETY: The function only write bytes to the buffer managed by the valid `CBB`
334 // object, and the key has been allocated by BoringSSL.
335 unsafe { EC_KEY_marshal_private_key(cbb.as_mut(), self.0.as_ptr(), enc_flags) };
336
337 check_int_result(ret, ApiName::EC_KEY_marshal_private_key)?;
338 // SAFETY: This is safe because the CBB pointer is a valid pointer initialized with
339 // `CBB_init_fixed()`.
340 check_int_result(unsafe { CBB_flush(cbb.as_mut()) }, ApiName::CBB_flush)?;
341 // SAFETY: This is safe because the CBB pointer is initialized with `CBB_init_fixed()`,
342 // and it has been flushed, thus it has no active children.
343 let len = unsafe { CBB_len(cbb.as_ref()) };
344 Ok(buf.get(0..len).ok_or_else(|| to_call_failed_error(ApiName::CBB_len))?.to_vec().into())
345 }
346 }
347
348 /// Convert a COSE format (R | S) ECDSA signature to a DER-encoded form.
ec_cose_signature_to_der(signature: &[u8]) -> Result<Vec<u8>>349 fn ec_cose_signature_to_der(signature: &[u8]) -> Result<Vec<u8>> {
350 let mut ec_sig = EcSignature::new()?;
351 ec_sig.load_from_cose(signature)?;
352 ec_sig.to_der()
353 }
354
355 /// Convert a DER-encoded signature to COSE format (R | S).
ec_der_signature_to_cose(signature: &[u8], coord_bytes: usize) -> Result<Vec<u8>>356 fn ec_der_signature_to_cose(signature: &[u8], coord_bytes: usize) -> Result<Vec<u8>> {
357 let ec_sig = EcSignature::new_from_der(signature)?;
358 ec_sig.to_cose(coord_bytes)
359 }
360
361 /// Wrapper for an `ECDSA_SIG` object representing an EC signature.
362 struct EcSignature(NonNull<ECDSA_SIG>);
363
364 impl EcSignature {
365 /// Allocate a signature object.
new() -> Result<Self>366 fn new() -> Result<Self> {
367 // SAFETY: We take ownership of the returned pointer if it is non-null.
368 let signature = unsafe { ECDSA_SIG_new() };
369
370 let signature =
371 NonNull::new(signature).ok_or_else(|| to_call_failed_error(ApiName::ECDSA_SIG_new))?;
372 Ok(Self(signature))
373 }
374
375 /// Populate the signature parameters from a COSE encoding (R | S).
load_from_cose(&mut self, signature: &[u8]) -> Result<()>376 fn load_from_cose(&mut self, signature: &[u8]) -> Result<()> {
377 let coord_bytes = signature.len() / 2;
378 if signature.len() != 2 * coord_bytes {
379 return Err(Error::InternalError);
380 }
381 let mut r = BigNum::from_slice(&signature[..coord_bytes])?;
382 let mut s = BigNum::from_slice(&signature[coord_bytes..])?;
383
384 check_int_result(
385 // SAFETY: The ECDSA_SIG was properly allocated and not yet freed. We have ownership
386 // of the two BigNums and they are not null.
387 unsafe { ECDSA_SIG_set0(self.0.as_mut(), r.as_mut_ptr(), s.as_mut_ptr()) },
388 ApiName::ECDSA_SIG_set0,
389 )?;
390
391 // On success, the ECDSA_SIG has taken ownership of the BigNums.
392 mem::forget(r);
393 mem::forget(s);
394
395 Ok(())
396 }
397
to_cose(&self, coord_bytes: usize) -> Result<Vec<u8>>398 fn to_cose(&self, coord_bytes: usize) -> Result<Vec<u8>> {
399 let mut result = vec![0u8; coord_bytes.checked_mul(2).unwrap()];
400 let (r_bytes, s_bytes) = result.split_at_mut(coord_bytes);
401
402 // SAFETY: The ECDSA_SIG was properly allocated and not yet freed. Always returns a valid
403 // non-null, non-owning pointer.
404 let r = unsafe { ECDSA_SIG_get0_r(self.0.as_ptr()) };
405 check_int_result(
406 // SAFETY: The r pointer is known to be valid. Only writes within the destination
407 // slice.
408 unsafe { BN_bn2bin_padded(r_bytes.as_mut_ptr(), r_bytes.len(), r) },
409 ApiName::BN_bn2bin_padded,
410 )?;
411
412 // SAFETY: The ECDSA_SIG was properly allocated and not yet freed. Always returns a valid
413 // non-null, non-owning pointer.
414 let s = unsafe { ECDSA_SIG_get0_s(self.0.as_ptr()) };
415 check_int_result(
416 // SAFETY: The r pointer is known to be valid. Only writes within the destination
417 // slice.
418 unsafe { BN_bn2bin_padded(s_bytes.as_mut_ptr(), s_bytes.len(), s) },
419 ApiName::BN_bn2bin_padded,
420 )?;
421
422 Ok(result)
423 }
424
425 /// Populate the signature parameters from a DER encoding
new_from_der(signature: &[u8]) -> Result<Self>426 fn new_from_der(signature: &[u8]) -> Result<Self> {
427 // SAFETY: Only reads within the bounds of the slice. Returns a pointer to a new ECDSA_SIG
428 // which we take ownership of, or null on error which we check.
429 let signature = unsafe { ECDSA_SIG_from_bytes(signature.as_ptr(), signature.len()) };
430
431 let signature = NonNull::new(signature)
432 .ok_or_else(|| to_call_failed_error(ApiName::ECDSA_SIG_from_bytes))?;
433 Ok(Self(signature))
434 }
435
436 /// Return the signature encoded as DER.
to_der(&self) -> Result<Vec<u8>>437 fn to_der(&self) -> Result<Vec<u8>> {
438 // SAFETY: The ECDSA_SIG was properly allocated and not yet freed. Null is a valid
439 // value for `outp`; no output is written.
440 let len = unsafe { i2d_ECDSA_SIG(self.0.as_ptr(), ptr::null_mut()) };
441 if len < 0 {
442 return Err(to_call_failed_error(ApiName::i2d_ECDSA_SIG));
443 }
444
445 let mut buf = vec![0; len.try_into().map_err(|_| Error::InternalError)?];
446 let outp = &mut buf.as_mut_ptr();
447 // SAFETY: The ECDSA_SIG was properly allocated and not yet freed. `outp` is a non-null
448 // pointer to a mutable buffer of the right size to which the result will be written.
449 let final_len = unsafe { i2d_ECDSA_SIG(self.0.as_ptr(), outp) };
450 if final_len < 0 {
451 return Err(to_call_failed_error(ApiName::i2d_ECDSA_SIG));
452 }
453 // The input hasn't changed, so the length of the output shouldn't have. If it has we
454 // already have potentially undefined behavior so panic.
455 assert_eq!(
456 len, final_len,
457 "i2d_ECDSA_SIG returned inconsistent lengths: {len}, {final_len}"
458 );
459
460 Ok(buf)
461 }
462 }
463
464 impl Drop for EcSignature {
drop(&mut self)465 fn drop(&mut self) {
466 // SAFETY: The pointer was allocated by `ECDSA_SIG_new`.
467 unsafe { ECDSA_SIG_free(self.0.as_mut()) };
468 }
469 }
470
471 /// Wrapper of an `EC_GROUP` reference.
472 struct EcGroup<'a>(&'a EC_GROUP);
473
474 impl<'a> EcGroup<'a> {
475 /// Returns the NID that identifies the EC group of the key.
curve_nid(&self) -> i32476 fn curve_nid(&self) -> i32 {
477 // SAFETY: It is safe since the inner pointer is valid and points to an initialized
478 // instance of `EC_GROUP`.
479 unsafe { EC_GROUP_get_curve_name(self.as_ref()) }
480 }
481
coset_curve(&self) -> Result<iana::EllipticCurve>482 fn coset_curve(&self) -> Result<iana::EllipticCurve> {
483 #[allow(non_upper_case_globals)]
484 match self.curve_nid() {
485 NID_X9_62_prime256v1 => Ok(P256_CURVE),
486 NID_secp384r1 => Ok(P384_CURVE),
487 name => {
488 error!("Unsupported curve NID: {}", name);
489 Err(Error::Unimplemented)
490 }
491 }
492 }
493
affine_coordinate_size(&self) -> Result<usize>494 fn affine_coordinate_size(&self) -> Result<usize> {
495 #[allow(non_upper_case_globals)]
496 match self.curve_nid() {
497 NID_X9_62_prime256v1 => Ok(P256_AFFINE_COORDINATE_SIZE),
498 NID_secp384r1 => Ok(P384_AFFINE_COORDINATE_SIZE),
499 name => {
500 error!("Unsupported curve NID: {}", name);
501 Err(Error::Unimplemented)
502 }
503 }
504 }
505
check_affine_coordinate_size(&self, coordinate: &[u8]) -> Result<()>506 fn check_affine_coordinate_size(&self, coordinate: &[u8]) -> Result<()> {
507 let expected_len = self.affine_coordinate_size()?;
508 if expected_len == coordinate.len() {
509 Ok(())
510 } else {
511 error!(
512 "The size of the affine coordinate '{}' does not match the expected size '{}'",
513 coordinate.len(),
514 expected_len
515 );
516 Err(Error::CoseKeyDecodingFailed)
517 }
518 }
519 }
520
521 impl<'a> AsRef<EC_GROUP> for EcGroup<'a> {
as_ref(&self) -> &EC_GROUP522 fn as_ref(&self) -> &EC_GROUP {
523 self.0
524 }
525 }
526
527 /// A u8 vector that is zeroed when dropped.
528 #[derive(Zeroize, ZeroizeOnDrop)]
529 pub struct ZVec(Vec<u8>);
530
531 impl ZVec {
532 /// Extracts a slice containing the entire vector.
as_slice(&self) -> &[u8]533 pub fn as_slice(&self) -> &[u8] {
534 &self.0[..]
535 }
536 }
537
538 impl From<Vec<u8>> for ZVec {
from(v: Vec<u8>) -> Self539 fn from(v: Vec<u8>) -> Self {
540 Self(v)
541 }
542 }
543
544 struct BigNum(NonNull<BIGNUM>);
545
546 impl Drop for BigNum {
drop(&mut self)547 fn drop(&mut self) {
548 // SAFETY: The pointer has been created with `BN_new`.
549 unsafe { BN_clear_free(self.as_mut_ptr()) }
550 }
551 }
552
553 impl BigNum {
from_slice(x: &[u8]) -> Result<Self>554 fn from_slice(x: &[u8]) -> Result<Self> {
555 // SAFETY: The function reads `x` within its bounds, and the returned
556 // pointer is checked below.
557 let bn = unsafe { BN_bin2bn(x.as_ptr(), x.len(), ptr::null_mut()) };
558 NonNull::new(bn).map(Self).ok_or_else(|| to_call_failed_error(ApiName::BN_bin2bn))
559 }
560
new() -> Result<Self>561 fn new() -> Result<Self> {
562 // SAFETY: The returned pointer is checked below.
563 let bn = unsafe { BN_new() };
564 NonNull::new(bn).map(Self).ok_or_else(|| to_call_failed_error(ApiName::BN_new))
565 }
566
567 /// Converts the `BigNum` to a big-endian integer. The integer is padded with leading zeros up
568 /// to size `len`. The conversion fails if `len` is smaller than the size of the integer.
to_padded_vec(&self, len: usize) -> Result<Vec<u8>>569 fn to_padded_vec(&self, len: usize) -> Result<Vec<u8>> {
570 let mut num = vec![0u8; len];
571 // SAFETY: The `BIGNUM` pointer has been created with `BN_new`.
572 let ret = unsafe { BN_bn2bin_padded(num.as_mut_ptr(), num.len(), self.0.as_ptr()) };
573 check_int_result(ret, ApiName::BN_bn2bin_padded)?;
574 Ok(num)
575 }
576
as_mut_ptr(&mut self) -> *mut BIGNUM577 fn as_mut_ptr(&mut self) -> *mut BIGNUM {
578 self.0.as_ptr()
579 }
580 }
581
582 impl AsRef<BIGNUM> for BigNum {
as_ref(&self) -> &BIGNUM583 fn as_ref(&self) -> &BIGNUM {
584 // SAFETY: The pointer is valid and points to an initialized instance of `BIGNUM`
585 // when the instance was created.
586 unsafe { self.0.as_ref() }
587 }
588 }
589