1 // Copyright 2022, 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 //! BoringSSL-based implementation of elliptic curve functionality.
16 use crate::types::{EvpMdCtx, EvpPkeyCtx};
17 use crate::{cvt, cvt_p, digest_into_openssl, openssl_err, openssl_last_err, ossl};
18 use alloc::boxed::Box;
19 use alloc::vec::Vec;
20 #[cfg(soong)]
21 use bssl_sys as ffi;
22 use core::ops::DerefMut;
23 use core::ptr;
24 use foreign_types::ForeignType;
25 use kmr_common::{
26     crypto,
27     crypto::{ec, ec::Key, AccumulatingOperation, CurveType, OpaqueOr},
28     explicit, km_err, vec_try, Error, FallibleAllocExt,
29 };
30 use kmr_wire::{
31     keymint,
32     keymint::{Digest, EcCurve},
33 };
34 use openssl::hash::MessageDigest;
35 
36 #[cfg(soong)]
private_key_from_der_for_group( der: &[u8], group: &openssl::ec::EcGroupRef, ) -> Result<openssl::ec::EcKey<openssl::pkey::Private>, openssl::error::ErrorStack>37 fn private_key_from_der_for_group(
38     der: &[u8],
39     group: &openssl::ec::EcGroupRef,
40 ) -> Result<openssl::ec::EcKey<openssl::pkey::Private>, openssl::error::ErrorStack> {
41     // This method is an Android modification to the rust-openssl crate.
42     openssl::ec::EcKey::private_key_from_der_for_group(der, group)
43 }
44 
45 #[cfg(not(soong))]
private_key_from_der_for_group( der: &[u8], _group: &openssl::ec::EcGroupRef, ) -> Result<openssl::ec::EcKey<openssl::pkey::Private>, openssl::error::ErrorStack>46 fn private_key_from_der_for_group(
47     der: &[u8],
48     _group: &openssl::ec::EcGroupRef,
49 ) -> Result<openssl::ec::EcKey<openssl::pkey::Private>, openssl::error::ErrorStack> {
50     // This doesn't work if the encoded data is missing the curve.
51     openssl::ec::EcKey::private_key_from_der(der)
52 }
53 
54 /// [`crypto::Ec`] implementation based on BoringSSL.
55 pub struct BoringEc {
56     /// Zero-sized private field to force use of [`default()`] for initialization.
57     _priv: core::marker::PhantomData<()>,
58 }
59 
60 impl core::default::Default for BoringEc {
default() -> Self61     fn default() -> Self {
62         ffi::init();
63         Self { _priv: core::marker::PhantomData }
64     }
65 }
66 
67 impl crypto::Ec for BoringEc {
generate_nist_key( &self, _rng: &mut dyn crypto::Rng, curve: ec::NistCurve, _params: &[keymint::KeyParam], ) -> Result<crypto::KeyMaterial, Error>68     fn generate_nist_key(
69         &self,
70         _rng: &mut dyn crypto::Rng,
71         curve: ec::NistCurve,
72         _params: &[keymint::KeyParam],
73     ) -> Result<crypto::KeyMaterial, Error> {
74         let ec_key = ossl!(openssl::ec::EcKey::<openssl::pkey::Private>::generate(
75             nist_curve_to_group(curve)?.as_ref()
76         ))?;
77         let nist_key = ec::NistKey(ossl!(ec_key.private_key_to_der())?);
78         let key = match curve {
79             ec::NistCurve::P224 => Key::P224(nist_key),
80             ec::NistCurve::P256 => Key::P256(nist_key),
81             ec::NistCurve::P384 => Key::P384(nist_key),
82             ec::NistCurve::P521 => Key::P521(nist_key),
83         };
84         Ok(crypto::KeyMaterial::Ec(curve.into(), CurveType::Nist, key.into()))
85     }
86 
generate_ed25519_key( &self, _rng: &mut dyn crypto::Rng, _params: &[keymint::KeyParam], ) -> Result<crypto::KeyMaterial, Error>87     fn generate_ed25519_key(
88         &self,
89         _rng: &mut dyn crypto::Rng,
90         _params: &[keymint::KeyParam],
91     ) -> Result<crypto::KeyMaterial, Error> {
92         let pkey = ossl!(openssl::pkey::PKey::generate_ed25519())?;
93         let key = ossl!(pkey.raw_private_key())?;
94         let key: [u8; ec::CURVE25519_PRIV_KEY_LEN] = key.try_into().map_err(|e| {
95             km_err!(UnsupportedKeySize, "generated Ed25519 key of unexpected size: {:?}", e)
96         })?;
97         let key = Key::Ed25519(ec::Ed25519Key(key));
98         Ok(crypto::KeyMaterial::Ec(EcCurve::Curve25519, CurveType::EdDsa, key.into()))
99     }
100 
generate_x25519_key( &self, _rng: &mut dyn crypto::Rng, _params: &[keymint::KeyParam], ) -> Result<crypto::KeyMaterial, Error>101     fn generate_x25519_key(
102         &self,
103         _rng: &mut dyn crypto::Rng,
104         _params: &[keymint::KeyParam],
105     ) -> Result<crypto::KeyMaterial, Error> {
106         let pkey = ossl!(openssl::pkey::PKey::generate_x25519())?;
107         let key = ossl!(pkey.raw_private_key())?;
108         let key: [u8; ec::CURVE25519_PRIV_KEY_LEN] = key.try_into().map_err(|e| {
109             km_err!(UnsupportedKeySize, "generated X25519 key of unexpected size: {:?}", e)
110         })?;
111         let key = Key::X25519(ec::X25519Key(key));
112         Ok(crypto::KeyMaterial::Ec(EcCurve::Curve25519, CurveType::Xdh, key.into()))
113     }
114 
nist_public_key(&self, key: &ec::NistKey, curve: ec::NistCurve) -> Result<Vec<u8>, Error>115     fn nist_public_key(&self, key: &ec::NistKey, curve: ec::NistCurve) -> Result<Vec<u8>, Error> {
116         let group = nist_curve_to_group(curve)?;
117         let ec_key = ossl!(private_key_from_der_for_group(&key.0, group.as_ref()))?;
118         let pt = ec_key.public_key();
119         let mut bn_ctx = ossl!(openssl::bn::BigNumContext::new())?;
120         ossl!(pt.to_bytes(
121             group.as_ref(),
122             openssl::ec::PointConversionForm::UNCOMPRESSED,
123             bn_ctx.deref_mut()
124         ))
125     }
126 
ed25519_public_key(&self, key: &ec::Ed25519Key) -> Result<Vec<u8>, Error>127     fn ed25519_public_key(&self, key: &ec::Ed25519Key) -> Result<Vec<u8>, Error> {
128         let pkey = ossl!(openssl::pkey::PKey::private_key_from_raw_bytes(
129             &key.0,
130             openssl::pkey::Id::ED25519
131         ))?;
132         ossl!(pkey.raw_public_key())
133     }
134 
x25519_public_key(&self, key: &ec::X25519Key) -> Result<Vec<u8>, Error>135     fn x25519_public_key(&self, key: &ec::X25519Key) -> Result<Vec<u8>, Error> {
136         let pkey = ossl!(openssl::pkey::PKey::private_key_from_raw_bytes(
137             &key.0,
138             openssl::pkey::Id::X25519
139         ))?;
140         ossl!(pkey.raw_public_key())
141     }
142 
begin_agree(&self, key: OpaqueOr<Key>) -> Result<Box<dyn AccumulatingOperation>, Error>143     fn begin_agree(&self, key: OpaqueOr<Key>) -> Result<Box<dyn AccumulatingOperation>, Error> {
144         let key = explicit!(key)?;
145         // Maximum size for a `SubjectPublicKeyInfo` that holds an EC public key is:
146         //
147         // 30 LL  SEQUENCE + len (SubjectPublicKeyInfo)
148         // 30 LL  SEQUENCE + len (AlgorithmIdentifier)
149         // 06 07  OID + len
150         //     2a8648ce3d0201  (ecPublicKey OID)
151         // 06 08  OID + len
152         //     2a8648ce3d030107 (P-256 curve OID, which is the longest)
153         // 03 42  BIT STRING + len
154         //     00  zero pad bits
155         //     04  uncompressed
156         //     ...  66 bytes of P-521 X coordinate
157         //     ...  66 bytes of P-521 Y coordinate
158         //
159         // Round up a bit just in case.
160         let max_size = 164;
161         Ok(Box::new(BoringEcAgreeOperation { key, pending_input: Vec::new(), max_size }))
162     }
163 
begin_sign( &self, key: OpaqueOr<Key>, digest: Digest, ) -> Result<Box<dyn AccumulatingOperation>, Error>164     fn begin_sign(
165         &self,
166         key: OpaqueOr<Key>,
167         digest: Digest,
168     ) -> Result<Box<dyn AccumulatingOperation>, Error> {
169         let key = explicit!(key)?;
170         let curve = key.curve();
171         match key {
172             Key::P224(key) | Key::P256(key) | Key::P384(key) | Key::P521(key) => {
173                 let curve = ec::NistCurve::try_from(curve)?;
174                 if let Some(digest) = digest_into_openssl(digest) {
175                     Ok(Box::new(BoringEcDigestSignOperation::new(key, curve, digest)?))
176                 } else {
177                     Ok(Box::new(BoringEcUndigestSignOperation::new(key, curve)?))
178                 }
179             }
180             Key::Ed25519(key) => Ok(Box::new(BoringEd25519SignOperation::new(key)?)),
181             Key::X25519(_) => {
182                 Err(km_err!(IncompatibleAlgorithm, "X25519 key not valid for signing"))
183             }
184         }
185     }
186 }
187 
188 /// [`crypto::EcAgreeOperation`] based on BoringSSL.
189 pub struct BoringEcAgreeOperation {
190     key: Key,
191     pending_input: Vec<u8>, // Limited to `max_size` below.
192     // Size of a `SubjectPublicKeyInfo` holding peer public key.
193     max_size: usize,
194 }
195 
196 impl crypto::AccumulatingOperation for BoringEcAgreeOperation {
max_input_size(&self) -> Option<usize>197     fn max_input_size(&self) -> Option<usize> {
198         Some(self.max_size)
199     }
200 
update(&mut self, data: &[u8]) -> Result<(), Error>201     fn update(&mut self, data: &[u8]) -> Result<(), Error> {
202         self.pending_input.try_extend_from_slice(data)?;
203         Ok(())
204     }
205 
finish(self: Box<Self>) -> Result<Vec<u8>, Error>206     fn finish(self: Box<Self>) -> Result<Vec<u8>, Error> {
207         let peer_key = ossl!(openssl::pkey::PKey::public_key_from_der(&self.pending_input))?;
208         match &self.key {
209             Key::P224(key) | Key::P256(key) | Key::P384(key) | Key::P521(key) => {
210                 let group = nist_key_to_group(&self.key)?;
211                 let ec_key = ossl!(private_key_from_der_for_group(&key.0, group.as_ref()))?;
212                 let pkey = ossl!(openssl::pkey::PKey::from_ec_key(ec_key))?;
213                 let mut deriver = ossl!(openssl::derive::Deriver::new(&pkey))?;
214                 ossl!(deriver.set_peer(&peer_key))
215                     .map_err(|e| km_err!(InvalidArgument, "peer key invalid: {:?}", e))?;
216                 let derived = ossl!(deriver.derive_to_vec())?;
217                 Ok(derived)
218             }
219             #[cfg(soong)]
220             Key::X25519(key) => {
221                 // The BoringSSL `EVP_PKEY` interface does not support X25519, so need to invoke the
222                 // `ffi:X25519()` method directly. First need to extract the raw peer key from the
223                 // `SubjectPublicKeyInfo` it arrives in.
224                 let peer_key =
225                     ossl!(openssl::pkey::PKey::public_key_from_der(&self.pending_input))?;
226                 let peer_key_type = peer_key.id();
227                 if peer_key_type != openssl::pkey::Id::X25519 {
228                     return Err(km_err!(
229                         InvalidArgument,
230                         "peer key for {:?} not supported with X25519",
231                         peer_key_type
232                     ));
233                 }
234                 let peer_key_data = ossl!(peer_key.raw_public_key())?;
235                 if peer_key_data.len() != ffi::X25519_PUBLIC_VALUE_LEN as usize {
236                     return Err(km_err!(
237                         UnsupportedKeySize,
238                         "peer raw key invalid length {}",
239                         peer_key_data.len()
240                     ));
241                 }
242 
243                 let mut sig = vec_try![0; ffi::X25519_SHARED_KEY_LEN as usize]?;
244                 // Safety: all pointer arguments need to point to 32-byte memory areas, enforced
245                 // above and in the definition of [`ec::X25519Key`].
246                 let result = unsafe {
247                     ffi::X25519(sig.as_mut_ptr(), &key.0 as *const u8, peer_key_data.as_ptr())
248                 };
249                 if result == 1 {
250                     Ok(sig)
251                 } else {
252                     Err(super::openssl_last_err())
253                 }
254             }
255             #[cfg(not(soong))]
256             Key::X25519(_) => Err(km_err!(UnsupportedEcCurve, "X25519 not supported in cargo")),
257             Key::Ed25519(_) => {
258                 Err(km_err!(IncompatibleAlgorithm, "Ed25519 key not valid for agreement"))
259             }
260         }
261     }
262 }
263 
264 /// [`crypto::EcSignOperation`] based on BoringSSL, when an external digest is used.
265 pub struct BoringEcDigestSignOperation {
266     // Safety: `pkey` internally holds a pointer to BoringSSL-allocated data (`EVP_PKEY`),
267     // as do both of the raw pointers.  This means that this item stays valid under moves,
268     // because the FFI-allocated data doesn't move.
269     pkey: openssl::pkey::PKey<openssl::pkey::Private>,
270 
271     // Safety invariant: both `pctx` and `md_ctx` are non-`nullptr` and valid once item is
272     // constructed.
273     md_ctx: EvpMdCtx,
274     pctx: EvpPkeyCtx,
275 }
276 
277 impl Drop for BoringEcDigestSignOperation {
drop(&mut self)278     fn drop(&mut self) {
279         // Safety: `EVP_MD_CTX_free()` handles `nullptr`, so it's fine to drop a partly-constructed
280         // item.  `pctx` is owned by the `md_ctx`, so no need to explicitly free it.
281         unsafe {
282             ffi::EVP_MD_CTX_free(self.md_ctx.0);
283         }
284     }
285 }
286 
287 impl BoringEcDigestSignOperation {
new(key: ec::NistKey, curve: ec::NistCurve, digest: MessageDigest) -> Result<Self, Error>288     fn new(key: ec::NistKey, curve: ec::NistCurve, digest: MessageDigest) -> Result<Self, Error> {
289         let group = nist_curve_to_group(curve)?;
290         let ec_key = ossl!(private_key_from_der_for_group(&key.0, group.as_ref()))?;
291         let pkey = ossl!(openssl::pkey::PKey::from_ec_key(ec_key))?;
292 
293         // Safety: each of the raw pointers have to be non-nullptr (and thus valid, as BoringSSL
294         // emits only valid pointers or nullptr) to get to the point where they're used.
295         unsafe {
296             let mut op = BoringEcDigestSignOperation {
297                 pkey,
298                 md_ctx: EvpMdCtx(cvt_p(ffi::EVP_MD_CTX_new())?),
299                 pctx: EvpPkeyCtx(ptr::null_mut()),
300             };
301 
302             let r = ffi::EVP_DigestSignInit(
303                 op.md_ctx.0,
304                 &mut op.pctx.0,
305                 digest.as_ptr(),
306                 ptr::null_mut(),
307                 op.pkey.as_ptr(),
308             );
309             if r != 1 {
310                 return Err(openssl_last_err());
311             }
312             if op.pctx.0.is_null() {
313                 return Err(km_err!(BoringSslError, "no PCTX!"));
314             }
315             // Safety invariant: both `pctx` and `md_ctx` are non-`nullptr` and valid on success.
316             Ok(op)
317         }
318     }
319 }
320 
321 impl crypto::AccumulatingOperation for BoringEcDigestSignOperation {
update(&mut self, data: &[u8]) -> Result<(), Error>322     fn update(&mut self, data: &[u8]) -> Result<(), Error> {
323         // Safety: `data` is a valid slice, and `self.md_ctx` is non-`nullptr` and valid.
324         unsafe {
325             cvt(ffi::EVP_DigestUpdate(self.md_ctx.0, data.as_ptr() as *const _, data.len()))?;
326         }
327         Ok(())
328     }
329 
finish(self: Box<Self>) -> Result<Vec<u8>, Error>330     fn finish(self: Box<Self>) -> Result<Vec<u8>, Error> {
331         let mut max_siglen = 0;
332         // Safety: `self.md_ctx` is non-`nullptr` and valid.
333         unsafe {
334             cvt(ffi::EVP_DigestSignFinal(self.md_ctx.0, ptr::null_mut(), &mut max_siglen))?;
335         }
336         let mut buf = vec_try![0; max_siglen]?;
337         let mut actual_siglen = max_siglen;
338         // Safety: `self.md_ctx` is non-`nullptr` and valid, and `buf` does have `actual_siglen`
339         // bytes.
340         unsafe {
341             cvt(ffi::EVP_DigestSignFinal(
342                 self.md_ctx.0,
343                 buf.as_mut_ptr() as *mut _,
344                 &mut actual_siglen,
345             ))?;
346         }
347         buf.truncate(actual_siglen);
348         Ok(buf)
349     }
350 }
351 
352 /// [`crypto::EcSignOperation`] based on BoringSSL, when data is undigested.
353 pub struct BoringEcUndigestSignOperation {
354     ec_key: openssl::ec::EcKey<openssl::pkey::Private>,
355     pending_input: Vec<u8>,
356     max_size: usize,
357 }
358 
359 impl BoringEcUndigestSignOperation {
new(key: ec::NistKey, curve: ec::NistCurve) -> Result<Self, Error>360     fn new(key: ec::NistKey, curve: ec::NistCurve) -> Result<Self, Error> {
361         let group = nist_curve_to_group(curve)?;
362         let ec_key = ossl!(private_key_from_der_for_group(&key.0, group.as_ref()))?;
363         // Input to an undigested EC signing operation must be smaller than key size.
364         Ok(Self { ec_key, pending_input: Vec::new(), max_size: curve.coord_len() })
365     }
366 }
367 
368 impl crypto::AccumulatingOperation for BoringEcUndigestSignOperation {
update(&mut self, data: &[u8]) -> Result<(), Error>369     fn update(&mut self, data: &[u8]) -> Result<(), Error> {
370         // For ECDSA signing, extra data beyond the maximum size is ignored (rather than being
371         // rejected via the `max_input_size()` trait method).
372         let max_extra_data = self.max_size - self.pending_input.len();
373         if max_extra_data > 0 {
374             let len = core::cmp::min(max_extra_data, data.len());
375             self.pending_input.try_extend_from_slice(&data[..len])?;
376         }
377         Ok(())
378     }
379 
finish(self: Box<Self>) -> Result<Vec<u8>, Error>380     fn finish(self: Box<Self>) -> Result<Vec<u8>, Error> {
381         // BoringSSL doesn't support `EVP_PKEY` use without digest, so use low-level ECDSA
382         // functionality.
383         let sig = ossl!(openssl::ecdsa::EcdsaSig::sign(&self.pending_input, &self.ec_key))?;
384         let sig = ossl!(sig.to_der())?;
385         Ok(sig)
386     }
387 }
388 
389 /// [`crypto::EcSignOperation`] based on BoringSSL for Ed25519.
390 pub struct BoringEd25519SignOperation {
391     pkey: openssl::pkey::PKey<openssl::pkey::Private>,
392     pending_input: Vec<u8>,
393 }
394 
395 impl BoringEd25519SignOperation {
new(key: ec::Ed25519Key) -> Result<Self, Error>396     fn new(key: ec::Ed25519Key) -> Result<Self, Error> {
397         let pkey = ossl!(openssl::pkey::PKey::private_key_from_raw_bytes(
398             &key.0,
399             openssl::pkey::Id::ED25519
400         ))?;
401         Ok(Self { pkey, pending_input: Vec::new() })
402     }
403 }
404 
405 impl crypto::AccumulatingOperation for BoringEd25519SignOperation {
max_input_size(&self) -> Option<usize>406     fn max_input_size(&self) -> Option<usize> {
407         // Ed25519 has an internal digest so could theoretically take arbitrary amounts of
408         // data. However, BoringSSL does not support incremental data feeding for Ed25519 so
409         // instead impose a message size limit (as required by the KeyMint HAL spec).
410         Some(ec::MAX_ED25519_MSG_SIZE)
411     }
412 
update(&mut self, data: &[u8]) -> Result<(), Error>413     fn update(&mut self, data: &[u8]) -> Result<(), Error> {
414         // OK to accumulate data as there is a size limit.
415         self.pending_input.try_extend_from_slice(data)?;
416         Ok(())
417     }
418 
finish(self: Box<Self>) -> Result<Vec<u8>, Error>419     fn finish(self: Box<Self>) -> Result<Vec<u8>, Error> {
420         let mut signer = ossl!(openssl::sign::Signer::new_without_digest(&self.pkey))?;
421         let sig = ossl!(signer.sign_oneshot_to_vec(&self.pending_input))?;
422         Ok(sig)
423     }
424 }
425 
nist_curve_to_group(curve: ec::NistCurve) -> Result<openssl::ec::EcGroup, Error>426 fn nist_curve_to_group(curve: ec::NistCurve) -> Result<openssl::ec::EcGroup, Error> {
427     use openssl::nid::Nid;
428     openssl::ec::EcGroup::from_curve_name(match curve {
429         ec::NistCurve::P224 => Nid::SECP224R1,
430         ec::NistCurve::P256 => Nid::X9_62_PRIME256V1,
431         ec::NistCurve::P384 => Nid::SECP384R1,
432         ec::NistCurve::P521 => Nid::SECP521R1,
433     })
434     .map_err(openssl_err!("failed to determine EcGroup"))
435 }
436 
nist_key_to_group(key: &ec::Key) -> Result<openssl::ec::EcGroup, Error>437 fn nist_key_to_group(key: &ec::Key) -> Result<openssl::ec::EcGroup, Error> {
438     use openssl::nid::Nid;
439     openssl::ec::EcGroup::from_curve_name(match key {
440         ec::Key::P224(_) => Nid::SECP224R1,
441         ec::Key::P256(_) => Nid::X9_62_PRIME256V1,
442         ec::Key::P384(_) => Nid::SECP384R1,
443         ec::Key::P521(_) => Nid::SECP521R1,
444         ec::Key::Ed25519(_) | ec::Key::X25519(_) => {
445             return Err(km_err!(UnsupportedEcCurve, "no NIST group for curve25519 key"))
446         }
447     })
448     .map_err(openssl_err!("failed to determine EcGroup"))
449 }
450