xref: /aosp_15_r20/system/keymint/boringssl/src/aes_cmac.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 AES-CMAC.
16*9860b763SAndroid Build Coastguard Worker use crate::types::CmacCtx;
17*9860b763SAndroid Build Coastguard Worker use crate::{malloc_err, openssl_last_err};
18*9860b763SAndroid Build Coastguard Worker use alloc::boxed::Box;
19*9860b763SAndroid Build Coastguard Worker use alloc::vec::Vec;
20*9860b763SAndroid Build Coastguard Worker use bssl_sys as ffi;
21*9860b763SAndroid Build Coastguard Worker use kmr_common::{crypto, crypto::OpaqueOr, explicit, km_err, vec_try, Error};
22*9860b763SAndroid Build Coastguard Worker use log::error;
23*9860b763SAndroid Build Coastguard Worker 
24*9860b763SAndroid Build Coastguard Worker /// [`crypto::AesCmac`] implementation based on BoringSSL.
25*9860b763SAndroid Build Coastguard Worker pub struct BoringAesCmac;
26*9860b763SAndroid Build Coastguard Worker 
27*9860b763SAndroid Build Coastguard Worker impl crypto::AesCmac for BoringAesCmac {
begin( &self, key: OpaqueOr<crypto::aes::Key>, ) -> Result<Box<dyn crypto::AccumulatingOperation>, Error>28*9860b763SAndroid Build Coastguard Worker     fn begin(
29*9860b763SAndroid Build Coastguard Worker         &self,
30*9860b763SAndroid Build Coastguard Worker         key: OpaqueOr<crypto::aes::Key>,
31*9860b763SAndroid Build Coastguard Worker     ) -> Result<Box<dyn crypto::AccumulatingOperation>, Error> {
32*9860b763SAndroid Build Coastguard Worker         let key = explicit!(key)?;
33*9860b763SAndroid Build Coastguard Worker         // Safety: all of the `ffi::EVP_aes_<N>_cbc` functions return a non-null valid pointer.
34*9860b763SAndroid Build Coastguard Worker         let (cipher, k) = unsafe {
35*9860b763SAndroid Build Coastguard Worker             match &key {
36*9860b763SAndroid Build Coastguard Worker                 crypto::aes::Key::Aes128(k) => (ffi::EVP_aes_128_cbc(), &k[..]),
37*9860b763SAndroid Build Coastguard Worker                 crypto::aes::Key::Aes192(k) => (ffi::EVP_aes_192_cbc(), &k[..]),
38*9860b763SAndroid Build Coastguard Worker                 crypto::aes::Key::Aes256(k) => (ffi::EVP_aes_256_cbc(), &k[..]),
39*9860b763SAndroid Build Coastguard Worker             }
40*9860b763SAndroid Build Coastguard Worker         };
41*9860b763SAndroid Build Coastguard Worker 
42*9860b763SAndroid Build Coastguard Worker         let op = BoringAesCmacOperation {
43*9860b763SAndroid Build Coastguard Worker             // Safety: raw pointer is immediately checked for null below, and BoringSSL only emits
44*9860b763SAndroid Build Coastguard Worker             // valid pointers or null.
45*9860b763SAndroid Build Coastguard Worker             ctx: unsafe { CmacCtx(ffi::CMAC_CTX_new()) },
46*9860b763SAndroid Build Coastguard Worker         };
47*9860b763SAndroid Build Coastguard Worker         if op.ctx.0.is_null() {
48*9860b763SAndroid Build Coastguard Worker             return Err(malloc_err!());
49*9860b763SAndroid Build Coastguard Worker         }
50*9860b763SAndroid Build Coastguard Worker 
51*9860b763SAndroid Build Coastguard Worker         // Safety: `op.ctx` is known non-null and valid, as is `cipher`.  `key_len` is length of
52*9860b763SAndroid Build Coastguard Worker         // `key.0`, which is a valid `Vec<u8>`.
53*9860b763SAndroid Build Coastguard Worker         let result = unsafe {
54*9860b763SAndroid Build Coastguard Worker             ffi::CMAC_Init(
55*9860b763SAndroid Build Coastguard Worker                 op.ctx.0,
56*9860b763SAndroid Build Coastguard Worker                 k.as_ptr() as *const libc::c_void,
57*9860b763SAndroid Build Coastguard Worker                 k.len(),
58*9860b763SAndroid Build Coastguard Worker                 cipher,
59*9860b763SAndroid Build Coastguard Worker                 core::ptr::null_mut(),
60*9860b763SAndroid Build Coastguard Worker             )
61*9860b763SAndroid Build Coastguard Worker         };
62*9860b763SAndroid Build Coastguard Worker         if result != 1 {
63*9860b763SAndroid Build Coastguard Worker             error!("Failed to CMAC_Init()");
64*9860b763SAndroid Build Coastguard Worker             return Err(openssl_last_err());
65*9860b763SAndroid Build Coastguard Worker         }
66*9860b763SAndroid Build Coastguard Worker         Ok(Box::new(op))
67*9860b763SAndroid Build Coastguard Worker     }
68*9860b763SAndroid Build Coastguard Worker }
69*9860b763SAndroid Build Coastguard Worker 
70*9860b763SAndroid Build Coastguard Worker /// AES-CMAC implementation based on BoringSSL.
71*9860b763SAndroid Build Coastguard Worker ///
72*9860b763SAndroid Build Coastguard Worker /// This implementation uses the `unsafe` wrappers around `CMAC_*` functions directly, because
73*9860b763SAndroid Build Coastguard Worker /// BoringSSL does not support the `EVP_PKEY_CMAC` implementations that are used in the rust-openssl
74*9860b763SAndroid Build Coastguard Worker /// crate.
75*9860b763SAndroid Build Coastguard Worker pub struct BoringAesCmacOperation {
76*9860b763SAndroid Build Coastguard Worker     // Safety: `ctx` is always non-null and valid except for initial error path in `begin()`
77*9860b763SAndroid Build Coastguard Worker     ctx: CmacCtx,
78*9860b763SAndroid Build Coastguard Worker }
79*9860b763SAndroid Build Coastguard Worker 
80*9860b763SAndroid Build Coastguard Worker impl core::ops::Drop for BoringAesCmacOperation {
drop(&mut self)81*9860b763SAndroid Build Coastguard Worker     fn drop(&mut self) {
82*9860b763SAndroid Build Coastguard Worker         // Safety: `self.ctx` might be null (in the error path when `ffi::CMAC_CTX_new` fails)
83*9860b763SAndroid Build Coastguard Worker         // but `ffi::CMAC_CTX_free` copes with null.
84*9860b763SAndroid Build Coastguard Worker         unsafe {
85*9860b763SAndroid Build Coastguard Worker             ffi::CMAC_CTX_free(self.ctx.0);
86*9860b763SAndroid Build Coastguard Worker         }
87*9860b763SAndroid Build Coastguard Worker     }
88*9860b763SAndroid Build Coastguard Worker }
89*9860b763SAndroid Build Coastguard Worker 
90*9860b763SAndroid Build Coastguard Worker impl crypto::AccumulatingOperation for BoringAesCmacOperation {
update(&mut self, data: &[u8]) -> Result<(), Error>91*9860b763SAndroid Build Coastguard Worker     fn update(&mut self, data: &[u8]) -> Result<(), Error> {
92*9860b763SAndroid Build Coastguard Worker         // Safety: `self.ctx` is non-null and valid, and `data` is a valid slice.
93*9860b763SAndroid Build Coastguard Worker         let result = unsafe { ffi::CMAC_Update(self.ctx.0, data.as_ptr(), data.len()) };
94*9860b763SAndroid Build Coastguard Worker         if result != 1 {
95*9860b763SAndroid Build Coastguard Worker             return Err(openssl_last_err());
96*9860b763SAndroid Build Coastguard Worker         }
97*9860b763SAndroid Build Coastguard Worker         Ok(())
98*9860b763SAndroid Build Coastguard Worker     }
99*9860b763SAndroid Build Coastguard Worker 
finish(self: Box<Self>) -> Result<Vec<u8>, Error>100*9860b763SAndroid Build Coastguard Worker     fn finish(self: Box<Self>) -> Result<Vec<u8>, Error> {
101*9860b763SAndroid Build Coastguard Worker         let mut output_len: usize = crypto::aes::BLOCK_SIZE;
102*9860b763SAndroid Build Coastguard Worker         let mut output = vec_try![0; crypto::aes::BLOCK_SIZE]?;
103*9860b763SAndroid Build Coastguard Worker         // Safety: `self.ctx` is non-null and valid; `output_len` is correct size of `output`
104*9860b763SAndroid Build Coastguard Worker         // buffer.
105*9860b763SAndroid Build Coastguard Worker         let result = unsafe {
106*9860b763SAndroid Build Coastguard Worker             ffi::CMAC_Final(self.ctx.0, output.as_mut_ptr(), &mut output_len as *mut usize)
107*9860b763SAndroid Build Coastguard Worker         };
108*9860b763SAndroid Build Coastguard Worker         if result != 1 {
109*9860b763SAndroid Build Coastguard Worker             return Err(openssl_last_err());
110*9860b763SAndroid Build Coastguard Worker         }
111*9860b763SAndroid Build Coastguard Worker         if output_len != crypto::aes::BLOCK_SIZE {
112*9860b763SAndroid Build Coastguard Worker             return Err(km_err!(BoringSslError, "Unexpected CMAC output size of {}", output_len));
113*9860b763SAndroid Build Coastguard Worker         }
114*9860b763SAndroid Build Coastguard Worker         Ok(output)
115*9860b763SAndroid Build Coastguard Worker     }
116*9860b763SAndroid Build Coastguard Worker }
117