TrustZone Kinibi の動作概要紹介

2024年2月20日

本記事では、TEE (Trusted Execution Environment) の基礎知識については触れませんが、「TEE」「TrustZone TEE」などの単語で検索して事前学習いただくと記事内容を理解しやすいと思います。

TEE (Trusted Execution Environment) とは、SoC 的に隔離された環境で安全にプログラム (TA: Trusted Application) を実行できる機能です。 応用例としては、秘密計算のオフローディング、暗復号の鍵管理、セキュアドライバ等が挙げられます。
現時点で TEE を実現できる HW 機能は以下の三種類があります。

  1. Intel SGX
    一部の Intel CPU で利用できる機能で、一つの TA が原則として一つの Enclave を起動します。複数の TA を起動した場合、それぞれ個別の Enclave を利用します。
    ほとんどの機能が Intel 提供の HW と SDK として固定されています。
  2. ARM TrustZone
    多くの ARM CPU (主に Cortex-A シリーズ) で利用できる機能で、SoC 全体で一つの Secure World を起動します。複数の TA を起動した場合、全てのプログラムが単一の Secure World で動作します。
    ベースとなる HW 機能のみが ARM から提供され、実際の TrustZone 制御はユーザ依存です。
  3. RISC-V PMP
    RISC-V CPU で利用できる機能です。
    ベースとなる HW 機能のみが RISC-V ISA として規定されており、Keystone という OSS で制御可能です。Keystone は SGX と同じく Enclave を利用する方式です。

ARM TrustZone 制御の実装は各社から提供されており、いくつか例を挙げると、

  1. OP-TEE
    1. 提供元:TrustedFirmware.org
    2. 提供形態:オープンソース
    3. 動作環境:Cortex-A コアを持つ SoC 中心 (Raspberry Pi や Xilinx FPGA もアリ) 一覧
  2. Trusty
    1. 提供元:Google (Android Open Source Project)
    2. 提供形態:オープンソース
    3. サポート環境:arm64 ボード (詳細は異なるが、x86 プロセッサでも動作可能)
  3. QSEE/QTEE
    1. 提供元:Qualcomm
    2. 提供形態:クローズドソース
    3. サポート環境:Qualcomm ボード
  4. Kinibi
    1. 提供元:Trustonic
    2. 提供形態:クローズドソース
    3. サポート環境:Cortex-A ボード、Cortex-M ボード
などがあります。 本記事では、この内 Trustonic 社の Kinibi にフォーカスします。

Kinibi 概要

Kinibi は Trustonic 社が提供する TrustZone 制御の実装です。 以下のような特徴を持ち、PKCS#11、EVITA HSM、AutoSAR crypto API の代替手段として用いることが可能です。

  1. TA のスケジューリング、I/O 管理、メモリ管理等の基本的な機能
  2. 各種暗復号・ハッシュ等の TA 内実行機能
  3. TA 開発用 SDK
  4. QEMU エミュレーションのサポート
  5. EAL5+、ISO27001、FIPS140-2 等の認証 (https://www.trustonic.com/certifications/)
今回は、この Kinibi の起動から TA の実行までを紹介します。

Kinibi ブートフロー

Kinibi の起動は、SecureBoot フローに沿って行われます。 SecureBoot は、BootLoader が次に実行する BootLoader の安全性を Signature を用いて確認してから起動するものです。 Kinibi のプログラム自体が改変されていないことを SecureBoot で保証します。 ARM Cortex-A のブートフローは BL1、BL2、BL3 (BL31、BL32、BL33) の3段階に分かれています。

  1. BL1 は最小限の起動コードで、ROM から起動し BL2 の検証を行った後に起動します。
  2. BL2 では SoC ベンダが提供する FW を使用して SoC 初期化を行います。 SoC 初期化の中で、HW 実装の TrustZone Protection Controller (TZPC) を使用し、Secure World と Normal World のアドレス空間の分離を行います。
  3. その後、BL2 は BL31、BL32、BL33 の検証・起動を行います。
    1. BL31 は ARM EL3 で動作するファームウェアで、Kinibi の Secure Monitor を含みます。
    2. BL32 は ARM EL1 の Secure World で動作する Trusted OS で、Kinibi TA を含みます。
    3. BL33 は ARM EL1 の Normal World で動作する通常の OS (Linux, etc.) です。

Kinibi SW/HW スタック

Kinibi SW/HWスタック

Kinibi のプログラムは SWd (Secure World) の TA (Trusted Application) と、NWd (Normal World) の CA (Client Application) に分かれています。 CA は TA に対して、Secure Monitor Call (SMC) 命令を発行して TA の処理を呼び出します。 SMC は EL1 (Kernel) を介して発行され、EL3 (Secure Monitor) で処理されます。 World 切替 (SWd NWd) は必ず EL3 を経由し、EL1 (NWd) で動作している CPU が直接 EL1 (SWd) に遷移する、といったことはありません。 また、データは NWd Memory (Normal Memory) に確保された Shared Memory (図中の Buffer#1 …) を介してやり取りされます。 (基本的に引数に対して一つの Buffer を使用) CA が TA を呼び出す際のコマンド及び引数は NWd Memory に格納されており、これを SWd の TA が参照します。 TA のデータは SWd Memory (Secure Memory) に格納され、必要に応じて Shared Memory にコピーされて CA に返却されます。

Kinibiの起動から終了まで

SWd の TA を実行するにあたって、NWd の CA を起点として、次のフローでコマンドが実行されます。

以下で使用している API 一覧

機能 API シグネチャ 概要
初期化 TEEC_InitializeContext TEEC_Result TEEC_InitializeContext(const char* name, TEEC_Context* context) TEE 実行に必要なコンテキストを取得(初期化)します
この API 終了時点では、まだ TA は起動していません
セッション開始 TEEC_OpenSession TEEC_Result TEEC_OpenSession (TEEC_Context* context, TEEC_Session* session, const TEEC_UUID* destination, uint32_t connectionMethod, const void* connectionData, TEEC_Operation* operation, uint32_t* returnOrigin) TA を起動・初期化して、呼び出し元の CA と紐づけます。以降、起動した TA はセッション TEEC_Session を指定することで呼び出せます
メモリ領域確保 TEEC_AllocateSharedMemory TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context* context, TEEC_SharedMemory* sharedMem) Swd/Nwd のデータ授受に用いるバッファを確保し、コンテキストに紐づけます
コマンド実行 TEEC_InvokeCommand void TEEC_CloseSession (TEEC_Session* session) TEEC_Session で指定された TA の処理を呼び出します。引数は必要に応じて TEEC_Session に紐づけておきます
メモリ領域解放 TEEC_ReleaseSharedMemory void TEEC_ReleaseSharedMemory (TEEC_SharedMemory* sharedMem) TEEC_AllocateSharedMemory で確保したバッファを解放します
セッション終了 TEEC_CloseSession void TEEC_CloseSession (TEEC_Session* session) TEEC_OpenSession で取得したセッションを終了し、TA をアンロードします
終了 TEEC_FinalizeContext void TEEC_FinalizeContext(TEEC_Context* context) TEEC_InitializeContext で取得されていたコンテキストを終了し、破棄処理を行います

1. 初期化

使用API:TEEC_InitializeContext

TA を開始する前に、TEE 実行環境を確認して実行コンテキスト TEEC_Context を初期化します。 具体的には、実行可能な TEE の種類、ドライバのバージョンなどを確認します。 バージョンを確認する理由は、想定より古いバージョンにはバグが残っている可能性があるためです。

2. セッション開始

使用API:TEEC_OpenSession

TA をロードして、TA を論理コンテナ TEEC_Session に紐づけます。 本処理の中で、TA は Secure Memory にロードされて初期化されます。 以降、起動した TA は TEEC_Session で指定します。

3. メモリ領域確保

使用API:TEEC_AllocateSharedMemory

CA と TA は、プロセス間通信と同じくスタックやヒープを共有していないため、データ授受を Normal Memory を介して行います。 基本的に、呼び出しの際に使用する引数一つに対して一つ確保します。 確保されたバッファは TEEC_Context に紐づけられます。

4. コマンド実行

使用API:TEEC_InvokeCommand

CA から TA の処理を呼び出すには、TEEC_InvokeCommand API を使用します。 引数を TEEC_AllocateSharedMemory で確保した領域に格納した後、TA 処理の ID を指定して呼び出します。 この ID は、呼び出す処理 (≒実行する TA 内関数) を指定するもので、TA 内で一意であるべきですが、値は CA/TA で共有されていれば大きな制限は問題ありません。 CA → TA の実行遷移は、SMC 命令によって実現されます。 TA は指定された処理が終わると ERET 命令で CA に処理を戻します。 SMC は同期例外のため、一度 TA に処理が移ると、TA の処理が終わるまで CA に処理が戻ることはありません。

5. メモリ領域解放

使用API:TEEC_ReleaseSharedMemory

TEEC_AllocateSharedMemory で確保した領域は、使用後に TEEC_ReleaseSharedMemory で解放します。

6. セッション終了

使用API:TEEC_CloseSession

TEEC_OpenSession で開始した TEEC_Session を破棄します。 本処理の中で、TEEC_Session に紐づけられた TA は終了処理が実行され、アンロードされます。

7. 終了

使用API:TEEC_FinalizeContext

TEEC_InitializeContext で生成した実行コンテキスト TEEC_Context を終了し、破棄します。

まとめ

以上、Kinibi 動作フローの概要でした。 多少の差異はあれど、他の TrustZone 制御 (OP-TEE …) も大枠は同じようなフローで動作します。 実際に利用する際は、複数回の例外レベル切替 (≒コンテキストスイッチ) を挟むため、セキュリティ強度と実行オーバヘッドのバランスが重要になります。

About Author

OmoriYu

Leave a Comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

Recent Comments

Social Media