Tüm eğitimler
TEKNİK REHBER GÖMÜLÜ LİNUX GÜVENLİK 2026

OP-TEE
ARM TrustZone Güvenli Dünya

Trusted Applications yazma, TEE Client API kullanma, güvenli depolama ve kriptografi — GlobalPlatform TEE standardı ile uçtan uca rehber.

00 TrustZone mimarisi

ARM TrustZone, tek bir SoC üzerinde iki tamamen ayrı çalışma ortamı oluşturur: Secure World ve Normal World. Donanım, bellek ve IO kaynaklarını bu iki dünya arasında yalıtır.

İki dünyanın yapısı

┌───────────────────────┐   ┌───────────────────────┐
│    NORMAL WORLD        │   │     SECURE WORLD       │
│                       │   │                        │
│  Linux Kernel (EL1)   │   │  OP-TEE OS (S-EL1)     │
│  User apps (EL0)      │   │  Trusted Apps (S-EL0)  │
│  KVM/Xen (EL2)        │   │                        │
└──────────┬────────────┘   └────────────┬───────────┘
           │   SMC                        │   SMC
           └──────────┬───────────────────┘
                      ▼
              Secure Monitor — EL3
              (TF-A BL31 — daima çalışır)
              NS bit: SCR_EL3.NS
                      │
              ┌───────▼────────┐
              │   SoC Hardware  │
              │  TZC-400 DRAM  │
              │  GIC (FIQ yön.) │
              │  Secure SRAM    │
              └────────────────┘

Secure/Non-Secure ayrımı

KaynakNormal WorldSecure World
DRAM bölgesiNS DRAM (Linux heap, stack)Secure DRAM (OP-TEE heap, TA stack)
SRAMErişim yokSecure SRAM — hızlı erişim
PeriferlerUART, USB, Ethernet vb.Güvenli UART, OTP, crypto HW
KesmelerIRQ (GIC NS interrupt)FIQ (GIC Secure interrupt)
CacheNS cache satırlarıSecure cache satırları (TrustZone cache)

Monitor modu ve geçiş

Normal World bir TEE servisi istediğinde smc #0 komutu çalıştırır. EL3'teki Secure Monitor (TF-A BL31) çağrıyı alır, NS bit'i sıfırlar ve S-EL1'deki OP-TEE'ye geçiş yapar. OP-TEE işi bitirdiğinde tekrar EL3 üzerinden Normal World'e dönülür.

/* Normal World çağrısı — libteec içindeki SMC wrapper */
static uint32_t smc(uint32_t func_id, uint32_t a1, uint32_t a2,
                    uint32_t a3, uint32_t a4, uint32_t a5,
                    uint32_t a6, struct smc_param *param)
{
    /* x0 = func_id (OPTEE_SMC_CALL_WITH_RPC_ARG)
       x1-x6 = argümanlar
       Sonuç x0-x3'te dönüyor */
    asm volatile(
        "mov x0, %[fid]\n"
        "mov x1, %[a1]\n"
        "mov x2, %[a2]\n"
        "smc #0\n"
        "str x0, %[ret0]\n"
        : [ret0] "=m" (param->a0)
        : [fid] "r" (func_id), [a1] "r" (a1), [a2] "r" (a2)
        : "x0", "x1", "x2", "memory"
    );
    return param->a0;
}

01 OP-TEE OS yapısı

OP-TEE, GlobalPlatform TEE Core API standardını implement eden açık kaynaklı bir Trusted Operating System'dir; Linaro tarafından geliştirilen proje TF-A ile entegre çalışır.

Kaynak ağacı

optee_os/
├── core/
│   ├── arch/arm/         # ARM-spesifik: entry, exception vektörleri, MMU
│   │   ├── sm/           # Secure Monitor interface (EL3 ↔ S-EL1)
│   │   ├── plat-*/       # Platform portları (stm32mp1, vexpress, rpi3 vb.)
│   │   └── tee/          # TEE çekirdek servisleri
│   ├── drivers/          # Crypto HW, UART, RNG, RPMB sürücüleri
│   ├── kernel/           # Thread scheduler, mutex, IPC
│   ├── mm/               # Güvenli bellek yönetimi, mobj
│   └── tee/              # GP TEE Core API impl: crypto, storage, time
├── lib/
│   ├── libutee/          # TA tarafı API (Trusted Applications bağlanır)
│   └── libutils/         # String, math yardımcıları
├── ta/                   # Yerleşik TA'lar: pkcs11, device_id, gprof
└── mk/                   # Derleme sistemi Makefile'ları

Thread modeli

OP-TEE, Normal World'den gelen her SMC çağrısı için bir S-EL1 thread tahsis eder. Thread sayısı CFG_NUM_THREADS ile sınırlandırılır; genellikle çekirdek sayısına eşittir. Her TA çağrısı ayrı thread bağlamında çalışır.

CFG_NUM_THREADSParalel TEE thread sayısı — genellikle SoC çekirdek sayısı (4)
CFG_TA_STACK_SIZEHer TA thread stack boyutu — varsayılan 8 KB, RAM kısıtlıysa azalt
CFG_CORE_HEAP_SIZEOP-TEE çekirdek heap — TA yükleme, kriptografi işlemleri için
CFG_RPMB_FSeMMC RPMB üzerinde güvenli depolama — tamper-evident
CFG_TEE_CORE_LOG_LEVEL0=kapalı, 1=hata, 2=info, 3=debug, 4=flow — build-time sabit

OP-TEE supplicant

Normal World'de çalışan tee-supplicant daemon'u, Trusted OS'un dosya sistemi, RPC ve RPMB erişimlerini karşılar. OP-TEE'nin disk dosyalarına erişmesi için gereklidir; sistem açılışında otomatik başlamalıdır.

# systemd servisi
# /lib/systemd/system/tee-supplicant.service
[Unit]
Description=TEE Supplicant Daemon
After=local-fs.target

[Service]
ExecStart=/usr/sbin/tee-supplicant
Restart=on-failure
RestartSec=1

[Install]
WantedBy=multi-user.target

02 Trusted Application anatomisi

Trusted Application (TA), Secure World'de S-EL0 seviyesinde çalışan, GlobalPlatform TEE Internal Core API'yi kullanan paylaşımlı kütüphane biçiminde ELF dosyasıdır.

TA giriş noktaları

Her TA beş zorunlu giriş noktası (entry point) implement etmek zorundadır. OP-TEE bu fonksiyonları TA yaşam döngüsü boyunca çağırır.

/* ta/hello_world/hello_world_ta.c */
#include <tee_internal_api.h>
#include <tee_internal_api_extensions.h>
#include "hello_world_ta.h"

/* TA ilk yüklendiğinde — instance oluştur */
TEE_Result TA_CreateEntryPoint(void)
{
    DMSG("TA_CreateEntryPoint cagrildi");
    /* Global kaynakları tahsis et */
    return TEE_SUCCESS;
}

/* TA kaldırılmadan önce */
void TA_DestroyEntryPoint(void)
{
    DMSG("TA_DestroyEntryPoint cagrildi");
    /* Global kaynakları serbest bırak */
}

/* Normal World bir session açtığında */
TEE_Result TA_OpenSessionEntryPoint(uint32_t param_types,
                                     TEE_Param params[4],
                                     void **sess_ctx)
{
    uint32_t exp_param_types = TEE_PARAM_TYPES(
        TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE,
        TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE);
    if (param_types != exp_param_types)
        return TEE_ERROR_BAD_PARAMETERS;

    /* Session'a özel bağlam tahsis et */
    struct session_ctx *ctx = TEE_Malloc(sizeof(*ctx), 0);
    if (!ctx) return TEE_ERROR_OUT_OF_MEMORY;
    *sess_ctx = ctx;
    return TEE_SUCCESS;
}

/* Session kapatılırken */
void TA_CloseSessionEntryPoint(void *sess_ctx)
{
    struct session_ctx *ctx = sess_ctx;
    TEE_Free(ctx);
}

/* Normal World komut çağırdığında — ana iş burada */
TEE_Result TA_InvokeCommandEntryPoint(void *sess_ctx,
                                       uint32_t cmd_id,
                                       uint32_t param_types,
                                       TEE_Param params[4])
{
    switch (cmd_id) {
    case TA_HELLO_WORLD_CMD_INC_VALUE:
        return inc_value(param_types, params);
    case TA_HELLO_WORLD_CMD_DEC_VALUE:
        return dec_value(param_types, params);
    default:
        EMSG("Bilinmeyen komut: 0x%x", cmd_id);
        return TEE_ERROR_NOT_SUPPORTED;
    }
}

TA UUID ve manifest

/* ta/hello_world/Android.mk veya Makefile içindeki UUID */
/* Her TA eşsiz bir UUID ile tanımlanır */

/* hello_world_ta.h */
#define TA_HELLO_WORLD_UUID \
    { 0x8aaaf200, 0x2450, 0x11e4, \
      { 0xab, 0xe2, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }

#define TA_HELLO_WORLD_CMD_INC_VALUE   0
#define TA_HELLO_WORLD_CMD_DEC_VALUE   1
/* user_ta_header_defines.h — TA özellikleri */
#define TA_UUID     TA_HELLO_WORLD_UUID
#define TA_FLAGS    (TA_FLAG_EXEC_DDR | TA_FLAG_SINGLE_INSTANCE)
#define TA_STACK_SIZE       (4 * 1024)    /* 4 KB */
#define TA_DATA_SIZE        (32 * 1024)   /* 32 KB heap */
#define TA_VERSION          "1.0"
#define TA_DESCRIPTION      "Hello World Ornek TA"

TA imzalama

Production ortamında TA'lar, OP-TEE'nin güvendiği bir anahtar çiftiyle imzalanmalıdır. Development modunda test anahtar çifti kullanılır; CFG_TA_KEY_SETUP değişkeniyle kontrol edilir.

# TA imzalama scripti (scripts/sign_encrypt.py)
python3 scripts/sign_encrypt.py \
    --uuid 8aaaf200-2450-11e4-abe2-0002a5d5c51b \
    --key keys/default_ta.pem \
    --in hello_world.stripped.elf \
    --out 8aaaf200-2450-11e4-abe2-0002a5d5c51b.ta

# İmzalanan .ta dosyası rootfs'e kopyalanır:
# /lib/optee_armtz/8aaaf200-2450-11e4-abe2-0002a5d5c51b.ta

03 TEE Client API — Normal World tarafı

libteec, Normal World uygulamalarının OP-TEE ile iletişim kurması için GlobalPlatform TEE Client API standardını implement eder; /dev/tee0 üzerinden çalışır.

Bağlantı akışı

Normal World uygulama
    │
    │ TEEC_InitializeContext()
    ▼
TEE Context  ──── /dev/tee0 ────>  OP-TEE driver (kernel)
    │                                    │
    │ TEEC_OpenSession()                 │ SMC
    ▼                                    ▼
TEE Session  <──────────────────>  OP-TEE OS (S-EL1)
    │                                    │
    │ TEEC_InvokeCommand()               │ TA_InvokeCommandEntryPoint()
    ▼                                    ▼
Sonuç & çıktı parametreler <──── TA işlem sonucu

Tam bir istemci örneği

/* host/main.c — Normal World istemci uygulaması */
#include <tee_client_api.h>
#include "hello_world_ta.h"

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

    /* 1. TEE bağlamını başlat — /dev/tee0 aç */
    res = TEEC_InitializeContext(NULL, &ctx);
    if (res != TEEC_SUCCESS) {
        fprintf(stderr, "TEEC_InitializeContext hata: 0x%x\n", res);
        return 1;
    }

    /* 2. TA ile oturum aç */
    res = TEEC_OpenSession(&ctx, &sess, &uuid,
                           TEEC_LOGIN_PUBLIC, NULL, NULL,
                           &err_origin);
    if (res != TEEC_SUCCESS) {
        fprintf(stderr, "TEEC_OpenSession hata: 0x%x (origin: 0x%x)\n",
                res, err_origin);
        TEEC_FinalizeContext(&ctx);
        return 1;
    }

    /* 3. Komut hazırla: VALUE_INOUT parametresi ile değer gönder */
    memset(&op, 0, sizeof(op));
    op.paramTypes = TEEC_PARAM_TYPES(
        TEEC_VALUE_INOUT,        /* params[0]: değer gönder/al */
        TEEC_NONE,
        TEEC_NONE,
        TEEC_NONE);
    op.params[0].value.a = 42;  /* giriş değeri */

    printf("TA'ya 42 gonderiyorum, artirmasini istiyorum...\n");
    res = TEEC_InvokeCommand(&sess,
                             TA_HELLO_WORLD_CMD_INC_VALUE,
                             &op, &err_origin);
    if (res != TEEC_SUCCESS) {
        fprintf(stderr, "InvokeCommand hata: 0x%x\n", res);
    } else {
        printf("TA sonucu: %d\n", op.params[0].value.a);  /* 43 */
    }

    /* 4. Temizle */
    TEEC_CloseSession(&sess);
    TEEC_FinalizeContext(&ctx);
    return (res == TEEC_SUCCESS) ? 0 : 1;
}

Hata kodları

KodDeğerAçıklama
TEEC_SUCCESS0x00000000Başarılı
TEE_ERROR_BAD_PARAMETERS0xFFFF0006Geçersiz parametre tipi ya da değeri
TEE_ERROR_ACCESS_DENIED0xFFFF0001İzin yok — TA imza hatası
TEE_ERROR_OUT_OF_MEMORY0xFFFF000CSecure heap tükendi
TEE_ERROR_ITEM_NOT_FOUND0xFFFF0008Secure storage'da nesne yok
TEE_ERROR_COMMUNICATION0xFFFF000EOP-TEE supplicant bağlantı hatası
TEE_ERROR_NOT_SUPPORTED0xFFFF000ABilinmeyen komut ID'si

04 Shared memory ve parametre tipleri

Normal World ile Secure World arasında büyük veri transferi için shared memory kullanılır; TEE Client API dört parametre tipini destekler.

Parametre tipleri

TEEC_VALUE_INPUT32-bit (a, b) çifti — sadece girdi; küçük skalar değerler için ideal
TEEC_VALUE_OUTPUT32-bit (a, b) çifti — sadece çıktı; TA'nın yazıp CA'nın okuduğu değerler
TEEC_VALUE_INOUT32-bit çift — hem girdi hem çıktı
TEEC_MEMREF_TEMP_INPUTGeçici buffer — sadece TA'ya gidiyor; OP-TEE otomatik kopyalar
TEEC_MEMREF_TEMP_OUTPUTGeçici buffer — sadece TA'dan dönüyor
TEEC_MEMREF_TEMP_INOUTGeçici buffer — çift yön; kriptografi şifreleme için tipik
TEEC_MEMREF_WHOLEKayıtlı shared memory bloğunun tamamı
TEEC_MEMREF_PARTIAL_*Kayıtlı shared memory'nin alt aralığı

Geçici buffer kullanımı (şifreleme örneği)

/* AES şifreleme: giriş düz metin → çıktı şifreli metin */
TEEC_Operation op;
uint8_t plaintext[64]  = "Gizli mesaj 12345678901234567890123456";
uint8_t ciphertext[64] = {0};

memset(&op, 0, sizeof(op));
op.paramTypes = TEEC_PARAM_TYPES(
    TEEC_MEMREF_TEMP_INPUT,    /* params[0]: düz metin */
    TEEC_MEMREF_TEMP_OUTPUT,   /* params[1]: şifreli metin */
    TEEC_VALUE_INPUT,          /* params[2]: anahtar handle */
    TEEC_NONE);

op.params[0].tmpref.buffer = plaintext;
op.params[0].tmpref.size   = sizeof(plaintext);
op.params[1].tmpref.buffer = ciphertext;
op.params[1].tmpref.size   = sizeof(ciphertext);
op.params[2].value.a       = key_handle_id;

res = TEEC_InvokeCommand(&sess, TA_CMD_AES_ENCRYPT, &op, &err_origin);
printf("Sifrelendi: %zu byte\n", op.params[1].tmpref.size);

Kayıtlı shared memory (büyük veri)

/* Büyük dosya transferi için shared memory kaydet */
TEEC_SharedMemory shm;

shm.size  = 1 * 1024 * 1024;  /* 1 MB */
shm.flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;

res = TEEC_AllocateSharedMemory(&ctx, &shm);
/* shm.buffer artık hem Normal hem Secure World görür */

/* Buffer'ı doldur */
memcpy(shm.buffer, large_data, shm.size);

/* MEMREF_WHOLE ile tüm bloğu geç */
op.params[0].memref.parent = &shm;
op.params[0].memref.offset = 0;
op.params[0].memref.size   = shm.size;
op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_WHOLE,
                                  TEEC_NONE, TEEC_NONE, TEEC_NONE);

TEEC_InvokeCommand(&sess, TA_CMD_PROCESS_BUFFER, &op, &err_origin);

/* Temizle */
TEEC_ReleaseSharedMemory(&shm);

05 Secure Storage — güvenli anahtar saklama

OP-TEE, kriptografik anahtarları ve hassas verileri kalıcı olarak depolamak için şifreli ve bütünlük korumalı Persistent Object API sunar.

Depolama arka uçları

TEE_STORAGE_PRIVATETA'ya özel depolama — TA UUID + Normal World kullanıcı kimliğiyle izole, /data/tee/ altında şifreli
TEE_STORAGE_USERBirden fazla TA'nın paylaşabildiği kullanıcı depolaması
RPMB (CFG_RPMB_FS=y)eMMC RPMB bölümü — donanım sayacı ile replay saldırısına karşı koruma

Nesne oluşturma ve yazma

/* TA içinde kalıcı nesne oluştur — AES-256 anahtar sakla */
#include <tee_internal_api.h>

TEE_Result store_aes_key(const uint8_t *key_data, size_t key_len)
{
    TEE_ObjectHandle obj = TEE_HANDLE_NULL;
    TEE_Result res;

    const char obj_id[]  = "device_aes_key_v1";
    size_t     obj_id_sz = sizeof(obj_id) - 1;

    /* Var olan nesneyi sil (idempotent) */
    TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
                             obj_id, obj_id_sz,
                             TEE_DATA_FLAG_ACCESS_WRITE_META,
                             &obj);
    if (obj != TEE_HANDLE_NULL) {
        TEE_CloseAndDeletePersistentObject1(obj);
        obj = TEE_HANDLE_NULL;
    }

    /* Yeni nesne oluştur */
    res = TEE_CreatePersistentObject(
        TEE_STORAGE_PRIVATE,
        obj_id, obj_id_sz,
        TEE_DATA_FLAG_ACCESS_WRITE |
        TEE_DATA_FLAG_ACCESS_READ  |
        TEE_DATA_FLAG_OVERWRITE,
        TEE_HANDLE_NULL,       /* attribute yok — ham veri */
        key_data, key_len,     /* başlangıç verisi */
        &obj);

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

Nesne okuma

TEE_Result read_aes_key(uint8_t *key_buf, size_t *key_len)
{
    TEE_ObjectHandle obj = TEE_HANDLE_NULL;
    TEE_ObjectInfo   info;
    TEE_Result       res;

    const char obj_id[]  = "device_aes_key_v1";

    res = TEE_OpenPersistentObject(
        TEE_STORAGE_PRIVATE,
        obj_id, sizeof(obj_id) - 1,
        TEE_DATA_FLAG_ACCESS_READ,
        &obj);
    if (res != TEE_SUCCESS) return res;

    /* Nesne boyutunu sorgula */
    TEE_GetObjectInfo1(obj, &info);
    if (*key_len < info.dataSize) {
        TEE_CloseObject(obj);
        *key_len = info.dataSize;
        return TEE_ERROR_SHORT_BUFFER;
    }

    uint32_t read_count;
    res = TEE_ReadObjectData(obj, key_buf, info.dataSize, &read_count);
    *key_len = read_count;

    TEE_CloseObject(obj);
    return res;
}

Anahtar nesne (TEE_Attribute) ile depolama

/* AES-256 key nesnesi oluştur ve kalıcı olarak sakla */
TEE_Result create_and_store_aes256(void)
{
    TEE_ObjectHandle transient = TEE_HANDLE_NULL;
    TEE_ObjectHandle persistent = TEE_HANDLE_NULL;
    TEE_Result res;

    /* Geçici AES-256 anahtar nesnesi oluştur */
    res = TEE_AllocateTransientObject(TEE_TYPE_AES, 256, &transient);
    if (res) return res;

    /* Rastgele anahtar üret */
    res = TEE_GenerateKey(transient, 256, NULL, 0);
    if (res) goto out;

    /* Kalıcı nesneye dönüştür */
    res = TEE_CreatePersistentObject(
        TEE_STORAGE_PRIVATE,
        "aes256_master_key", 18,
        TEE_DATA_FLAG_ACCESS_WRITE,
        transient,          /* attribute kaynağı */
        NULL, 0,            /* ek veri yok */
        &persistent);

out:
    if (transient)  TEE_FreeTransientObject(transient);
    if (persistent) TEE_CloseObject(persistent);
    return res;
}

06 Kriptografi API

OP-TEE, GlobalPlatform TEE Cryptographic API üzerinden AES, RSA, ECC, HMAC, SHA gibi algoritmaları hem yazılım hem donanım hızlandırıcıyla sunar.

Simetrik şifreleme — AES-CBC

/* TA içinde AES-128-CBC şifreleme */
TEE_Result aes_cbc_encrypt(TEE_ObjectHandle key_obj,
                            const uint8_t *iv, size_t iv_len,
                            const uint8_t *in, size_t in_len,
                            uint8_t *out, size_t *out_len)
{
    TEE_OperationHandle op = TEE_HANDLE_NULL;
    TEE_Result res;

    /* İşlem nesnesi oluştur */
    res = TEE_AllocateOperation(&op, TEE_ALG_AES_CBC_NOPAD,
                                TEE_MODE_ENCRYPT, 128);
    if (res) return res;

    /* Anahtarı işleme ata */
    res = TEE_SetOperationKey(op, key_obj);
    if (res) goto out;

    /* IV ile başlat */
    TEE_CipherInit(op, iv, iv_len);

    /* Şifrele */
    res = TEE_CipherDoFinal(op, in, in_len, out, out_len);

out:
    TEE_FreeOperation(op);
    return res;
}

Özet hesaplama — SHA-256

TEE_Result sha256_hash(const uint8_t *data, size_t data_len,
                        uint8_t *digest, size_t *digest_len)
{
    TEE_OperationHandle op = TEE_HANDLE_NULL;
    TEE_Result res;

    res = TEE_AllocateOperation(&op, TEE_ALG_SHA256,
                                TEE_MODE_DIGEST, 0);
    if (res) return res;

    /* Veriyi bloklara bölerek besleyebiliriz */
    TEE_DigestUpdate(op, data, data_len / 2);
    TEE_DigestUpdate(op, data + data_len / 2, data_len - data_len / 2);

    /* Sonuç üret */
    res = TEE_DigestDoFinal(op, NULL, 0, digest, digest_len);

    TEE_FreeOperation(op);
    return res;  /* *digest_len = 32 (SHA-256 = 256 bit) */
}

Asimetrik şifreleme — RSA-OAEP

/* RSA-2048 OAEP ile şifreleme (public key ile) */
TEE_Result rsa_oaep_encrypt(TEE_ObjectHandle pub_key,
                             const uint8_t *plain, size_t plain_len,
                             uint8_t *cipher, size_t *cipher_len)
{
    TEE_OperationHandle op = TEE_HANDLE_NULL;
    TEE_Result res;

    res = TEE_AllocateOperation(&op,
        TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA256,
        TEE_MODE_ENCRYPT, 2048);
    if (res) return res;

    res = TEE_SetOperationKey(op, pub_key);
    if (res) goto out;

    res = TEE_AsymmetricEncrypt(op, NULL, 0,
                                plain, plain_len,
                                cipher, cipher_len);
out:
    TEE_FreeOperation(op);
    return res;
}

/* ECC-P256 imzalama */
TEE_Result ecdsa_sign(TEE_ObjectHandle priv_key,
                       const uint8_t *hash, size_t hash_len,
                       uint8_t *sig, size_t *sig_len)
{
    TEE_OperationHandle op = TEE_HANDLE_NULL;
    TEE_Result res;

    res = TEE_AllocateOperation(&op,
        TEE_ALG_ECDSA_P256, TEE_MODE_SIGN, 256);
    if (res) return res;

    res = TEE_SetOperationKey(op, priv_key);
    if (res) goto out;

    res = TEE_AsymmetricSignDigest(op, NULL, 0,
                                   hash, hash_len,
                                   sig, sig_len);
out:
    TEE_FreeOperation(op);
    return res;
}

HMAC — mesaj doğrulama

TEE_Result hmac_sha256(TEE_ObjectHandle hmac_key,
                        const uint8_t *msg, size_t msg_len,
                        uint8_t *mac, size_t *mac_len)
{
    TEE_OperationHandle op = TEE_HANDLE_NULL;
    TEE_Result res;

    res = TEE_AllocateOperation(&op, TEE_ALG_HMAC_SHA256,
                                TEE_MODE_MAC, 256);
    if (res) return res;
    res = TEE_SetOperationKey(op, hmac_key);
    if (res) goto out;

    TEE_MACInit(op, NULL, 0);  /* IV yok */
    TEE_MACUpdate(op, msg, msg_len);
    res = TEE_MACComputeFinal(op, NULL, 0, mac, mac_len);

out:
    TEE_FreeOperation(op);
    return res;
}

Desteklenen algoritmalar

KategoriAlgoritmaTEE_ALG sabit
SimetrikAES-ECB/CBC/CTR/GCM/CCMTEE_ALG_AES_*
AsimetrikRSA-1024/2048/4096TEE_ALG_RSAES_* / TEE_ALG_RSASSA_*
ECCECDSA P-192/224/256/384/521TEE_ALG_ECDSA_P*
ECDHECDH P-192..521TEE_ALG_ECDH_P*
ÖzetSHA-1/224/256/384/512TEE_ALG_SHA*
MACHMAC-SHA*, AES-CMACTEE_ALG_HMAC_* / TEE_ALG_AES_CMAC
KDFHKDF, PBKDF2, Concat KDFTEE_ALG_HKDF_* (GP ext.)

07 PSA Certified ve attestation

OP-TEE, PSA Certified çerçevesindeki Initial Attestation Token (IAT) standardını destekler; cihazın güvenilir kimliğini uzak tarafa kriptografik olarak kanıtlar.

PSA Attestation mimarisi

Cihaz (OP-TEE + TF-A)              Uzak Doğrulayıcı
─────────────────────               ─────────────────
1. Client: psa_initial_attest_get_token()
   │
   ▼
OP-TEE Attestation TA
  - Cihaz boot ölçümleri (BL1,BL2,BL31 hash)
  - Platform instance ID (hardware unique key)
  - SW bileşen listesi
  - Nonce (challenge)
  → COSE_Sign1 [ EAT / IAT claim seti ]
    ↳ ECC-P256 ile imzalı (DAK — Device Attestation Key)
   │
   ▼ token (CBOR)
                                 2. Verifier:
                                   - CBOR ayrıştır
                                   - COSE imzasını doğrula (DAK cert chain)
                                   - Claim'leri politikayla karşılaştır
                                   - Güven kararı ver

PSA API kullanımı

/* psa/crypto.h ve psa/initial_attestation.h */
#include <psa/crypto.h>
#include <psa/initial_attestation.h>

int get_attestation_token(const uint8_t *nonce, size_t nonce_len,
                           uint8_t *token_buf, size_t token_buf_size,
                           size_t *token_len)
{
    psa_status_t status;

    /* PSA kriptografi alt sistemini başlat */
    status = psa_crypto_init();
    if (status != PSA_SUCCESS) return -1;

    /* Initial Attestation Token talep et */
    status = psa_initial_attest_get_token(
        nonce, nonce_len,          /* challenge — tekrar saldırısı önler */
        token_buf, token_buf_size,
        token_len);

    return (status == PSA_SUCCESS) ? 0 : -1;
}

IAT claim içeriği

Claim (CBOR tag)İçerikZorunlu
EAT_NONCE (10)Verifier'ın gönderdiği nonceEvet
EAT_INSTANCE_ID (256)UEID — cihaza özgü 33 byte IDEvet
EAT_BOOT_SEED (268)Boot sırasında üretilen 32 byte rastgele değerEvet
EAT_SW_COMPONENTS (2393)BL1/BL2/BL31/OP-TEE/Linux hash listesiEvet
EAT_IMPLEMENTATION_ID (265)Platform UUID — donanım kimliğiEvet
EAT_SECURITY_LIFECYCLE (267)PSA güvenlik yaşam döngüsü aşamasıEvet
EAT_CLIENT_ID (71)Çağıran NSPE/SPE bileşeni kimliğiHayır

08 Derleme, yükleme ve debug

OP-TEE ekosistemini derleme, hedef sisteme kurma, TA yükleme ve xtest ile doğrulama adımları.

Repo manifest ile tam build

# OP-TEE manifest ile tüm bileşenleri çek
mkdir optee-project && cd optee-project
repo init -u https://github.com/OP-TEE/manifest.git \
          -m qemu_v8.xml -b 3.21.0
repo sync -j4

# QEMU ARM v8 için derleme
cd build
make toolchains -j2
make PLATFORM=vexpress-qemu_armv8a -j$(nproc)

# Çıktılar:
# out-br/images/rootfs.cpio.gz       — Normal World rootfs
# out/bin/tee.bin                    — OP-TEE OS binary (BL32)
# out-br/images/u-boot.bin           — BL33

TA derleme (tek TA için)

# OP-TEE examples reposunu çek
git clone https://github.com/linaro-swg/optee_examples.git
cd optee_examples

# Cross-compile toolchain ortamı
export CROSS_COMPILE=aarch64-linux-gnu-
export CROSS_COMPILE_HOST=aarch64-linux-gnu-
export TA_DEV_KIT_DIR=/path/to/optee_os/export-ta_arm64
export TEEC_EXPORT=/path/to/optee_client/export-usr__aarch64

make -C hello_world

# Çıktılar:
# hello_world/ta/
#   8aaaf200-2450-11e4-abe2-0002a5d5c51b.ta  (imzalı TA)
# hello_world/host/
#   optee_example_hello_world                (CA binary)

Hedef sisteme kurma

# TA'yı rootfs'e kopyala
scp 8aaaf200-2450-11e4-abe2-0002a5d5c51b.ta \
    root@target:/lib/optee_armtz/

# CA'yı kopyala
scp optee_example_hello_world root@target:/usr/bin/

# Hedef sistem üzerinde çalıştır
ssh root@target
systemctl status tee-supplicant     # supplicant çalışıyor mu?
optee_example_hello_world           # TA'yı çağır

xtest — kapsamlı test süiti

# Tüm GP API testlerini çalıştır
xtest

# Belirli test grubunu çalıştır
xtest -t regression                 # Regresyon testleri
xtest 4001                          # Tek test senaryosu (crypto)
xtest -t pkcs11                     # PKCS#11 testleri
xtest --level 15                    # Uzun süreli dayanıklılık

# Tipik başarılı çıktı:
# +-----------------------------------------------------
# 26944 subtests of which 0 failed
# 104 test cases of which 0 failed
# 0 test cases were skipped
# TEE test application done!

TA debug — OP-TEE syslog

# OP-TEE log mesajları kernel syslog'a gider
dmesg | grep optee
journalctl -u tee-supplicant -f

# TA içinde debug mesajları için (TA kaynak kodu):
DMSG("Deger: %d, ptr: %p", val, ptr);   /* debug build'de görünür */
IMSG("Bilgi mesaji");
EMSG("Hata: res=0x%x", res);

# Kernel OP-TEE driver debug
echo 8 > /proc/sys/kernel/printk      # Tüm seviyeleri etkinleştir
cat /sys/kernel/debug/optee/call_count
ls /sys/kernel/debug/optee/