#![allow(non_camel_case_types)]
use std::{
ffi::c_void,
io::{Error, ErrorKind},
mem, ptr,
};
use num_enum::{FromPrimitive, IntoPrimitive};
use uuid::Uuid;
use cc_teec::{
TEEC_AllocateSharedMemory, TEEC_CloseSession, TEEC_FinalizeContext, TEEC_InitializeContext,
TEEC_InvokeCommand, TEEC_OpenSession, TEEC_RegisterSharedMemory, TEEC_ReleaseSharedMemory, raw,
};
const EXAMPLE_TA_UUID: &str = "9b28392f-39d2-497d-91af-b6600e3d6a3e";
#[derive(FromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum Command {
ValueInputOutput = 0, ValueInout = 1,
MemrefTempInputOutput = 10, MemrefTempInout = 11,
MemrefWholeInputOutput = 20, MemrefWholeInout = 21,
MemrefPartialInputOutput = 30, MemrefPartialInout = 31,
MixedParams = 100,
#[default]
Unknown = 0xFF,
}
type Result<T> = std::result::Result<T, Error>;
struct Client_Session {
ctx: Box<raw::TEEC_Context>,
session: raw::TEEC_Session,
}
impl Client_Session {
fn new(uuid: &raw::TEEC_UUID) -> Result<Self> {
let mut ctx: Box<raw::TEEC_Context> = Box::new(unsafe { mem::zeroed() });
let mut session: raw::TEEC_Session = unsafe { mem::zeroed() };
let mut origin = 0_u32;
let res = TEEC_InitializeContext(ptr::null(), ctx.as_mut());
if res != raw::TEEC_SUCCESS {
return Err(Error::from_raw_os_error(res as i32));
}
let res = TEEC_OpenSession(
ctx.as_mut(),
&mut session,
uuid,
raw::TEEC_LOGIN_PUBLIC,
ptr::null(),
ptr::null_mut(),
&mut origin,
);
if res != raw::TEEC_SUCCESS {
TEEC_FinalizeContext(ctx.as_mut());
return Err(Error::from_raw_os_error(res as i32));
}
Ok(Self { ctx, session })
}
fn invoke_command(&self, cmd_id: u32, op: &mut raw::TEEC_Operation) -> Result<()> {
let mut origin = 0_u32;
let res = TEEC_InvokeCommand(&self.session as *const _ as *mut _, cmd_id, op, &mut origin);
if res != raw::TEEC_SUCCESS {
return Err(Error::from_raw_os_error(res as i32));
}
Ok(())
}
fn context_mut(&mut self) -> &mut raw::TEEC_Context {
self.ctx.as_mut()
}
}
impl Drop for Client_Session {
fn drop(&mut self) {
TEEC_CloseSession(&mut self.session);
TEEC_FinalizeContext(self.ctx.as_mut());
}
}
fn main() -> Result<()> {
let uuid = Uuid::parse_str(EXAMPLE_TA_UUID)
.map_err(|_| Error::new(ErrorKind::InvalidInput, "无效 UUID"))?;
let teec_uuid = uuid_to_teec_uuid(&uuid)?;
let mut session = Client_Session::new(&teec_uuid)?;
value_types(&session)?;
memref_temp_types(&session)?;
memref_whole(&mut session)?;
memref_partial(&mut session)?;
mixed_params(&session)?;
Ok(())
}
fn value_types(session: &Client_Session) -> Result<()> {
println!("\nVALUE 参数类型");
{
let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
op.paramTypes = raw::TEEC_PARAM_TYPES(
raw::TEEC_VALUE_INPUT,
raw::TEEC_VALUE_OUTPUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
);
op.params[0].value.a = 100;
op.params[0].value.b = 200;
session.invoke_command(Command::ValueInputOutput.into(), &mut op)?;
let result = unsafe { op.params[1].value.a };
println!(" VALUE_INPUT+OUTPUT: {} + {} = {}", 100, 200, result);
}
{
let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
op.paramTypes = raw::TEEC_PARAM_TYPES(
raw::TEEC_VALUE_INOUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
);
op.params[0].value.a = 42;
op.params[0].value.b = 99;
session.invoke_command(Command::ValueInout.into(), &mut op)?;
let a_out = unsafe { op.params[0].value.a };
let b_out = unsafe { op.params[0].value.b };
println!(" VALUE_INOUT: (42, 99) → ({}, {})", a_out, b_out);
}
Ok(())
}
fn memref_temp_types(session: &Client_Session) -> Result<()> {
println!("\nMEMREF TEMP 参数类型");
{
let input_data = vec![1u8, 2, 3, 4, 5];
let mut output_data = vec![0u8; 16];
let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
op.paramTypes = raw::TEEC_PARAM_TYPES(
raw::TEEC_MEMREF_TEMP_INPUT,
raw::TEEC_MEMREF_TEMP_OUTPUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
);
op.params[0].tmpref.buffer = input_data.as_ptr() as *mut _;
op.params[0].tmpref.size = input_data.len();
op.params[1].tmpref.buffer = output_data.as_mut_ptr() as *mut _;
op.params[1].tmpref.size = output_data.len();
session.invoke_command(Command::MemrefTempInputOutput.into(), &mut op)?;
println!(
" TEMP_INPUT+OUTPUT: {:?} → {:?}",
input_data,
&output_data[..8]
);
}
{
let mut inout_data: Vec<u8> = vec![0xAA, 0xBB, 0xCC, 0xDD];
let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
op.paramTypes = raw::TEEC_PARAM_TYPES(
raw::TEEC_MEMREF_TEMP_INOUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
);
op.params[0].tmpref.buffer = inout_data.as_mut_ptr() as *mut _;
op.params[0].tmpref.size = inout_data.len();
session.invoke_command(Command::MemrefTempInout.into(), &mut op)?;
println!(
" TEMP_INOUT: {:?} → {:?}",
&[0xAA, 0xBB, 0xCC, 0xDD],
inout_data
);
}
Ok(())
}
fn memref_whole_input_output(session: &mut Client_Session) -> Result<()> {
let input_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
let output_size = 8;
let mut input_shm =
allocate_shared_memory(session.context_mut(), input_data.len(), raw::TEEC_MEM_INPUT)?;
copy_to_shm(&input_data, &input_shm);
let mut output_shm =
allocate_shared_memory(session.context_mut(), output_size, raw::TEEC_MEM_OUTPUT)?;
let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
op.paramTypes = raw::TEEC_PARAM_TYPES(
raw::TEEC_MEMREF_WHOLE,
raw::TEEC_MEMREF_WHOLE,
raw::TEEC_NONE,
raw::TEEC_NONE,
);
op.params[0].memref.parent = &mut input_shm as *mut _;
op.params[0].memref.size = input_data.len();
op.params[1].memref.parent = &mut output_shm as *mut _;
op.params[1].memref.size = output_size;
session.invoke_command(Command::MemrefWholeInputOutput.into(), &mut op)?;
let output_data = read_from_shm(&output_shm, output_size);
println!(" WHOLE_INPUT+OUTPUT: {:?} → {:?}", input_data, output_data);
TEEC_ReleaseSharedMemory(&mut input_shm);
TEEC_ReleaseSharedMemory(&mut output_shm);
Ok(())
}
fn memref_whole_inout_allocated(session: &mut Client_Session) -> Result<()> {
let mut data = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
let original = data.clone();
let flags = raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT;
let mut shm = allocate_shared_memory(session.context_mut(), data.len(), flags)?;
copy_to_shm(&data, &shm);
let mut op = create_memref_operation(&mut shm, data.len());
session.invoke_command(Command::MemrefWholeInout.into(), &mut op)?;
copy_from_shm(&shm, &mut data);
println!(" WHOLE_INOUT (Alloc): {:?} → {:?}", original, data);
TEEC_ReleaseSharedMemory(&mut shm);
Ok(())
}
fn memref_whole_inout_registered(session: &mut Client_Session) -> Result<()> {
let mut data = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
let original = data.clone();
let flags = raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT;
let mut shm = register_shared_memory(
session.context_mut(),
data.as_mut_ptr() as *mut c_void,
data.len(),
flags,
)?;
let mut op = create_memref_operation(&mut shm, data.len());
session.invoke_command(Command::MemrefWholeInout.into(), &mut op)?;
copy_from_shm(&shm, &mut data);
println!(" WHOLE_INOUT (Register): {:?} → {:?}", original, data);
TEEC_ReleaseSharedMemory(&mut shm);
Ok(())
}
fn memref_whole(session: &mut Client_Session) -> Result<()> {
println!("\nMEMREF WHOLE 参数类型");
memref_whole_input_output(session)?;
memref_whole_inout_allocated(session)?;
memref_whole_inout_registered(session)?;
Ok(())
}
fn allocate_shared_memory(
ctx: &mut raw::TEEC_Context,
size: usize,
flags: u32,
) -> Result<raw::TEEC_SharedMemory> {
let mut shm: raw::TEEC_SharedMemory = unsafe { mem::zeroed() };
shm.size = size;
shm.flags = flags;
let res = TEEC_AllocateSharedMemory(ctx, &mut shm);
if res != raw::TEEC_SUCCESS {
return Err(Error::from_raw_os_error(res as i32));
}
Ok(shm)
}
fn register_shared_memory(
ctx: &mut raw::TEEC_Context,
buffer: *mut c_void,
size: usize,
flags: u32,
) -> Result<raw::TEEC_SharedMemory> {
let mut shm: raw::TEEC_SharedMemory = unsafe { mem::zeroed() };
shm.buffer = buffer;
shm.size = size;
shm.flags = flags;
let res = TEEC_RegisterSharedMemory(ctx, &mut shm);
if res != raw::TEEC_SUCCESS {
return Err(Error::from_raw_os_error(res as i32));
}
Ok(shm)
}
fn copy_to_shm(data: &[u8], shm: &raw::TEEC_SharedMemory) {
unsafe {
ptr::copy_nonoverlapping(data.as_ptr(), shm.buffer as *mut u8, data.len());
}
}
fn copy_from_shm(shm: &raw::TEEC_SharedMemory, data: &mut [u8]) {
unsafe {
ptr::copy_nonoverlapping(shm.buffer as *const u8, data.as_mut_ptr(), data.len());
}
}
fn read_from_shm(shm: &raw::TEEC_SharedMemory, size: usize) -> Vec<u8> {
let mut data = vec![0u8; size];
unsafe {
ptr::copy_nonoverlapping(shm.buffer as *const u8, data.as_mut_ptr(), size);
}
data
}
fn read_from_shm_offset(shm: &raw::TEEC_SharedMemory, offset: usize, size: usize) -> Vec<u8> {
let mut data = vec![0u8; size];
unsafe {
ptr::copy_nonoverlapping(
(shm.buffer as *const u8).add(offset),
data.as_mut_ptr(),
size,
);
}
data
}
fn copy_to_shm_offset(data: &[u8], shm: &raw::TEEC_SharedMemory, offset: usize) {
unsafe {
ptr::copy_nonoverlapping(
data.as_ptr(),
(shm.buffer as *mut u8).add(offset),
data.len(),
);
}
}
fn create_memref_operation(shm: &mut raw::TEEC_SharedMemory, size: usize) -> raw::TEEC_Operation {
let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
op.paramTypes = raw::TEEC_PARAM_TYPES(
raw::TEEC_MEMREF_WHOLE,
raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
);
op.params[0].memref.parent = shm;
op.params[0].memref.size = size;
op
}
fn memref_partial_input_output(
session: &mut Client_Session,
shm: &mut raw::TEEC_SharedMemory,
page_size: usize,
) -> Result<()> {
let input_data = vec![0x10, 0x20, 0x30, 0x40];
let output_size = 8;
let input_offset = 0; let output_offset = page_size;
copy_to_shm_offset(&input_data, shm, input_offset);
let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
op.paramTypes = raw::TEEC_PARAM_TYPES(
raw::TEEC_MEMREF_PARTIAL_INPUT,
raw::TEEC_MEMREF_PARTIAL_OUTPUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
);
op.params[0].memref.parent = shm;
op.params[0].memref.offset = input_offset;
op.params[0].memref.size = input_data.len();
op.params[1].memref.parent = shm;
op.params[1].memref.offset = output_offset;
op.params[1].memref.size = output_size;
session.invoke_command(Command::MemrefPartialInputOutput.into(), &mut op)?;
let output_data = read_from_shm_offset(shm, output_offset, output_size);
println!(
" PARTIAL_INPUT+OUTPUT:\toffset[0]={:?} → offset[{}]={:?}",
input_data, output_offset, output_data
);
Ok(())
}
fn memref_partial_inout(
session: &mut Client_Session,
shm: &mut raw::TEEC_SharedMemory,
page_size: usize,
) -> Result<()> {
let data = vec![0x01, 0x02, 0x03, 0x04];
let key = 0x55u8;
let original = data.clone();
let offset = 2 * page_size;
copy_to_shm_offset(&data, shm, offset);
let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
op.paramTypes = raw::TEEC_PARAM_TYPES(
raw::TEEC_VALUE_INPUT,
raw::TEEC_MEMREF_PARTIAL_INOUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
);
op.params[0].value.a = key as u32;
op.params[1].memref.parent = shm;
op.params[1].memref.offset = offset;
op.params[1].memref.size = data.len();
session.invoke_command(Command::MemrefPartialInout.into(), &mut op)?;
let result = read_from_shm_offset(shm, offset, data.len());
println!(
" PARTIAL_INOUT: offset[{}]={:?} ^ 0x{:02X} → {:?}",
offset, original, key, result
);
Ok(())
}
fn memref_partial(session: &mut Client_Session) -> Result<()> {
println!("\nMEMREF PARTIAL 参数类型");
let page_size = 4096;
let shm_size = 8 * page_size; let mut shm = allocate_shared_memory(
session.context_mut(),
shm_size,
raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT,
)?;
memref_partial_input_output(session, &mut shm, page_size)?;
memref_partial_inout(session, &mut shm, page_size)?;
TEEC_ReleaseSharedMemory(&mut shm);
Ok(())
}
fn mixed_params(session: &Client_Session) -> Result<()> {
println!("\n混合参数示例");
let input_data = vec![10u8, 20, 30, 40, 50];
let mut output_hash = vec![0u8; 4];
let mut op: raw::TEEC_Operation = unsafe { mem::zeroed() };
op.paramTypes = raw::TEEC_PARAM_TYPES(
raw::TEEC_VALUE_INOUT,
raw::TEEC_MEMREF_TEMP_INPUT,
raw::TEEC_MEMREF_TEMP_OUTPUT,
raw::TEEC_VALUE_OUTPUT,
);
op.params[0].value.a = 7; op.params[1].tmpref.buffer = input_data.as_ptr() as *mut _;
op.params[1].tmpref.size = input_data.len();
op.params[2].tmpref.buffer = output_hash.as_mut_ptr() as *mut _;
op.params[2].tmpref.size = output_hash.len();
session.invoke_command(Command::MixedParams.into(), &mut op)?;
let counter = unsafe { op.params[0].value.a };
let status = unsafe { op.params[3].value.a };
let processed = unsafe { op.params[3].value.b };
println!(" 输入: counter={}, data={:?}", 7, input_data);
println!(
" 输出: counter={}, hash=0x{:02X}{:02X}{:02X}{:02X}, status=0x{:08X}, bytes={}",
counter, output_hash[3], output_hash[2], output_hash[1], output_hash[0], status, processed
);
Ok(())
}
fn uuid_to_teec_uuid(uuid: &Uuid) -> Result<raw::TEEC_UUID> {
let (time_low, time_mid, time_hi_and_version, clock_seq_and_node) = uuid.as_fields();
Ok(raw::TEEC_UUID {
timeLow: time_low,
timeMid: time_mid,
timeHiAndVersion: time_hi_and_version,
clockSeqAndNode: *clock_seq_and_node,
})
}