/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //! Client used to connect to the keybox service. use crate::ffi_bindings::{KeyboxUnwrapReq, KeyboxUnwrapResp, KEYBOX_PORT, KEYBOX_RESP_HDR_SIZE}; use core::ffi::CStr; use kmr_common::{km_err, vec_try, Error}; use tipc::{Handle, TipcError}; /// A `KeyboxSession` is a `Handle`. type KeyboxSession = Handle; /// Connection to the keybox service. #[derive(Debug, Eq, PartialEq)] struct Keybox(KeyboxSession); impl Keybox { /// Attempt to open a keybox session. /// /// # Examples /// /// ``` /// let keybox = keybox::open().expect("could not open hwkey session"); /// ``` /// fn new() -> Result { let port = CStr::from_bytes_with_nul(KEYBOX_PORT).expect("KEYBOX_PORT was not null terminated"); KeyboxSession::connect(port).map(Self) } pub(crate) fn keybox_unwrap(&self, wrapped_keybox: &[u8]) -> Result, Error> { let req = KeyboxUnwrapReq::new(wrapped_keybox); self.0 .send(&req) .map_err(|e| km_err!(SecureHwCommunicationFailed, "send unwrap cmd failed: {:?}", e))?; // This uses the same assumption as SetWrappedAttestationKey on the c++ code; which is that // the size of the unwrapped key won't be bigger than the size of the wrapped one. let mut buffer = vec_try![0; wrapped_keybox.len() + KEYBOX_RESP_HDR_SIZE]?; let response: KeyboxUnwrapResp = self .0 .recv(&mut buffer) .map_err(|e| km_err!(SecureHwCommunicationFailed, "unwrap response error: {:?}", e))?; Ok(response.get_unwrapped_keybox()) } } pub(crate) fn keybox_unwrap(wrapped_keybox: &[u8]) -> Result, Error> { let keybox = Keybox::new().map_err(|e| { km_err!(SecureHwCommunicationFailed, "error opening keybox service: {:?}", e) })?; keybox.keybox_unwrap(wrapped_keybox) } #[cfg(test)] mod tests { use super::*; use test::{expect, expect_eq, skip}; // AOSP keybox test server just XORs data with a constant and checksum it, it is not intended to // be secure; just to be used to check the IPC commands. fn create_fake_wrapped_data(data: &[u8]) -> Vec { let mut wrapped_data = Vec::::new(); let mut checksum: u8 = 0; for &element in data { let wrapped_element = element ^ 0x42; wrapped_data.push(wrapped_element); checksum ^= wrapped_element; } wrapped_data.push(checksum); wrapped_data } #[test] fn unwrap_fake_keybox_data() { if true { skip!("TODO: reinstate test"); } let original_data = b"test_data_to_wrap".as_slice(); let wrapped_data = create_fake_wrapped_data(original_data); let result = keybox_unwrap(&wrapped_data); expect!(result.is_ok(), "Failed to unwrap data: {:?}", result); let unwrapped_data = result.expect("Couldn't unwrap data"); expect_eq!(original_data, unwrapped_data, "Unwrapped data do not match original one"); } }