Skip to main content

cc_teec/teec/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2025-2026 KylinSoft Co., Ltd. <https://www.kylinos.cn/>
3// See LICENSES for license details.
4
5//! TEE 客户端库实现,基于 GlobalPlatform TEE Client API 规范
6//!
7//! 提供与可信执行环境(TEE)通信的接口,包括:
8//! - 上下文管理(初始化/销毁)
9//! - 会话管理(打开/关闭)
10//! - 命令调用(通过机密通信通道序列化传输参数)
11//! - 共享内存管理(用于 MEMREF 类型参数的缓冲区管理)
12//! - CA 认证(为 TA 提供 ACL 访问控制信息)
13//!
14//! ## 通信机制
15//!
16//! CA 与 TA 之间的所有通信都通过机密通信通道(TLS + VSOCK)进行:
17//! - 请求和响应数据被序列化为字节流,通过 TLS 加密后发送
18//! - 共享内存(TEEC_SharedMemory)仅用于管理 MEMREF 参数的本地缓冲区
19//! - 真正的“共享”是通过网络传输实现的,而非传统意义上的内存映射
20//!
21//! ## 线程安全
22//!
23//! 所有 FFI 函数都是线程安全的,内部使用 `DashMap` 和 `Mutex` 保证并发访问安全。
24//! 但是,同一会话上的并发操作可能导致竞态条件,建议调用方进行同步。
25//!
26//! ## 错误处理
27//!
28//! FFI 函数返回 `TEEC_Result`(u32),通过 `ret_origin` 参数返回错误来源。
29//! 内部使用 Rust 的 `Result<T, Error>` 进行错误处理,最后转换为 C 风格的返回值。
30
31#![allow(non_camel_case_types)]
32#![allow(non_upper_case_globals)]
33#![allow(non_snake_case)]
34
35mod ca_auth;
36mod context;
37mod operation;
38mod safe_ptr;
39mod shared_memory;
40
41pub use ca_auth::{clear_cache, get_or_verify_ca};
42pub use context::ContextManager;
43pub use operation::{build_parameters_from_operation, update_operation_from_parameters};
44pub use shared_memory::SharedMemoryManager;
45
46use std::{
47    ffi::{c_char, c_void},
48    ptr,
49    sync::{
50        LazyLock,
51        atomic::{AtomicI32, Ordering},
52    },
53};
54
55use crate::{Error, ErrorKind, ErrorOrigin, Result, cc_client::client::CcClient, raw};
56use teec_protocol::{PacketType, TEE_Parameters, TEE_Request, TEE_Response};
57
58use log::{debug, warn};
59use postcard::{take_from_bytes, to_allocvec};
60use uuid::Uuid;
61
62static CONTEXT_ID_COUNTER: LazyLock<AtomicI32> = LazyLock::new(|| AtomicI32::new(-1));
63
64/// 将 GP TEE UUID 格式转换为标准 UUID 字符串
65fn uuid_to_string(uuid: &raw::TEEC_UUID) -> Result<String> {
66    let bytes: [u8; 16] = [
67        (uuid.timeLow >> 24) as u8,
68        (uuid.timeLow >> 16) as u8,
69        (uuid.timeLow >> 8) as u8,
70        uuid.timeLow as u8,
71        (uuid.timeMid >> 8) as u8,
72        uuid.timeMid as u8,
73        (uuid.timeHiAndVersion >> 8) as u8,
74        uuid.timeHiAndVersion as u8,
75        uuid.clockSeqAndNode[0],
76        uuid.clockSeqAndNode[1],
77        uuid.clockSeqAndNode[2],
78        uuid.clockSeqAndNode[3],
79        uuid.clockSeqAndNode[4],
80        uuid.clockSeqAndNode[5],
81        uuid.clockSeqAndNode[6],
82        uuid.clockSeqAndNode[7],
83    ];
84
85    Uuid::from_slice(&bytes)
86        .map(|u| u.to_string())
87        .map_err(|_| Error::new(ErrorKind::BadFormat))
88}
89
90/// 处理错误并返回 TEEC_Result
91fn handle_error(result: Result<u32>, ret_origin: *mut u32) -> raw::TEEC_Result {
92    match result {
93        Ok(code) => code,
94        Err(e) => {
95            if !ret_origin.is_null() {
96                // SAFETY: `ret_origin` 已通过 null 检查验证为非空指针。
97                // 写入 u32 值是安全的,调用方保证指针有效且可写。
98                unsafe {
99                    *ret_origin = e.origin().unwrap_or(ErrorOrigin::API) as u32;
100                }
101            }
102            e.raw_code()
103        }
104    }
105}
106
107/// 发送请求并接收响应
108fn send_request_and_recv_response(
109    ctx: *mut raw::TEEC_Context,
110    packet_type: PacketType,
111    request: &TEE_Request,
112) -> Result<TEE_Response> {
113    let client_arc = ContextManager::get_client(ctx)?;
114    let mut client = client_arc
115        .lock()
116        .map_err(|_| Error::new(ErrorKind::Generic).with_origin(ErrorOrigin::API))?;
117
118    let request_data = to_allocvec(request).map_err(|e| {
119        warn!("序列化请求失败:{e}");
120        Error::new(ErrorKind::BadFormat).with_origin(ErrorOrigin::API)
121    })?;
122
123    // 防止 OOM 攻击:限制请求数据最大为 64MB
124    const MAX_REQUEST_SIZE: usize = 64 * 1024 * 1024; // 64MB
125
126    if request_data.len() > MAX_REQUEST_SIZE {
127        warn!(
128            "请求数据过大:{} bytes (最大允许 {} bytes)",
129            request_data.len(),
130            MAX_REQUEST_SIZE
131        );
132        return Err(Error::new(ErrorKind::BadFormat).with_origin(ErrorOrigin::API));
133    }
134
135    client
136        .send_data_with_header(packet_type, &request_data)
137        .map_err(|e| {
138            warn!("发送请求失败:{e}");
139            Error::new(ErrorKind::Communication).with_origin(ErrorOrigin::COMMS)
140        })?;
141
142    let mut len_buf = [0u8; 4];
143
144    client.recv_data(&mut len_buf).map_err(|e| {
145        warn!("接收响应长度失败:{e}");
146        Error::new(ErrorKind::Communication).with_origin(ErrorOrigin::COMMS)
147    })?;
148
149    // 防止整数溢出:先验证 u32 值在合理范围内,再转换为 usize
150    let response_len_u32 = u32::from_ne_bytes(len_buf);
151    const MAX_RESPONSE_SIZE: usize = 64 * 1024 * 1024; // 64MB
152
153    if response_len_u32 > MAX_RESPONSE_SIZE as u32 {
154        warn!(
155            "响应数据过大:{} bytes (最大允许 {} bytes)",
156            response_len_u32, MAX_RESPONSE_SIZE
157        );
158        return Err(Error::new(ErrorKind::BadFormat).with_origin(ErrorOrigin::COMMS));
159    }
160
161    let response_len = response_len_u32 as usize;
162    let mut response_data = vec![0u8; response_len];
163
164    client.recv_data(&mut response_data).map_err(|e| {
165        warn!("接收响应数据失败:{e}");
166        Error::new(ErrorKind::Communication).with_origin(ErrorOrigin::COMMS)
167    })?;
168
169    take_from_bytes::<TEE_Response>(&response_data)
170        .map(|(response, _)| response)
171        .map_err(|e| {
172            warn!("反序列化响应失败:{e}");
173            Error::new(ErrorKind::BadFormat).with_origin(ErrorOrigin::API)
174        })
175}
176
177/// 向 ret_origin 指针写入错误来源(安全封装)
178fn set_ret_origin(p: *mut u32, v: u32) -> Result<()> {
179    safe_ptr::write_raw(p, v)
180}
181
182#[unsafe(no_mangle)]
183pub extern "C" fn TEEC_InitializeContext(
184    _name: *const c_char,
185    ctx: *mut raw::TEEC_Context,
186) -> raw::TEEC_Result {
187    debug!("TEEC_InitializeContext");
188
189    let result = (|| -> Result<()> {
190        let mut ctx_nn = safe_ptr::deref_mut(ctx)?;
191        // SAFETY: `ctx_nn` 已由 `deref_mut` 验证为非空。`as_mut()` 返回指向
192        // 上下文的可变引用,该引用在此作用域中有效。
193        let ctx_ref = unsafe { ctx_nn.as_mut() };
194
195        let client = CcClient::init().map_err(|e| {
196            warn!("TEEC_InitializeContext:初始化机密通信上下文失败:{e}");
197            Error::new(ErrorKind::Communication)
198        })?;
199
200        let id = CONTEXT_ID_COUNTER.fetch_add(1, Ordering::SeqCst);
201
202        ctx_ref.imp.fd = id;
203        ctx_ref.imp.reg_mem = true;
204        ctx_ref.imp.memref_null = true;
205
206        ContextManager::add_context(ctx, client)
207    })();
208
209    match result {
210        Ok(_) => raw::TEEC_SUCCESS,
211        Err(e) => e.raw_code(),
212    }
213}
214
215/// TEEC_FinalizeContext() - 销毁保存连接信息的上下文。
216///
217/// 该函数用于销毁已初始化的 TEE 上下文,关闭客户端应用与 TEE 之间的连接。
218/// 仅当与该上下文关联的所有会话已关闭且所有共享内存块已释放时才可调用。
219///
220/// @param ctx       要销毁的上下文。
221#[unsafe(no_mangle)]
222pub extern "C" fn TEEC_FinalizeContext(ctx: *mut raw::TEEC_Context) {
223    debug!("TEEC_FinalizeContext");
224    ContextManager::remove_context(ctx);
225}
226
227/// TEEC_OpenSession() - 与指定的受信任应用打开一个新会话。
228///
229/// @param ctx                已初始化的 TEE 上下文,在其作用域内打开会话。
230/// @param session            要初始化的会话结构体指针。
231/// @param destination        标识要打开会话的受信任应用的 UUID 结构。
232/// @param connection_method  要使用的连接方法。
233/// @param connection_data    与所选连接方法有关的连接数据。本实现不支持,
234///                           应设置为 NULL。
235/// @param operation          用于会话的操作结构。若不需要则传入 NULL。
236/// @param ret_origin         若函数返回非 TEEC_SUCCESS,此参数将保存错误来源。
237///
238/// @return TEEC_SUCCESS      成功打开会话。
239/// @return TEEC_Result       出现错误。
240#[unsafe(no_mangle)]
241pub extern "C" fn TEEC_OpenSession(
242    ctx: *mut raw::TEEC_Context,
243    session: *mut raw::TEEC_Session,
244    destination: *const raw::TEEC_UUID,
245    connection_method: u32,
246    _connection_data: *const c_void,
247    operation: *mut raw::TEEC_Operation,
248    ret_origin: *mut u32,
249) -> raw::TEEC_Result {
250    debug!("TEEC_OpenSession");
251
252    let result = (|| -> Result<u32> {
253        let _ = safe_ptr::deref_mut(ctx)?;
254        let _ = safe_ptr::deref_mut(session)?;
255        let uuid_nn = safe_ptr::deref(destination)?;
256        // SAFETY: `uuid_nn` 已由 `deref` 验证为非空。`as_ref()` 返回对
257        // 调用方提供的 UUID 的不可变引用,该引用在此处有效。
258        let uuid = unsafe { uuid_nn.as_ref() };
259        let uuid_str = uuid_to_string(uuid)?;
260
261        // 在 OpenSession 开始时立即执行 CA 认证(带缓存)
262        // 尽早认证可以提前发现 CA 文件问题,避免后续不必要的操作
263        #[cfg(feature = "ca-sign-verify")]
264        let ca_auth_info = {
265            use teec_protocol::CaAuthInfo;
266
267            let auth_result = get_or_verify_ca();
268
269            // 记录认证结果(警告式,不阻断)
270            if !auth_result.verified {
271                warn!("CA 签名验证失败: ca_uuid={}", auth_result.ca_uuid);
272            } else {
273                debug!("CA 签名验证通过: ca_uuid={}", auth_result.ca_uuid);
274            }
275
276            // 转换为协议格式(直接使用 CaAuthInfo,无需转换)
277            Some(CaAuthInfo {
278                ca_uuid: auth_result.ca_uuid,
279                verified: auth_result.verified,
280            })
281        };
282
283        #[cfg(not(feature = "ca-sign-verify"))]
284        let ca_auth_info: Option<crate::common::protocol::CaAuthInfo> = None;
285
286        let params = if operation.is_null() {
287            TEE_Parameters::default()
288        } else {
289            build_parameters_from_operation(operation)?
290        };
291
292        let request = TEE_Request::OpenSession {
293            uuid: uuid_str,
294            connection_method,
295            params,
296            ca_auth_info,
297        };
298
299        let mut session_nn = safe_ptr::deref_mut(session)?;
300        // SAFETY: `session_nn` 已验证非空;`as_mut()` 返回针对会话结构的
301        // 可变引用,该引用在此作用域中有效。
302        let session_ref = unsafe { session_nn.as_mut() };
303        let response = send_request_and_recv_response(ctx, PacketType::OpenSession, &request)?;
304
305        match response {
306            TEE_Response::OpenSession { session_id, result } => {
307                debug!("TEEC_OpenSession: 接收 session_id 和结果: {session_id}, {result}");
308
309                session_ref.imp.ctx = ctx;
310                session_ref.imp.session_id = session_id;
311
312                let _ = set_ret_origin(ret_origin, ErrorOrigin::TEE.into());
313                Ok(result)
314            }
315            _ => Err(Error::new(ErrorKind::BadParameters).with_origin(ErrorOrigin::API)),
316        }
317    })();
318
319    handle_error(result, ret_origin)
320}
321
322/// TEEC_CloseSession() - 关闭已与受信任应用打开的会话。
323///
324/// @param session 要关闭的会话。
325#[unsafe(no_mangle)]
326pub extern "C" fn TEEC_CloseSession(session: *mut raw::TEEC_Session) {
327    debug!("TEEC_CloseSession");
328
329    let result = (|| -> Result<()> {
330        let mut session_nn = safe_ptr::deref_mut(session)?;
331        // SAFETY: `session_nn` 已验证非空;`as_mut()` 返回针对会话结构的
332        // 可变引用,可用于读取其字段。
333        let session_ref = unsafe { session_nn.as_mut() };
334        let session_id = session_ref.imp.session_id;
335        let ctx = session_ref.imp.ctx;
336
337        if ctx.is_null() {
338            return Err(Error::new(ErrorKind::BadParameters));
339        }
340
341        let request = TEE_Request::CloseSession { session_id };
342        let response = send_request_and_recv_response(ctx, PacketType::CloseSession, &request)?;
343
344        match response {
345            TEE_Response::CloseSession { result } => {
346                debug!("TEEC_CloseSession: 接收结果: {result}");
347                session_ref.imp.ctx = ptr::null_mut();
348                session_ref.imp.session_id = 0;
349                Ok(())
350            }
351            _ => Err(Error::new(ErrorKind::BadParameters)),
352        }
353    })();
354
355    if let Err(e) = result {
356        // CloseSession 失败不应该阻断清理,但需要记录错误以便调试
357        warn!("TEEC_CloseSession 失败:{e}");
358    }
359}
360
361/// TEEC_InvokeCommand() - 在指定的受信任应用中执行命令。
362///
363/// @param session        已打开的受信任应用会话句柄。
364/// @param cmd_id         要在受信任应用中调用的命令标识符。
365/// @param operation      用于调用命令的操作结构;若不需要则传入 NULL。
366/// @param error_origin   若函数返回非 TEEC_SUCCESS,此参数将保存错误来源。
367///
368/// @return TEEC_SUCCESS  操作成功。
369/// @return TEEC_Result   出现错误。
370#[unsafe(no_mangle)]
371pub extern "C" fn TEEC_InvokeCommand(
372    session: *mut raw::TEEC_Session,
373    cmd_id: u32,
374    operation: *mut raw::TEEC_Operation,
375    error_origin: *mut u32,
376) -> raw::TEEC_Result {
377    debug!("TEEC_InvokeCommand");
378
379    let result = (|| -> Result<u32> {
380        let mut session_nn = safe_ptr::deref_mut(session)?;
381        // SAFETY: `session_nn` 已验证非空;`as_mut()` 返回的可变引用在此
382        // 作用域内有效,可用于读取 `imp.session_id` 和 `imp.ctx`。
383        let session_ref = unsafe { session_nn.as_mut() };
384        let session_id = session_ref.imp.session_id;
385        let ctx = session_ref.imp.ctx;
386
387        if ctx.is_null() {
388            return Err(Error::new(ErrorKind::BadParameters));
389        }
390
391        let params = if operation.is_null() {
392            TEE_Parameters::default()
393        } else {
394            let mut operation_nn = safe_ptr::deref_mut(operation)?;
395            // SAFETY: `operation_nn` 已验证非空,且 `deref_mut` 提供独占访问;
396            // 调用 `as_mut()` 可获得可变引用,可安全修改 `imp.session` 字段。
397            let operation_ref = unsafe { operation_nn.as_mut() };
398            operation_ref.imp.session = session;
399
400            build_parameters_from_operation(operation)?
401        };
402
403        let request = TEE_Request::InvokeCommand {
404            session_id,
405            cmd_id,
406            params,
407        };
408
409        let response = send_request_and_recv_response(ctx, PacketType::InvokeCommand, &request)?;
410
411        match response {
412            TEE_Response::InvokeCommand { params, result } => {
413                if result != raw::TEEC_SUCCESS {
414                    return Err(Error::new(ErrorKind::from(result)).with_origin(ErrorOrigin::API));
415                }
416
417                if !operation.is_null() {
418                    update_operation_from_parameters(operation, params)?;
419                }
420                Ok(result)
421            }
422            _ => Err(Error::new(ErrorKind::BadParameters).with_origin(ErrorOrigin::API)),
423        }
424    })();
425
426    handle_error(result, error_origin)
427}
428
429/// TEEC_RegisterSharedMemory() - 将现有内存块注册为在指定上下文作用域内的
430/// 共享内存块。
431///
432/// @param ctx    已初始化的 TEE 上下文。
433/// @param sharedMem  要注册的共享内存结构指针。
434///
435/// @return TEEC_SUCCESS              注册成功。
436/// @return TEEC_ERROR_OUT_OF_MEMORY  内存不足。
437/// @return TEEC_Result               其他错误。
438#[unsafe(no_mangle)]
439pub extern "C" fn TEEC_RegisterSharedMemory(
440    ctx: *mut raw::TEEC_Context,
441    shm: *mut raw::TEEC_SharedMemory,
442) -> raw::TEEC_Result {
443    debug!("TEEC_RegisterSharedMemory");
444
445    let result = SharedMemoryManager::allocate(ctx, shm, true);
446
447    match result {
448        Ok(_) => raw::TEEC_SUCCESS,
449        Err(e) => e.raw_code(),
450    }
451}
452
453#[unsafe(no_mangle)]
454pub extern "C" fn TEEC_RegisterSharedMemoryFileDescriptor(
455    _ctx: *mut raw::TEEC_Context,
456    _shm: *mut raw::TEEC_SharedMemory,
457    _fd: i32,
458) -> raw::TEEC_Result {
459    // TODO: 实现此函数
460    ErrorKind::NotImplemented.into()
461}
462
463/// TEEC_AllocateSharedMemory() - 为 TEE 分配共享内存。
464///
465/// @param ctx         已初始化的 TEE 上下文。
466/// @param sharedMem   指向要分配的共享内存结构的指针(由调用者填写希望的属性)。
467///
468/// @return TEEC_SUCCESS              分配/注册成功。
469/// @return TEEC_ERROR_OUT_OF_MEMORY  内存不足。
470/// @return TEEC_Result               其他错误。
471#[unsafe(no_mangle)]
472pub extern "C" fn TEEC_AllocateSharedMemory(
473    ctx: *mut raw::TEEC_Context,
474    shm: *mut raw::TEEC_SharedMemory,
475) -> raw::TEEC_Result {
476    debug!("TEEC_AllocateSharedMemory");
477
478    match SharedMemoryManager::allocate(ctx, shm, false) {
479        Ok(_) => raw::TEEC_SUCCESS,
480        Err(e) => e.raw_code(),
481    }
482}
483
484/// TEEC_ReleaseSharedMemory() - 释放或取消注册共享内存。
485///
486/// @param sharedMem  要释放或取消注册的共享内存指针。
487#[unsafe(no_mangle)]
488pub extern "C" fn TEEC_ReleaseSharedMemory(shm: *mut raw::TEEC_SharedMemory) {
489    debug!("TEEC_ReleaseSharedMemory");
490    SharedMemoryManager::release(shm);
491}
492
493/// TEEC_RequestCancellation() - 请求取消正在等待的打开会话或命令调用。
494///
495/// @param operation 指向先前传递给 open session 或 invoke 的操作结构的指针。
496#[unsafe(no_mangle)]
497pub extern "C" fn TEEC_RequestCancellation(operation: *mut raw::TEEC_Operation) {
498    debug!("TEEC_RequestCancellation");
499
500    let result = (|| -> Result<()> {
501        let mut operation_nn = safe_ptr::deref_mut(operation)?;
502        // SAFETY: `operation_nn` 已验证非空,`deref_mut` 提供独占访问;
503        // `as_mut()` 返回的可变引用可安全用于读取 `imp.session`。
504        let operation_ref = unsafe { operation_nn.as_mut() };
505        let session = operation_ref.imp.session;
506
507        if session.is_null() {
508            return Ok(());
509        }
510
511        let mut session_nn = safe_ptr::deref_mut(session)?;
512        // SAFETY: `session_nn` 已验证非空;`as_mut()` 返回的可变引用在此作用域内有效,
513        // 可用于读取 `imp.session_id` 和 `imp.ctx`。
514        let session_ref = unsafe { session_nn.as_mut() };
515        let session_id = session_ref.imp.session_id;
516        let ctx = session_ref.imp.ctx;
517
518        if ctx.is_null() {
519            return Ok(());
520        }
521
522        let request = TEE_Request::RequestCancellation { session_id };
523        let response =
524            send_request_and_recv_response(ctx, PacketType::RequestCancellation, &request)?;
525
526        match response {
527            TEE_Response::RequestCancellation { result: _ } => {
528                debug!("TEEC_RequestCancellation: 接收结果");
529                Ok(())
530            }
531            _ => Err(Error::new(ErrorKind::BadParameters)),
532        }
533    })();
534
535    if let Err(e) = result {
536        // RequestCancellation 失败不应该阻断,但需要记录错误以便调试
537        warn!("TEEC_RequestCancellation 失败:{e}");
538    }
539}