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