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