ソフトウェア実行環境の保護

この章ではソフトウェア実行環境を守るセキュリティ技術を適用する方法を説明します。 説明するセキュリティ技術は以下のとおりです。

  • OP-TEE

    • CAAM を利用した OP-TEE
    • SE050 を利用した OP-TEE

6.1. OP-TEE

6.1.1. Arm TrustZone と TEE の活用

Linux を利用するシステムでは、自社開発したソフトウェアだけでなく複数の OSS が導入されるケースがあります。このような状況下では、自社開発したタスクだけでなく、同時にOSSのタスクが実行されることになり、システムのどこかに悪意のあるコードが含まれるのか、その可能性を排除することは困難です。仮にすべての OSS が信頼できるものであったとしても、不具合がないことを保証することはほぼ不可能であり、結局のところどのソフトウェアが脆弱性のきっかけになるかは分からないのです。

そういった背景から Arm は TrustZone 技術を導入しました。リソースアクセス制限によって敵対的なソフトウェアからソフトウェア実行環境を隔離することができます。TrustZone の導入によって、自社開発以外のソフトウェアが多数動作する状況においても、通常はセキュアワールドにその影響が及びません。TrustZone を利用したものとして、GlobalPlatform の TEE (Trusted Execution Environment) を実現するソフトウェアがいくつか存在します。TEE を活用すると secure world において信頼できるソフトウェアだけを実行させることが可能です。

では、どういったケースで TEE を採用するべきでしょうか。一概には言えませんが、情報資産とその資産を処理するライブラリなどをまとめて保護するケースで利用することが考えられます。具体的には、電子決済処理、証明書の処理、有料コンテンツの処理、個人情報の処理などで利用するケースが考えられます。

6.1.2. OP-TEE とは

商用、OSS の TEE などいくつかの TEE 実装が存在します。Armadillo Base OS では OP-TEE を採用します。OSS である OP-TEE は Arm コア向け TEE 実装の1つです。Arm TrustZone テクノロジーによって情報資産とその処理をセキュアワールドに隔離して攻撃から保護します。OP-TEE は GlobalPlatform によって定義される TEE Client API や TEE Core API といった GlobalPlatformAPI に準拠したライブラリを提供しています。これらのAPI を利用することでユーザーはカスタムアプリケーションを開発することが可能です。imx-optee-xxx は NXP による i.MX ボートのサポート対応が含まれる OP-TEE の派生プロジェクトです。

[注記]

OP-TEE の詳しい情報は公式のドキュメントを参照してください。

6.2. OP-TEE の構成

OP-TEE を構成する主要なリポジトリは以下のとおりです。

  • imx-optee-os

    • セキュアワールドで動作する TEE。optee-os の派生
  • imx-optee-client

    • TEE を呼び出すためのノンセキュア、セキュアワールド向けの API ライブラリ。optee-client の派生
  • imx-optee-test

    • OP-TEE の基本動作のテスト、パフォーマンス測定を行う。optee-test の派生。NXP 独自のテストが追加される
  • optee_examples

    • サンプルアプリケーション

このうち、imx- というプレフィックスが付加されるリポジトリは、アップストリームのリポジトリに対して NXP による i.MX シリーズ向けの対応が入ったリポジトリになります。OP-TEE を利用するためには imx-optee-os をブートローダーに配置するだけでなく、Linux 上で動作するコンパニオン環境 (imx-optee-client) が必要です。また、TEE を利用するために CA (Client Application), TA (Trusted Application) を、imx-optee-os と imx-optee-client を用いてビルドします。必要に応じてテスト環境 (imx-optee-test) も追加してください。

[注記]

詳しい OP-TEE のシステム構成については 「ソフトウェア全体像」 を参照してください。

[注記]

OP-TEE git に関する詳しい情報は公式のドキュメントを参照してください。

6.2.1. Armadillo Base OS への組み込み

前節で説明した OP-TEE の主要なリポジトリを実際に Armdillo BaseOS に適用する場合、Armadillo Base OS とどのように関係するのか全体像を説明します。

以下が Armadillo Base OS との関係を表した全体像。

./images/charge_of_preparation.png

図6.1 Armadillo Base OS と OP-TEE の担当範囲


  • 青色の部分は Armadillo Base OS によってカバーされる範囲
  • 赤色の部分は OP-TEE を組み込むために用意しなければならない部分
  • 紫色の部分は デフォルトで Armadillo Base OS に組み込まれているが更新が必要な部分

imx-optee-os を組み込む作業は煩雑です。ユーザーの手間を省くために Armadillo Base OS には常に imx-optee-os バイナリがブートローダーに組み込むように実装されています。工場出荷状態イメージや製品アップデート向け Armadillo Base OS イメージにも含まれます。しかし、セキュリティ上の懸念から OP-TEE が利用できる状態で組み込まれていません。詳しくは 「鍵の更新」 で説明します。

6.3. OP-TEE を利用する前に

OP-TEE を組み込むための準備を行います。

6.3.1. 鍵の更新

imx-optee-os リポジトリには TA を署名するためのデフォルトの秘密鍵が配置されています。その秘密鍵はあくまでテストや試行のためのものです。そのまま同じ秘密鍵を使い続けると、攻撃者がデフォルトの秘密鍵で署名した TA が動作する環境になってしまいます。各ユーザーが新しい鍵を用意する必要があります。

  1. ソースコードを取得する Armadillo-IoT ゲートウェイ G4 製品マニュアルの 「ブートローダーをビルドする」 の章を参考にしてビルド環境の構築と、ブートローダーのソースコードの取得を行ってください。
  2. RSA 鍵ペアを生成します。

    次のコマンドを実行します。RSA/ECC を選択できます。

    [PC ~]$ cd imx-boot/imx-optee-os/keys
    [PC ~/imx-boot/imx-optee-os/keys]$ openssl genrsa -out rsa4096.pem 4096
    [PC ~/imx-boot/imx-optee-os/keys]$ openssl rsa -in rsa4096.pem -pubout -out rsa4096_pub.pem
[重要項目]

生成した秘密鍵 (上記の rsa4096.pem) は TA を更新していくために、今後も利用するものです。壊れにくい、セキュアなストレージにコピーしておくことをお勧めします。

[重要項目]

鍵の更新は計画性を持って行ってください。たとえば開発時のみ利用する鍵、運用時に利用する鍵を使い分ける。また、鍵は定期的に更新が必要です。以下を参考にしてください。

[注記]

鍵の更新に関する詳しい情報は公式のドキュメントを参照してください。

6.4. CAAM を活用した TEE を構築する

i.MX 8M Plus には CAAM (Cryptographic Acceleration and Assurance Module) と呼ばれる高機能暗号アクセラレータが搭載されています。CAAM は SoC 内部にあるためセキュアかつ高速に暗号処理を行うことが可能です。

6.4.1. ビルドの流れ

OP-TEE が含まれるブートローダーをビルドしていきます。Armadillo Base OS を利用した OP-TEE のビルドの流れは以下のとおりです。

  1. ブートローダーをビルドする
  2. imx-optee-client をビルドする
  3. TA, CA をビルドする
  4. ビルド結果を集める

本マニュアルで説明するビルド環境でのディレクトリ構成の概略は以下のとおりです。

optee_examples はユーザーアプリケーションを配置する場所です。本マニュアルでは Linaro が提供するアプリケーションのサンプルプログラムである optee_examples としました。本来は各ユーザーのアプリケーションを配置する場所になります。

├── imx-boot
│   ├── imx-atf
│   ├── imx-mkimage
│   ├── imx-optee-os
│   └── uboot-imx
├── imx-optee-client
├── imx-optee-test
├── optee_examples
└── out

6.4.2. ビルド環境を構築する

Armadillo-IoT ゲートウェイ G4 製品マニュアルの 「ブートローダーをビルドする」 を参考にしてビルド環境の構築と、ブートローダーのソースコードの取得、 ビルドを事前に行ってください。

imx-optee-test をビルドするために必要になります。

[PC ~]$ sudo apt install g++-aarch64-linux-gnu

6.4.3. ブートローダーを再ビルドする

新しい鍵を取り込むためにブートローダーを再ビルドする必要があります。

  1. uboot-imx のバージョンを変更する

    この後の作業で SWUpdate を利用してアップデートを行いますが、ターゲットボード上の uboot-imx と同じバージョンではアップデートが実行されないので、imx-boot を更新するたびに uboot-imx のバージョンも更新する必要があります。

    uboot-imx ディレクトリに localversion ファイルを作ります。

    [PC ~]$ cd imx-boot/uboot-imx
    [PC ~/imx-boot/uboot-imx]$ echo "-localv1.0.0" > localversion
    [ティップ]

    localversion の仕様はユーザーによって定義されます。

  2. ブートローダーをビルドする

    次のコマンドを実行します。 デフォルトの設定ではデフォルトの鍵を利用してしまうので make 引数で鍵のパスを渡す必要があります。「鍵の更新」 で生成した鍵のパスを変数 TA_SIGN_KEY で渡します。ここでは鍵名を rsa4096 としましたが、各ユーザーの環境に合わせた鍵名と読み替えてください。

    [PC ~]$ make CFG_CC_OPT_LEVEL=2 \
            TA_SIGN_KEY="${PWD}/imx-boot/imx-optee-os/keys/rsa4096.pem" \
            -C imx-boot imx-boot_armadillo_x2
    [ティップ]

    引数 TA_SIGN_KEY で秘密鍵をわたすことで、ビルド時に TA の署名に利用されます。また、実行時の署名確認のためには公開鍵を取り出して実行バイナリに取り込みます。

    ビルド結果をコピーしておきます。

    [PC ~]$ install -D -t ${PWD}/out/lib/optee_armtz \
            -m644 ${PWD}/imx-boot/imx-optee-os/out/export-ta_arm64/ta/*

6.4.4. imx-optee-client をビルドする

imx-optee-client は TA, CA が利用するライブラリ。アプリケーションをビルドする前にビルド必要がある。

[注記]

imx-optee-client は imx-optee-os のビルド結果を参照しているので、事前にブートローダーをビルドする必要があります。

  1. imx-optee-client をクローンする

    imx-boot のディレクトリと並列に配置されるように imx-optee-client をクローンして、必要に応じて適切なブランチなどをチェックアウトしてください。

    [PC ~]$ git clone https://source.codeaurora.org/external/imx/imx-optee-client.git \
            -b lf-5.10.72_2.2.0
  2. imx-optee-client をビルドする

    基本的な情報を参照するために TA_DEV_KIT_DIR を渡します。フォルトのターゲットでインストールも合わせて行うので DESTDIR を渡します。アプリケーションをビルドする際に API ライブラリとして利用されます。

    [PC ~]$ make -C imx-optee-client \
            DESTDIR="${PWD}/out" \
            CROSS_COMPILE="aarch64-linux-gnu-" \
            TA_DEV_KIT_DIR="${PWD}/imx-boot/imx-optee-os/out/export-ta_arm64"

6.4.5. アプリケーションをビルドする

本来はユーザーが独自に作ったアプリケーションをビルドしますが、ここでは参考までにサンプルアプリケーション optee_examples をビルドします。アプリケーション開発の参考にしてください。

[注記]
  • アプリケーションをビルドするためには imx-optee-os, imx-optee-client のビルド結果を参照しているので、一度は imx-boot, imx-optee-client をビルドする必要があります
  • optee_examples にはインストールする make ターゲットがないので、ビルド後に手動で集める作業が必要があります
  1. optee_examples をクローンする

    imx-boot や imx-optee-client ディレクトリと並列に配置されるように optee_examples をクローンして、必要に応じて適切なブランチなどをチェックアウトしてください。

    [PC ~]$ git clone https://github.com/linaro-swg/optee_examples.git \
            -b 3.15.0
  2. optee_examples をビルドする

    基本的な情報を参照するために TA_DEV_KIT_DIR、TA を署名するために TA_SIGN_KEY、ライブラリ参照のために TEEC_EXPORT を渡します。インストールターゲットがないので後ほど手動でビルド結果を収集する必要があります。

    [PC ~]$ make -C optee_examples \
            TA_CROSS_COMPILE="aarch64-linux-gnu-" \
            HOST_CROSS_COMPILE="aarch64-linux-gnu-" \
            TA_DEV_KIT_DIR="${PWD}/imx-boot/imx-optee-os/out/export-ta_arm64" \
            TEEC_EXPORT="${PWD}/out/usr" \
            TA_SIGN_KEY="$PWD/imx-boot/imx-optee-os/keys/rsa4096.pem"

    ビルド結果をコピーしておきます。

    [PC ~]$ install -D -t ${PWD}/out/lib/optee_armtz -m644 ${PWD}/optee_examples/out/ta/*
    [PC ~]$ install -D -t ${PWD}/out/usr/bin -m755 ${PWD}/optee_examples/out/ca/*

6.4.6. imx-optee-test をビルドする

imx-optee-test は必ずしも必要ではありません。利用機会は限られますが、OP-TEE の基本動作を確認するため、パフォーマンスを計測するために imx-optee-test を利用することができます。組み込むかどうかの判断はお任せします。

[注記]

アプリケーションをビルドするためには imx-optee-os, imx-optee-client のビルド結果を参照しているので、一度は imx-boot, imx-optee-client をビルドする必要があります。

  1. imx-optee-test をクローンする

    imx-boot や imx-optee-client ディレクトリと並列に配置されるように imx-optee-client をクローンして、必要に応じて適切なブランチなどをチェックアウトしてください。

    [PC ~]$ git clone https://source.codeaurora.org/external/imx/imx-optee-test.git \
            -b lf-5.10.72_2.2.0
  2. imx-optee-test をビルドする

    基本的な情報を参照するために TA_DEV_KIT_DIR、TA を署名するために TA_SIGN_KEY、ライブラリ参照のために TEEC_EXPORT を渡します。ビルドとインストールは別のターゲットなのでそれぞれ make を実行する必要があります。

    [PC ~]$ CFLAGS=-O2 make -R -C imx-optee-test \
            CROSS_COMPILE="aarch64-linux-gnu-" \
            TA_DEV_KIT_DIR="${PWD}/imx-boot/imx-optee-os/out/export-ta_arm64" \
            OPTEE_CLIENT_EXPORT="${PWD}/out/usr" \
            TA_SIGN_KEY="${PWD}/imx-boot/imx-optee-os/keys/rsa4096.pem"

    インストールします。

    [PC ~]$ make -C imx-optee-test install \
            DESTDIR="${PWD}/out" \
            TA_DEV_KIT_DIR="${PWD}/imx-boot/imx-optee-os/out/export-ta_arm64" \
            OPTEE_CLIENT_EXPORT="${PWD}/out/usr"
[注記]

本リリース時点では xtest 1014 にてエラーになる問題があります。そのため環境変数で CFLAGS=-O2 を渡しています。make 引数で渡すとヘッダファイルの include 設定がなくなります。 ブートローダーのビルド時に O2 としているのも同様の理由です。

6.4.7. ビルド結果の確認と結果の収集

imx-optee-os, imx-optee-client の最小構成では以下のとおりです。

out/
|-- lib
|   `-- optee_armtz 1
|       |-- 023f8f1a-292a-432b-8fc4-de8471358067.ta
|       |-- f04a0fe7-1f5d-4b9b-abf7-619b85b4ce8c.ta
|       `-- fd02c9da-306c-48c7-a49c-bbd827ae86ee.ta
`-- usr
    |-- include
    |   |-- ck_debug.h
    |   |-- optee_client_config.mk
    |   |-- pkcs11.h
    |   |-- pkcs11_ta.h
    |   |-- tee_bench.h
    |   |-- tee_client_api.h
    |   |-- tee_client_api_extensions.h
    |   |-- tee_plugin_method.h
    |   `-- teec_trace.h
    |-- lib 2
    |   |-- libckteec.a
    |   |-- libckteec.so -> libckteec.so.0
    |   |-- libckteec.so.0 -> libckteec.so.0.1
    |   |-- libckteec.so.0.1 -> libckteec.so.0.1.0
    |   |-- libckteec.so.0.1.0
    |   |-- libteec.a
    |   |-- libteec.so -> libteec.so.1
    |   |-- libteec.so.1 -> libteec.so.1.0.0
    |   |-- libteec.so.1.0 -> libteec.so.1.0.0
    |   `-- libteec.so.1.0.0
    `-- sbin 3
        `-- tee-supplicant

1

Dynamic TA。Linux のファイルシステムに保存される

2

TEE client API, TEE, internal core API

3

Linux 上で動作する OP-TEE の補助的な機能をもつ

imx-optee-test, optee_examples を含めたビルド結果は以下のとおりです。

out
|-- bin
|   `-- xtest
|-- lib
|   `-- optee_armtz
|       |-- 023f8f1a-292a-432b-8fc4-de8471358067.ta
|       |-- 2a287631-de1b-4fdd-a55c-b9312e40769a.ta
|       |-- 380231ac-fb99-47ad-a689-9e017eb6e78a.ta
|       |-- 484d4143-2d53-4841-3120-4a6f636b6542.ta
|       |-- 528938ce-fc59-11e8-8eb2-f2801f1b9fd1.ta
|       |-- 5b9e0e40-2636-11e1-ad9e-0002a5d5c51b.ta
|       |-- 5ce0c432-0ab0-40e5-a056-782ca0e6aba2.ta
|       |-- 5dbac793-f574-4871-8ad3-04331ec17f24.ta
|       |-- 614789f2-39c0-4ebf-b235-92b32ac107ed.ta
|       |-- 690d2100-dbe5-11e6-bf26-cec0c932ce01.ta
|       |-- 731e279e-aafb-4575-a771-38caa6f0cca6.ta
|       |-- 873bcd08-c2c3-11e6-a937-d0bf9c45c61c.ta
|       |-- 8aaaf200-2450-11e4-abe2-0002a5d5c51b.ta
|       |-- a4c04d50-f180-11e8-8eb2-f2801f1b9fd1.ta
|       |-- a734eed9-d6a1-4244-aa50-7c99719e7b7b.ta
|       |-- b3091a65-9751-4784-abf7-0298a7cc35ba.ta
|       |-- b689f2a7-8adf-477a-9f99-32e90c0ad0a2.ta
|       |-- b6c53aba-9669-4668-a7f2-205629d00f86.ta
|       |-- c3f6e2c0-3548-11e1-b86c-0800200c9a66.ta
|       |-- cb3e5ba0-adf1-11e0-998b-0002a5d5c51b.ta
|       |-- d17f73a0-36ef-11e1-984a-0002a5d5c51b.ta
|       |-- e13010e0-2ae1-11e5-896a-0002a5d5c51b.ta
|       |-- e626662e-c0e2-485c-b8c8-09fbce6edf3d.ta
|       |-- e6a33ed4-562b-463a-bb7e-ff5e15a493c8.ta
|       |-- f04a0fe7-1f5d-4b9b-abf7-619b85b4ce8c.ta
|       |-- f157cda0-550c-11e5-a6fa-0002a5d5c51b.ta
|       |-- f4e750bb-1437-4fbf-8785-8d3580c34994.ta
|       |-- fd02c9da-306c-48c7-a49c-bbd827ae86ee.ta
|       `-- ffd2bded-ab7d-4988-95ee-e4962fff7154.ta
`-- usr
    |-- bin
    |   |-- optee_example_acipher
    |   |-- optee_example_aes
    |   |-- optee_example_hello_world
    |   |-- optee_example_hotp
    |   |-- optee_example_plugins
    |   |-- optee_example_random
    |   `-- optee_example_secure_storage
    |-- include
    |   |-- ck_debug.h
    |   |-- optee_client_config.mk
    |   |-- pkcs11.h
    |   |-- pkcs11_ta.h
    |   |-- tee_bench.h
    |   |-- tee_client_api.h
    |   |-- tee_client_api_extensions.h
    |   |-- tee_plugin_method.h
    |   `-- teec_trace.h
    |-- lib
    |   |-- libckteec.a
    |   |-- libckteec.so -> libckteec.so.0
    |   |-- libckteec.so.0 -> libckteec.so.0.1
    |   |-- libckteec.so.0.1 -> libckteec.so.0.1.0
    |   |-- libckteec.so.0.1.0
    |   |-- libteec.a
    |   |-- libteec.so -> libteec.so.1
    |   |-- libteec.so.1 -> libteec.so.1.0.0
    |   |-- libteec.so.1.0 -> libteec.so.1.0.0
    |   |-- libteec.so.1.0.0
    |   `-- tee-supplicant
    |       `-- plugins
    |           `-- f07bfc66-958c-4a15-99c0-260e4e7375dd.plugin
    `-- sbin
        `-- tee-supplicant

ターゲット上のコンテナに展開するために、tarball で固めます。

[PC ~]$ tar -caf optee.tar.gz -C out .
[ティップ]

Armadillo-IoT ゲートウェイ G4 製品マニュアルの 「アプリケーションをコンテナで実行する を参考にしてコンテナ作成の時に組み込むことをお勧めします。

6.4.8. OP-TEE を組み込む

ターゲットデバイスで debian コンテナを起動して、その上で OP-TEE を動作させます。

  1. swu でブートローダーをアップデートする Armadillo-IoT ゲートウェイ G4 製品マニュアルの 「Armadilloのソフトウェアをアップデートする を参考にしてアップデートしてください。
  2. ビルド結果が置かれているパスでコンテナを立ち上げます

    ここでは debian を利用しています。

    [armadillo ~]# podman run -it --name=dev_optee --device=/dev/tee0 \
            --device=/dev/teepriv0 -v "$(pwd)":/mnt docker.io/debian /bin/bash
  3. ビルド結果を展開する

    tarball を展開します。

    [container ~]# tar -xaf /mnt/optee.tar.gz -C /
  4. tee-supplicant を起動する

    [container ~]# tee-supplicant -d
  5. xtest で動作を確認する

    xtest で OP-TEE の基本動作を確認します。以下のログは全テストをパスしたログです。

    [container ~]# xtest
    Run test suite with level=0
    
    TEE test application started over default TEE instance
    ######################################################
    #
    # regression+pkcs11+regression_nxp
    #
    ######################################################
    
    * regression_1001 Core self tests
      regression_1001 OK
    : (省略)
    +-----------------------------------------------------
    33939 subtests of which 0 failed
    114 test cases of which 0 failed
    0 test cases were skipped
    TEE test application done!
[注記]

xtest の全テストをパスできない場合は環境構築から見直していただくことをお勧めします。問題が解決できないようであればサポートにご連絡ください。

  1. アプリケーションを起動する

    ビルド結果を展開したことで CA も TA も配置されました。目的の CA を起動してください。ここでは optee_examples の optee_example_hello_world を実行します。

    [container ~]# optee_example_hello_world
    D/TA:  TA_CreateEntryPoint:39 has been called
    D/TA:  TA_OpenSessionEntryPoint:68 has been called
    I/TA: Hello World!
    D/TA:  inc_value:105 has been called
    I/TA: Got value: 42 from NW
    I/TA: Increase value to: 43
    I/TA: Goodbye!
    Invoking TA to increment 42
    TA incremented value to 43
    D/TA:  TA_DestroyEntryPoint:50 has been called
[ティップ]

tee-supplicant は OP-TEE の linux 環境のコンパニオンプロセスです。 OP-TEE を利用するためにはなくてはならないものです。 自動起動することをお勧めします。詳しくは、 Armadillo-IoT ゲートウェイ G4 製品マニュアルの 「アプリケーションをコンテナで実行する」 を参考にしてください。

6.5. パフォーマンスを測定する

xtest を利用することで AES, SHA アルゴリズムの OP-TEE OS のパフォーマンスを測定することができます。

AES のパフォーマンスを計測するために次のコマンドを実行します。この結果は例になります。

[container ~]# xtest --aes-perf
min=113.753us max=191.881us mean=116.426us stddev=4.10202us (cv 3.5233%) (8.38786MiB/s)

SHA のパフォーマンスを計測するためのコマンドを実行します。この結果も例になります。

[container ~]# xtest --sha-perf
min=50.876us max=123.003us mean=52.8036us stddev=2.4365us (cv 4.61427%) (18.494

6.6. Edgelogck SE050 を活用した TEE を構築する

NXP Semiconductors の EdgeLock SE050 は IoT アプリケーション向けのセキュアエレメントです。様々なアルゴリズムに対応した暗号エンジン、セキュアストレージを搭載します。GlobalPlatform によって標準化されている Secure Channel Protocol 03 に準拠し、バスレベル暗号化 (AES)、ホストとカードの相互認証 (CMAC ベース) を行います。

OP-TEE で SE050 を用いるユースケースとしては、IoT アプリケーション向けに特化された豊富な機能を活用した上で、ホスト側の処理を守りたい場合に利用することが考えられます。OP-TEE を組み合わせることで SE050 へアクセスする部分、保存された情報資産を取り出して実際に処理する部分を守ることができます。

[ティップ]

ユーザーが SE050 にアクセスする場合は、OP-TEE の TEE Client API や TEE Core API といった GlobalPlatformAPI を呼び出すことになります。デバイスの変更などの状況で比較的容易に移植が可能になります。

[ティップ]

SE050 の詳細については以下の NXP Semiconductors のページから検索して、ご確認ください。

6.6.1. OP-TEE 向け plug-and-trust ライブラリ

NXP Semiconductors が開発するライブラリ plug-and-trust を利用してSE050 にアクセスします。OP-TEE への移植は Foundries.io によって行われ、Github にて公開されています。現状、SE050 の全ての機能を使えるわけではありません。主に暗号強度が弱い鍵長が無効化されています。

現状で対応する処理:

  • RSA 2048, 4096 encrypt/decrypt/sign/verify
  • ECC sign/verify
  • AES CTR
  • RNG
  • SCP03 (i2c communications between the processor and the device are encrypted)
  • DieID generation
  • cryptoki integration
[ティップ]

OP-TEE 向け plug-and-trust の詳細の情報は以下を参照してください。

[ティップ]

本ガイドで利用したバージョンは以下のとおりです。

  • plug-and-trust: 0.0.2
  • imx-optee: lf-5.10.72_2.2.0 (3.15.0ベース)
  • trusted-fimware-a: lf_v2.4 (2.4ベース)

6.6.2. ビルドの流れ

基本的には CAAM の場合と同様の流れになる。

  1. ブートローダーをビルドする
  2. imx-optee-client をビルドする
  3. TA, CA をビルドする
  4. ビルド結果を集める

ディレクトリ構成の概略は以下のとおりです。

├── imx-boot
│   ├── imx-atf
│   ├── imx-mkimage
│   ├── imx-optee-os
│   └── uboot-imx
├── imx-optee-client
├── imx-optee-test
├── optee_examples
├── plug-and-trust
└── out

6.6.3. ビルド環境を構築する

OP-TEE 向け plug-and-trust をビルドするために必要なパッケージをインストールします。

[PC ~]$ sudo apt install cmake

6.6.4. OP-TEE 向け plug-and-trust をビルドする

  1. OP-TEE 向け plug-and-trust をクローンする

    imx-boot や imx-optee-client ディレクトリと並列に配置されるように OP-TEE 向け plug-and-trust をクローンして、必要に応じて適切なブランチなどをチェックアウトしてください。

    [PC ~]$ git clone https://github.com/foundriesio/plug-and-trust.git -b optee_lib
  2. OP-TEE 向け plug-and-trust をビルドする

    [PC ~]$ mkdir -p plug-and-trust/optee_lib/build
    [PC ~]$ cd plug-and-trust/optee_lib/build
    [PC ~/plug-and-trust/optee_lib/build]$ cmake \
            -DCMAKE_C_FLAGS="-mstrict-align -mgeneral-regs-only" \
            -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \
            -DOPTEE_TREE="${PWD}/../../../imx-boot/imx-optee-os" ..
    
    -- The C compiler identification is GNU 10.2.1
    -- The CXX compiler identification is GNU 10.2.1
    : (省略)
    -- Generating done
    -- Build files have been written to: /path/plug-and-trust/optee_lib/build
    [PC ~/plug-and-trust/optee_lib/build]$ make
    make
    Consolidate compiler generated dependencies of target se050
    [  4%] Building C object CMakeFiles/se050.dir/path/plug-and-trust/hostlib/hostLib/libCommon/infra/global_platf.c.o
    [  8%] Building C object CMakeFiles/se050.dir/path/plug-and-trust/hostlib/hostLib/libCommon/infra/sm_apdu.c.o
    : (省略)
    [100%] Linking C static library libse050.a
    [100%] Built target se050

6.6.5. imx-optee-os のコンフィグの修正

SE050 を crypto driver として利用するためにコンフィグを修正する。

SE050 向けにビルドするために imx-boot/Makefile を追加する。

$(OPTEE)/out/tee.bin: $(OPTEE)/.git FORCE
        $(MAKE) -C $(OPTEE) O=out ARCH=arm PLATFORM=imx CFG_WERROR=y \
        PLATFORM_FLAVOR=mx8mpevk \
        CFG_NXP_SE05X=y \ 1
        CFG_IMX_I2C=y \ 2
        CFG_CORE_SE05X_I2C_BUS=2 \
        CFG_CORE_SE05X_BAUDRATE=400000 \
        CFG_CORE_SE05X_OEFID=0xA200 \
        CFG_IMX_CAAM=n \ 3
        CFG_NXP_CAAM=n \
        CFG_CRYPTO_WITH_CE=y \ 4
        CFG_STACK_THREAD_EXTRA=8192 \ 5
        CFG_STACK_TMP_EXTRA=8192 \
        CFG_NUM_THREADS=1 \ 6
        CFG_WITH_SOFTWARE_PRNG=n \ 7
        CFG_NXP_SE05X_PLUG_AND_TRUST_LIB=~/plug-and-trust/optee_lib/build/libse050.a \ 8
        CFG_NXP_SE05X_PLUG_AND_TRUST=~/plug-and-trust/

コンフィグの修正に関する詳細

1

SE050 を利用するために有効にする

2

imx-i2c ドライバ を有効にする

3

CAAM は無効化する

4

AES や SHA は高速な Arm CE を利用する

5

スタックを通常よりも多く消費するためにスタックを増量する

6

スレッドによる複数のコンテキストに対応していないためスレッドを1つとする

7

ハードウェア乱数発生器を利用するために無効にする

8

SE050 のドライバの実装は OP-TEE 向け plug-and-trust ライブラリ内に存在する

[注記]
  • SE050 の host 接続用 I2C は最大 3.2 MHz (high speed)ですが、i.MX 8M Plus の i2c の最大周波数は 400kHz のため、遅い通信速度で実装されています
  • CAAM と SE050 の共存は、SE050 を有効にすることによって CAAM の個別のドライバの依存関係が不正になるため、実行時にエラーになる問題があります

6.6.6. uboot-imx の修正

Armadillo は消費電力の削減のため SE050 を Deep Power-down モードに設定してパワーゲーティングしている。Deep Power-down モードを解除して SE050 を利用するためには、i.MX 8M Plus に接続されている SE050 の ENA ピンをアサートする必要があります。ENA ピンをアサートすると SE050 は一定時間の後に起動するので SE050 を利用すためには若干の待ち時間が必要となります。OP-TEE OS は起動時にドライバの初期化等を行う実装になっている。そのため、OP-TEE OS が起動する前に生存している SPL (Secondary Program Loader) で Deep Power-down を解除することで待ち時間を稼いでいる。

以下はシステムの起動と SE050 の関係を示したシーケンス図。

./images/se050_optee_boot_sequence.png

図6.2 SE050 向け OP-TEE の起動シーケンス図


ENA をアサートするために以下のように変更する

diff --git a/board/atmark-techno/armadillo_x2/spl.c b/board/atmark-techno/armadillo_x2/spl.c
index a26bc85633..88f5b8560c 100644
--- a/board/atmark-techno/armadillo_x2/spl.c
+++ b/board/atmark-techno/armadillo_x2/spl.c
@@ -111,6 +111,11 @@ static struct fsl_esdhc_cfg usdhc_cfg[2] = {
        {USDHC3_BASE_ADDR, 0, 8},
 };

+#define SE_RST_N IMX_GPIO_NR(1, 12)
+static iomux_v3_cfg_t const se_rst_n_pads[] = {
+       MX8MP_PAD_GPIO1_IO12__GPIO1_IO12 | MUX_PAD_CTRL(NO_PAD_CTRL),
+};
+
 int board_mmc_init(bd_t *bis)
 {
        int i, ret;
@@ -228,6 +233,12 @@ void spl_board_init(void)
        clock_enable(CCGR_GIC, 1);
 #endif

+       imx_iomux_v3_setup_multiple_pads(se_rst_n_pads,
+                                        ARRAY_SIZE(se_rst_n_pads));
+
+       gpio_request(SE_RST_N, "se_rst_n");
+       gpio_direction_output(SE_RST_N, 1);
+
        puts("Normal Boot\n");
 }

6.6.7. imx-optee-os の imx-i2c ドライバの修正

imx-optee-os の imx-i2c ドライバには i.MX 8M Plus の対応が入っていないため、レジスタ等の定義を追加する必要がある。imx-optee-os には lf-5.10.y_2.0.0 からSE050 ドライバが取り込まれている。

以下のように修正する。

diff --git a/core/arch/arm/plat-imx/conf.mk b/core/arch/arm/plat-imx/conf.mk
index b4fbfed5..3f6388f3 100644
--- a/core/arch/arm/plat-imx/conf.mk
+++ b/core/arch/arm/plat-imx/conf.mk
@@ -555,7 +555,7 @@ endif

 else

-$(call force,CFG_CRYPTO_DRIVER,n)
-$(call force,CFG_WITH_SOFTWARE_PRNG,y)
+#$(call force,CFG_CRYPTO_DRIVER,n) 1
+#$(call force,CFG_WITH_SOFTWARE_PRNG,y) 2

 ifneq (,$(filter y, $(CFG_MX6) $(CFG_MX7) $(CFG_MX7ULP)))
diff --git a/core/arch/arm/plat-imx/registers/imx8m.h b/core/arch/arm/plat-imx/registers/imx8m.h
index 9b6a50ee..59fcea88 100644
--- a/core/arch/arm/plat-imx/registers/imx8m.h
+++ b/core/arch/arm/plat-imx/registers/imx8m.h
@@ -42,6 +42,17 @@
 #define IOMUXC_I2C1_SDA_CFG_OFF        0x480
 #define IOMUXC_I2C1_SCL_MUX_OFF        0x214
 #define IOMUXC_I2C1_SDA_MUX_OFF        0x218
+#elif defined(CFG_MX8MP)
+#define I2C1_BASE              0x30a20000
+#define I2C2_BASE              0x30a30000
+#define I2C3_BASE              0x30a40000
+
+#define IOMUXC_I2C1_SCL_CFG_OFF        0x460
+#define IOMUXC_I2C1_SDA_CFG_OFF        0x464
+#define IOMUXC_I2C1_SCL_MUX_OFF        0x200
+#define IOMUXC_I2C1_SDA_MUX_OFF        0x204
+#define IOMUXC_I2C1_SCL_INP_OFF        0x5A4
+#define IOMUXC_I2C1_SDA_INP_OFF        0x5A8
 #endif

 #endif /* __IMX8M_H__ */
diff --git a/core/drivers/imx_i2c.c b/core/drivers/imx_i2c.c
index a318c32c..a9dab31c 100644
--- a/core/drivers/imx_i2c.c
+++ b/core/drivers/imx_i2c.c
@@ -34,6 +34,16 @@
 /* Clock */
 #define I2C_CLK_CGRBM(__x)     0 /* Not implemented */
 #define I2C_CLK_CGR(__x)       CCM_CCRG_I2C##__x
+#elif defined(CFG_MX8MP)
+/* IOMUX */
+#define I2C_INP_SCL(__x)       (IOMUXC_I2C1_SCL_INP_OFF + ((__x) - 1) * 0x8)
+#define I2C_INP_SDA(__x)       (IOMUXC_I2C1_SDA_INP_OFF + ((__x) - 1) * 0x8)
+#define I2C_INP_VAL(__x)       (((__x) == 1 || (__x) == 2) ? 0x2 : 0x4)
+#define I2C_MUX_VAL(__x)       0x010
+#define I2C_CFG_VAL(__x)       0x1c6
+/* Clock */
+#define I2C_CLK_CGRBM(__x)     0 /* Not implemented */
+#define I2C_CLK_CGR(__x)       CCM_CCRG_I2C##__x
 #elif defined(CFG_MX6ULL)
 /* IOMUX */
 #define I2C_INP_SCL(__x)       (IOMUXC_I2C1_SCL_INP_OFF + ((__x) - 1) * 0x8)
@@ -182,7 +192,7 @@ static void i2c_set_bus_speed(uint8_t bid, int bps)
        vaddr_t addr = i2c_clk.base.va;
        uint32_t val = 0;

-#if defined(CFG_MX8MM)
+#if defined(CFG_MX8MM) || defined(CFG_MX8MP)
        addr += CCM_CCGRx_SET(i2c_clk.i2c[bid]);
        val = CCM_CCGRx_ALWAYS_ON(0);
 #elif defined(CFG_MX6ULL)

以下は imx プラットフォームの makefile の問題です。回避するためにコメントアウトします。

1

imx プラットフォームで CAAM 以外の crypto driver を利用することを想定していない

2

CAAM の HWRNG を利用しないということは PRNG を使うことしか想定しない

6.6.8. ビルドとターゲットボードへの組み込み

修正した後は、ビルドからターゲットボードへの組み込みまで CAAM 向けの OP-TEE と同様の手順で作業することが可能です。 「ブートローダーを再ビルドする」 の作業から開始して組み込みしてください。

6.6.9. xtest の制限

「OP-TEE 向け plug-and-trust ライブラリ」 で説明したように一部のアルゴリズムに制限があります。そのため xtest の全てのテスト項目をパスするわけではありません。以下に失敗するテスト項目を列挙する。

仕様どおりのエラー:

  • regression 1009 TEE Wait cancel

    • キャンセル処理をするために OP-TEE はマルチスレッドが有効な構成でなくてはならない。SE050 へのアクセスをシリアライズする利用するために imx-optee-os の make 時にスレッドを1つにしているため

対応していない鍵長のためにエラー:

  • regression 4006 Test TEE Internal API Asymmetric Cipher operations
  • regression 4007 rsa.1 Generate RSA-256 key
  • regression 4011 Test TEE Internal API Bleichenbacher attack
  • pkcs11 1021.3 RSA-1024: Sign & verify - oneshot - CKM_MD5_RSA_PKCS
  • pkcs11 1022.2 RSA-1024: Sign & verify - oneshot - RSA-PSS/SHA1
  • pkcs11 1023.2 RSA OAEP key generation and crypto operations

optee os の不具合 (既知の問題):

  • regression 4009 Test TEE Internal API Derive key ECDH
  • regression 6018 Large object
  • pkcs11 1019.3 P-256: Sign & verify - oneshot - CKM_ECDSA_SHA1

以下は特に問題はないが時間がかかるためにフリーズしているかのように見える。

  • regression 1006 Secure time source
  • regression nxp 0001, regression_nxp_0003
[ティップ]

xtest を行う際にはデフォルトでテストに失敗しても先に進む設定となっています。ただ、時間のかかるテストは無効にすることも可能です。

[container ~]# xtest -x 1006 -x regression_nxp_0003

6.7. imx-optee-os 技術情報

6.7.1. ソフトウェア全体像

OP-TEE のアーキテクチャの概要を説明する。ここでは i.MX 8M Plus に搭載される Cortex-A53 コアのアーキテクチャである aarch64 を前提に話を進める。

以下にのシステム図を示す。

./images/optee_system_diagram.png

図6.3 OPTEE のシステム図


以下のコンポーネントによってシステムが構成される。概要と主な責務について説明する。

  • OP-TEE

    • GlobalPlatform の TEE 実装。secure EL1 に配置される
  • Trusted Firmware-A

    • Linaro によって開発される Secure monitor の実装
    • secure state と non-secure state の遷移管理、PSCI に準拠した電源管理などを担当する
    • optee dispatcher と呼ばれる OP-TEE の呼び出しモジュールを内部に持つ
  • Client Application (CA)

    • TA を呼び出すアプリケーション
  • Trusted Application (TA)

    • TEE 上で CA からの呼び出しを処理
    • Dynamic TA と Pesudo TA がある

      • Pesudo は TA ではありません。通常は Dynamic TA を利用してください。Pesudo TA は OP-TEE OS に直接リンクされるため TEE Internal Core API は呼べません
    • Dynamic TA は Linux のファイルシステム上に配置される。tee-supplicant によって OP-TEE OS に引き渡される
  • tee-supplicant

    • Linux user 空間で動作する OP-TEE を補うプロセス。目的は Linux のリソースを OP-TEE OS が利用するため

6.7.2. フロー

TEE を呼び出すフローについて説明する。

CA が OP-TEE 上の TA とのセッションを確立する流れ

  1. Linux 上の CA が、セッションを開くために uuid を指定して TEE Client API を呼び出す

    • システムコールで tee driver が呼ばれる
  2. tee driver は セキュアモニタコールで Trusted Firmware-A (ATF) 上の OP-TEE dispacher を呼び出す
  3. OP-TEE dispatcher は optee vector table に登録されている OP-TEE のハンドラを呼び出す

    • この段階ではまだ EL3 の状態
  4. OP-TEE OS は自ら SEL1 に落ちて、内部処理をしてから、ここまでの逆順で tee-supplicant を呼び出す
  5. tee-supplicant は uuid を基に TA をロードして共有メモリに配置して OP-TEE OS を呼び出す
  6. OP-TEE は TA をロードする
  7. セッションができる

CA が TEE Client API を通して TA 上である処理を実行する流れ

  1. Linux 上の CA が TEE Client API を呼び出す

    • システムコールで tee driver が呼ばれる
  2. tee driver は セキュアモニタコールで Trusted Firmware-A (ATF) 上の OP-TEE dispacher を呼び出す
  3. OP-TEE dispatcher は optee vector table に登録されている OP-TEE のハンドラを呼び出す
  4. ハンドラ (OP-TEE OS) は自ら SEL1 に落ちる。内部処理をしてから、SEL0 に落ちて TA を呼び出す
  5. TA は API の引数を基にある処理を実行する
  6. ここまでの逆順で CA まで戻る
[注記]

より詳しい内容については公式ドキュメントをご覧ください。

6.7.3. メモリマップ

セキュリティ関連の領域を含めた i.MX 8M Plus の物理メモリマップを次に示します。

./images/memory_mapping.png

図6.4 i.MX 8M Plus の物理メモリマップ


imx-optee-os のメモリマップを次に示します。デバッグ等にお役立てください。

表6.1 OP-TEE メモリマップ

type virtual address physical address size description

TEE_RAM_RX/RW

0x5600_0000.. 0x561f_ffff

0x5600_0000.. 0x561f_ffff

0x0020_0000 (smallpg)

OP-TEE text + data セクション

IO_SEC

0x5620_0000.. 0x5620_ffff

0x32f8_0000.. 0x32f8_ffff

0x0001_0000 (smallpg)

TZASC

SHM_VASPACE

0x5640_0000.. 0x583f_ffff

0x0000_0000.. 0x01ff_ffff

0x0200_0000 (pgdir)

OP-TEE dynamic shared memory area, va の確保のみ

RES_VASPACE

0x5840_0000.. 0x58df_ffff

0x0000_0000.. 0x009f_ffff

0x00a0_0000 (pgdir)

OP-TEE 予約領域 (late mapping), va の確保のみ

IO_SEC

0x58e0_0000.. 0x591f_ffff

0x3020_0000.. 0x305f_ffff

0x0040_0000 (pgdir)

AIPS1(GPIO1, GPT, IOMUXC など)

IO_NSEC

0x5920_0000.. 0x595f_ffff

0x3080_0000.. 0x30bf_ffff

0x0040_0000 (pgdir)

AIPS3(UART2, CAAM, I2C など)

IO_SEC

0x5960_0000.. 0x597f_ffff

0x3880_0000.. 0x389f_ffff

0x0020_0000 (pgdir)

GICv3

TA_RAM

0x5980_0000.. 0x5b1f_ffff

0x5620_0000.. 0x57bf_ffff

0x01a0_0000 (pgdir)

TA ロード、実行領域

NSEC_SHM

0x5b20_0000.. 0x5b5f_ffff

0x57c0_0000.. 0x57ff_ffff

0x0040_0000 (pgdir)

OP-TEE contignuous shared memory area