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