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