xref: /aosp_15_r20/system/keymint/boringssl/src/rsa.rs (revision 9860b7637a5f185913c70aa0caabe3ecb78441e4)
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 RSA.
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::ptr;
23 use foreign_types::ForeignType;
24 use kmr_common::crypto::{
25     rsa::{DecryptionMode, SignMode, PKCS1_UNDIGESTED_SIGNATURE_PADDING_OVERHEAD},
26     OpaqueOr,
27 };
28 use kmr_common::{crypto, explicit, km_err, vec_try, Error, FallibleAllocExt};
29 use kmr_wire::{keymint, keymint::Digest, KeySizeInBits, RsaExponent};
30 use openssl::hash::MessageDigest;
31 
32 /// Smallest allowed public exponent.
33 const MIN_RSA_EXPONENT: RsaExponent = RsaExponent(3);
34 
35 /// [`crypto::Rsa`] implementation based on BoringSSL.
36 pub struct BoringRsa {
37     /// Zero-sized private field to force use of [`default()`] for initialization.
38     _priv: core::marker::PhantomData<()>,
39 }
40 
41 impl core::default::Default for BoringRsa {
default() -> Self42     fn default() -> Self {
43         ffi::init();
44         Self { _priv: core::marker::PhantomData }
45     }
46 }
47 
48 impl crypto::Rsa for BoringRsa {
generate_key( &self, _rng: &mut dyn crypto::Rng, key_size: KeySizeInBits, pub_exponent: RsaExponent, _params: &[keymint::KeyParam], ) -> Result<crypto::KeyMaterial, Error>49     fn generate_key(
50         &self,
51         _rng: &mut dyn crypto::Rng,
52         key_size: KeySizeInBits,
53         pub_exponent: RsaExponent,
54         _params: &[keymint::KeyParam],
55     ) -> Result<crypto::KeyMaterial, Error> {
56         // Reject some obviously-wrong parameter values.
57         if pub_exponent < MIN_RSA_EXPONENT {
58             return Err(km_err!(
59                 InvalidArgument,
60                 "Invalid public exponent, {:?} < {:?}",
61                 pub_exponent,
62                 MIN_RSA_EXPONENT
63             ));
64         }
65         if pub_exponent.0 % 2 != 1 {
66             return Err(km_err!(
67                 InvalidArgument,
68                 "Invalid public exponent {:?} (even number)",
69                 pub_exponent
70             ));
71         }
72         let exponent = openssl::bn::BigNum::from_slice(&pub_exponent.0.to_be_bytes()[..])
73             .map_err(openssl_err!("failed to create BigNum for exponent {:?}", pub_exponent))?;
74 
75         let rsa_key =
76             openssl::rsa::Rsa::generate_with_e(key_size.0, &exponent).map_err(openssl_err!(
77                 "failed to generate RSA key size {:?} exponent {:?}",
78                 key_size,
79                 pub_exponent
80             ))?;
81         let asn1_data = ossl!(rsa_key.private_key_to_der())?;
82         Ok(crypto::KeyMaterial::Rsa(crypto::rsa::Key(asn1_data).into()))
83     }
84 
begin_decrypt( &self, key: OpaqueOr<crypto::rsa::Key>, mode: DecryptionMode, ) -> Result<Box<dyn crypto::AccumulatingOperation>, Error>85     fn begin_decrypt(
86         &self,
87         key: OpaqueOr<crypto::rsa::Key>,
88         mode: DecryptionMode,
89     ) -> Result<Box<dyn crypto::AccumulatingOperation>, Error> {
90         let key = explicit!(key)?;
91         let max_size = key.size();
92         Ok(Box::new(BoringRsaDecryptOperation { key, mode, pending_input: Vec::new(), max_size }))
93     }
94 
begin_sign( &self, key: OpaqueOr<crypto::rsa::Key>, mode: SignMode, ) -> Result<Box<dyn crypto::AccumulatingOperation>, Error>95     fn begin_sign(
96         &self,
97         key: OpaqueOr<crypto::rsa::Key>,
98         mode: SignMode,
99     ) -> Result<Box<dyn crypto::AccumulatingOperation>, Error> {
100         let key = explicit!(key)?;
101         let padding = match mode {
102             SignMode::NoPadding => openssl::rsa::Padding::NONE,
103             SignMode::Pkcs1_1_5Padding(_) => openssl::rsa::Padding::PKCS1,
104             SignMode::PssPadding(_) => openssl::rsa::Padding::PKCS1_PSS,
105         };
106 
107         match mode {
108             SignMode::NoPadding | SignMode::Pkcs1_1_5Padding(Digest::None) => {
109                 Ok(Box::new(BoringRsaUndigestSignOperation::new(key, mode)?))
110             }
111             SignMode::Pkcs1_1_5Padding(digest) | SignMode::PssPadding(digest) => {
112                 if let Some(digest) = digest_into_openssl(digest) {
113                     Ok(Box::new(BoringRsaDigestSignOperation::new(key, mode, digest, padding)?))
114                 } else {
115                     Err(km_err!(InvalidArgument, "no digest provided for mode {:?}", mode))
116                 }
117             }
118         }
119     }
120 }
121 
122 /// RSA decryption operation based on BoringSSL.
123 pub struct BoringRsaDecryptOperation {
124     key: crypto::rsa::Key,
125     mode: DecryptionMode,
126     pending_input: Vec<u8>, // Limited to size of key (`max_size` below).
127     max_size: usize,
128 }
129 
130 impl crypto::AccumulatingOperation for BoringRsaDecryptOperation {
max_input_size(&self) -> Option<usize>131     fn max_input_size(&self) -> Option<usize> {
132         Some(self.max_size)
133     }
134 
update(&mut self, data: &[u8]) -> Result<(), Error>135     fn update(&mut self, data: &[u8]) -> Result<(), Error> {
136         self.pending_input.try_extend_from_slice(data)?;
137         Ok(())
138     }
139 
finish(mut self: Box<Self>) -> Result<Vec<u8>, Error>140     fn finish(mut self: Box<Self>) -> Result<Vec<u8>, Error> {
141         let rsa_key = ossl!(openssl::rsa::Rsa::private_key_from_der(&self.key.0))?;
142         let priv_key = ossl!(openssl::pkey::PKey::from_rsa(rsa_key))?;
143         let mut decrypter = ossl!(openssl::encrypt::Decrypter::new(&priv_key))?;
144 
145         let padding = match self.mode {
146             DecryptionMode::NoPadding => openssl::rsa::Padding::NONE,
147             DecryptionMode::OaepPadding { msg_digest: _, mgf_digest: _ } => {
148                 openssl::rsa::Padding::PKCS1_OAEP
149             }
150             DecryptionMode::Pkcs1_1_5Padding => openssl::rsa::Padding::PKCS1,
151         };
152         decrypter
153             .set_rsa_padding(padding)
154             .map_err(openssl_err!("failed to create set_rsa_padding for {:?}", self.mode))?;
155 
156         if let DecryptionMode::OaepPadding { msg_digest, mgf_digest } = self.mode {
157             let omsg_digest = digest_into_openssl(msg_digest).ok_or_else(|| {
158                 km_err!(UnsupportedDigest, "Digest::None not allowed for RSA-OAEP msg digest")
159             })?;
160             let omgf_digest = digest_into_openssl(mgf_digest).ok_or_else(|| {
161                 km_err!(UnsupportedDigest, "Digest::None not allowed for RSA-OAEP MGF1 digest")
162             })?;
163             decrypter
164                 .set_rsa_oaep_md(omsg_digest)
165                 .map_err(openssl_err!("failed to set digest {:?}", msg_digest))?;
166             decrypter
167                 .set_rsa_mgf1_md(omgf_digest)
168                 .map_err(openssl_err!("failed to set MGF digest {:?}", mgf_digest))?;
169         }
170 
171         let buf_len = ossl!(decrypter.decrypt_len(&self.pending_input))?;
172         let mut output = vec_try![0; buf_len]?;
173 
174         if self.mode == DecryptionMode::NoPadding && self.pending_input.len() < buf_len {
175             self.pending_input = zero_pad_left(&self.pending_input, buf_len)?;
176         }
177 
178         let actual_len = ossl!(decrypter.decrypt(&self.pending_input, &mut output))?;
179         output.truncate(actual_len);
180 
181         Ok(output)
182     }
183 }
184 
185 /// RSA signing operation based on BoringSSL, for when an external digest is used.
186 /// Directly uses FFI functions because [`openssl::sign::Signer`] requires a lifetime.
187 pub struct BoringRsaDigestSignOperation {
188     // Safety: `pkey` internally holds a pointer to BoringSSL-allocated data (`EVP_PKEY`),
189     // as do both of the raw pointers.  This means that this item stays valid under moves,
190     // because the FFI-allocated data doesn't move.
191     pkey: openssl::pkey::PKey<openssl::pkey::Private>,
192 
193     // Safety invariant: both `pctx` and `md_ctx` are non-`nullptr` (and valid and non-aliased) once
194     // item is constructed.
195     md_ctx: EvpMdCtx,
196     pctx: EvpPkeyCtx,
197 }
198 
199 impl Drop for BoringRsaDigestSignOperation {
drop(&mut self)200     fn drop(&mut self) {
201         // Safety: `md_ctx` is non-`nullptr` and valid due to invariant. `pctx` is owned by the
202         // `md_ctx`, so no need to explicitly free it.
203         unsafe {
204             ffi::EVP_MD_CTX_free(self.md_ctx.0);
205         }
206     }
207 }
208 
209 impl BoringRsaDigestSignOperation {
new( key: crypto::rsa::Key, mode: SignMode, digest: MessageDigest, padding: openssl::rsa::Padding, ) -> Result<Self, Error>210     fn new(
211         key: crypto::rsa::Key,
212         mode: SignMode,
213         digest: MessageDigest,
214         padding: openssl::rsa::Padding,
215     ) -> Result<Self, Error> {
216         let rsa_key = ossl!(openssl::rsa::Rsa::private_key_from_der(&key.0))?;
217         let pkey = ossl!(openssl::pkey::PKey::from_rsa(rsa_key))?;
218 
219         // Safety: all raw pointers are non-`nullptr` (and valid and non-aliasing) if returned
220         // without error from BoringSSL entrypoints.
221         unsafe {
222             let mut op = BoringRsaDigestSignOperation {
223                 pkey,
224                 md_ctx: EvpMdCtx(cvt_p(ffi::EVP_MD_CTX_new())?),
225                 pctx: EvpPkeyCtx(ptr::null_mut()),
226             };
227 
228             let r = ffi::EVP_DigestSignInit(
229                 op.md_ctx.0,
230                 &mut op.pctx.0,
231                 digest.as_ptr(),
232                 ptr::null_mut(),
233                 op.pkey.as_ptr(),
234             );
235             if r != 1 {
236                 return Err(openssl_last_err());
237             }
238             if op.pctx.0.is_null() {
239                 return Err(km_err!(BoringSslError, "no PCTX!"));
240             }
241 
242             // Safety: `op.pctx` is not `nullptr` and is valid.
243             cvt(ffi::EVP_PKEY_CTX_set_rsa_padding(op.pctx.0, padding.as_raw()))?;
244 
245             if let SignMode::PssPadding(digest) = mode {
246                 let digest_len = (kmr_common::tag::digest_len(digest)? / 8) as libc::c_int;
247                 // Safety: `op.pctx` is not `nullptr` and is valid.
248                 cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen(op.pctx.0, digest_len))?;
249             }
250 
251             // Safety invariant: both `pctx` and `md_ctx` are non-`nullptr` and valid pointers on
252             // success.
253             Ok(op)
254         }
255     }
256 }
257 
258 impl crypto::AccumulatingOperation for BoringRsaDigestSignOperation {
update(&mut self, data: &[u8]) -> Result<(), Error>259     fn update(&mut self, data: &[u8]) -> Result<(), Error> {
260         // Safety: `data` is a valid slice, and `self.md_ctx` is non-`nullptr` and valid.
261         unsafe {
262             cvt(ffi::EVP_DigestUpdate(self.md_ctx.0, data.as_ptr() as *const _, data.len()))?;
263         }
264         Ok(())
265     }
266 
finish(self: Box<Self>) -> Result<Vec<u8>, Error>267     fn finish(self: Box<Self>) -> Result<Vec<u8>, Error> {
268         let mut max_siglen = 0;
269         // Safety: `self.md_ctx` is non-`nullptr` and valid.
270         unsafe {
271             cvt(ffi::EVP_DigestSignFinal(self.md_ctx.0, ptr::null_mut(), &mut max_siglen))?;
272         }
273         let mut buf = vec_try![0; max_siglen]?;
274         let mut actual_siglen = max_siglen;
275         // Safety: `self.md_ctx` is non-`nullptr` and valid, and `buf` does have `actual_siglen`
276         // bytes.
277         unsafe {
278             cvt(ffi::EVP_DigestSignFinal(
279                 self.md_ctx.0,
280                 buf.as_mut_ptr() as *mut _,
281                 &mut actual_siglen,
282             ))?;
283         }
284         buf.truncate(actual_siglen);
285         Ok(buf)
286     }
287 }
288 
289 /// RSA signing operation based on BoringSSL, for undigested data.
290 pub struct BoringRsaUndigestSignOperation {
291     rsa_key: openssl::rsa::Rsa<openssl::pkey::Private>,
292     left_pad: bool,
293     pending_input: Vec<u8>,
294     max_size: usize,
295 }
296 
297 impl BoringRsaUndigestSignOperation {
new(key: crypto::rsa::Key, mode: SignMode) -> Result<Self, Error>298     fn new(key: crypto::rsa::Key, mode: SignMode) -> Result<Self, Error> {
299         let rsa_key = ossl!(openssl::rsa::Rsa::private_key_from_der(&key.0))?;
300         let (left_pad, max_size) = match mode {
301             SignMode::NoPadding => (true, rsa_key.size() as usize),
302             SignMode::Pkcs1_1_5Padding(Digest::None) => {
303                 (false, (rsa_key.size() as usize) - PKCS1_UNDIGESTED_SIGNATURE_PADDING_OVERHEAD)
304             }
305             _ => return Err(km_err!(UnsupportedPaddingMode, "sign undigested mode {:?}", mode)),
306         };
307         Ok(Self { rsa_key, left_pad, pending_input: Vec::new(), max_size })
308     }
309 }
310 
311 impl crypto::AccumulatingOperation for BoringRsaUndigestSignOperation {
max_input_size(&self) -> Option<usize>312     fn max_input_size(&self) -> Option<usize> {
313         Some(self.max_size)
314     }
315 
update(&mut self, data: &[u8]) -> Result<(), Error>316     fn update(&mut self, data: &[u8]) -> Result<(), Error> {
317         // OK to accumulate data as there is a size limit.
318         self.pending_input.try_extend_from_slice(data)?;
319         Ok(())
320     }
321 
finish(self: Box<Self>) -> Result<Vec<u8>, Error>322     fn finish(self: Box<Self>) -> Result<Vec<u8>, Error> {
323         let mut buf = vec_try![0; self.rsa_key.size() as usize]?;
324         if self.left_pad {
325             let padded_input = zero_pad_left(&self.pending_input, self.max_size)?;
326             ossl!(self.rsa_key.private_encrypt(
327                 &padded_input,
328                 &mut buf,
329                 openssl::rsa::Padding::NONE
330             ))?;
331         } else {
332             ossl!(self.rsa_key.private_encrypt(
333                 &self.pending_input,
334                 &mut buf,
335                 openssl::rsa::Padding::PKCS1
336             ))?;
337         }
338 
339         Ok(buf)
340     }
341 }
342 
zero_pad_left(data: &[u8], len: usize) -> Result<Vec<u8>, Error>343 fn zero_pad_left(data: &[u8], len: usize) -> Result<Vec<u8>, Error> {
344     let mut dest = vec_try![0; len]?;
345     let padding_len = len - data.len();
346     dest[padding_len..].copy_from_slice(data);
347     Ok(dest)
348 }
349