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