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