1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 //! Client used to connect to the keybox service.
17 use crate::ffi_bindings::{KeyboxUnwrapReq, KeyboxUnwrapResp, KEYBOX_PORT, KEYBOX_RESP_HDR_SIZE};
18 use core::ffi::CStr;
19 use kmr_common::{km_err, vec_try, Error};
20 use tipc::{Handle, TipcError};
21
22 /// A `KeyboxSession` is a `Handle`.
23 type KeyboxSession = Handle;
24 /// Connection to the keybox service.
25 #[derive(Debug, Eq, PartialEq)]
26 struct Keybox(KeyboxSession);
27
28 impl Keybox {
29 /// Attempt to open a keybox session.
30 ///
31 /// # Examples
32 ///
33 /// ```
34 /// let keybox = keybox::open().expect("could not open hwkey session");
35 /// ```
36 ///
new() -> Result<Self, TipcError>37 fn new() -> Result<Self, TipcError> {
38 let port =
39 CStr::from_bytes_with_nul(KEYBOX_PORT).expect("KEYBOX_PORT was not null terminated");
40 KeyboxSession::connect(port).map(Self)
41 }
42
keybox_unwrap(&self, wrapped_keybox: &[u8]) -> Result<Vec<u8>, Error>43 pub(crate) fn keybox_unwrap(&self, wrapped_keybox: &[u8]) -> Result<Vec<u8>, Error> {
44 let req = KeyboxUnwrapReq::new(wrapped_keybox);
45 self.0
46 .send(&req)
47 .map_err(|e| km_err!(SecureHwCommunicationFailed, "send unwrap cmd failed: {:?}", e))?;
48 // This uses the same assumption as SetWrappedAttestationKey on the c++ code; which is that
49 // the size of the unwrapped key won't be bigger than the size of the wrapped one.
50 let mut buffer = vec_try![0; wrapped_keybox.len() + KEYBOX_RESP_HDR_SIZE]?;
51 let response: KeyboxUnwrapResp = self
52 .0
53 .recv(&mut buffer)
54 .map_err(|e| km_err!(SecureHwCommunicationFailed, "unwrap response error: {:?}", e))?;
55 Ok(response.get_unwrapped_keybox())
56 }
57 }
58
keybox_unwrap(wrapped_keybox: &[u8]) -> Result<Vec<u8>, Error>59 pub(crate) fn keybox_unwrap(wrapped_keybox: &[u8]) -> Result<Vec<u8>, Error> {
60 let keybox = Keybox::new().map_err(|e| {
61 km_err!(SecureHwCommunicationFailed, "error opening keybox service: {:?}", e)
62 })?;
63 keybox.keybox_unwrap(wrapped_keybox)
64 }
65
66 #[cfg(test)]
67 mod tests {
68 use super::*;
69 use test::{expect, expect_eq, skip};
70
71 // AOSP keybox test server just XORs data with a constant and checksum it, it is not intended to
72 // be secure; just to be used to check the IPC commands.
create_fake_wrapped_data(data: &[u8]) -> Vec<u8>73 fn create_fake_wrapped_data(data: &[u8]) -> Vec<u8> {
74 let mut wrapped_data = Vec::<u8>::new();
75 let mut checksum: u8 = 0;
76 for &element in data {
77 let wrapped_element = element ^ 0x42;
78 wrapped_data.push(wrapped_element);
79 checksum ^= wrapped_element;
80 }
81 wrapped_data.push(checksum);
82 wrapped_data
83 }
84
85 #[test]
unwrap_fake_keybox_data()86 fn unwrap_fake_keybox_data() {
87 if true {
88 skip!("TODO: reinstate test");
89 }
90 let original_data = b"test_data_to_wrap".as_slice();
91 let wrapped_data = create_fake_wrapped_data(original_data);
92 let result = keybox_unwrap(&wrapped_data);
93 expect!(result.is_ok(), "Failed to unwrap data: {:?}", result);
94 let unwrapped_data = result.expect("Couldn't unwrap data");
95 expect_eq!(original_data, unwrapped_data, "Unwrapped data do not match original one");
96 }
97 }
98