tee/
lib.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5mod tee_client_api;
6
7use self::tee_client_api::*;
8use log::error;
9use std::{mem, ptr};
10
11use self::tee_client_api::{
12    TEEC_TempMemoryReference as TeecTempMemoryReference, TEEC_Value as TeecValue,
13};
14
15pub use self::tee_client_api::{
16    TEEC_Operation as TeecOperation, TEEC_Parameter as TeecParameter, TEEC_ERROR_NOT_SUPPORTED,
17    TEEC_ERROR_SHORT_BUFFER, TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE,
18    TEEC_SUCCESS, TEEC_VALUE_INPUT,
19};
20
21/// The TA UUID for keysafe: the trust side app for KMS.
22pub static KEYSAFE_TA_UUID: TEEC_UUID = TEEC_UUID {
23    timeLow: 0x808032e0,
24    timeMid: 0xfd9e,
25    timeHiAndVersion: 0x4e6f,
26    clockSeqAndNode: [0x88, 0x96, 0x54, 0x47, 0x35, 0xc9, 0x84, 0x80],
27};
28
29/// This is the same macro definition as TEEC_PARAM_TYPES in tee-client-types.h
30pub fn teec_param_types(
31    param0_type: u32,
32    param1_type: u32,
33    param2_type: u32,
34    param3_type: u32,
35) -> u32 {
36    ((param0_type & 0xF) << 0)
37        | ((param1_type & 0xF) << 4)
38        | ((param2_type & 0xF) << 8)
39        | ((param3_type & 0xF) << 12)
40}
41
42/// Gets a None parameter.
43pub fn get_zero_parameter() -> TeecParameter {
44    let zero_parameter: TeecParameter = unsafe { mem::zeroed() };
45    zero_parameter
46}
47
48/// Gets a value parameter.
49pub fn get_value_parameter(a: u32, b: u32) -> TeecParameter {
50    TeecParameter { value: TeecValue { a, b } }
51}
52
53/// Gets a temp memory reference parameter as output.
54pub fn get_memref_output_parameter(data: &mut [u8]) -> TeecParameter {
55    TeecParameter {
56        tmpref: TeecTempMemoryReference {
57            buffer: data.as_mut_ptr() as *mut std::ffi::c_void,
58            size: data.len() as u64,
59        },
60    }
61}
62
63/// Gets a temp memory reference parameter as input.
64pub fn get_memref_input_parameter(data: &[u8]) -> TeecParameter {
65    TeecParameter {
66        tmpref: TeecTempMemoryReference {
67            buffer: data.as_ptr() as *mut std::ffi::c_void,
68            size: data.len() as u64,
69        },
70    }
71}
72
73/// Creates an operation object that would be used in call_command.
74pub fn create_operation(param_type: u32, params: [TeecParameter; 4]) -> TeecOperation {
75    TeecOperation {
76        started: 0,
77        paramTypes: param_type,
78        params,
79        imp: teec_operation_impl { reserved: 0 as ::std::os::raw::c_char },
80    }
81}
82
83/// Creates a temporary session and call a command.
84///
85/// Returns error code on failure.
86pub fn call_command(op: &mut TeecOperation, command_id: u32) -> Result<(), u32> {
87    let mut tee_context = TeeContext::new()?;
88    let mut tee_session = tee_context.new_session()?;
89    let mut return_origin: u32 = 0;
90    tee_session.invoke_command(command_id, op, &mut return_origin)
91}
92
93/// Creates a temporary session using the provided device and call a command.
94///
95/// Returns error code on failure.
96pub fn call_command_on_device(
97    dev: &std::ffi::CStr,
98    op: &mut TeecOperation,
99    command_id: u32,
100) -> Result<(), u32> {
101    let mut tee_context = TeeContext::new_with_device(dev)?;
102    let mut tee_session = tee_context.new_session()?;
103    let mut return_origin: u32 = 0;
104    tee_session.invoke_command(command_id, op, &mut return_origin)
105}
106
107struct TeeContext {
108    context: TEEC_Context,
109}
110
111impl TeeContext {
112    pub fn new() -> Result<Self, u32> {
113        Self::new_with_ptr(ptr::null())
114    }
115
116    pub fn new_with_device(dev: &std::ffi::CStr) -> Result<Self, u32> {
117        Self::new_with_ptr(dev.as_ptr())
118    }
119
120    fn new_with_ptr(dev: *const std::os::raw::c_char) -> Result<Self, u32> {
121        let mut context: TEEC_Context = unsafe { mem::zeroed() };
122        let result = unsafe { TEEC_InitializeContext(dev, &mut context) };
123        if result != TEEC_SUCCESS {
124            error!("Failed to initialize context: {:?}", result);
125            return Err(result);
126        }
127        Ok(TeeContext { context })
128    }
129
130    pub fn new_session(&mut self) -> Result<TeeSession, u32> {
131        let mut session: TEEC_Session = unsafe { mem::zeroed() };
132
133        let mut return_origin: u32 = 0;
134        let result = unsafe {
135            TEEC_OpenSession(
136                &mut self.context,
137                &mut session,
138                &KEYSAFE_TA_UUID,
139                TEEC_LOGIN_PUBLIC,
140                ptr::null_mut(),
141                ptr::null_mut(),
142                &mut return_origin,
143            )
144        };
145        if result != TEEC_SUCCESS {
146            error!("Failed to open session ({:?} {:?})\n", result, return_origin);
147            return Err(result);
148        }
149        Ok(TeeSession { session })
150    }
151}
152
153impl Drop for TeeContext {
154    fn drop(&mut self) {
155        unsafe { TEEC_FinalizeContext(&mut self.context) };
156    }
157}
158
159struct TeeSession {
160    session: TEEC_Session,
161}
162
163impl TeeSession {
164    pub fn invoke_command(
165        &mut self,
166        command_id: u32,
167        operation: *mut TEEC_Operation,
168        return_origin: *mut u32,
169    ) -> Result<(), u32> {
170        let result =
171            unsafe { TEEC_InvokeCommand(&mut self.session, command_id, operation, return_origin) };
172        if result != TEEC_SUCCESS {
173            error!("TEEC_InvokeCommand failed with code {:?} origin {:?}", result, return_origin);
174            return Err(result);
175        }
176        Ok(())
177    }
178}
179
180impl Drop for TeeSession {
181    fn drop(&mut self) {
182        unsafe { TEEC_CloseSession(&mut self.session) };
183    }
184}