Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

凖備你的環境

本次課程為了統一開發環境,我們會使用虛擬機運行 Ubuntu 作為測試環境,然後在虛擬機中執行 qemu 運行 OP-TEE 的系統。

使用凖備好的VM

1. 下載VM映像檔,並匯入virtualbox:

  • https://github.com/NTHU-SCOPELAB/cr-tee-lab/releases/latest
  • 使用者帳號: ubuntu
  • 使用者密碼: ubuntu
  • 下載所有zip檔之後解壓就可以得到一個ova檔,再進行匯入即可。
映像檔匯入VirtualBox教學(點我展開)

image image image image image

系統簡介

image

圖一:ARM v8 系統設計

在圖一展示的 ARM 系統中,橘底的方形標示出傳統系統的部分。隨著 non-secure OS(又稱 rich OS)的功能增強,漏洞也隨之增加。一旦rich OS(ROS)遭攻破,攻擊者便可操控所有分配給 ROS 記憶體與周邊設備,威脅所有程式的機密性與完整性。信任執行環境(TEE)為了解決此問題,確保系統安全,在系統中加入 TrustZone 的硬體進行隔離,並且為了避免攻擊面擴大,只有重視安全的服務會被分配到 Secure 的環境,其他的功能仍然是透過 ROS 完成。

image

圖二:OP-TEE 系統設計

OP-TEE 是個基於上述概念實作的專案。在這個環境下,應用開發將分為非安全的 client app(CA)和安全的 trusted app(TA)兩部分。 CA 可以使用 ROS 系統呼叫提供一般功能,另外,可以透過 TEE 客戶端 API 與 TEE 交互;TA 則會使用 TEE 內部 API,處理敏感數據與安全操作,如加密、認證等。

應用開發

image

圖三:TEE 交互

CA 和 TA 的通訊會依序使用圖三列出的 api,由 CA 主動呼叫,最終調用 TA 對應的函式。

  • TEEC_InitializaContext/TA_CreateEntryPoint:TOS 對 TA 進行驗證,然後動態將執行檔載入記憶體
  • TEEC_OpenSession/TA_OpenSessionEntryPoint:CA 和 TA 以 session 的形式建立溝通,此步驟進行登入、驗證
  • TEEC_InvokeCommand/TA_InvokeCommandEntryPoint:使用 TA 提供的各項功能,可能重複多次
    TEEC_Result TEEC_InvokeCommand(
            TEEC_Session*    session,
            uint32_t         commandID,
            TEEC_Operation*  operation,
            uint32_t*        returnOrigin)
    
    更進一步解釋,TA 會根據 commandID 判斷 CA 請求的服務,實際的參數則透過 operation 傳遞
  • 其他負責完成執行以後,清理的部分

傳遞參數

typedef union {
    TEEC_TempMemoryReference        tmpref;
    TEEC_RegisteredMemoryReference  memref;
    TEEC_Value                      value;
} TEEC_Parameter;

typedef struct {
    uint32_t            started;
    uint32_t            paramTypes;
    TEEC_Parameter      params[4];
    <Implementation-Defined Type> imp;
} TEEC_Operation;

總共可以傳遞四個參數,每個 TEEC_Parameter 參數可能代表 TEEC_TempMemoryReferenceTEEC_RegisteredMemoryReferenceTEEC_Value 的其中之一。

  • TEEC_RegisteredMemoryReference:使用 api 申請或註冊的記憶體,作業不會用到
  • TEEC_TempMemoryReference:不用 api 申請或註冊,CA 中的任意一塊記憶體
  • TEEC_Value:小的資料,例如 uint32_t

TEEC_Operation 中,另一個重要的成員就是 paramTypes,type 除了上面三種分類,另外還會依據輸入輸出分類,總共有以下九類

  • TEEC_RegisteredMemoryReference

    Parameter TypeField to use
    TEEC_MEMREF_WHOLE_INPUTmemref
    TEEC_MEMREF_PARTIAL_OUTPUTmemref
    TEEC_MEMREF_PARTIAL_INOUTmemref
  • TEEC_TempMemoryReference

    Parameter TypeField to use
    TEEC_MEMREF_TEMP_INPUTtmpref
    TEEC_MEMREF_TEMP_OUTPUTtmpref
    TEEC_MEMREF_TEMP_INOUTtmpref
  • TEEC_Value

    Parameter TypeField to use
    TEEC_VALUE_INPUTvalue
    TEEC_VALUE_OUTPUTvalue
    TEEC_VALUE_INOUTvalue

執行OP-TEE系統

課程提供的 OP-TEE 專案位於目錄 optee/,先建置需要的目標檔案

$ cd ~/optee/build
$ make toolchains -j$(nproc)
$ make -j$(nproc)
  • 可能會跑一段時間,經過測試4核心的CPU大約需要1小時左右。

專案建置完成後,可以啟動 qemu 運行 OP-TEE

# 在 ~/optee/build/
$ make run-only

如果要新增檔案到虛擬機的檔案系統,需要重新執行 buildroot 的建置再啟動 qemu,命令則要改成:

# 在 ~/optee/build/
$ make run

接著,輸入 make 的終端會進入 qemu 的 CLI,並且會生成兩個新的終端機,分別是安全世界(Secure World)和正常世界(Normal World)。qemu CLI 會輸出提示等待用戶反應,用戶輸入 c 後,其他的終端會開始輸出 OP-TEE 開機過程的日誌

(qemu) c

接著在正常世界的終端,可以輸入登入的使用者。完成登入後,就可以執行 OP-TEE 專案包含的測試和範例

# 測試
$ xtest
# 範例
$ optee_example_hello_world

作業說明

本次作業分為實作與簡答兩部分。繳交時,實作部分只需要截圖表示;回答問題時,需簡要說明答案思路。最後,將兩部分合併為一份 PDF,上傳至 eeclass。

檔名格式請按照: HW1_<學號>。e.g. HW1_113062595

實作

課程提供的 aes 專案位於目錄~/aes。aes 依賴於前面我們編譯完的 OP-TEE 專案,並且 aes/Makefile 需要設定 OP-TEE 的正確路徑,否則會無法編譯 aes 專案。 image

aes 專案的結構如下:

  • host/:CA 的目錄
    • Makefile:不能直接使用
    • main.c:CA 程式,需要同學修改
  • ta/:TA 的目錄
    • Makefile:不能直接使用
    • aes_ta.c:TA 程式,需要同學修改
    • ...
  • Makefile:生成或清除 aes 專案的目標檔案
  • ...

a. 實作目標

參考ta/include/aes_ta.h的檔案內容。e.g.
image

並完成host/main.c, ta/aes_ta.c中指定的TODO修改。

b. 測試

程式修改完以後,可以在 qemu 內執行測試。首先使用生成目標檔案

# 在aes專案目錄下
$ make

然後將檔案放到 buildroot 對應的路徑

# 在aes專案目錄下
$ make install

重新執行 buildroot 的建置再啟動 qemu

# 在 optee/build/
$ make run

在Normal World中登入之後,應該就會出現下列指令可以使用來測試我們修改完的 aes 專案:

$ optee_example_aes

簡答

  • 提供 $ optee_example_aes 的執行輸出的截圖。
  • 說明 aes 實作部分,修改的程式目的是什麼?以及如何依據 ta/include/aes_ta.h 內容進行修改?
  • 說明 aes CA 的程式流程,每個步驟是如何操作 TA?
  • 參考 api 文件,說明 aes TA 使用 key/operation handle 的時候,呼叫 api 的流程以及使用的參數。
  • OP-TEE 支援 Value parameter, Memory reference 中哪些形式的參數? TA_InvokeCommandEntryPoint 的 Value parameter 最多能傳入幾個 32-bit 的參數

其它資源

  • CA 和 TA 範例程式:位於 OP-TEE 專案 optee/optee_examples/
  • TEE Client API:DOC
  • TEE internal API:DOC

簡介

OP-TEE 文件:REE Filesystem TA

TEE 的系統其實需仰賴 TEE 和 REE 協作來運行,舉例來說,物件可以存放在 REE 檔案系統,但在需要信任的情況下,藉由簽名和加密的方式,保證物件的機密性和完整性,確保 TEE 獲取的資源都是可信任。

實際上,其中一種 TA ---- REE Filesystem TA(REE FS TA)就是將 TA 儲存在REE 檔案系統上。 TA 以 <UUID>.ta 名稱儲存在 REE 的磁碟上,例如 Linux 檔案系統,檔案內容包含 ELF 檔、簽名,並且可以選擇對其加密。這比將 TA 燒錄在 secure flash(如 RPMB 或 secure storage)要靈活許多,特別適合開發階段使用。

REE FS TA 格式

共分為以下三種格式:

  • Legacy TA:簽章、不加密。自 OP-TEE 3.7.0 起已不支援自動產生
    hash = H(<struct shdr> || <stripped ELF>)
    signature = RSA-Sign(hash)
    legacy_binary = <struct shdr> || <hash> || <signature> || <stripped ELF>
    
  • Bootstrap TA:簽章、不加密
    hash = H(<struct shdr> || <struct shdr_bootstrap_ta> || <stripped ELF>)
    signature = RSA-Sign(<hash>)
    bootstrap_binary = <struct shdr> || <hash> || <signature> ||
                       <struct shdr_bootstrap_ta> || <stripped ELF>
    
  • Encrypted TA:先進行簽章、加密,再做 MAC 驗證
    nonce = <unique random value>
    ciphertext, tag = AES_GCM(<stripped ELF>)
    hash = H(<struct shdr> || <struct shdr_bootstrap_ta> ||
             <struct shdr_encrypted_ta> || <nonce> || <tag> || <stripped ELF>)
    signature = RSA-Sign(<hash>)
    encrypted_binary = <struct shdr> || <hash> || <signature> ||
                       <struct shdr_bootstrap_ta> ||
                       <struct shdr_encrypted_ta> || <nonce> || <tag> ||
                       <ciphertext>
    

Subkey驗證及載入流程

Subkey 驗證

OP-TEE 支援使用 subkey(子金鑰)或 subkey 鏈(chain of subkeys) 來驗證 TA,這使得可以在不洩漏 root key 的情況下,將簽章權限授予第三方,支援多方獨立簽署 TA。另外,因為子金鑰簽署的 TA 必須位於該子金鑰的 UUID-V5 命名空間,這種方式還能防止 TA UUID 混淆,避免 UUID 衝突。

REE FS TA 載入流程

以下為從 REE 載入 REE FS TA 的流程:

  1. REE 世界的 Client App 請求啟動 TA
  2. TEE Core 收到請求後,透過 RPC 要求 tee-supplicant 幫忙讀取 TA
  3. supplicant 根據 UUID 在 /lib/optee_armtz/ 中找對應的 .ta 檔案
  4. supplicant 將整個 .ta 檔案讀入 shared memory,並傳給 TEE Core
  5. TEE Core 對 TA 映像進行簽章驗證
  6. 驗證通過後,TA 被載入並初始化執行

TA簽署流程

OP-TEE 文件:Signing of TAs

所有 REE FS TA 都必須簽章。OP-TEE 的原始碼中,預設包含一把私鑰用於對 TA 簽名,對應的公鑰則會被編進 optee_os 的二進位中。每次載入 TA 時,核心都會用這把公鑰驗證該 TA 的簽章是否合法。

原始碼中預設的私鑰僅適用於開發與測試,產品環境的部署應更換為私人的金鑰

簽署相關元件介紹

在 optee_os 下有底下元件

  • keys/default_ta.pem:預設私鑰
  • scripts/sign_encrypt.py:用來簽署的腳本。使用說明可以查看
$ sign_encrypt.py -h
$ sign_encrypt.py <command> -h
  • ta/mk/ta_dev_kit.mk:cross compile 的 makefile,用來編譯執行在 optee_os 上 TA,會生成 TA 的 .stripped.elf.ta 檔。

ta_dev_kit.mk 雖然會生成 .ta,但是簽署的私鑰是採用 default_ta.pem,產品環境需要改以私人金鑰對 .stripped.elf 簽署

簽署操作流程

0. 在安全環境中產生 RSA 金鑰(2048 或 4096 bit)並匯出公鑰

$ openssl genrsa -out <privkey>.pem 2048
$ openssl rsa -in <privkey>.pem -pubout -out <pubkey>.pem

1. 編譯 OP-TEE OS 並指定公鑰。沒設定 TA_PUBLIC_KEY 的情況會自動生成和使用 default_ta.pem 對應的公鑰

$ TA_PUBLIC_KEY=<pubkey>.pem make all

2. 編譯、生成 TA 的 .stripped.elf

3. 設置 UUID 與金鑰變數

$ export TA_SIGN_KEY=<privkey>.pem
$ export TA_PUBLIC_KEY=<pubkey>.pem
$ export UUID=<uuid>

4. 產生 digest

$ sign_encrypt.py digest --key $TA_PUBLIC_KEY --uuid $UUID \
    --in $UUID.stripped.elf --dig $UUID.dig

5. 離線簽署 digest

$ base64 --decode $UUID.dig | \
    openssl pkeyutl -sign -inkey $TA_SIGN_KEY \
    -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss \
    -pkeyopt rsa_pss_saltlen:digest -pkeyopt rsa_mgf1_md:sha256 | \
    base64 > $UUID.sig

6. 合併 TA 與簽章

$ sign_encrypt.py stitch --key $TA_PUBLIC_KEY --uuid $UUID \
    --in $UUID.stripped.elf --sig $UUID.sig --out $UUID.ta

作業說明

本次作業分為實作與簡答兩部分。繳交時,實作部分只需要截圖表示;回答問題時,需簡要說明答案思路。最後,將兩部分合併為一份 PDF,上傳至 eeclass。

檔名格式請按照: HW2_<學號>。e.g. HW2_113062595

實作

aes 專案的結構如下:

  • host/:CA 的目錄
    • ...
  • ta/:TA 的目錄
    • include/
      • aes_ta.h:修改 TA_AES_UUID
    • Makefile:修改 BINARY
    • ...
  • ...

使用下方的 UUID 修改 LAB 1 的 aes 專案

aed564f1-960e-4117-8bb4-417b4e79c130

#define TA_UUID
    { 0xaed564f1, 0x960e, 0x4117, \
        { 0x8b, 0xb4, 0x41, 0x7b, 0x4e, 0x79, 0xc1, 0x30} }

根據簽署操作流程生成 .ta。私鑰使用 default_ta.pem,因此「編譯 OP-TEE OS」的步驟可以跳過。

簡答

  • 提供簽署過程的截圖,包含所有終端執行的命令,以及 sign_encrypt.py 兩個命令的輸出。

    $ sign_encrypt.py display --in <.ta>
    $ sign_encrypt.py verify --uuid <uuid> --in <.ta> --key <default_ta.pem>
    
  • 參考文件 12,說明 subkeys 機制、流程。

參考客戶 api第三章底下的相關章節,回答以下問題:

  • CA 與 TA 使用的共享記憶體屬於安全記憶體還是非安全記憶體?
  • 共享記憶體區塊是否可以在多個會話(Sessions)中重複使用?
  • TEEC_AllocateSharedMemory、TEEC_RegisterSharedMemory 和 TEEC_TempMemoryReference 三種記憶體,可以實現 zero-copy 的機會從高到低排序是?