ARM TrustZone & OP-TEE

ARM TrustZone 하드웨어 보안 기술과 OP-TEE(Open Portable Trusted Execution Environment)를 통한 신뢰 실행 환경(TEE) 구현을 심층 분석합니다. Secure/Normal World 분리, SMC 호출 규약(Calling Convention), TF-A(Trusted Firmware-A), 커널 TEE 프레임워크, OP-TEE 드라이버, Trusted Application 개발, Secure Storage, fTPM, GlobalPlatform 규격까지 다룹니다.

ℹ️

선행 지식: 이 문서는 ARM 아키텍처의 Exception Level, 인터럽트(Interrupt) 처리, 메모리 보호 기본 개념을 알고 있다고 가정합니다. 필요하다면 ARM 아키텍처, 인터럽트 처리 문서를 먼저 참고하세요.

💡

일상 비유: TrustZone은 은행의 금고실과 같습니다. 일반 업무 공간(Normal World)과 금고실(Secure World)이 물리적으로 분리되어 있고, 금고실에 접근하려면 반드시 보안 게이트(SMC)를 통과해야 합니다. OP-TEE는 금고실 안에서 동작하는 보안 운영체제로, 금고 안에서 암호 키 관리, 생체 인증, DRM 등 민감한 작업을 수행합니다.

핵심 요약

  • TrustZone — ARM 프로세서의 하드웨어 보안 확장으로, 단일 물리 코어를 Secure World와 Normal World 두 가상 프로세서로 분리합니다.
  • SMC (Secure Monitor Call) — Normal World에서 Secure World로 전환하는 유일한 게이트웨이입니다. SMCCC(SMC Calling Convention)가 호출 규약을 표준화합니다.
  • TF-A (Trusted Firmware-A) — EL3 Secure Monitor로, BL1→BL2→BL31→BL32→BL33 부팅 체인과 런타임 SMC 디스패치(Dispatch)를 담당합니다.
  • OP-TEE — Linaro가 주도하는 오픈소스 TEE OS로, S-EL1에서 동작하며 GlobalPlatform TEE 규격을 구현합니다.
  • 커널 TEE 프레임워크drivers/tee/ 아래 /dev/tee*, /dev/teepriv* 장치를 제공하여 사용자 공간(User Space)에서 TA(Trusted Application)와 통신합니다.
  • Trusted Application — Secure World 내에서 실행되는 독립 프로그램으로, UUID로 식별되며 GlobalPlatform Internal Core API를 사용합니다.
  • Secure Storage — REE 파일시스템(Filesystem) 또는 RPMB(Replay Protected Memory Block)를 백엔드로 사용하여 암호화(Encryption)된 데이터를 안전하게 저장합니다.
  • fTPM — OP-TEE TA로 구현된 펌웨어(Firmware) TPM 2.0으로, 별도 TPM 칩 없이 TPM 기능을 제공합니다.

TrustZone 아키텍처

ARM TrustZone은 ARMv6K부터 도입된 하드웨어 보안 확장입니다. 프로세서, 메모리 컨트롤러, 버스(Bus) 인터커넥트, 주변 장치까지 시스템 전체에 걸쳐 SecureNon-secure(Normal) 두 상태를 하드웨어 수준에서 분리합니다.

NS 비트 (Non-Secure bit)

TrustZone의 핵심은 SCR_EL3.NS (Secure Configuration Register) 비트입니다. 이 1비트가 프로세서의 현재 보안 상태를 결정하며, AXI 버스의 AxPROT[1] 신호로 전파되어 메모리 컨트롤러와 주변 장치가 접근 권한을 판별합니다.

NS 비트상태접근 가능 메모리용도
0SecureSecure + Non-secure 전체TEE OS, TA, Secure 펌웨어
1Non-secureNon-secure 영역만Linux 커널, 일반 앱
TrustZone Secure/Normal World 분리 아키텍처 Normal World (NS=1) EL0: 사용자 앱 / TEE Client libteec, tee-supplicant EL1: Linux 커널 drivers/tee/, optee 드라이버 EL2: Hypervisor (선택) Secure World (NS=0) S-EL0: Trusted Application (TA) fTPM, DRM, 생체인증 TA S-EL1: TEE OS (OP-TEE) TA 관리, 암호 서비스, SHM S-EL2: Secure Partition Manager (v8.4+) EL3: Secure Monitor (TF-A / BL31) SMC 디스패치, World 전환, SCR_EL3.NS 제어 SMC ERET AXI/ACE 버스 (AxPROT[1] = NS bit) TZASC / TZC-400 — 메모리 영역별 Secure/Non-secure 접근 제어
TrustZone은 NS 비트 하나로 전체 시스템을 Secure/Normal 두 세계로 분리합니다. EL3 Secure Monitor가 World 전환을 중재합니다.

TrustZone 하드웨어 구성요소

구성요소역할커널 소스 위치
CPU NS bit프로세서 보안 상태 결정 (SCR_EL3.NS)arch/arm64/kernel/
TZASC (TZC-400)DRAM 영역별 Secure/Non-secure 접근 제어(Access Control)TF-A: drivers/arm/tzc/
TZMASRAM 보호 (TrustZone Memory Adapter)TF-A: plat/
TZPC주변 장치 Secure/Non-secure 분류TF-A: plat/
GIC Security Extension인터럽트 Group 0/1 분리, FIQ 라우팅(Routing)drivers/irqchip/irq-gic-v3.c
AXI/ACE AxPROT버스 트랜잭션(Transaction)에 NS 비트 전파하드웨어 시그널(Signal)
ℹ️

ARMv9 Realm Management Extension (RME): ARMv9에서는 TrustZone의 2-World 모델을 확장하여 Realm 세계를 추가했습니다. 이는 Confidential Computing을 위한 것으로, 기밀 컴퓨팅(Confidential Computing) 문서에서 자세히 다룹니다.

Exception Level과 Security State

ARMv8-A 아키텍처는 4개의 Exception Level(EL0~EL3)에 보안 상태(Secure/Non-secure)를 결합하여 최대 7개의 실행 컨텍스트를 제공합니다. TrustZone 환경에서 각 레벨의 역할을 정확히 이해하는 것이 필수입니다.

ARMv8-A Exception Level & Security State EL3 — Secure Monitor (항상 Secure) EL2 — Hypervisor (Non-secure) S-EL2 — Secure Partition Mgr (v8.4+) EL1 — Linux 커널 (Non-secure) drivers/tee/optee/ S-EL1 — OP-TEE OS (Secure) TEE 커널, TA 관리, 암호 서비스 EL0 — 사용자 앱 (Non-secure) S-EL0 — Trusted Application (Secure) 높음 낮음 특권 SMC ERET Non-secure (Normal World) Secure (Secure World) EL3 Monitor (World 전환 게이트)
EL3만이 두 World 사이의 전환을 제어할 수 있으며, SMC 명령이 EL3로의 진입점(Entry Point)입니다
레벨Non-secureSecure전환 방법
EL3Secure Monitor (TF-A BL31)SMC, FIQ, 시스템 리셋
EL2KVM/Xen HypervisorS-EL2: Secure Partition Manager (FF-A)HVC (EL1→EL2)
EL1Linux 커널OP-TEE OSSVC (EL0→EL1), ERET (EL3→S-EL1)
EL0사용자 앱Trusted ApplicationSVC (EL0→EL1)
⚠️

중요: Normal World의 EL2(Hypervisor)는 Secure World에 직접 접근할 수 없습니다. Hypervisor가 아무리 높은 특권을 가져도 NS=1 상태이므로 Secure 메모리에 접근하면 External Abort가 발생합니다. World 전환은 반드시 EL3 Secure Monitor를 경유해야 합니다.

보안 상태 전환 시 레지스터(Register) 저장

World 전환 시 EL3 Monitor는 현재 World의 전체 레지스터 컨텍스트를 저장하고 대상 World의 컨텍스트를 복원합니다. 이 과정에서 다음 레지스터가 관리됩니다.

/* TF-A: lib/el3_runtime/aarch64/context_mgmt.c */
typedef struct cpu_context {
    gp_regs_t     gpregs_ctx;     /* x0-x30, SP_EL0 */
    el3_state_t   el3state_ctx;   /* SCR_EL3, SCTLR_EL3, ... */
    el1_sysregs_t el1_sysregs_ctx;/* SCTLR_EL1, TTBR0/1_EL1, ... */
    el2_sysregs_t el2_sysregs_ctx;/* HCR_EL2, VTTBR_EL2, ... */
    fp_regs_t     fpregs_ctx;     /* SIMD/FP: v0-v31, FPCR, FPSR */
} cpu_context_t;

/* World 전환: Normal → Secure */
void cm_el1_sysregs_context_save(uint32_t security_state);
void cm_el1_sysregs_context_restore(uint32_t security_state);
void cm_set_next_eret_context(uint32_t security_state);

SMC 호출규약 (SMCCC)

SMC(Secure Monitor Call)는 Normal World에서 Secure World 서비스를 요청하는 동기적 호출 메커니즘입니다. ARM은 SMCCC(SMC Calling Convention) 규격을 통해 Function ID 인코딩, 파라미터 전달, 반환값 규약을 표준화했습니다.

SMC Function ID 인코딩 (32비트)

비트필드설명
[31]Calling Convention0 = SMC32, 1 = SMC64
[30]Call Type0 = Yielding Call, 1 = Fast Call
[29:24]Service Range서비스 소유자 (0x00=ARM, 0x02=SiP, 0x04=OEM, 0x30-0x31=TA, 0x32-0x3F=TEE OS)
[23:16]ReservedMBZ (Must Be Zero)
[15:0]Function Number서비스 내 함수 번호
SMC 호출 흐름 (Normal World → Secure World) Normal World (EL1) EL3 Monitor Secure World (S-EL1) 1. arm_smccc_smc() x0=func_id, x1-x6=args SMC #0 2. SMC 핸들러 진입 NW 컨텍스트 저장 3. SCR_EL3.NS = 0 Secure 컨텍스트 복원 ERET 4. OP-TEE 진입 thread_vector_table 5. TA 호출 / 서비스 TEE_InvokeTACommand 6. 처리 완료 SMC 7. SCR_EL3.NS = 1 NW 컨텍스트 복원 ERET 8. 결과 수신 (x0-x3)
SMC 호출은 EL1→EL3→S-EL1→EL3→EL1 경로를 거치며, EL3 Monitor가 World 전환마다 전체 컨텍스트를 저장/복원합니다

Fast Call vs Yielding Call

특성Fast CallYielding Call (Standard Call)
인터럽트Secure World에서 비선점(Non-preemptive)Normal World 인터럽트로 선점(Preemption) 가능
용도PSCI, CPU 전원 관리(Power Management), 짧은 쿼리TA 호출, 긴 암호 연산
bit[30]10
커널 호출arm_smccc_smc()arm_smccc_smc() + 스레드(Thread) 양보(Yield)

Linux 커널 SMCCC 인터페이스

/* include/linux/arm-smccc.h */
struct arm_smccc_res {
    unsigned long a0;  /* 반환값 / 에러 코드 */
    unsigned long a1;
    unsigned long a2;
    unsigned long a3;
};

/* SMC 호출 매크로 */
void arm_smccc_smc(
    unsigned long a0, unsigned long a1,
    unsigned long a2, unsigned long a3,
    unsigned long a4, unsigned long a5,
    unsigned long a6, unsigned long a7,
    struct arm_smccc_res *res);

/* HVC 호출 (EL2 서비스) */
void arm_smccc_hvc(
    unsigned long a0, unsigned long a1,
    unsigned long a2, unsigned long a3,
    unsigned long a4, unsigned long a5,
    unsigned long a6, unsigned long a7,
    struct arm_smccc_res *res);

/* SMCCC 버전 확인 */
#define ARM_SMCCC_VERSION_1_0     0x10000
#define ARM_SMCCC_VERSION_1_1     0x10001
#define ARM_SMCCC_VERSION_1_2     0x10002
💡

SMCCC 1.2+의 SVE 레지스터: SMCCC 1.2부터 SMC/HVC 호출 시 SVE(Scalable Vector Extension) 레지스터의 보존 규칙이 명시되었습니다. Fast Call은 SVE 레지스터를 보존하지 않으므로 호출자가 저장해야 합니다.

TF-A (Trusted Firmware-A)

TF-A(구 ATF, ARM Trusted Firmware)는 ARM 레퍼런스 Secure Monitor 구현체로, EL3에서 실행됩니다. 시스템 부팅 체인의 Root of Trust를 설정하고, 런타임에 SMC 디스패치와 PSCI(Power State Coordination Interface) 서비스를 제공합니다.

부팅 단계 (Boot Loader Stages)

단계실행 레벨역할다음 단계 로딩
BL1EL3AP Trusted ROM — 최초 부팅 코드, BL2 인증/로딩BL2
BL2S-EL1 (또는 EL3)Trusted Boot Firmware — BL31/BL32/BL33 로딩, 이미지 인증BL31, BL32, BL33
BL31EL3EL3 Runtime Firmware — Secure Monitor, SMC 디스패치, PSCI상주 런타임
BL32S-EL1Secure-EL1 Payload — OP-TEE 또는 다른 TEE OS상주 런타임
BL33EL2/EL1Non-secure Firmware — U-Boot 또는 UEFILinux 커널

TF-A SMC 디스패치

/* TF-A: services/std_svc/std_svc_setup.c */
static uintptr_t std_svc_smc_handler(
    uint32_t smc_fid,       /* SMC Function ID */
    u_register_t x1, u_register_t x2,
    u_register_t x3, u_register_t x4,
    void *cookie, void *handle, u_register_t flags)
{
    /* PSCI 서비스 (0x84000000-0xBFFF_FFFF) */
    if (is_psci_fid(smc_fid))
        return psci_smc_handler(smc_fid, x1, x2, x3, x4,
                                cookie, handle, flags);

    /* OP-TEE/TEE OS로 전달 (Yielding Call) */
    if (is_tee_fid(smc_fid))
        return opteed_smc_handler(smc_fid, x1, x2, x3, x4,
                                  cookie, handle, flags);

    SMC_RET1(handle, SMC_UNK);  /* 미지원 서비스 */
}

PSCI (Power State Coordination Interface)

PSCI는 TF-A가 제공하는 표준 전원 관리 인터페이스로, Linux 커널이 CPU 온/오프, 시스템 리셋, 서스펜드를 수행할 때 사용합니다.

/* include/linux/psci.h — 주요 PSCI 함수 */
#define PSCI_0_2_FN_CPU_ON        0x84000003
#define PSCI_0_2_FN_CPU_OFF       0x84000002
#define PSCI_0_2_FN_SYSTEM_RESET  0x84000009
#define PSCI_0_2_FN_SYSTEM_OFF    0x84000008
#define PSCI_1_0_FN_SYSTEM_SUSPEND 0xC400000E

/* 커널에서 PSCI 호출 예시 */
static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point)
{
    return invoke_psci_fn(PSCI_0_2_FN_CPU_ON, cpuid, entry_point, 0);
}

TF-A Secure Boot Chain

TF-A는 Trusted Board Boot (TBB) 사양에 따라 각 부팅 단계의 이미지를 암호학적으로 검증합니다. Chain of Trust의 Root은 칩 OTP(One-Time Programmable) 퓨즈에 저장된 ROTPK(Root of Trust Public Key) 해시(Hash)입니다.

/* TF-A: drivers/auth/mbedtls/mbedtls_x509_parser.c */
/* 인증서 체인 검증 구조 */
/*
 * ROTPK (OTP 퓨즈)
 *   └─ Trusted Key Certificate
 *        ├─ SoC Firmware Key Cert → BL31 Content Cert → BL31 이미지
 *        ├─ Trusted OS Key Cert  → BL32 Content Cert → BL32 (OP-TEE)
 *        └─ Non-Trusted FW Key   → BL33 Content Cert → BL33 (U-Boot)
 */

/* 이미지 인증 호출 */
int auth_mod_verify_img(
    unsigned int img_id,
    void *img_ptr,
    unsigned int img_len)
{
    const auth_img_desc_t *img_desc;

    img_desc = FCONF_GET_PROPERTY(tbbr, cot, img_id);

    /* 1. 부모 인증서 검증 */
    if (img_desc->parent)
        auth_mod_verify_img(img_desc->parent->img_id, ...);

    /* 2. 현재 이미지의 해시/서명 검증 */
    return auth_hash(img_desc->img_auth_methods, img_ptr, img_len);
}

TF-A 런타임 서비스 등록

/* TF-A: 런타임 서비스 매크로로 등록 */
DECLARE_RT_SVC(
    opteed_fast,                     /* 서비스 이름 */
    OEN_TOS_START,                   /* 시작 OEN (Owning Entity Number) */
    OEN_TOS_END,                     /* 종료 OEN */
    SMC_TYPE_FAST,                   /* Fast Call 타입 */
    opteed_setup,                    /* 초기화 함수 */
    opteed_smc_handler               /* SMC 핸들러 */
);

/* OP-TEE SPD(Secure Payload Dispatcher) 핸들러 */
static uintptr_t opteed_smc_handler(
    uint32_t smc_fid, u_register_t x1,
    u_register_t x2, u_register_t x3,
    u_register_t x4, void *cookie,
    void *handle, u_register_t flags)
{
    switch (smc_fid) {
    case OPTEE_SMC_CALL_WITH_ARG:
        /* Normal→Secure: OP-TEE에 요청 전달 */
        cm_el1_sysregs_context_save(NON_SECURE);
        cm_el1_sysregs_context_restore(SECURE);
        cm_set_next_eret_context(SECURE);
        SMC_RET4(handle, x1, x2, x3, x4);
        break;

    case OPTEE_SMC_RETURN_FROM_RPC:
        /* OP-TEE→Normal: RPC 결과 반환 */
        cm_el1_sysregs_context_save(SECURE);
        cm_el1_sysregs_context_restore(NON_SECURE);
        cm_set_next_eret_context(NON_SECURE);
        SMC_RET4(handle, x1, x2, x3, x4);
        break;
    }
    SMC_RET1(handle, SMC_UNK);
}

FF-A (Firmware Framework for Arm)

FF-A는 TF-A의 차세대 메시징 프레임워크로, Secure Partition Manager(SPM)를 통해 여러 Secure Partition(SP)을 관리합니다. OP-TEE 3.x+에서는 SMC ABI 대신 FF-A ABI를 선택적으로 사용할 수 있습니다.

특성기존 SMC ABIFF-A ABI
메시징직접 SMC 레지스터 전달FFA_MSG_SEND_DIRECT_REQ/RESP
메모리 공유OPTEE_MSG_CMD_REGISTER_SHMFFA_MEM_SHARE / FFA_MEM_LEND
SP 발견OP-TEE 전용 UUID 매칭FFA_PARTITION_INFO_GET
인터럽트FIQ 직접 라우팅Secure/Non-secure 가상 인터럽트
S-EL2미지원SPMC at S-EL2 (v8.4+)
커널 드라이버optee/smc_abi.coptee/ffa_abi.c

메모리 보호 (TZASC/TZC-400)

TrustZone의 메모리 격리(Isolation)는 TZASC(TrustZone Address Space Controller)가 담당합니다. TZASC는 DRAM 컨트롤러 앞에 위치하여 각 메모리 영역에 대한 Secure/Non-secure 접근 권한을 하드웨어 수준에서 강제합니다.

TZC-400 메모리 영역 분리 ARM Core NS=0 or NS=1 AXI TZC-400 영역별 접근 권한 검사 최대 9개 Region (0~8) DRAM 물리 주소 공간 Region 0: Secure Only OP-TEE OS + TA 코드/데이터 0x0E100000 - 0x0FFFFFFF Region 1: Shared Memory NW/SW 모두 접근 가능 0x10000000 - 0x101FFFFF Region 2: Non-secure Linux 커널 + 사용자 공간 0x10200000 - 0x7FFFFFFF Region 3: TF-A / Secure FW BL31 런타임 메모리 0x0E000000 - 0x0E0FFFFF NS=1이 Secure 영역 접근 → DECERR (Bus Fault) NS=0은 모든 영역 접근 → Secure가 NW 메모리도 읽기 가능
TZC-400은 DRAM을 최대 9개 영역으로 분할하고, 각 영역에 Secure/Non-secure 접근 정책을 설정합니다

TZC-400 리전 설정

/* TF-A: drivers/arm/tzc/tzc400.c */
void tzc400_configure_region(
    unsigned int filters,
    unsigned int region,
    unsigned long long region_base,
    unsigned long long region_top,
    unsigned int sec_attr,      /* TZC_REGION_S_RDWR 등 */
    unsigned int nsaid_permissions)
{
    /* Base/Top 주소 설정 */
    mmio_write_32(base + REGION_BASE_LOW_OFF, (uint32_t)region_base);
    mmio_write_32(base + REGION_TOP_LOW_OFF,  (uint32_t)region_top);
    /* 보안 속성: Secure R/W, Non-secure 접근 거부 */
    mmio_write_32(base + REGION_ATTRIBUTES_OFF,
        sec_attr | filters << REGION_ATTRIBUTES_FILTER_BIT_SHIFT);
    /* NSAID(Non-Secure Access ID) 퍼미션 */
    mmio_write_32(base + REGION_ID_ACCESS_OFF, nsaid_permissions);
}
⚠️

TZC-400 vs TZC-380: TZC-400은 최대 9개 리전과 4개 필터를 지원하며, 리전 크기가 4KB 정렬이면 됩니다. 구형 TZC-380은 리전 크기가 2의 거듭제곱이어야 하는 제약이 있습니다. 최신 SoC는 대부분 TZC-400을 사용합니다.

GIC 보안 확장

GIC(Generic Interrupt Controller)의 보안 확장은 인터럽트를 Group 0Group 1으로 분류하여, Secure World와 Normal World 간 인터럽트 격리를 보장합니다.

GICv3 보안 인터럽트 라우팅 인터럽트 소스 Secure Timer Secure Watchdog UART, ETH, USB 일반 디바이스 GIC Distributor GICD_IGROUPR: 그룹 분류 Group 0 Group 1 FIQ IRQ EL3 Secure Monitor FIQ → Secure 핸들러 디스패치 S-EL1: OP-TEE (Secure IRQ) EL1 Linux 커널 IRQ → Normal 핸들러 GICv3 그룹 모델: Group 0 → FIQ → EL3 (Secure) Group 1 NS → IRQ → EL1 (Normal)
Group 0 인터럽트는 FIQ로 EL3에 트랩되어 Secure World에서 처리되고, Group 1 NS 인터럽트는 IRQ로 Linux 커널에 전달됩니다
그룹시그널타겟용도레지스터
Group 0FIQEL3 → S-EL1Secure Timer, Secure Watchdog, TrustZone 전용GICD_IGROUPR bit=0
Group 1 SecureFIQ (S-EL1)S-EL1OP-TEE 내부 인터럽트GICD_IGRPMODR bit=1
Group 1 NSIRQEL1일반 디바이스 인터럽트GICD_IGROUPR bit=1

Normal World 실행 중 Secure 인터럽트 발생

Normal World에서 Linux 커널이 실행 중일 때 Secure 인터럽트(Group 0 FIQ)가 발생하면, 프로세서는 즉시 EL3로 트랩됩니다. EL3 Monitor는 Normal World 컨텍스트를 저장하고, OP-TEE의 인터럽트 핸들러(Handler)에 제어를 넘깁니다.

/* OP-TEE: core/arch/arm/kernel/thread_a64.S */
/* Secure World에서 FIQ 발생 시 진입점 */
thread_fiq_handler:
    /* 현재 스레드 컨텍스트 저장 */
    sub     sp, sp, #THREAD_ABT_REGS_SIZE
    store_xregs sp, THREAD_ABT_REGS_X0, 0, 3
    /* GIC에서 인터럽트 번호 읽기 */
    mrs     x0, ICC_IAR0_EL1      /* Group 0 인터럽트 ACK */
    /* 핸들러 디스패치 */
    bl      itr_core_handler
    /* EOI */
    msr     ICC_EOIR0_EL1, x0

GIC 보안 설정 코드

/* TF-A: drivers/arm/gic/v3/gicv3_main.c */
/* 인터럽트를 Group 0 (Secure)로 설정 */
void gicv3_set_interrupt_type(
    unsigned int id,
    unsigned int type)      /* GICV3_G0 or GICV3_G1S or GICV3_G1NS */
{
    /* GICD_IGROUPR 비트 설정 */
    if (type == GICV3_G0) {
        gicd_clr_igroupr(base, id);       /* Group bit = 0 */
        gicd_clr_igrpmodr(base, id);      /* Modifier bit = 0 → Group 0 */
    } else if (type == GICV3_G1S) {
        gicd_clr_igroupr(base, id);       /* Group bit = 0 */
        gicd_set_igrpmodr(base, id);      /* Modifier bit = 1 → Group 1 Secure */
    } else {
        gicd_set_igroupr(base, id);       /* Group bit = 1 → Group 1 NS */
    }
}

/* OP-TEE에서 Secure Timer 인터럽트 등록 */
/* Secure Physical Timer (PPI 29)를 Group 0으로 설정 */
gicv3_set_interrupt_type(29, GICV3_G0);
gicd_set_isenabler(base, 29);

Secure World 실행 중 Normal World 인터럽트

OP-TEE가 TA를 실행하는 동안 Normal World 인터럽트(Group 1 NS IRQ)가 발생하면, OP-TEE는 현재 작업을 일시 중단하고 EL3를 경유하여 Normal World로 복귀합니다. Linux 커널이 인터럽트를 처리한 후, 다시 SMC로 OP-TEE의 중단된 작업을 재개합니다. 이것이 Yielding Call이 선점 가능한 이유입니다.

/* OP-TEE: Normal World 인터럽트 발생 시 처리 */
/* core/arch/arm/kernel/thread_a64.S */
thread_nintr_handler:
    /* 1. 현재 TA 스레드 상태를 SUSPENDED로 변경 */
    thread_save_state
    /* 2. EL3에 RPC 반환: "NW 인터럽트 처리 필요" */
    smc #0     /* OPTEE_SMC_RETURN_RPC_FOREIGN_INTR */
    /* 3. (NW가 인터럽트 처리 후 다시 SMC로 복귀) */
    /* 4. TA 스레드 상태를 ACTIVE로 복원하고 계속 실행 */
    thread_resume_state

커널 TEE 프레임워크

Linux 커널의 TEE 프레임워크(drivers/tee/)는 다양한 TEE 구현체(OP-TEE, AMD-TEE, Qualcomm QTEE 등)에 대한 통일된 사용자 공간 인터페이스를 제공합니다.

Linux 커널 TEE 프레임워크 계층 사용자 공간 TEE Client (libteec) tee-supplicant fTPM Client DRM/Widevine ioctl TEE Core (drivers/tee/tee_core.c) /dev/tee0 /dev/teepriv0 tee_context tee_session tee_shm (SHM) tee_param tee_driver_ops 콜백 TEE 드라이버 백엔드 OP-TEE (drivers/tee/optee/) AMD-TEE (amdtee/) TF-A SPM (FF-A) 기타 TEE 드라이버 SMC / FF-A Secure World OP-TEE OS (S-EL1) TA Manager, Crypto, SHM Trusted App 1 Trusted App 2 fTPM TA
TEE Core가 /dev/tee* 장치를 통해 사용자 공간과 TEE 드라이버 백엔드를 연결하고, SMC/FF-A를 통해 Secure World와 통신합니다

주요 데이터 구조체(Struct)

/* include/linux/tee_drv.h */
struct tee_device {
    char                name[32];
    const struct tee_desc *desc;
    int                 id;
    struct device       dev;
    struct cdev         cdev;
    struct tee_shm_pool *pool;  /* 공유 메모리 풀 */
};

struct tee_driver_ops {
    int (*get_version)(struct tee_device *, struct tee_ioctl_version_data *);
    int (*open)(struct tee_context *ctx);
    void (*release)(struct tee_context *ctx);
    int (*open_session)(struct tee_context *ctx,
                       struct tee_ioctl_open_session_arg *arg,
                       struct tee_param *param);
    int (*close_session)(struct tee_context *ctx, u32 session);
    int (*invoke_func)(struct tee_context *ctx,
                      struct tee_ioctl_invoke_arg *arg,
                      struct tee_param *param);
    int (*cancel_req)(struct tee_context *ctx, u32 cancel_id, u32 session);
    struct tee_shm *(*shm_register)(struct tee_context *ctx,
                                    struct page **pages, size_t num_pages,
                                    unsigned long start);
};

/* TEE 컨텍스트 — 파일 디스크립터당 하나 */
struct tee_context {
    struct tee_device   *teedev;
    void                *data;      /* 드라이버 private 데이터 */
    struct kref         refcount;
    bool                releasing;
    bool                supp_nowait;
};

TEE ioctl 인터페이스

ioctl디바이스용도
TEE_IOC_VERSION/dev/tee0TEE 구현체 버전 조회
TEE_IOC_OPEN_SESSION/dev/tee0TA 세션 열기 (UUID 지정)
TEE_IOC_INVOKE/dev/tee0TA 함수 호출
TEE_IOC_CLOSE_SESSION/dev/tee0TA 세션 닫기
TEE_IOC_SHM_ALLOC/dev/tee0공유 메모리 할당
TEE_IOC_SHM_REGISTER/dev/tee0기존 버퍼(Buffer)를 공유 메모리로 등록
TEE_IOC_SUPPL_RECV/dev/teepriv0supplicant: RPC 요청 수신
TEE_IOC_SUPPL_SEND/dev/teepriv0supplicant: RPC 응답 전송

OP-TEE 커널 드라이버

OP-TEE 커널 드라이버(drivers/tee/optee/)는 TEE Core 프레임워크의 백엔드로, Normal World 커널과 Secure World OP-TEE OS 사이의 통신을 담당합니다.

드라이버 파일 구조

파일역할
core.c프로브(Probe)/초기화, TEE 장치 등록
call.cSMC 호출 래퍼, Yielding Call 처리
rpc.cRPC(Remote Procedure Call) 처리 — OP-TEE → REE 요청
smc_abi.cSMC ABI 기반 메시지 포맷
ffa_abi.cFF-A(Firmware Framework for Arm) ABI 기반 메시지 포맷
shm_pool.c공유 메모리 풀 관리
supp.ctee-supplicant 데몬 인터페이스
device.cOP-TEE 하위 장치(TA) 열거
notif.c비동기 알림 (OP-TEE 3.x+)

tee-supplicant 데몬

tee-supplicant는 OP-TEE가 Normal World의 서비스(파일 시스템, RPMB, 소켓(Socket) 등)를 필요로 할 때 RPC를 처리하는 사용자 공간 데몬입니다. /dev/teepriv0을 통해 커널 드라이버와 통신합니다.

/* OP-TEE RPC 요청 유형 */
#define OPTEE_RPC_CMD_LOAD_TA       0   /* TA 바이너리 로딩 */
#define OPTEE_RPC_CMD_RPMB          1   /* RPMB 읽기/쓰기 */
#define OPTEE_RPC_CMD_FS            2   /* REE 파일시스템 접근 */
#define OPTEE_RPC_CMD_GET_TIME      3   /* REE 시간 조회 */
#define OPTEE_RPC_CMD_WAIT_QUEUE    4   /* 대기 큐 관리 */
#define OPTEE_RPC_CMD_SUSPEND       5   /* 스레드 중단 */
#define OPTEE_RPC_CMD_SHM_ALLOC     6   /* 공유 메모리 동적 할당 */
#define OPTEE_RPC_CMD_SHM_FREE      7   /* 공유 메모리 해제 */
#define OPTEE_RPC_CMD_NOTIFICATION  8   /* 비동기 알림 */

/* tee-supplicant RPC 루프 */
while (1) {
    /* 커널에서 RPC 요청 수신 */
    ioctl(fd_priv, TEE_IOC_SUPPL_RECV, &recv_arg);

    switch (recv_arg.func) {
    case OPTEE_RPC_CMD_LOAD_TA:
        load_ta_from_filesystem(recv_arg.params);
        break;
    case OPTEE_RPC_CMD_FS:
        handle_fs_request(recv_arg.params);
        break;
    case OPTEE_RPC_CMD_RPMB:
        handle_rpmb_request(recv_arg.params);
        break;
    }

    /* 결과를 커널로 전송 */
    ioctl(fd_priv, TEE_IOC_SUPPL_SEND, &send_arg);
}

OP-TEE 드라이버 프로브 과정

/* drivers/tee/optee/core.c */
static int optee_probe(struct platform_device *pdev)
{
    struct optee *optee;
    struct tee_device *teedev, *supp_teedev;
    int rc;

    /* 1. SMC/HVC 호출 방식 결정 (DT의 method 속성) */
    rc = optee_get_invoke_func(np);

    /* 2. OP-TEE 버전/기능 쿼리 (OPTEE_SMC_CALLS_UID) */
    optee_get_version(optee, &sec_caps);

    /* 3. Dynamic SHM 지원 여부 확인 */
    if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
        optee->pool = optee_shm_pool_alloc_pages();
    else
        optee->pool = optee_shm_pool_alloc_carveout(pdev);

    /* 4. /dev/tee0 등록 */
    teedev = tee_device_alloc(&optee_clnt_desc, NULL,
                              optee->pool, optee);
    rc = tee_device_register(teedev);

    /* 5. /dev/teepriv0 등록 (supplicant 전용) */
    supp_teedev = tee_device_alloc(&optee_supp_desc, NULL,
                                   optee->pool, optee);
    rc = tee_device_register(supp_teedev);

    /* 6. TA 장치 열거 (PTA_DEVICE) */
    optee_enumerate_devices(PTA_CMD_GET_DEVICES);

    pr_info("optee: initialized driver\n");
    return 0;
}

비동기 알림 (Notification)

OP-TEE 3.x+에서는 Secure World가 Normal World에 비동기 알림을 보낼 수 있습니다. 기존에는 OP-TEE가 NW에 알려야 할 이벤트가 있으면 RPC로 반환한 뒤 NW가 다시 호출해야 했지만, 알림 메커니즘으로 불필요한 왕복을 제거합니다.

/* drivers/tee/optee/notif.c */
static irqreturn_t notif_irq_handler(
    int irq, void *dev_id)
{
    struct optee *optee = dev_id;

    /* Secure World에서 GIC를 통해 NW에 인터럽트 전달 */
    /* 대기 중인 RPC 요청을 즉시 처리하도록 트리거 */
    optee_notif_send(optee, OPTEE_SMC_ASYNC_NOTIF_VALUE_DO_BOTTOM_HALF);

    return IRQ_HANDLED;
}

OP-TEE 공유 메모리

Normal World와 Secure World 간 데이터 교환은 공유 메모리(Shared Memory, SHM)를 통해 이루어집니다. 공유 메모리는 양 World에서 모두 접근 가능한 Non-secure 메모리 영역에 위치합니다.

OP-TEE 공유 메모리 모델 Static SHM (레거시) 고정 물리 메모리 영역 (DT에 지정) 카빙(carve-out) 방식, 크기 고정 Dynamic SHM (현대) 커널 페이지를 동적 등록 (register) scatter-gather 지원, 유연한 크기 Non-secure 물리 메모리 Normal World 매핑 Linux VA → PA → SHM 버퍼 Secure World 매핑 OP-TEE VA → PA → 동일 SHM 버퍼 동일 물리 페이지
Dynamic SHM 모드에서는 Linux 커널이 일반 페이지(Page)를 할당한 후 OP-TEE에 물리 주소(Physical Address)를 등록하여 양쪽에서 접근합니다

SHM 할당 코드

/* drivers/tee/optee/shm_pool.c */
static struct tee_shm_pool *optee_shm_pool_alloc_pages(void)
{
    /* Dynamic SHM: 일반 커널 페이지 할당 후 OP-TEE에 등록 */
    struct tee_shm_pool *pool;
    pool = kzalloc(sizeof(*pool), GFP_KERNEL);
    pool->ops = &pool_ops_generic;
    return pool;
}

/* 공유 메모리 등록: 물리 페이지 목록을 OP-TEE에 전달 */
static int optee_shm_register(
    struct tee_context *ctx,
    struct tee_shm *shm,
    struct page **pages,
    size_t num_pages,
    unsigned long start)
{
    /* 페이지 테이블을 MessageArg에 담아 SMC로 OP-TEE에 등록 */
    struct optee_msg_arg *msg_arg;
    msg_arg->cmd = OPTEE_MSG_CMD_REGISTER_SHM;
    /* 물리 주소 목록 설정 */
    optee_fill_pages_list(pages_data, pages, num_pages, PAGE_SIZE);
    return optee_do_call_with_arg(ctx, msg_arg, 0);
}

TEE Client API

TEE Client API는 GlobalPlatform이 정의한 표준 C API로, Normal World 애플리케이션이 TEE와 상호작용하는 인터페이스입니다. OP-TEE의 libteec 라이브러리가 이를 구현합니다.

핵심 API 함수

함수역할내부 동작
TEEC_InitializeContext()TEE 연결 초기화open(/dev/tee0)
TEEC_OpenSession()TA 세션 열기ioctl(TEE_IOC_OPEN_SESSION) → SMC → TA_OpenSessionEntryPoint
TEEC_InvokeCommand()TA 함수 호출ioctl(TEE_IOC_INVOKE) → SMC → TA_InvokeCommandEntryPoint
TEEC_CloseSession()TA 세션 닫기ioctl(TEE_IOC_CLOSE_SESSION) → SMC → TA_CloseSessionEntryPoint
TEEC_FinalizeContext()TEE 연결 종료close(fd)
TEEC_AllocateSharedMemory()공유 메모리 할당ioctl(TEE_IOC_SHM_ALLOC) + mmap()
TEEC_RegisterSharedMemory()기존 버퍼 등록ioctl(TEE_IOC_SHM_REGISTER)

TEE Client API 사용 예시

#include <tee_client_api.h>

/* TA UUID: 예시 — OP-TEE os_test TA */
static const TEEC_UUID ta_uuid = {
    0x5b9e0e40, 0x2636, 0x11e1,
    { 0xad, 0x9e, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }
};

int main(void)
{
    TEEC_Context ctx;
    TEEC_Session sess;
    TEEC_Operation op;
    TEEC_Result res;
    uint32_t err_origin;

    /* 1. TEE 컨텍스트 초기화 */
    res = TEEC_InitializeContext(NULL, &ctx);
    if (res != TEEC_SUCCESS)
        errx(1, "TEEC_InitializeContext failed: 0x%x", res);

    /* 2. TA 세션 열기 */
    res = TEEC_OpenSession(&ctx, &sess, &ta_uuid,
                          TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
    if (res != TEEC_SUCCESS)
        errx(1, "TEEC_OpenSession failed: 0x%x origin=0x%x", res, err_origin);

    /* 3. 파라미터 설정 및 TA 함수 호출 */
    memset(&op, 0, sizeof(op));
    op.paramTypes = TEEC_PARAM_TYPES(
        TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
    op.params[0].value.a = 42;

    res = TEEC_InvokeCommand(&sess, 0 /* cmd_id */, &op, &err_origin);
    printf("TA returned: %u\n", op.params[0].value.a);

    /* 4. 정리 */
    TEEC_CloseSession(&sess);
    TEEC_FinalizeContext(&ctx);
    return 0;
}

TEEC_Operation 파라미터 타입

타입설명방향
TEEC_NONE미사용
TEEC_VALUE_INPUT32비트 값 2개 (a, b)CA → TA
TEEC_VALUE_OUTPUT32비트 값 2개TA → CA
TEEC_VALUE_INOUT32비트 값 2개양방향
TEEC_MEMREF_TEMP_INPUT임시 공유 메모리CA → TA
TEEC_MEMREF_TEMP_OUTPUT임시 공유 메모리TA → CA
TEEC_MEMREF_TEMP_INOUT임시 공유 메모리양방향
TEEC_MEMREF_WHOLE등록된 SHM 전체SHM 플래그
TEEC_MEMREF_PARTIAL_*등록된 SHM 일부오프셋(Offset) + 크기

TA 생명주기

Trusted Application(TA)은 OP-TEE 내에서 실행되는 보안 프로그램으로, GlobalPlatform TEE Internal Core API에 정의된 4개의 진입점 함수를 구현합니다.

TA 진입점 함수

/* GlobalPlatform TEE Internal Core API */

/* TA 로딩 시 1회 호출 — 전역 초기화 */
TEE_Result TA_CreateEntryPoint(void);

/* TA 언로딩 시 1회 호출 — 전역 정리 */
void TA_DestroyEntryPoint(void);

/* TEEC_OpenSession() 시 호출 — 세션별 초기화 */
TEE_Result TA_OpenSessionEntryPoint(
    uint32_t param_types,
    TEE_Param params[4],
    void **sess_ctx);       /* 세션 컨텍스트 out */

/* TEEC_CloseSession() 시 호출 — 세션별 정리 */
void TA_CloseSessionEntryPoint(void *sess_ctx);

/* TEEC_InvokeCommand() 시 호출 — 실제 비즈니스 로직 */
TEE_Result TA_InvokeCommandEntryPoint(
    void *sess_ctx,
    uint32_t cmd_id,       /* 명령 식별자 */
    uint32_t param_types,
    TEE_Param params[4]);

TA 유형

유형설명저장 위치로딩 방식
User TAS-EL0에서 실행, 격리된 주소 공간(Address Space)REE 파일시스템 (/lib/optee_armtz/)tee-supplicant RPC로 로딩
Pseudo TAS-EL1(OP-TEE 커널 모드)에서 실행OP-TEE 바이너리에 내장정적 링크
Early TA부팅 초기 사용 가능한 TAOP-TEE 바이너리에 내장tee-supplicant 없이 로딩
ℹ️

Single Instance vs Multi Instance: TA 매니페스트의 TA_FLAG_SINGLE_INSTANCE 플래그로 제어합니다. Single Instance TA는 시스템에 하나만 존재하며 모든 세션이 같은 인스턴스를 공유합니다. Multi Instance TA는 세션마다 별도 인스턴스를 생성합니다.

TA 로딩 상세 흐름

User TA가 처음 호출될 때의 전체 로딩 과정입니다. tee-supplicant가 Normal World 파일시스템에서 TA 바이너리를 읽어 Secure World에 전달합니다.

/* TA 로딩 흐름 (시간 순서) */
/*
 * 1. CA: TEEC_OpenSession(uuid) → ioctl → 커널 optee 드라이버
 * 2. 커널: SMC → EL3 → OP-TEE OS
 * 3. OP-TEE: TA 캐시에 uuid 없음 → RPC_CMD_LOAD_TA 반환
 * 4. 커널: tee-supplicant에 RPC 전달 (TEE_IOC_SUPPL_RECV)
 * 5. tee-supplicant:
 *    a. /lib/optee_armtz/UUID.ta 파일 열기
 *    b. 파일 크기 확인 → SHM 할당 (TEE_IOC_SHM_ALLOC)
 *    c. TA 바이너리를 SHM에 복사
 *    d. 결과를 커널에 반환 (TEE_IOC_SUPPL_SEND)
 * 6. 커널: SMC로 OP-TEE에 SHM 주소 전달
 * 7. OP-TEE:
 *    a. 서명 헤더(SHDR) 파싱
 *    b. RSA 서명 검증 (ROTPK → TA 공개키)
 *    c. (Encrypted TA라면) 복호화
 *    d. ELF 파싱 → S-EL0 가상 주소 공간 생성
 *    e. .text/.data/.bss 매핑, 스택/힙 할당
 *    f. TA_CreateEntryPoint() 호출
 *    g. TA_OpenSessionEntryPoint() 호출
 * 8. 커널 → CA: 세션 ID 반환
 */

TA 플래그 상세

플래그설명
TA_FLAG_SINGLE_INSTANCE0x00000001시스템에 인스턴스 1개만 존재
TA_FLAG_MULTI_SESSION0x00000002여러 세션이 같은 인스턴스 공유
TA_FLAG_INSTANCE_KEEP_ALIVE0x00000004마지막 세션 종료 후에도 인스턴스 유지
TA_FLAG_SECURE_DATA_PATH0x00000008SDP(Secure Data Path) 버퍼 접근 허용
TA_FLAG_CACHE_MAINTENANCE0x00000010캐시(Cache) 유지보수 syscall 허용

TA간 통신 (TA-to-TA)

OP-TEE에서는 한 TA가 다른 TA의 세션을 열어 함수를 호출할 수 있습니다. 이를 통해 공통 기능(암호 서비스, 키 관리 등)을 별도 TA로 모듈화할 수 있습니다.

/* TA 내부에서 다른 TA 호출 */
TEE_Result call_crypto_ta(void *data, size_t len)
{
    TEE_TASessionHandle sess;
    TEE_Param params[4];
    uint32_t param_types;
    TEE_Result res;
    uint32_t ret_orig;

    /* 다른 TA의 세션 열기 */
    static const TEE_UUID crypto_uuid = { ... };
    res = TEE_OpenTASession(&crypto_uuid,
                            TEE_TIMEOUT_INFINITE,
                            0, NULL, &sess, &ret_orig);
    if (res != TEE_SUCCESS)
        return res;

    /* 다른 TA의 함수 호출 */
    param_types = TEE_PARAM_TYPES(
        TEE_PARAM_TYPE_MEMREF_INOUT,
        TEE_PARAM_TYPE_NONE,
        TEE_PARAM_TYPE_NONE,
        TEE_PARAM_TYPE_NONE);

    params[0].memref.buffer = data;
    params[0].memref.size = len;

    res = TEE_InvokeTACommand(sess, TEE_TIMEOUT_INFINITE,
                              0 /* cmd */, param_types,
                              params, &ret_orig);

    TEE_CloseTASession(sess);
    return res;
}

TA 개발 가이드

OP-TEE TA 개발은 OP-TEE SDK(ta_dev_kit)를 사용합니다. TA는 고유 UUID로 식별되며, 서명된 바이너리로 배포됩니다.

TA 프로젝트 구조

my_ta/
├── Makefile                  # TA 빌드 규칙
├── include/
│   └── my_ta.h               # CA/TA 공유 헤더 (cmd ID, UUID)
├── sub.mk                    # OP-TEE 빌드 시스템 통합
├── user_ta_header_defines.h  # TA 속성 (UUID, 스택 크기 등)
└── my_ta.c                   # TA 소스 코드

TA 헤더 정의

/* user_ta_header_defines.h */
#ifndef USER_TA_HEADER_DEFINES_H
#define USER_TA_HEADER_DEFINES_H

#include "my_ta.h"

#define TA_UUID                MY_TA_UUID
#define TA_FLAGS               (TA_FLAG_SINGLE_INSTANCE | \
                                TA_FLAG_MULTI_SESSION)
#define TA_STACK_SIZE          (2 * 1024)    /* 2KB */
#define TA_DATA_SIZE           (32 * 1024)   /* 32KB */

#define TA_CURRENT_TA_EXT_PROPERTIES \
    { "gp.ta.description", \
      USER_TA_PROP_TYPE_STRING, "My Example TA" }, \
    { "gp.ta.version", \
      USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0010 } }

#endif

TA 빌드 및 서명

# OP-TEE SDK로 TA 빌드
export TA_DEV_KIT_DIR=/path/to/optee_os/out/arm-plat-vexpress/export-ta_arm64
make CROSS_COMPILE=aarch64-linux-gnu- \
     PLATFORM=vexpress-qemu_armv8a

# 빌드 결과: UUID.ta (서명된 TA 바이너리)
# 배포: /lib/optee_armtz/UUID.ta 에 복사
ls -la *.ta
# -rw-r--r-- 1 root root 15360 my_ta_uuid.ta

# TA 서명 검증
# OP-TEE는 부팅 시 로딩된 공개키로 TA 서명을 검증
# sign_encrypt.py: TA_SIGN_KEY로 서명 (기본: keys/default_ta.pem)
python3 scripts/sign_encrypt.py \
    --key keys/default_ta.pem \
    --uuid $UUID \
    --ta-version 0 \
    --in my_ta.stripped.elf \
    --out $UUID.ta
⚠️

프로덕션 TA 서명: OP-TEE 기본 키(keys/default_ta.pem)는 개발용입니다. 프로덕션 환경에서는 반드시 자체 RSA 2048/4096 키 쌍을 생성하고, 공개키를 OP-TEE OS 빌드에 포함시키며, 개인키는 HSM(Hardware Security Module)에서 관리해야 합니다.

Secure Storage

OP-TEE의 Secure Storage는 TA가 암호화된 데이터를 영구적으로 저장할 수 있는 기능을 제공합니다. 두 가지 백엔드를 지원합니다.

OP-TEE Secure Storage 아키텍처 Trusted Application TEE_CreatePersistentObject() GlobalPlatform TEE Trusted Storage API 암호화 계층 AES-GCM (FEK) + SSK/TSK/DSK 키 체인 | 무결성: HMAC-SHA256 REE FS 백엔드 tee-supplicant RPC로 파일 I/O /data/tee/ 또는 /var/lib/tee/ 롤백 공격에 취약 (파일 교체 가능) 기본값, 모든 플랫폼 지원 RPMB 백엔드 eMMC/UFS RPMB 파티션 직접 접근 인증된 읽기/쓰기 (HMAC-SHA256) Write Counter로 롤백 방지 eMMC/UFS 장치 필요
Secure Storage는 FEK(File Encryption Key)로 데이터를 암호화하고, FEK 자체는 TSK(TA Storage Key)로 보호합니다. RPMB 백엔드는 롤백(Rollback) 방지를 추가합니다.

키 체인 구조

파생 방식보호 대상
HUK (Hardware Unique Key)SoC 퓨즈 / TRNG에서 유도SSK 파생의 루트
SSK (Secure Storage Key)HMAC(HUK, "SECURE_STORAGE" + chip_id)TSK 파생
TSK (TA Storage Key)HMAC(SSK, TA_UUID)FEK 암호화
FEK (File Encryption Key)PRNG (파일 생성 시)파일 데이터 암호화 (AES-GCM)

Secure Storage API 사용 예시

/* TA 내부: Secure Storage에 데이터 저장 */
TEE_Result save_secret(void *data, size_t len)
{
    TEE_ObjectHandle obj;
    TEE_Result res;

    /* 영구 객체 생성 (또는 열기) */
    res = TEE_CreatePersistentObject(
        TEE_STORAGE_PRIVATE,          /* 스토리지 ID */
        "my_secret", 9,                /* 객체 ID */
        TEE_DATA_FLAG_ACCESS_WRITE |
        TEE_DATA_FLAG_OVERWRITE,
        TEE_HANDLE_NULL,               /* 속성 없음 */
        data, len,                     /* 초기 데이터 */
        &obj);

    if (res == TEE_SUCCESS)
        TEE_CloseObject(obj);

    return res;
}

/* TA 내부: Secure Storage에서 데이터 읽기 */
TEE_Result load_secret(void *buf, size_t *len)
{
    TEE_ObjectHandle obj;
    TEE_Result res;

    res = TEE_OpenPersistentObject(
        TEE_STORAGE_PRIVATE,
        "my_secret", 9,
        TEE_DATA_FLAG_ACCESS_READ,
        &obj);

    if (res == TEE_SUCCESS) {
        res = TEE_ReadObjectData(obj, buf, *len, len);
        TEE_CloseObject(obj);
    }
    return res;
}

fTPM (Firmware TPM)

fTPM(firmware TPM)은 OP-TEE TA로 구현된 TPM 2.0 에뮬레이션입니다. 별도의 TPM 칩 없이도 TPM 기능(Measured Boot, 키 저장, 원격 증명 등)을 제공합니다. Microsoft가 최초 구현했으며(ms-tpm-20-ref), OP-TEE에 공식 통합되어 있습니다. 커널에서는 tpm_ftpm_tee.c 드라이버가 TEE 프레임워크를 통해 Secure World의 fTPM TA와 통신합니다.

ℹ️

fTPM: fTPM 아키텍처(소프트웨어 스택, 커널 드라이버 내부 구현), dTPM/fTPM/sTPM 보안 경계 비교, 성능 특성, 인증 가능성, fTPM 취약점(Vulnerability) 이력 등의 상세 내용은 TPM 2.0 문서를 참조하세요.

GlobalPlatform 규격

GlobalPlatform(GP)은 TEE 기술의 표준화 단체로, TEE의 아키텍처, API, 보안 요구사항을 규격화합니다. OP-TEE는 GP TEE 규격의 오픈소스 레퍼런스 구현체입니다.

주요 GP TEE 규격

규격버전대상주요 내용
TEE Client API1.0Normal World 앱TEEC_* 함수, 세션/컨텍스트/파라미터 관리
TEE Internal Core API1.3.1TA 개발암호, 스토리지, 시간, 수학, 속성 관리
TEE System Architecture1.3TEE OS 구현TA 관리, 메모리, 보안 모델, 통신
TEE Protection Profile1.3보안 인증CC(Common Criteria) EAL 기반 보안 평가
TEE TA Debug1.0디버깅(Debugging)Secure World 디버그 인터페이스

TEE Internal Core API 주요 카테고리

카테고리주요 함수용도
암호 연산TEE_AllocateOperation, TEE_AEInit, TEE_AEEncryptFinalAES, RSA, ECC, HMAC, SHA
영구 스토리지TEE_CreatePersistentObject, TEE_ReadObjectData파일 암호화 저장/조회
임시 객체TEE_AllocateTransientObject, TEE_GenerateKey키 생성, 속성 관리
시간TEE_GetSystemTime, TEE_GetREETimeSecure/REE 타이머(Timer) 접근
메모리TEE_Malloc, TEE_Realloc, TEE_MemMoveTA 힙 관리
산술TEE_BigIntInit, TEE_BigIntMul, TEE_BigIntMod빅넘 연산

GP 인증 (Compliance)

GlobalPlatform은 TEE 구현체의 보안 수준을 평가하기 위한 Protection Profile (PP)적합성 테스트 스위트를 제공합니다.

인증 레벨보안 수준평가 기준대상
GP TEE PPCC EAL2+기본 보안 요구사항일반 TEE 구현
GP TEE PP (augmented)CC EAL4+강화된 취약성 분석금융/결제 TEE
SESIP Level 3Security Evaluation Standard for IoT PlatformsIoT 보안 평가IoT TEE

GP API 확장: PKCS#11 TA

OP-TEE는 GlobalPlatform API 위에 PKCS#11 TA를 제공하여 표준 암호 토큰 인터페이스를 지원합니다. OpenSSL, p11-kit 등 기존 PKCS#11 소비자가 OP-TEE의 Secure Storage에 키를 저장하고 암호 연산을 수행할 수 있습니다.

# PKCS#11 TA를 통한 키 생성 (pkcs11-tool)
pkcs11-tool --module /usr/lib/libckteec.so \
    --keypairgen --key-type rsa:2048 \
    --label "my-rsa-key" --id 01

# 생성된 키로 서명
pkcs11-tool --module /usr/lib/libckteec.so \
    --sign --mechanism SHA256-RSA-PKCS \
    --id 01 --input-file data.bin \
    --output-file sig.bin

# OpenSSL PKCS#11 엔진 통합
openssl req -engine pkcs11 \
    -keyform engine \
    -key "pkcs11:token=OP-TEE;id=%01;type=private" \
    -new -x509 -sha256 \
    -out cert.pem

OP-TEE 내부 구현

OP-TEE OS는 마이크로커널 스타일의 TEE 운영체제로, S-EL1에서 실행됩니다. User TA는 S-EL0에서 격리된 가상 주소 공간을 가지며, OP-TEE 커널이 시스템 콜(System Call)을 통해 서비스를 제공합니다.

OP-TEE 스레드 모델

/* OP-TEE: core/kernel/thread.c */
struct thread_ctx {
    struct thread_ctx_regs regs; /* 범용/시스템 레지스터 */
    enum thread_state state;     /* FREE, SUSPENDED, ACTIVE */
    vaddr_t stack_va_end;        /* 스레드 스택 끝 */
    uint32_t flags;              /* THREAD_FLAGS_* */
    void *rpc_arg;               /* 현재 RPC 인자 */
    struct mutex_head mutexes;   /* 보유 중인 뮤텍스 */
};

/* 스레드 수 = CFG_NUM_THREADS (기본 8) */
static struct thread_ctx threads[CFG_NUM_THREADS];

/* 스레드 할당: SMC 진입 시 free 스레드 배정 */
static int thread_alloc_and_run(
    uint32_t a0, uint32_t a1,
    uint32_t a2, uint32_t a3)
{
    size_t n;
    for (n = 0; n < CFG_NUM_THREADS; n++) {
        if (threads[n].state == THREAD_STATE_FREE) {
            threads[n].state = THREAD_STATE_ACTIVE;
            thread_resume(&threads[n]);
            return n;
        }
    }
    return OPTEE_SMC_RETURN_ETHREAD_LIMIT; /* 스레드 부족 */
}

OP-TEE 메모리 관리(Memory Management)

메모리 영역용도보호 수준
TEE RAMOP-TEE 코드, 데이터, BSS, 힙Secure only (TZC-400)
TA RAMUser TA 코드, 데이터, 스택, 힙Secure only, TA별 격리 (MMU)
SHMNW/SW 공유 데이터Non-secure (양쪽 접근 가능)
MEM_AREA_IOSecure 주변장치 MMIOSecure only, 비캐시

OP-TEE Pager

Secure RAM이 제한된 환경(수 백 KB)에서 OP-TEE는 자체 페이징 메커니즘으로 코드와 읽기 전용(Read-Only) 데이터를 Non-secure 메모리에 암호화하여 캐싱합니다.

/* OP-TEE: core/mm/pager.c */
/* 페이지 폴트 핸들러: Secure RAM 풀에서 빈 페이지 확보 */
static bool pager_handle_abort(
    struct abort_info *ai)
{
    struct pager_area *area;
    struct page *page;

    /* 폴트 주소에 해당하는 pager area 검색 */
    area = find_pager_area(ai->va);
    if (!area)
        return false;

    /* LRU 정책으로 희생 페이지 선택 */
    page = TAILQ_LAST(&pager_page_list);

    /* 1. 희생 페이지를 AES-GCM으로 암호화하여 NS 메모리에 저장 */
    pager_save_page(page);

    /* 2. 요청 페이지를 NS 메모리에서 읽어와 복호화/무결성 검증 */
    pager_restore_page(area, page);

    /* 3. MMU 매핑 갱신 */
    core_mmu_set_entry(&area->tbl_info, page->pa,
                       TEE_MATTR_VALID_BLOCK | area->flags);
    return true;
}

OP-TEE 시스템 콜

User TA(S-EL0)는 SVC 명령으로 OP-TEE 커널(S-EL1)의 서비스를 호출합니다. 주요 시스템 콜 번호는 다음과 같습니다.

시스콜 번호함수용도
0syscall_returnTA 진입점 반환
1syscall_logSecure 로그 출력
2syscall_panicTA 패닉 (즉시 종료)
5syscall_get_propertyTA/Client 속성 조회
10syscall_open_ta_session다른 TA 세션 열기 (TA→TA)
12syscall_invoke_ta_command다른 TA 함수 호출
25syscall_cryp_obj_alloc암호 객체 할당
30syscall_cryp_state_alloc암호 연산 상태 할당
33syscall_cipher_init대칭 암호 초기화
34syscall_cipher_update대칭 암호 업데이트
40syscall_storage_obj_createSecure Storage 객체 생성
44syscall_storage_obj_readSecure Storage 읽기

OP-TEE 암호 라이브러리

OP-TEE는 자체 암호 라이브러리로 LibTomCrypt(소프트웨어)와 ARMv8 Crypto Extension(하드웨어) 두 백엔드를 지원합니다. 빌드 시 CFG_CRYPTO_DRIVER로 하드웨어 가속을 선택할 수 있습니다.

/* OP-TEE: core/crypto/aes-gcm.c */
/* ARMv8 CE 가속 AES-GCM */
TEE_Result crypto_aes_gcm_enc_final(
    void *ctx,
    const uint8_t *src, size_t len,
    uint8_t *dst,
    uint8_t *tag, size_t *tag_len)
{
    struct aes_gcm_ctx *c = ctx;

    /* CE 가속: AESE/AESMC/AESD/AESIMC 명령 사용 */
    ce_aes_gcm_encrypt(c->key, c->rounds,
                       src, dst, len,
                       c->ctr, c->hash_subkey);

    /* GHASH 계산: PMULL/PMULL2 명령 */
    ce_gcm_ghash(c->hash_subkey, c->ghash, dst, len);

    /* 태그 생성 */
    ce_aes_gcm_final(c, tag, tag_len);
    return TEE_SUCCESS;
}
ℹ️

Crypto Extension 성능 향상: ARMv8 CE를 활용하면 AES-256-GCM 처리량(Throughput)이 소프트웨어 대비 5~10배 향상됩니다. Cortex-A53에서 CE 미사용 시 ~45 MB/s, CE 사용 시 ~310 MB/s 수준입니다. 대부분의 최신 ARM SoC는 CE를 지원합니다.

OP-TEE 보안 기능

OP-TEE는 Secure World 내에서도 다층 보안 메커니즘을 적용하여 TA 간 격리와 코드 무결성(Integrity)을 보장합니다.

보안 메커니즘 요약

메커니즘설명설정
TA 서명 검증(Signature Verification)TA 로딩 시 RSA 2048 서명 검증, 무결성 확인TA_SIGN_KEY
TA 주소 공간 격리각 User TA는 독립 가상 주소 공간 (S-EL0 MMU)기본 활성
ASLRTA 로드 주소 랜덤화 (CFG_TA_ASLR)CFG_TA_ASLR=y
스택 카나리(Stack Canary)스택 오버플로(Stack Overflow) 탐지CFG_WITH_STACK_CANARIES=y
TA Paging 암호화페이지 아웃된 코드/데이터를 AES-GCM으로 암호화CFG_WITH_PAGER=y
TA 암호화 (Encrypted TA)TA 바이너리 자체를 암호화하여 배포CFG_ENCRYPT_TA=y
PAN (Privileged Access Never)S-EL1이 S-EL0 메모리를 의도치 않게 접근 방지하드웨어 지원 시 자동
메모리 태깅 (MTE)ARMv8.5+ MTE를 활용한 메모리 안전성CFG_MEMTAG=y

TA 서명 검증 흐름

/* OP-TEE: core/kernel/signed_hdr.c */
TEE_Result shdr_verify_signature(
    const struct shdr *shdr)
{
    struct rsa_public_key key;
    TEE_Result res;

    /* 1. OP-TEE에 내장된 TA 서명 공개키 로딩 */
    res = crypto_acipher_alloc_rsa_public_key(&key, 2048);

    /* 2. 해시 검증: SHA-256(TA 코드 + 데이터) */
    res = crypto_hash_final(hash_ctx, digest, TEE_SHA256_HASH_SIZE);

    /* 3. RSA PKCS#1 v1.5 서명 검증 */
    res = crypto_acipher_rsassa_verify(
        TEE_ALG_RSASSA_PKCS1_V1_5_SHA256,
        &key, -1, digest, TEE_SHA256_HASH_SIZE,
        sig, sig_len);

    if (res != TEE_SUCCESS)
        EMSG("TA signature verification failed!");

    return res;
}

TA 주소 공간 격리 상세

각 User TA는 S-EL0에서 독립된 가상 주소 공간을 할당받습니다. OP-TEE 커널(S-EL1)은 TA 전환 시 TTBR0_EL1을 교체하여 TA 간 메모리 격리를 보장합니다.

/* OP-TEE: core/arch/arm/mm/core_mmu.c */
/* TA 전환 시 MMU 컨텍스트 교체 */
void core_mmu_set_user_map(struct core_mmu_user_map *map)
{
    if (map) {
        /* 새 TA의 페이지 테이블로 교체 */
        write_ttbr0_el1(map->user_map);
        write_contextidr_el1(map->asid);
    } else {
        /* TA 없음: TTBR0 무효화 */
        write_ttbr0_el1(0);
    }
    isb();
    /* ASID 기반 TLB 무효화 */
    tlbi_asid(map ? map->asid : 0);
    dsb();
    isb();
}

/* TA 메모리 영역 보호 속성 */
/* .text  → RX (실행 가능, 쓰기 불가) */
/* .rodata → RO (읽기 전용) */
/* .data/.bss → RW (읽기/쓰기, 실행 불가) */
/* 스택 → RW + 가드 페이지 (스택 오버플로 탐지) */
/* 힙 → RW (TEE_Malloc으로 동적 할당) */

Encrypted TA (암호화된 TA)

OP-TEE 3.7+에서는 CFG_ENCRYPT_TA=y로 TA 바이너리 자체를 암호화하여 배포할 수 있습니다. 이는 TA 코드의 리버스 엔지니어링을 방지하며, REE 파일시스템에 저장된 TA가 평문으로 노출되는 것을 막습니다.

/* OP-TEE Encrypted TA 구조 */
/*
 * +------------------+
 * | SHDR (서명 헤더)  | — RSA 서명, 해시 알고리즘, 이미지 크기
 * +------------------+
 * | EHD (암호 헤더)   | — 암호화 알고리즘, IV/nonce, 태그
 * +------------------+
 * | 암호화된 TA 코드  | — AES-GCM(TA_ENC_KEY, IV, plaintext TA)
 * +------------------+
 *
 * 로딩 순서:
 * 1. SHDR 서명 검증 (공개키)
 * 2. EHD에서 IV/태그 추출
 * 3. TA_ENC_KEY로 복호화 + GCM 태그 검증
 * 4. 복호화된 ELF를 S-EL0 주소 공간에 매핑
 */

TrustZone 공격 벡터와 방어

공격 벡터설명방어 메커니즘
Cold Boot Attack전원 차단 후 DRAM 잔류 데이터 읽기키를 레지스터에만 유지, DRAM 스크럽, MTE
DMA 공격악성 DMA 마스터가 Secure 메모리 접근TZASC/SMMU, IOMMU 기반 DMA 보호
사이드 채널캐시 타이밍, 전력 분석으로 키 추출상수 시간 암호 구현, 캐시 플러시(Flush), ASLR
RoP/JoPTA 취약점을 통한 코드 재사용 공격PAN, BTI(Branch Target Identification), ASLR
Rollback AttackSecure Storage 파일을 이전 버전으로 교체RPMB Write Counter, Anti-Rollback 버전
Fault Injection전압/클럭 글리칭으로 서명 검증 우회이중 검증, 중복 검사, 하드웨어 센서
Debug Port 접근JTAG/SWD로 Secure 상태 접근Secure JTAG 비활성화 (퓨즈), DBGEN=0
⚠️

프로덕션 보안 체크리스트: (1) TA 서명키를 프로덕션 키로 교체, (2) JTAG/SWD를 퓨즈로 비활성화, (3) RPMB 키 프로비저닝, (4) OP-TEE 디버그 로그 비활성화(CFG_TEE_CORE_LOG_LEVEL=0), (5) Encrypted TA 활성화, (6) ASLR 활성화, (7) anti-rollback 버전 관리. 자세한 커널 보안 기법은 커널 하드닝 문서를 참고하세요.

QEMU 실습

OP-TEE는 QEMU(ARM virt/vexpress) 환경에서 전체 스택을 실습할 수 있습니다. OP-TEE 프로젝트의 manifest 레포지토리가 repo를 통한 전체 빌드를 지원합니다.

OP-TEE QEMU 실습 구성 QEMU ARMv8-A (virt machine) TF-A (BL31) Secure Monitor OP-TEE OS (BL32) S-EL1 TEE U-Boot (BL33) 부트로더 Linux 커널 EL1 tee-supplicant xtest (테스트) optee_example_* TA 바이너리 시리얼 콘솔: Normal World (54320) | Secure World (54321) nc localhost 54320 (Linux) / nc localhost 54321 (OP-TEE 로그)
QEMU에서 TF-A→OP-TEE→U-Boot→Linux 전체 부팅 체인을 실습할 수 있으며, 두 개의 시리얼 콘솔로 NW/SW 로그를 분리 확인합니다

빌드 및 실행 절차

# 1. repo 도구 설치 및 매니페스트 초기화
mkdir -p optee-qemu && cd optee-qemu
repo init -u https://github.com/OP-TEE/manifest.git \
    -m qemu_v8.xml -b 4.1.0
repo sync -j$(nproc)

# 2. 전체 빌드 (TF-A + OP-TEE + U-Boot + Linux + Buildroot)
cd build
make -j$(nproc) toolchains
make -j$(nproc) all

# 3. QEMU 실행
make run
# 별도 터미널에서 Normal World 콘솔 연결
# nc localhost 54320

# 4. OP-TEE xtest (GP 적합성 테스트) 실행
# Normal World 콘솔에서:
xtest

# 5. 예제 TA 실행
optee_example_hello_world
optee_example_secure_storage
optee_example_aes

QEMU GDB 디버깅

# OP-TEE Secure World 디버깅
make run-only QEMU_VIRTFS_AUTOMOUNT=y \
    GDBSERVER=y

# 별도 터미널에서 GDB 연결
aarch64-linux-gnu-gdb \
    -ex "target remote :1234" \
    -ex "symbol-file optee_os/out/arm/core/tee.elf" \
    -ex "break thread_std_smc_entry"

# TA 디버깅 (TA ELF 심볼 로딩)
# OP-TEE 로그에서 TA 로드 주소 확인 후:
add-symbol-file path/to/ta.elf 0x40010000

SoC별 구현

주요 SoC 벤더들은 TrustZone 위에 자체 TEE 솔루션을 구축합니다. 각 구현체의 특성과 차이점을 비교합니다.

SoC별 TEE 구현 비교 Qualcomm QSEE / QTEE 독자 TEE OS Qualcomm 전용 TA Widevine L1 DRM 생체인증 (Iris/FP) SMMU 기반 격리 Secure Boot Chain qseecom 커널 드라이버 최근 FF-A 전환 중 Samsung TEEGRIS / Knox Exynos: TEEGRIS Knox 보안 프레임워크 Samsung Pay TEE TIMA (TrustZone IMA) RKP (RealTime Kernel Protection) S-EL2 Hypervisor GP TEE 호환 MediaTek Trustonic / microTEE Trustonic Kinibi TEE OP-TEE 일부 채택 DRM/Widevine SPI secure 접근 TEE를 통한 GZ (GenieZone) 하이퍼바이저 GP TEE 호환 NXP / STM / TI OP-TEE (공식) OP-TEE 직접 채택 오픈소스 플랫폼 지원 i.MX 8/9 (NXP) STM32MP1/2 (STM) AM62x/64x (TI) PKCS#11 TA 지원 Buildroot/Yocto 통합 SCP/SCMI 펌웨어
모바일 SoC 벤더는 독자 TEE를 사용하고, 임베디드/산업용 SoC 벤더는 OP-TEE를 직접 채택하는 경향이 있습니다

SoC별 TEE 커널 드라이버 비교

SoC 벤더TEE 구현커널 드라이버SMC/통신 방식GP 호환
QualcommQSEE/QTEEdrivers/firmware/qcom_scm.cSCM(Secure Channel Manager) SMC부분적
SamsungTEEGRISdrivers/misc/tzdev/ (삼성 BSP)SMC + 공유 메모리완전
MediaTekTrustonic/OP-TEEdrivers/tee/ 표준 + MTK 확장SMC완전
NXP i.MXOP-TEEdrivers/tee/optee/ 표준SMC완전
STM32MPOP-TEEdrivers/tee/optee/ 표준SMC완전
TI AM6xOP-TEEdrivers/tee/optee/ 표준SMC완전
Renesas R-CarOP-TEEdrivers/tee/optee/ 표준SMC완전
Broadcom독자 TEEBSP 전용Mailbox부분적

Qualcomm SCM(Secure Channel Manager) 인터페이스

Qualcomm SoC에서는 OP-TEE 대신 자체 TEE(QSEE/QTEE)를 사용하며, qcom_scm 드라이버가 SMC 호출을 래핑합니다.

/* drivers/firmware/qcom_scm.c */
int qcom_scm_call(
    struct device *dev,
    const struct qcom_scm_desc *desc,
    struct qcom_scm_res *res)
{
    /* Qualcomm SCM은 두 가지 호출 규약을 지원 */
    if (likely(__qcom_scm_is_call_available(dev, desc->svc, desc->cmd)))
        return qcom_scm_call_smccc(dev, desc, res, false);
    else
        return qcom_scm_call_legacy(dev, desc, res);
}

/* Qualcomm SCM 서비스 예시 */
#define QCOM_SCM_SVC_PIL        0x02  /* Peripheral Image Loader */
#define QCOM_SCM_SVC_IO         0x05  /* IO 접근 보호 */
#define QCOM_SCM_SVC_INFO       0x06  /* SoC 정보 */
#define QCOM_SCM_SVC_HDCP       0x11  /* HDCP DRM */
#define QCOM_SCM_SVC_SMMU       0x15  /* SMMU 보안 설정 */
ℹ️

OP-TEE 지원 SoC 목록: OP-TEE는 NXP i.MX 6/7/8/9, STM32MP1/2, TI AM62x/64x/65x, Renesas R-Car, Marvell ARMADA, Broadcom BCM2711(Raspberry Pi 4), QEMU virt, Hisilicon, Rockchip 등 30개 이상의 플랫폼을 공식 지원합니다. 전체 목록은 optee_os/core/arch/arm/plat-*/ 디렉토리에서 확인할 수 있습니다.

TrustZone vs CCA vs SEV/TDX 비교

하드웨어 기반 격리 기술은 ARM TrustZone, ARM CCA(Confidential Computing Architecture), AMD SEV, Intel TDX 등 여러 방식이 있습니다. 각 기술의 아키텍처와 보호 범위를 비교합니다.

특성ARM TrustZoneARM CCA (Realm)AMD SEV(-SNP)Intel TDX
보호 모델2-World (S/NS)4-World (Root/Realm/Secure/NS)VM 메모리 암호화TD(Trust Domain) 격리
격리 단위Secure World (단일)Realm VM (다수)VMTD (VM)
하이퍼바이저(Hypervisor) 신뢰Normal World만불신 (RMM이 중재)불신불신
메모리 암호화물리적 분리 (TZASC)GPT 기반 접근 제어AES-128 (키 per VM)AES-128/256 (키 per TD)
원격 증명제한적 (TEE 의존)CCA 증명 서비스SEV-SNP AttestationTDX Attestation
대상모바일/임베디드서버/클라우드서버/클라우드서버/클라우드
아키텍처ARMv6K+ARMv9.2+AMD EPYCIntel Xeon (Sapphire Rapids+)
Linux 지원drivers/tee/optee/drivers/virt/coco/arch/x86/coco/sev/arch/x86/coco/tdx/
ℹ️

TrustZone과 CCA의 관계: ARMv9 CCA에서 TrustZone은 사라지지 않습니다. TrustZone(Secure World)은 펌웨어와 TEE용으로 유지되고, Realm World가 기밀 VM용으로 추가됩니다. 자세한 내용은 기밀 컴퓨팅 문서를 참고하세요.

성능 분석

TrustZone/TEE 호출은 World 전환 오버헤드(Overhead)를 수반합니다. 이 오버헤드를 이해하고 최적화하는 것이 중요합니다.

SMC 호출 오버헤드

구간소요 시간 (대략)주요 비용
SMC 명령 실행~50 nsEL1→EL3 트랩
컨텍스트 저장/복원~500 ns - 2 usGP/시스템/FP 레지스터, TLB/캐시
OP-TEE 스레드 할당~200 nsfree 스레드 검색
TA 세션 조회~100 nsUUID→세션 매핑(Mapping)
왕복 합계 (빈 TA 호출)~5-20 us플랫폼 의존
AES-256-GCM 1KB~30-50 usTA 호출 + 암호 연산 + SHM 복사
RSA-2048 서명~2-5 ms연산 집약적

성능 최적화 기법

기법설명효과
배치 호출여러 명령을 하나의 SMC로 묶어 호출왕복 횟수 감소
세션 재사용TA 세션을 열어둔 채 반복 호출OpenSession 오버헤드 제거
Dynamic SHM대량 데이터 시 메모리 복사 회피데이터 전송 지연(Latency) 감소
Pseudo TAS-EL1에서 직접 실행 (S-EL0 전환 없음)컨텍스트 스위치 제거
CE 가속ARMv8 Crypto Extension 활용AES/SHA 10-50x 속도향상
비동기 호출Yielding Call로 NW에 CPU 양보NW 지연 최소화

벤치마크 측정 예시

# xtest 벤치마크 모드
xtest --aes-perf
xtest --sha-perf

# 결과 예시 (Cortex-A53 1.2GHz)
# AES-256-CBC encrypt:  45.2 MB/s (SW) → 312.8 MB/s (CE hw)
# SHA-256 hash:         78.5 MB/s (SW) → 425.1 MB/s (CE hw)
# AES-256-GCM encrypt:  38.7 MB/s (SW) → 287.3 MB/s (CE hw)

# SMC 왕복 레이턴시 측정
xtest 1001   # 빈 TA 호출 왕복 시간

World 전환 비용 분해

SMC 왕복의 비용을 구간별로 분해하면 다음과 같습니다. 최적화 타겟을 식별하는 데 유용합니다.

단계Cortex-A53 (cycles)Cortex-A72 (cycles)비고
SMC 트랩 (EL1→EL3)~30~25프로세서 파이프라인(Pipeline) 플러시
EL3 핸들러 진입~50~40벡터 테이블 점프
NW 컨텍스트 저장~200~180GP + 시스템 레지스터 31개+
SW 컨텍스트 복원~200~180GP + 시스템 레지스터
FP/SIMD 레지스터~150~120v0-v31 (선택적, lazy)
TLB 무효화(Invalidation)~100~80ASID 기반 최소화 가능
ERET (EL3→S-EL1)~20~15예외 복귀
OP-TEE 스레드 디스패치~100~80스레드 상태 확인
단방향 합계~850~720
왕복 합계~1,700~1,440빈 호출 기준

OP-TEE ftrace 지원

# OP-TEE 내부 함수 트레이싱 (CFG_FTRACE_SUPPORT=y 빌드 시)
# Normal World에서 ftrace 덤프 트리거:
echo 1 > /proc/optee/ftrace_dump

# OP-TEE 시리얼 로그에 ftrace 출력:
# Thread 0 (0x00000001)
#   entry_std_smc_handler           1234 ns
#     tee_ta_open_session           567 ns
#       ta_load                     234 ns
#       check_open_params           45 ns
#     tee_ta_invoke_command         890 ns
#       TA_InvokeCommand            678 ns
💡

캐시 영향 최소화: World 전환 시 L1 캐시를 플러시해야 할 수 있는데(사이드 채널 방어), 이는 큰 성능 비용을 초래합니다. CFG_CORE_UNMAP_CORE_AT_EL0=y로 S-EL0에서 커널 매핑을 제거하면 Spectre 방어가 되지만, TA↔커널 전환 비용이 증가합니다. 성능과 보안 사이의 트레이드오프를 고려하세요.

커널 설정

Linux 커널에서 TEE/OP-TEE를 사용하기 위한 Kconfig 옵션입니다.

필수 설정

# TEE 프레임워크 기본
CONFIG_TEE=y              # TEE 서브시스템 활성화
CONFIG_OPTEE=y            # OP-TEE 드라이버

# SMCCC 지원
CONFIG_HAVE_ARM_SMCCC=y   # ARM SMC Calling Convention
CONFIG_ARM_SMCCC_SOC_ID=y # SoC ID 쿼리 via SMCCC

# fTPM (선택)
CONFIG_TCG_TPM=y          # TPM 서브시스템
CONFIG_TCG_FTPM_TEE=y     # fTPM via TEE 드라이버

# FF-A (ARMv8.4+ Secure Partition, 선택)
CONFIG_ARM_FFA_TRANSPORT=y # FF-A 메시징

# RPMB 지원 (Secure Storage 백엔드)
CONFIG_MMC=y
CONFIG_MMC_BLOCK=y        # eMMC RPMB 접근

# PSCI (전원 관리, TF-A 연동)
CONFIG_ARM_PSCI_FW=y      # PSCI 펌웨어 인터페이스

디버그 설정

# TEE 디버그 로그
CONFIG_TEE_DEBUG=y        # TEE 프레임워크 디버그 메시지

# 커널 로그에서 확인
dmesg | grep -i optee
# [    1.234567] optee: probing for conduit method.
# [    1.234589] optee: revision 3.19 (abcdef01)
# [    1.234601] optee: dynamic shared memory is enabled
# [    1.234615] optee: initialized driver

OP-TEE 빌드 시 주요 CFG 옵션

옵션기본값설명
CFG_NUM_THREADS8동시 TA 실행 스레드 수
CFG_TA_ASLRyTA 로드 주소 랜덤화
CFG_TA_DYNLINKyTA 동적 링킹 (공유 라이브러리(Shared Library))
CFG_ENCRYPT_TAnTA 바이너리 암호화
CFG_WITH_PAGERnSecure RAM 페이징
CFG_WITH_STACK_CANARIESy스택 카나리 보호
CFG_CORE_ASLRyOP-TEE 커널 ASLR
CFG_RPMB_FSnRPMB Secure Storage 백엔드
CFG_REE_FSyREE 파일시스템 Secure Storage 백엔드
CFG_CRYPTO_WITH_CE플랫폼 의존ARMv8 Crypto Extension 활용
CFG_TEE_CORE_LOG_LEVEL1로그 레벨 (0=없음, 4=상세)
CFG_FTRACE_SUPPORTn내부 함수 트레이싱
CFG_CORE_UNMAP_CORE_AT_EL0yS-EL0에서 커널 매핑 제거 (Spectre 방어)
CFG_MEMTAGnARMv8.5 MTE 메모리 태깅
CFG_PKCS11_TAyPKCS#11 TA 포함

트러블슈팅

일반적인 문제와 해결

증상원인해결
/dev/tee0 미생성OP-TEE 드라이버 미로딩 또는 DT 누락CONFIG_OPTEE=y, DT에 linaro,optee-tz 노드 확인
SMC 호출 시 SMC_UNK 반환EL3 Monitor 미설정 또는 서비스 미등록TF-A BL31 설정, OPTEE_SPD=opteed 빌드 옵션 확인
TEEC_ERROR_COMMUNICATIONSecure World 크래시 또는 스레드 부족OP-TEE 시리얼 로그 확인, CFG_NUM_THREADS 증가
TA 로딩 실패 (ITEM_NOT_FOUND)TA 파일 경로 오류 또는 tee-supplicant 미실행/lib/optee_armtz/UUID.ta 확인, tee-supplicant & 실행
TA 서명 검증 실패TA 서명키와 OP-TEE 공개키 불일치동일 키 쌍으로 TA 서명 / OP-TEE 빌드
RPMB 접근 오류eMMC RPMB 키 미프로비저닝mmc rpmb key write로 RPMB 인증키 설정
SHM 할당 실패공유 메모리 풀 소진Static SHM 크기 확장 또는 Dynamic SHM 전환
Normal World에서 Secure 메모리 접근 크래시TZASC 보호 위반TZC-400 리전 설정 확인, DT reserved-memory 확인
fTPM /dev/tpm0 미생성fTPM TA 미설치 또는 드라이버 미설정CONFIG_TCG_FTPM_TEE=y, TA 설치 확인

디버깅 명령

# OP-TEE 드라이버 상태 확인
cat /sys/bus/tee/devices/optee/version
cat /sys/bus/tee/devices/optee/pool_size

# TEE 장치 목록
ls -la /dev/tee*
# crw-rw---- 1 root tee 253, 0 /dev/tee0
# crw-rw---- 1 root tee 253, 16 /dev/teepriv0

# tee-supplicant 프로세스 확인
ps aux | grep tee-supplicant

# OP-TEE Secure World 로그 (QEMU)
# 시리얼 콘솔 또는:
cat /sys/kernel/debug/optee/log   # (빌드 옵션에 따라)

# SMC 호출 카운터 (ftrace)
echo 1 > /sys/kernel/debug/tracing/events/arm_smccc/enable
cat /sys/kernel/debug/tracing/trace | grep smc

# fTPM 상태
tpm2_getcap properties-fixed
tpm2_pcrread sha256

OP-TEE 에러 코드 참조

에러 코드의미일반적 원인
TEEC_SUCCESS0x00000000성공
TEEC_ERROR_GENERIC0xFFFF0000일반 오류TA 내부 로직 오류
TEEC_ERROR_ACCESS_DENIED0xFFFF0001접근 거부잘못된 로그인 방식, 권한 부족
TEEC_ERROR_CANCEL0xFFFF0002작업 취소TEEC_RequestCancellation() 호출
TEEC_ERROR_BAD_PARAMETERS0xFFFF0006잘못된 파라미터param_types 불일치, NULL 포인터
TEEC_ERROR_ITEM_NOT_FOUND0xFFFF0008항목 미발견TA 파일 없음, Secure Storage 객체 없음
TEEC_ERROR_NOT_SUPPORTED0xFFFF000A미지원TA가 해당 cmd_id 미구현
TEEC_ERROR_COMMUNICATION0xFFFF000E통신 오류SW 크래시, 스레드 부족, SHM 오류
TEEC_ERROR_SECURITY0xFFFF000F보안 오류TA 서명 실패, 무결성 위반
TEEC_ERROR_SHORT_BUFFER0xFFFF0010버퍼 부족출력 버퍼 크기 부족
TEEC_ERROR_OUT_OF_MEMORY0xFFFF000C메모리 부족TA 힙/스택 소진, SHM 풀 소진
TEEC_ERROR_TARGET_DEAD0xFFFF3024TA 사망TA 패닉, 메모리 접근 위반

Origin 코드

TEEC_OpenSession()TEEC_InvokeCommand()는 에러 발생 위치를 returnOrigin 파라미터로 반환합니다.

Origin의미
TEEC_ORIGIN_API0x1TEE Client API 라이브러리 내부 오류
TEEC_ORIGIN_COMMS0x2커널 드라이버/SMC 통신 오류
TEEC_ORIGIN_TEE0x3OP-TEE OS 내부 오류 (TA 관리자 등)
TEEC_ORIGIN_TRUSTED_APP0x4TA 코드에서 반환한 오류

Device Tree 바인딩

OP-TEE 드라이버는 Device Tree를 통해 Secure World의 존재와 통신 방식을 확인합니다.

OP-TEE Device Tree 노드 구조 / (루트) firmware { } optee { compatible = "linaro,optee-tz"; method = "smc"; /* 또는 "hvc" */ }; reserved-memory { } optee_shm: optee-shmem { reg = <0x0 0x10000000 0x0 0x200000>; no-map; }; optee_core: optee-core { reg = <0x0 0x0E100000 0x0 0x1F00000>; no-map; }; psci { compatible = "arm,psci-1.0"; method = "smc"; };
OP-TEE DT 노드는 firmware/ 아래에 위치하며, reserved-memory로 Secure 메모리 영역과 SHM 영역을 선언합니다

Device Tree 예시

/* OP-TEE Device Tree 바인딩 */
/ {
    /* Secure 메모리 예약 */
    reserved-memory {
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;

        /* OP-TEE OS 코어 메모리 (Secure, no-map) */
        optee_core: optee-core@0e100000 {
            reg = <0x0 0x0e100000 0x0 0x01f00000>;
            no-map;
        };

        /* Static 공유 메모리 (Dynamic SHM 미사용 시) */
        optee_shm: optee-shmem@10000000 {
            compatible = "restricted-dma-pool";
            reg = <0x0 0x10000000 0x0 0x00200000>;
            no-map;
        };
    };

    /* OP-TEE 펌웨어 노드 */
    firmware {
        optee {
            compatible = "linaro,optee-tz";
            method = "smc";   /* "smc" 또는 "hvc" */
        };
    };

    /* PSCI (TF-A 전원 관리) */
    psci {
        compatible = "arm,psci-1.0";
        method = "smc";
    };
};

DT 바인딩 속성 상세

속성필수설명
compatible필수"linaro,optee-tz"OP-TEE 드라이버 매칭
method필수"smc" 또는 "hvc"Secure World 진입 방식
reg (reserved-memory)Static SHM 시물리 주소 + 크기공유 메모리 영역
no-map권장(flag)커널 선형 매핑에서 제외
💡

Dynamic SHM에서는 optee_shm reserved-memory 노드가 불필요합니다. OP-TEE 3.1+에서 Dynamic SHM이 기본이며, 커널이 일반 페이지를 할당하여 OP-TEE에 등록합니다. Device Tree 관련 상세 내용은 Device Tree 문서를 참고하세요.

SoC별 DT 예시

/* NXP i.MX8MM — OP-TEE DT 바인딩 */
/ {
    firmware {
        optee: optee {
            compatible = "linaro,optee-tz";
            method = "smc";
        };
    };

    reserved-memory {
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;

        /* i.MX8MM: OP-TEE 메모리 (Secure DDR) */
        optee@0x56000000 {
            reg = <0 0x56000000 0 0x02000000>;
            no-map;
        };
    };
};

/* STM32MP157 — OP-TEE DT 바인딩 */
/ {
    firmware {
        optee {
            compatible = "linaro,optee-tz";
            method = "smc";
        };
    };

    reserved-memory {
        /* STM32MP1: 보안 메모리는 TZC-400으로 보호 */
        optee@de000000 {
            reg = <0xde000000 0x02000000>;
            no-map;
        };
    };
};

커널 DT 매칭 코드

/* drivers/tee/optee/core.c */
static const struct of_device_id optee_dt_match[] = {
    { .compatible = "linaro,optee-tz" },
    {},
};
MODULE_DEVICE_TABLE(of, optee_dt_match);

static struct platform_driver optee_driver = {
    .probe  = optee_probe,
    .remove = optee_remove,
    .driver = {
        .name = "optee",
        .of_match_table = optee_dt_match,
    },
};

외부 참고 자료