| | この章では、Armadillo を利用したシステム上に存在する情報資産を守るための方法について説明する。 製品開発に費やすコストには様々なものがありますが、セキュリティのような機能性につながらないコストは軽視されがちです。しかし、一旦セキュリティ問題が発生してしまうと、業務停止など直接的な影響だけでなく、社会的な信用の低下、損害賠償など様々な被害につながってしまう可能性があります。守るべき情報資産が明確に存在するのであれば、セキュリティは重要視されるべきです。しかし、コスト度外視でありったけの対策を盛り込むのではコストが膨らみます。適切かつ適度なセキュリティ対策を講じることが大切です。製品開発の早い段階で守るべき情報資産を認識し、それら情報資産に対する脅威とリスクを分析して、リスクを評価する作業を行うことをお勧めします。そのうえで、費用対効果に見合ったセキュリティ技術を選択するとよいでしょう。 11.2. Armadillo Base OS のセキュリティ幅広い利用者のユースケースに沿った製品セキュリティ実現のため、Armadillo Base OS に様々なセキュリティ技術を組み込むことが可能です。
ソフトウェア実行環境の保護
-
TEE (Trusted Execution Environment)
セキュアブート、チェーンオブトラスト
-
HAB (High Assurance Boot)
-
SE050 secure storage
ストレージの秘匿化
キーストレージ
メモリの完全性チェック
-
RTIC (Run-Time Integrity Checker)
暗号処理のアクセラレータ
-
CAAM (Cryptographic Acceleration and Assurance Module)
次に各セキュリティ技術のカバーする範囲を示します。セキュリティ技術を採用する際には、採用する技術によってどこまでの範囲が守られるのかを把握することが大切です。設定次第でそれぞれの技術は高いセキュリティ性能を実現するものになり得ますが、単独で利用するだけではその効果は限定的で回避可能なものになってしまいます。そのため、いくつかの技術を適切に組み合わせて利用することで、より広範囲をカバーする回避困難なセキュリティを実現できます。そして、カバーする範囲が重なりあうことで突破困難なセキュリティを実現します。 *1 i.MX 8M Plus には RTIC (Run-time Integrity Checker) が含まれます。この機能を利用することでブート時、ランタイム時の周辺メモリの完全性をチェックすることが可能です Armadillo は様々な製品、様々な環境で利用されることが想定されます。それぞれのケースによって考慮すべき脅威が存在します。それらを正しく把握してセキュリティ技術を選択、組み合わせることが 大切です。 組み合わせの例としていくつかのモデルユースケースを示します。
デフォルト
クラウドサービスのデバイス認証が可能なレベル
方針
-
ネットワークを突破されても情報資産は守る
-
部分的な情報資産(暗号処理や鍵)の保護
-
デバイスへの直接攻撃は想定しない
技術
-
+OP-TEE
-
+鍵のストレージは SE050
-
+ファイルシステムの暗号化
決済処理が可能なレベル
方針
-
ネットワークを突破されても情報資産は守る
-
スクリプトキディによるデバイスへの直接攻撃は守るが、ラボレベルの攻撃は想定しない
技術
-
+セキュアブート
-
+チェーンオブトラストを使った鍵のストレージ
-
+パーティションの暗号化
-
+メモリの完全性チェック
この章では情報資産を保護するための方法を説明します。説明するセキュリティ技術は以下のとおり。 情報資産はデータとして永続的にストレージや一次的にRAM上に保存されます。セキュリティ対策が講じられていないデバイスでは情報資産が露出していることになり、改竄や盗聴につながる可能性があります。 鍵や証明書をストレージに保存する、暗号処理のために一次的に鍵や証明書をRAM上に展開するケースでデータ保護を採用することが考えられます。 NXP Semiconductors の EdgeLock SE050 は IoT アプリケーション向けのセキュアエレメントです。様々なアルゴリズムに対応した暗号エンジン、セキュアストレージを搭載します。GlobalPlatform が規定する Secure Channel Protocol 03 に準拠し、バスレベル暗号化 (AES)、ホストとカードの相互認証 (CMAC ベース) を行います。 | |
---|
SE050 の詳細については以下の NXP Semiconductors のページから検索して、ご確認ください。 |
Plug and trust ミドルウェアをダウンロードします
以下のサイトからダウンロードします。ここではユーザーが NXP Semiconductors のサイトで最新版を検索してダウンロードすることを想定しています。 コンテナ上から参照できる位置に配置しておいてください。 | |
---|
-
ダウンロードには NXP Semiconductors サイトへのユーザー登録が必要になります
-
本マニュアル作成時点では 04.00.00 を利用しました
|
コンテナを立ち上げる
NXP Semiconductors のビルド環境はターゲットボード上のコンテナになります。ここでは alpine を利用します。 [armadillo ~]# podman run -it --name=dev_se050 --device=/dev/i2c-2 \
-v "$(pwd)":/mnt docker.io/alpine /bin/sh
ビルド環境を構築する
plug and trust をビルドするために必要なパッケージをインストールします。 [container ~]# apk add musl-dev gcc make g++ file \
linux-headers openssl-dev cmake python3
Armadillo は消費電力の削減のため SE050 を Deep Power-down モードに設定してパワーゲーティングしている。Deep Power-down モードを解除して SE050 を利用するためには、i.MX 8M Plus に接続されている SE050 の ENA ピンをアサートする必要があります。 表11.1 SE050 ena pin SE050 PIN | i.MX8MP port | initial port status |
---|
ENA | GPIO1_IO12 | GPIO input |
sysfs を利用して GPIO1_IO12 を出力ポートに変更して high にする。 [armadillo ~]# echo 12 > /sys/class/gpio/export
[armadillo ~]# echo "out" > /sys/class/gpio/gpio12/direction
[armadillo ~]# echo 1 > /sys/class/gpio/gpio12/value 11.3.3.2. Plug and trust ミドルウェアをビルドする
Plug and trust ミドルウェアを展開します
[container /mnt]# unzip SE-PLUG-TRUST-MW.zip
ビルドスクリプトを変更する
コンテナ上でビルドスクリプトを実行すると正しくプラットフォームを認識できないために、異なるプラットフォーム向けのバイナリを作ってしまいます。imx_native_se050_t1oi2c_openssl_el2go 向けを強制的に True になるように変更する必要があります。以下が変更箇所です。i.MX6UL/ULL, i.MX8M Mini 向けの条件文が真になるように変更します。 [container /mnt]# cd simw-top
[container /mnt/simw-top]# vi scripts/create_cmake_projects.py
: (省略)
# i.MX6UL/ULL and i.MX8M Mini EVK
if True: #gc.imx_native_compilation() and gc.is_with_el2go():
e = gc.generate_native("imx_native_se050_t1oi2c_openssl_el2go", {
"PTMW_Applet": "SE05X_C",
"PTMW_SE05X_Auth": "None",
: (省略) |
if 文を強制的に True にする。元の行はコメントアウトした
|
ビルドする
プロジェクトをつくるスクリプトを実行する。 [container /mnt]# cd simw-top
[container /mnt/simw-top]# python3 scripts/create_cmake_projects.py
### Native compilation on iMX Linux for SE05X using T=1 Over I2C for EdgeLock 2GO
#cmake -DPTMW_Applet=SE05X_C -DPTMW_SE05X_Auth=None (省略)...
-- The C compiler identification is GNU 10.3.1
-- The CXX compiler identification is GNU 10.3.1
: (省略)
-- Generating done
Build files have been written to: /simw-top_build/(省略)... simw-top_build に移動してビルドする。 [container /mnt]# cd simw-top_build/imx_native_se050_t1oi2c_openssl_el2go
[container /mnt/simw-top_build/imx_native_(省略)...]# cmake --build .
: (省略)
[ 1%] Linking C shared library libmwlog.so
[ 1%] Built target mwlog
[100%] Linking C executable ../../../bin/nxp_iot_agent_demo
[100%] Built target nxp_iot_agent_demo
ビルド結果の確認
以下の2つのディレクトリができる。 [container /mnt/simw-top_build]# ls
imx_native_se050_t1oi2c_openssl_el2go simw-top-eclipse_jrcpv1 以下のデモアプリケーションがビルドされる。 [container /mnt/simw-top_build/imx_native_se050_t1oi2c_openssl_el2go]# ls bin
MQTTVersion se05x_ConcurrentEcc
accessManager se05x_ConcurrentSymm
apdu_player_demo se05x_Delete_and_test_provision
claimcode_inject se05x_GetInfo
ex_attest_ecc se05x_I2cMaster
ex_attest_mont se05x_I2cMasterWithAttestation
ex_ecc se05x_InjectCertificate
ex_ecdaa se05x_InvokeGarbageCollection
ex_ecdh se05x_MandatePlatformSCP
ex_hkdf se05x_Minimal
ex_hmac se05x_MultiThread
ex_md se05x_MultipleDigestCryptoObj
ex_policy se05x_PCR
ex_rsa se05x_ReadWithAttestation
ex_se05x_WiFiKDF_derive se05x_TimeStamp
ex_se05x_WiFiKDF_inject se05x_TransportLock
ex_symmetric se05x_TransportUnLock
generate_certificate se05x_ex_export_se_to_host
generate_certificate_key se05x_ex_import_host_to_se
jrcpv1_server seTool
nxp_iot_agent_demo test_Crypto
remote_provisioning_client
デモアプリケーションで動作を確認する
se05x_GetInfo を実行する。SE050 にアクセスできると以下のようなログが出力される。 [container /mnt/simw-top_build/imx_native_(省略)/bin]# ./se05x_GetInfo \
/dev/i2c-2:0x48
App :INFO :PlugAndTrust_v03.03.00_20210528
App :INFO :Running ./se05x_GetInfo
App :INFO :Using PortName='/dev/i2c-2:0x48' (CLI)
: (省略)
App :WARN :#####################################################
App :INFO :Applet Major = 3
App :INFO :Applet Minor = 1
App :INFO :Applet patch = 1
App :INFO :AppletConfig = 6FFF
App :INFO :With ECDAA
App :INFO :With ECDSA_ECDH_ECDHE
App :INFO :With EDDSA
App :INFO :With DH_MONT
App :INFO :With HMAC
App :INFO :With RSA_PLAIN
App :INFO :With RSA_CRT
App :INFO :With AES
App :INFO :With DES
App :INFO :With PBKDF
App :INFO :With TLS
App :INFO :With MIFARE
App :INFO :With I2CM
: (省略)
plug and trust ミドルウェアにはでもアプリケーションが含まれます。そちらを参考にしてアプリケーションを作成することができます。 詳しくはミドルウェア内の doc ディレクトリ以下を参考にしてください。 この章ではソフトウェア実行環境を守るセキュリティ技術を適用する方法を説明します。 説明するセキュリティ技術は以下のとおりです。
OP-TEE
-
CAAM を利用した OP-TEE
-
SE050 を利用した OP-TEE
11.4.1.1. Arm TrustZone と TEE の活用Linux を利用するシステムでは、自社開発したソフトウェアだけでなく複数の OSS が導入されるケースがあります。このような状況下では、自社開発したタスクだけでなく、同時にOSSのタスクが実行されることになり、システムのどこかに悪意のあるコードが含まれるのか、その可能性を排除することは困難です。仮にすべての OSS が信頼できるものであったとしても、不具合がないことを保証することはほぼ不可能であり、結局のところどのソフトウェアが脆弱性のきっかけになるかは分からないのです。 そういった背景から Arm は TrustZone 技術を導入しました。リソースアクセス制限によって敵対的なソフトウェアからソフトウェア実行環境を隔離することができます。TrustZone の導入によって、自社開発以外のソフトウェアが多数動作する状況においても、通常はセキュアワールドにその影響が及びません。TrustZone を利用したものとして、GlobalPlatform の TEE (Trusted Execution Environment) を実現するソフトウェアがいくつか存在します。TEE を活用すると secure world において信頼できるソフトウェアだけを実行させることが可能です。 では、どういったケースで 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 の詳しい情報は公式のドキュメントを参照してください。 |
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 git に関する詳しい情報は公式のドキュメントを参照してください。 |
11.4.2.1. Armadillo Base OS への組み込み前節で説明した OP-TEE の主要なリポジトリを実際に Armdillo BaseOS に適用する場合、Armadillo Base OS とどのように関係するのか全体像を説明します。 以下が Armadillo Base OS との関係を表した全体像。 -
青色の部分は Armadillo Base OS によってカバーされる範囲
-
赤色の部分は OP-TEE を組み込むために用意しなければならない部分
-
紫色の部分は デフォルトで Armadillo Base OS に組み込まれているが更新が必要な部分
imx-optee-os を組み込む作業は煩雑です。ユーザーの手間を省くために Armadillo Base OS には常に imx-optee-os バイナリがブートローダーに組み込むように実装されています。工場出荷状態イメージや製品アップデート向け Armadillo Base OS イメージにも含まれます。しかし、セキュリティ上の懸念から OP-TEE が利用できる状態で組み込まれていません。詳しくは 「鍵の更新」 で説明します。 OP-TEE を組み込むための準備を行います。 imx-optee-os リポジトリには TA を署名するためのデフォルトの秘密鍵が配置されています。その秘密鍵はあくまでテストや試行のためのものです。そのまま同じ秘密鍵を使い続けると、攻撃者がデフォルトの秘密鍵で署名した TA が動作する環境になってしまいます。各ユーザーが新しい鍵を用意する必要があります。 -
ソースコードを取得する
「Armadilloのソフトウェアをビルドする」 の章を参考にしてビルド環境の構築と、ブートローダーのソースコードの取得を行ってください。
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 を更新していくために、今後も利用するものです。壊れにくい、セキュアなストレージにコピーしておくことをお勧めします。 |
| |
---|
鍵の更新は計画性を持って行ってください。たとえば開発時のみ利用する鍵、運用時に利用する鍵を使い分ける。また、鍵は定期的に更新が必要です。以下を参考にしてください。 |
| |
---|
鍵の更新に関する詳しい情報は公式のドキュメントを参照してください。 |
11.4.4. CAAM を活用した TEE を構築するi.MX 8M Plus には CAAM (Cryptographic Acceleration and Assurance Module) と呼ばれる高機能暗号アクセラレータが搭載されています。CAAM は SoC 内部にあるためセキュアかつ高速に暗号処理を行うことが可能です。 OP-TEE が含まれるブートローダーをビルドしていきます。Armadillo Base OS を利用した OP-TEE のビルドの流れは以下のとおりです。 -
ブートローダーをビルドする
-
imx-optee-client をビルドする
-
TA, CA をビルドする
-
ビルド結果を集める
本マニュアルで説明するビルド環境でのディレクトリ構成の概略は以下のとおりです。 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 「Armadilloのソフトウェアをビルドする」 の章を参考にしてビルド環境の構築からブートローダーのビルドまでを事前に行ってください。 imx-optee-test をビルドするために必要になります。 [PC ~]$ sudo apt install g++-aarch64-linux-gnu 新しい鍵を取り込むためにブートローダーを再ビルドする必要があります。
uboot-imx のバージョンを変更する
この後の作業で swupdate を利用してアップデートを行いますが、ターゲットボード上の uboot-imx と同じバージョンではアップデートが実行されないので、imx-boot を更新するたびに uboot-imx のバージョンも更新する必要があります。 uboot-imx ディレクトリに localvesion ファイルを作ります。 [PC ~]$ cd imx-boot/uboot-imx
[PC ~/imx-boot/uboot-imx]$ echo "-localv1.0.0" > localversion | |
---|
localversion の仕様はユーザーによって定義されます。 |
ブートローダーをビルドする
次のコマンドを実行します。
デフォルトの設定ではデフォルトの鍵を利用してしまうので 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/*
11.4.4.4. imx-optee-client をビルドするimx-optee-client は TA, CA が利用するライブラリ。アプリケーションをビルドする前にビルド必要がある。 | |
---|
imx-optee-client は imx-optee-os のビルド結果を参照しているので、事前にブートローダーをビルドする必要があります。 |
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.y_2.0.0
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"
本来はユーザーが独自に作ったアプリケーションをビルドしますが、ここでは参考までにサンプルアプリケーション optee_examples をビルドします。アプリケーション開発の参考にしてください。 | |
---|
-
アプリケーションをビルドするためには imx-optee-os, imx-optee-client のビルド結果を参照しているので、一度は imx-boot, imx-optee-client をビルドする必要があります
-
optee_examples にはインストールする make ターゲットがないので、ビルド後に手動で集める作業が必要があります
|
optee_examples をクローンする
imx-boot や imx-optee-client ディレクトリと並列に配置されるように optee_examples をクローンして、必要に応じて適切なブランチなどをチェックアウトしてください。 [PC ~]$ git clone https://github.com/linaro-swg/optee_examples.git \
-b 3.13.0
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/*
11.4.4.6. imx-optee-test をビルドするimx-optee-test は必ずしも必要ではありません。利用機会は限られますが、OP-TEE の基本動作を確認するため、パフォーマンスを計測するために imx-optee-test を利用することができます。組み込むかどうかの判断はお任せします。 | |
---|
アプリケーションをビルドするためには imx-optee-os, imx-optee-client のビルド結果を参照しているので、一度は imx-boot, imx-optee-client をビルドする必要があります。 |
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.y_2.0.0
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 としているのも同様の理由です。 |
imx-optee-os, imx-optee-client の最小構成では以下のとおりです。 out/
|-- lib
| `-- optee_armtz
| |-- 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
| |-- 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
`-- tee-supplicant |
Dynamic TA。Linux のファイルシステムに保存される
| |
TEE client API, TEE, internal core API
| |
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 . ターゲットデバイスで debian コンテナを起動して、その上で OP-TEE を動作させます。 -
swu でブートローダーをアップデートする
「Armadilloのソフトウェアをアップデートする」 を参考にアップデートしてください。
ビルド結果が置かれているパスでコンテナを立ち上げます
ここでは debian を利用しています。 [armadillo ~]# podman run -it --name=dev_optee --device=/dev/tee0 \
--device=/dev/teepriv0 -v "$(pwd)":/mnt docker.io/debian /bin/bash
ビルド結果を展開する
tarball を展開します。 [container ~]# tar -xaf /mnt/optee.tar.gz -C /
tee-supplicant を起動する
[container ~]# tee-supplicant -d
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 の全テストをパスできない場合は環境構築から見直していただくことをお勧めします。問題が解決できないようであればサポートにご連絡ください。 |
アプリケーションを起動する
ビルド結果を展開したことで 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 を利用するためにはなくてはならないものです。自動起動することをお勧めします。詳しくは、「アプリケーションをコンテナで実行する」 を参考にしてください。 |
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 11.4.6. 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 のページから検索して、ご確認ください。 |
11.4.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 の詳細の情報は以下を参照してください。 |
基本的には CAAM の場合と同様の流れになる。 -
ブートローダーをビルドする
-
imx-optee-client をビルドする
-
TA, CA をビルドする
-
ビルド結果を集める
ディレクトリ構成の概略は以下のとおりです。 ├── imx-boot
│ ├── imx-atf
│ ├── imx-mkimage
│ ├── imx-optee-os
│ └── uboot-imx
├── imx-optee-client
├── imx-optee-test
├── optee_examples
├── plug-and-trust
└── out OP-TEE 向け plug-and-trust をビルドするために必要なパッケージをインストールします。 [PC ~]$ sudo apt install cmake 11.4.6.4. OP-TEE 向け plug-and-trust をビルドする
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
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
11.4.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 \
CFG_IMX_I2C=y \
CFG_CORE_SE05X_I2C_BUS=2 \
CFG_CORE_SE05X_BAUDRATE=400000 \
CFG_CORE_SE05X_OEFID=0xA200 \
CFG_IMX_CAAM=n \
CFG_NXP_CAAM=n \
CFG_CRYPTO_WITH_CE=y \
CFG_STACK_THREAD_EXTRA=8192 \
CFG_STACK_TMP_EXTRA=8192 \
CFG_NUM_THREADS=1 \
CFG_WITH_SOFTWARE_PRNG=n \
CFG_NXP_SE05X_PLUG_AND_TRUST_LIB=~/plug-and-trust/optee_lib/build/libse050.a \
CFG_NXP_SE05X_PLUG_AND_TRUST=~/plug-and-trust/ コンフィグの修正に関する詳細 |
SE050 を利用するために有効にする
| |
imx-i2c ドライバ を有効にする
| |
CAAM は無効化する
| |
AES や SHA は高速な Arm CE を利用する
| |
スタックを通常よりも多く消費するためにスタックを増量する
| |
スレッドによる複数のコンテキストに対応していないためスレッドを1つとする
| |
ハードウェア乱数発生器を利用するために無効にする
| |
SE050 のドライバの実装は OP-TEE 向け plug-and-trust ライブラリ内に存在する
|
| |
---|
-
SE050 の host 接続用 I2C は最大 3.2 MHz (high speed)ですが、i.MX 8M Plus の i2c の最大周波数は 400kHz のため、遅い通信速度で実装されています
-
CAAM と SE050 の共存は、SE050 を有効にすることによって CAAM の個別のドライバの依存関係が不正になるため、実行時にエラーになる問題があります
|
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 の関係を示したシーケンス図。 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");
} 11.4.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)
+#$(call force,CFG_WITH_SOFTWARE_PRNG,y)
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 の問題です。回避するためにコメントアウトします。 |
imx プラットフォームで CAAM 以外の crypto driver を利用することを想定していない
| |
CAAM の HWRNG を利用しないということは PRNG を使うことしか想定しない
|
11.4.6.8. ビルドとターゲットボードへの組み込み修正した後は、ビルドからターゲットボードへの組み込みまで CAAM 向けの OP-TEE と同様の手順で作業することが可能です。 「ブートローダーを再ビルドする」 の作業から開始して組み込みしてください。 「OP-TEE 向け plug-and-trust ライブラリ」 で説明したように一部のアルゴリズムに制限があります。そのため xtest の全てのテスト項目をパスするわけではありません。以下に失敗するテスト項目を列挙する。
1009 TEE Wait cancel
-
キャンセル処理をするために OP-TEE はマルチスレッドが有効な構成でなくてはならない。SE050 へのアクセスをシリアライズする利用するために imx-optee-os の make 時にスレッドを1つにしているため
regression_4007_rsa.1 Generate RSA-256 key
regression_4006 Test TEE Internal API Asymmetric Cipher operations
regression_4009 Test TEE Internal API Derive key ECDH
-
E/TC:? 0 shared_secret:333 private key must be stored in SE050 flash
-
provisioning が必要
regression_4011 Test TEE Internal API Bleichenbacher attack
regression_6018 Large object
以下は特に問題はないが時間がかかるためにフリーズしているかのように見える。 | |
---|
xtest を行う際にはデフォルトでテストに失敗しても先に進む設定となっています。ただ、時間のかかるテストは無効にすることも可能です。 [container ~]# xtest -x 1006 -x regression_nxp_0003 |
11.4.7. imx-optee-os 技術情報OP-TEE のアーキテクチャの概要を説明する。ここでは i.MX 8M Plus に搭載される Cortex-A53 コアのアーキテクチャである aarch64 を前提に話を進める。 以下にのシステム図を示す。 以下のコンポーネントによってシステムが構成される。概要と主な責務について説明する。
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)
Trusted Application (TA)
tee-supplicant
-
Linux user 空間で動作する OP-TEE を補うプロセス。目的は Linux のリソースを OP-TEE OS が利用するため
TEE を呼び出すフローについて説明する。 CA が OP-TEE 上の TA とのセッションを確立する流れ
Linux 上の CA が、セッションを開くために uuid を指定して TEE Client API を呼び出す
-
システムコールで tee driver が呼ばれる
-
tee driver は セキュアモニタコールで Trusted Firmware-A (ATF) 上の OP-TEE dispacher を呼び出す
OP-TEE dispatcher は optee vector table に登録されている OP-TEE のハンドラを呼び出す
-
OP-TEE OS は自ら SEL1 に落ちて、内部処理をしてから、ここまでの逆順で tee-supplicant を呼び出す
-
tee-supplicant は uuid を基に TA をロードして共有メモリに配置して OP-TEE OS を呼び出す
-
OP-TEE は TA をロードする
-
セッションができる
CA が TEE Client API を通して TA 上である処理を実行する流れ
Linux 上の CA が TEE Client API を呼び出す
-
システムコールで tee driver が呼ばれる
-
tee driver は セキュアモニタコールで Trusted Firmware-A (ATF) 上の OP-TEE dispacher を呼び出す
-
OP-TEE dispatcher は optee vector table に登録されている OP-TEE のハンドラを呼び出す
-
ハンドラ (OP-TEE OS) は自ら SEL1 に落ちる。内部処理をしてから、SEL0 に落ちて TA を呼び出す
-
TA は API の引数を基にある処理を実行する
-
ここまでの逆順で CA まで戻る
| |
---|
より詳しい内容については公式ドキュメントをご覧ください。 |
セキュリティ関連の領域を含めた i.MX 8M Plus の物理メモリマップを次に示します。 imx-optee-os のメモリマップを次に示します。デバッグ等にお役立てください。 表11.2 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 |
この章では起動ソフトウェアを認証するセキュリティ技術を適用する方法を説明します。 11.5.1. セキュアブートとチェーンオブトラスト組み込みデバイスへの攻撃は様々な方向から行われます。ある方向のセキュリティ対策が強固な場合、攻撃者は回避可能な別の方向がないのか模索します。攻撃者のコードを何らかの方法でデバイスに組み込んで対策を回避するのが、単純ですが有効な方法でしょう。IoT デバイスはネットワーク上のサービスとデータのやり取りを行います。通信路の暗号化、サーバーとデバイスの相互認証などの対策を講じたとしても、IoT デバイス上にあるソフトウェアに攻撃者のコードを組み込むことで対策を回避してシステムに侵入される可能性があるのです。 セキュアブートは、起動ソフトウェアのディジタル署名を用いて正規ソフトウェアであることを確認してから起動する処理のことです。攻撃者によって作られた不正なコードを実行前に検出することができます。セキュアブートはチェーンオブトラスト (chain of trust) と表裏一体に実装されます。チェーンオブトラストとは、その名の通り、信頼を繋いでいく形態のことを指します。ルートオブトラストと呼ばれる基礎となる情報から枝葉のように繋がれた情報を認証していくことで、繋がれた個々のコンポーネントだけでなくシステムを信頼できるものにしてくれます。セキュアブートは、起動時にソフトウェアを順番に認証することで信頼を次に繋いでいるのです。セキュアブートの範囲をどこまでにするかによりますが、起動時に認証されたソフトウェアで別の情報を認証すれば、チェーンオブトラストを繋げていくことができます。また、IoT デバイスとクラウドサービスから構成されるような広範囲に及ぶシステムは特に信頼が必要になります。信頼できるセキュリティ基盤を構築するためには、構成するソフトウェアが正規のリリース物であることを確認することが重要になります。チェーンオブトラストを採用することでより信頼できる IoT システムとなり得るのです。 では、どういったケースでセキュアブートを採用するべきでしょうか。セキュアブートはセキュアな組み込みデバイスを実現する上で最初のステップにするべき技術です。しかし、導入するのであればコスト面にも配慮することが必要でしょう。まず、製造時の追加コストが必要です。鍵等を書き込む工程が必要になります。ただ書き込めばよいわけではなく、漏洩があってはいけないので物理的な隔離などセキュアに書き込む必要があります。メンテナンスにも追加のコストが必要です。ソフトウェアのリリース時にはソフトウェアの署名が必要になります。こちらも、物理的な隔離などの漏洩、汚染対策が必要になります。また、どこまでやるかによりますが、定期的な鍵の更新、インシデントや製品寿命による鍵のリボーケーションなどのメンテナンスコストが必要になってきます。費用対効果を検討してからの導入をお勧めします。 HAB (High Assurance Booting) は、NXP Semiconductors が提供するセキュアブートの実装です。i.MX 8M Plus の BootROM には HABv4 が組み込まれます。デフォルトでは無効な状態になっていますが、一度、eFuse に情報を書き込むことでセキュアブートが有効になり、それ以降、有効な状態のまま変更不可能になります。HABv4 で規定する仕様では次の情報をブートローダーイメージに追加することで BootROM が起動時にブートローダーの認証を行います。 -
CSF (Command Sequence File)、IVT (Image Vector Table)
-
SRK (Super Root Key)、CSF、IMG 署名確認鍵
-
イメージの署名
NXP Semiconductors は署名ツールとして CST (Code Signing Tool) をリリースしています。本来、署名範囲などは環境によって様々な実装がなされるべきなので署名ツール自体にはその辺りの仕様が含まれません。ブートローダーの実装仕様に依存します。Armadillo Base OS で採用される uboot-imx のセキュアブート処理では、Trusted Firmware-A (ATF)、OP-TEE OS、Linux カーネルイメージまでが認証の対象になります。署名に関する概要は以下のとおりです。 -
署名確認用の鍵は X.509 証明書に対応する
署名は RSA に対応する
-
1024, 2048, 3072, 4096 bits
-
署名のダイジェストは SHA256 のみ
| |
---|
HAB の詳しい仕様は以下を参照してください。 |
NXP Semiconductors からリリースされる署名ツール (cts)、設定ファイルを準備してから、鍵の証明書を生成します。 ディレクトリ構成の一部抜粋は以下のとおり。 ├── cst_3.3.1
│ ├── crts
│ ├── keys
│ └── linux64/bin
├── imx-boot
├── linux-[VERSION]
├── build-rootfs-[VERSION]
├── csf
└── out |
本マニュアルでは v3.3.1 を利用した
| |
ブートローダーに組み込む自己証明書群が配置される
| |
鍵の生成ツール、生成された鍵が配置される
| |
ビルド済み署名ツールが配置される
| |
CSF が配置される
| |
署名済みイメージが配置される
|
NXP Semiconductors から署名ツールをダウンロードします
以下のサイトからダウンロードします。ここではユーザーが NXP Semiconductors のサイトで最新版を検索してダウンロードすることを想定しています。 | |
---|
-
ダウンロードには NXP Semiconductors サイトへのユーザー登録が必要になります
-
本マニュアル作成時点では v3.3.1 を利用しました
|
ツールを展開します
[PC ~]$ tar -xaf cst-3.3.1.tgz
11.5.3.3. シリアル番号、パスワードを設定するPKI 証明書を作るために、証明書のシリアル番号、パスワードを事前に作っておく必要があります。
シリアル番号ファイルとパスワードファイルを作ります。 シリアル番号とパスワードは任意の値を設定してください。 [PC ~]$ cd cst-3.1.1/keys
[PC ~/cst-3.1.1/keys]$ echo "12345678" > serial
[PC ~/cst-3.1.1/keys]$ echo "pass_phrase" > key_pass.txt
[PC ~/cst-3.1.1/keys]$ echo "pass_phrase" >> key_pass.txt セキュアブート用の PKI tree を作ります。生成する鍵とその証明書は以下のとおりです。 表11.3 セキュアブート用の鍵と証明書 name | description | file name |
---|
CA 鍵ペア | ルート CA | CA1_sha256_[alg]_v3_ca_crt | SRK 鍵ペア | Super Root Key 用の鍵ペア | SRK[n]_sha256_[alg]_v3_ca_key | CSF 鍵ペア | CSF 用の鍵ペア | CSF[n]_sha256_[alg]_v3_usr_key | IMG 鍵ペア | イメージ用の鍵ペア | IMG[n]_sha256_[alg]_v3_usr_key | SRK 証明書 | CA 鍵によって署名されたSRK 公開鍵を含んだ証明書 | SRK[n]_sha256_[alg]_v3_ca_crt | CSF 証明書 | SRK によって署名された CSF 公開鍵を含んだ証明書 | CSF[n]_sha256_[alg]_v3_usr_crt | IMG 証明書 | SRK によって署名された IMG 公開鍵を含んだ証明書 | IMG[n]_sha256_[alg]_v3_usr_crt |
-
[alg]: アルゴリズム
[n]: n = 1,2,3,4
鍵を生成する
既存の CA 証明書を利用せずに、例として期限5年の4本の RSA-2048 の鍵を生成する。 [PC ~/cst-3.1.1/keys]$ ./hab4_pki_tree.sh -existing-ca n \
-use-ecc n -kl 2048 \
-duration 5 \
-num-srk 4 \
-srk-ca y |
既存の CA 証明書を利用するかどうか
| |
-use-ecc は ECC を利用するかどうか。-kl は鍵長。-use-ecc が n の場合は RSA になる
| |
期限は5年
| |
SRK の数は4本
| |
標準的な PKI ツリー
|
| |
---|
生成した鍵は今後も利用するものです。壊れにくい、セキュアなストレージにコピーしておくことをお勧めします。 |
| |
---|
鍵の更新は計画性を持って行ってください。たとえば開発時のみ利用する鍵、運用時に利用する鍵を使い分ける。また、鍵は定期的に更新が必要です。以下を参考にしてください。 |
| |
---|
-
詳しくは cst 内の docs ディレクトリにある CST_UG.pdf をご参照ください
-
自己署名証明書の場合は、hab4_pki_tree.sh の実装として、openssl-req の subj オプションで CN=CA1_sha256_[alg]_v3_ca のみを設定している
|
生成された鍵の確認
以下のファイルが生成されたことを確認してください。 cst-3.3.1
├── crts
│ ├── CA1_sha256_2048_65537_v3_ca_crt.der
│ ├── CA1_sha256_2048_65537_v3_ca_crt.pem
│ ├── CSF1_1_sha256_2048_65537_v3_usr_crt.der
│ ├── CSF1_1_sha256_2048_65537_v3_usr_crt.pem
│ ├── CSF2_1_sha256_2048_65537_v3_usr_crt.der
│ ├── CSF2_1_sha256_2048_65537_v3_usr_crt.pem
│ ├── CSF3_1_sha256_2048_65537_v3_usr_crt.der
│ ├── CSF3_1_sha256_2048_65537_v3_usr_crt.pem
│ ├── CSF4_1_sha256_2048_65537_v3_usr_crt.der
│ ├── CSF4_1_sha256_2048_65537_v3_usr_crt.pem
│ ├── IMG1_1_sha256_2048_65537_v3_usr_crt.der
│ ├── IMG1_1_sha256_2048_65537_v3_usr_crt.pem
│ ├── IMG2_1_sha256_2048_65537_v3_usr_crt.der
│ ├── IMG2_1_sha256_2048_65537_v3_usr_crt.pem
│ ├── IMG3_1_sha256_2048_65537_v3_usr_crt.der
│ ├── IMG3_1_sha256_2048_65537_v3_usr_crt.pem
│ ├── IMG4_1_sha256_2048_65537_v3_usr_crt.der
│ ├── IMG4_1_sha256_2048_65537_v3_usr_crt.pem
│ ├── SRK1_sha256_2048_65537_v3_ca_crt.der
│ ├── SRK1_sha256_2048_65537_v3_ca_crt.pem
│ ├── SRK2_sha256_2048_65537_v3_ca_crt.der
│ ├── SRK2_sha256_2048_65537_v3_ca_crt.pem
│ ├── SRK3_sha256_2048_65537_v3_ca_crt.der
│ ├── SRK3_sha256_2048_65537_v3_ca_crt.pem
│ ├── SRK4_sha256_2048_65537_v3_ca_crt.der
│ └── SRK4_sha256_2048_65537_v3_ca_crt.pem
└── keys
├── CA1_sha256_2048_65537_v3_ca_key.der
├── CA1_sha256_2048_65537_v3_ca_key.pem
├── CSF1_1_sha256_2048_65537_v3_usr_key.der
├── CSF1_1_sha256_2048_65537_v3_usr_key.pem
├── CSF2_1_sha256_2048_65537_v3_usr_key.der
├── CSF2_1_sha256_2048_65537_v3_usr_key.pem
├── CSF3_1_sha256_2048_65537_v3_usr_key.der
├── CSF3_1_sha256_2048_65537_v3_usr_key.pem
├── CSF4_1_sha256_2048_65537_v3_usr_key.der
├── CSF4_1_sha256_2048_65537_v3_usr_key.pem
├── IMG1_1_sha256_2048_65537_v3_usr_key.der
├── IMG1_1_sha256_2048_65537_v3_usr_key.pem
├── IMG2_1_sha256_2048_65537_v3_usr_key.der
├── IMG2_1_sha256_2048_65537_v3_usr_key.pem
├── IMG3_1_sha256_2048_65537_v3_usr_key.der
├── IMG3_1_sha256_2048_65537_v3_usr_key.pem
├── IMG4_1_sha256_2048_65537_v3_usr_key.der
├── IMG4_1_sha256_2048_65537_v3_usr_key.pem
├── SRK1_sha256_2048_65537_v3_ca_key.der
├── SRK1_sha256_2048_65537_v3_ca_key.pem
├── SRK2_sha256_2048_65537_v3_ca_key.der
├── SRK2_sha256_2048_65537_v3_ca_key.pem
├── SRK3_sha256_2048_65537_v3_ca_key.der
├── SRK3_sha256_2048_65537_v3_ca_key.pem
├── SRK4_sha256_2048_65537_v3_ca_key.der
└── SRK4_sha256_2048_65537_v3_ca_key.pem
SRK テーブルと SRK ハッシュテーブルを生成する
以下のコマンドを実行してください。 [PC ~/]$ cd cst-3.3.1/crts
[PC ~/cst-3.3.1/crts]$ ../linux64/bin/srktool --hab_ver 4 --digest sha256 \
--table SRK_1_2_3_4_table.bin --efuses SRK_1_2_3_4_fuse.bin --fuse_format 1 \
--certs "./SRK1_sha256_2048_65537_v3_ca_crt.pem,./SRK2_sha256_2048_65537_v3_ca_crt.pem,./SRK3_sha256_2048_65537_v3_ca_crt.pem,./SRK4_sha256_2048_65537_v3_ca_crt.pem" 以下の2つのファイルが生成されていれば成功です。 [PC ~/cst-3.3.1/crts]$ ls
: (省略)
SRK_1_2_3_4_fuse.bin
SRK_1_2_3_4_table.bin
: (省略)
生成した鍵と証明書を用いてセキュアブートを有効にしていきます。 | |
---|
セキュアブート有効後は、基本的に起動毎に署名確認が実行されるようになります。既に eMMC に書かれている署名されていないファームウェアは起動に失敗するようになります。そのため、署名済みイメージを書き込む作業が必要になります。セキュアブートを有効にする前に、一度 「セキュアブート有効後のファームウェアの書き込みについて」 に目を通すことをお勧めします。 |
11.5.4.1. eFuse に SRK ハッシュを書き込むセキュアブートを有効にするためには、i.MX 8M Plus の eFuse に SRK のハッシュ値を書く必要があります。i.MX 8M Plus の OCOTP (On-chip One-Time Programmable Element Controller) のレジスタ経由で書き込むことになります。uboot-imx には OCOTPA へのアクセスを行う fuse コマンドがあります。
生成されたハッシュ値を確認する
PC 上の cst ディレクトリで、以下のコマンドでハッシュ値を表示する [PC ~]$ cd cst/crts
[PC ~/cst/crts]$ hexdump -e '1/4 "0x"' -e '1/4 "%X""\n"' SRK_1_2_3_4_fuse.bin 結果の例 (ハッシュ値は生成された鍵毎に異なります) 0x72DBC22F
0xDCAB0F6E
0xBEBA9104
0x35E61298
0x768FA4B5
0x2179343B
0x92BF13D4
0x461BAE7C
ハッシュ値を書き込む
| |
---|
eFuse は OTP なので一度作業を行うと変更はできません。注意して作業してください。 |
| |
---|
ハッシュ値は生成された鍵毎にことなります。例の値をそのまま書かないで下さい。 |
書き込みコマンドのヘルプです。 fuse prog [-y] <bank> <word> <hexval> [<hexval>...] u-boot コマンドを利用して、確認したハッシュ値を eFuse に書いていきます。u-boot プロンプトを立ち上げてください。 以下に例を示します (あくまで例なのでそのまま書かないでください)。 u-boot=> fuse prog 6 0 0x72DBC22F
u-boot=> fuse prog 6 1 0xDCAB0F6E
u-boot=> fuse prog 6 2 0xBEBA9104
u-boot=> fuse prog 6 3 0x35E61298
u-boot=> fuse prog 7 0 0x768FA4B5
u-boot=> fuse prog 7 1 0x2179343B
u-boot=> fuse prog 7 2 0x92BF13D4
u-boot=> fuse prog 7 3 0x461BAE7C 1つのコマンドのログは以下のように出力されます。 u-boot=> fuse prog 6 0 0x72DBC22F
Programming bank 6 word 0x00000000 to 0x72dbc22f...
Warning: Programming fuses is an irreversible operation!
This may brick your system.
Use this command only if you are sure of what you are doing!
Really perform this fuse programming? <y/N>
y
SRK 領域をロックする
このままでは SRK 領域はビットの状態によっては書き込み可能な状態なのでロックする必要があります。 u-boot=> fuse prog 0 0 0x200
11.5.5. セキュアブート有効後のファームウェアの書き込みについてセキュアブートを有効にした直後の初回書き込みは、再起動による再試行が可能な SD ブートを利用します。SD ブートを利用して署名済みイメージの書き込みが成功したのちには、Armadillo Base OS のファームウェアアップデート機能の利用が再び可能になります。 以下は初回とそれ以降のファームウェア書き込みの流れです。 セキュアブート有効直後の初回書き込み 二回目以降の書き込み セキュアブートで利用するブートローダーイメージを署名していきます。
Armadillo Base OS を利用した署名済みイメージを生成するまでの流れは以下のとおりです。 -
ブートローダーをビルドする
-
イメージ情報を抽出する
-
CSF 設定ファイルを書く
-
CST を実行する
-
ブートローダーイメージに CSF ファイルを書き込む
ソースコードの取得を行うために 「Armadilloのソフトウェアをビルドする」 の章を参考にしてビルド環境の構築からブートローダーのビルドまでを事前に行ってください。
uboot-imx のコンフィグを変更する
x2_defconfig に CONFIG_IMX_HAB=y を追加する [PC ~]$ cd imx-boot/uboot-imx/
[PC ~/imx-boot/uboot-imx]$ vi configs/x2_defconfig
CONFIG_IMX_HAB=y
ブートローダーを再ビルドする
「ブートローダーを再ビルドする」 を参考にして、ブートローダーのバージョンを変更してから、ブートローダーのビルドを行ってください。
11.5.6.2. ブートローダーイメージの情報を取得するNXP Semiconductors が提供する cst (code signing tool) はイメージを署名をする機能、CSF をつくる機能を持っているだけで、実際にどの部分を署名するのかは実装依存となっています。Armadillo Base OS では uboot-imx を採用しているので、uboot-imx のガイドに従うことになります。uboot-imx のガイドによると、ビルドログに含まれている情報を抜き出して CSF ファイルを作成するように書かれています。イメージの詳しい情報については 図11.7「ブートローダーの署名済みイメージ」 を参照してください。 取得する情報は以下のとおりです。 表11.4 署名済みイメージ向けの情報 name | description | source | example |
---|
csf_off | SPL CSF の情報 | ビルドログ OFFSET dump | csf_off 0x22e00 | sld_csf_off | 2nd loader CSF の情報 | ビルドログ 中の OFFSET dump | sld_csf_off 0x59020 | spl hab block | SPL IVT, SPL イメージの情報 | ビルドログ 中の OFFSET dump | spl hab block: 0x91ffc0 0x0 0x22e00 | sld hab block | 2nd loader IVT (uboot, atf, op-tee, dtb が記載される) の情報 | ビルドログ 中の OFFSET dump | sld hab block: 0x401fcdc0 0x58000 0x1020 | fit_hab | 2nd loader (uboot, atf, op-tee, dtb) イメージの情報 | make print_fit_hab | 0x40200000 0x5B000 0xCC1E8 … |
ビルドログから情報を抽出する
ブートローダーのビルドログの一番最後のログに情報があります。抜き出してください。以下の結果は例となります。そのまま利用しないでください。 ========= OFFSET dump =========
Loader IMAGE:
header_image_off 0x0
dcd_off 0x0
image_off 0x40
csf_off 0x22e00
spl hab block: 0x91ffc0 0x0 0x22e00
Second Loader IMAGE:
sld_header_off 0x58000
sld_csf_off 0x59020
sld hab block: 0x401fcdc0 0x58000 0x1020 |
SPL CSF の情報
| |
SPL IVT と SPL image の情報
| |
2nd loader CSF の情報
| |
2nd loader IVT の情報
|
print_fit_hab から情報を抽出する
以下コマンドを実行して <1> の部分をメモする。以下の結果は例となります。そのまま利用しないでください。 [PC ~]$ cd imx-boot
[PC ~/imx-boot]$ make -C imx-mkimage/armadillo_x2 -f soc.mak SOC=iMX8MP print_fit_hab
make: Entering directory '/home/xxx/imx-boot/imx-mkimage/armadillo_x2'
./../scripts/dtb_check.sh imx8mp-evk.dtb evk.dtb
Use u-boot DTB: imx8mp-evk.dtb
./../scripts/pad_image.sh tee.bin
./../scripts/pad_image.sh bl31.bin
./../scripts/pad_image.sh u-boot-nodtb.bin evk.dtb
u-boot-nodtb.bin + evk.dtb are padded to 866464
TEE_LOAD_ADDR=0x56000000 ATF_LOAD_ADDR=0x00970000 VERSION=v2 ./print_fit_hab.sh 0x60000 evk.dtb
0x40200000 0x5B000 0xCC1E8
0x402CC1E8 0x1271E8 0x76B8
0x970000 0x12E8A0 0xA150
0x56000000 0x1389F0 0x206600
make: Leaving directory '/home/xxx/imx-boot/imx-mkimage/armadillo_x2' |
2nd loader (u-boot, atf, op-tee, dtb) のイメージ情報
|
csf_spl.txt を作る
以下のコマンドを実行して下さい。 [PC ~]$ mkdir -p csf
[PC ~]$ cd csf
[PC ~/csf]$ vi csf_spl.txt 以下は csf_spl.txt のサンプルです。注釈のある行以外はそのまま利用してください。 [Header]
Version = 4.3
Hash Algorithm = sha256
Engine = CAAM
Engine Configuration = 0
Certificate Format = X509
Signature Format = CMS
[Install SRK]
File = "cst-3.3.1/crts/SRK_1_2_3_4_table.bin"
Source index = 0
[Install CSFK]
File = "cst-3.3.1/crts/CSF1_1_sha256_2048_65537_v3_usr_crt.pem"
[Authenticate CSF]
[Install Key]
Verification index = 0
Target index = 2
File = "cst-3.3.1/crts/IMG1_1_sha256_2048_65537_v3_usr_crt.pem"
[Authenticate Data]
Verification index = 2
Blocks = 0x91ffc0 0x0 0x22e00 "imx-boot/imx-boot_armadillo_x2"
[Unlock]
Engine = CAAM
Features = MID |
SRK テーブルファイルを指定する
| |
SRK1 (0 はじまり) を指定する
| |
CSF1 ファイルを指定する
| |
IMG1 ファイルを指定する
| |
spl hab block の情報を書き込む
|
csf_fit.txt をつくる
以下のコマンドを実行して下さい。 [PC ~]$ cd csf
[PC ~/csf]$ vi csf_fit.txt 以下は csf_fit.txt のサンプルです。ここでは csf_spl と鍵は同一です。注釈のある行以外はそのまま利用してください。 [Header]
Version = 4.3
Hash Algorithm = sha256
Engine = CAAM
Engine Configuration = 0
Certificate Format = X509
Signature Format = CMS
[Install SRK]
File = "cst-3.3.1/crts/SRK_1_2_3_4_table.bin"
Source index = 0
[Install CSFK]
File = "cst-3.3.1/crts/CSF1_1_sha256_2048_65537_v3_usr_crt.pem"
[Authenticate CSF]
[Install Key]
Verification index = 0
Target index = 2
File = "cst-3.3.1/crts/IMG1_1_sha256_2048_65537_v3_usr_crt.pem"
[Authenticate Data]
Verification index = 2
Blocks = 0x401fcdc0 0x58000 0x1020 "imx-boot/imx-boot_armadillo_x2", \
0x40200000 0x5B000 0xCC1E8 "imx-boot/imx-boot_armadillo_x2", \
0x402CC1E8 0x1271E8 0x76B8 "imx-boot/imx-boot_armadillo_x2", \
0x970000 0x12E8A0 0xA150 "imx-boot/imx-boot_armadillo_x2", \
0x56000000 0x1389F0 0x206600 "imx-boot/imx-boot_armadillo_x2" |
sld hab block の情報を1行目
| |
それ以降の署名対象について fit_hab の情報を書き込む
|
CSF 設定ファイルから CSF ファイルを作ります。 csf_spl.bin を作ります。 [PC ~]$ mkdir -p out
[PC ~]$ ./cst-3.3.1/linux64/bin/cst -i csf/csf_spl.txt -o out/csf_spl.bin
Install SRK
Install CSFK
Authenticate CSF
Install key
Authenticate data
CSF Processed successfully and signed data available in out/csf_spl.bin csf_fit.bin を作ります。 [PC ~]$ ./cst-3.3.1/linux64/bin/cst -i csf/csf_fit.txt -o out/csf_fit.bin
Install SRK
Install CSFK
Authenticate CSF
Install key
Authenticate data
CSF Processed successfully and signed data available in out/csf_fit.bin 以下のファイルができていれば成功です。 [PC ~]$ ls out
csf_fit.bin csf_spl.bin 11.5.6.5. ブートローダーイメージに CSF ファイルを書き込むCSF をブートローダーイメージ内に予約された領域に書き込みます。seek で書き込み位置を合わせます。ここでのアドレス 0x22e0 と 0x59020 は例です。そのまま実行しないでください。 以下のコマンドを実行する。 [PC ~]$ cp imx-boot/imx-boot_armadillo_x2 out/signed_imx-boot_armadillo_x2
[PC ~]$ dd if=out/csf_spl.bin of=out/signed_imx-boot_armadillo_x2 seek=$((0x22e00)) \
oflag=seek_bytes bs=4K conv=notrunc
[PC ~]$ dd if=out/csf_fit.bin of=out/signed_imx-boot_armadillo_x2 seek=$((0x59020)) \
oflag=seek_bytes bs=4K conv=notrunc |
csf_off の情報を引数とする
| |
sld_csf_off の情報を引数とする
|
11.5.7. Linux カーネルイメージを署名するセキュアブートで利用する Linux カーネルイメージを署名していきます。
Armadillo Base OS を利用した署名済みイメージを生成するまでの流れは以下のとおりです。 -
イメージ情報を抽出して加工する
-
IVT を生成する
-
CSF 設定ファイルを書く
-
CST を実行する
-
Linux カーネルイメージに CSF を追加する
11.5.7.1. イメージ情報を抽出して加工する署名確認対象となる Linux カーネルイメージが実際にメモリに展開されるサイズを取得します。ビルドされた Linux カーネルイメージ (Image) は bss 領域などの領域が省略されます。そのため、ファイルサイズではなく、イメージの内部に組み込まれている値を取得します。 イメージ情報を抽出するために Linux カーネルイメージが必要です。ブートローダーのようにセキュアブート処理を有効にするために再ビルドが必要なわけではないので、ビルド済みイメージを用意するか、「Armadilloのソフトウェアをビルドする」 を参考に Linux カーネルをビルドするかしてください。
イメージ情報を抽出する
ファイルから16バイト目を32ビット分取得する。 [PC ~]$ hexdump -s 16 -n 4 -e '"0x""%X""\n"' linux-[VERSION]/arch/arm64/boot/Image 以下は結果の例です。 0x1E80000
イメージにパディングを追加する
省略される領域をパディングとして追加します。--pad-to に取得したサイズを入力します。ここでは 0x1E80000 を入力します。 [PC ~]$ objcopy -I binary -O binary --pad-to 0x1E80000 --gap-fill=0x00 \
linux-[VERSION]/arch/arm64/boot/Image out/Image_pad.bin
-
IVT 生成スクリプト (genIVT.pl) を編集する
コピーしてから編集します。 [PC ~]$ cp imx-boot/uboot-imx/doc/imx/habv4/script_examples/genIVT.pl out/
[PC ~]$ cd out
[PC ~/out]$ vi genIVT.pl イメージの編集箇所は以下のとおりです。Self Pointer と CSF Pointer を抽出した実際のサイズを基に変更します。イメージの構成についての詳細は 図11.8「Linux カーネルの署名済みイメージ」 を参考にしてください。それ以外の行はそのまま利用してください。 #! /usr/bin/perl -w
use strict;
open(my $out, '>:raw', 'ivt.bin') or die "Unable to open: $!";
print $out pack("V", 0x412000D1); # Signature
print $out pack("V", 0x40480000); # Load Address (*load_address)
print $out pack("V", 0x0); # Reserved
print $out pack("V", 0x0); # DCD pointer
print $out pack("V", 0x0); # Boot Data
print $out pack("V", 0x42300000); # Self Pointer (*ivt)
print $out pack("V", 0x42300020); # CSF Pointer (*csf)
print $out pack("V", 0x0); # Reserved
close($out); |
0x42300000 = [load_address] + [actual_image_size] = 0x40480000 + 0x1E80000
| |
0x42300020 = [ivt] + 0x20 = 0x42300000 + 0x20
|
IVT を生成する
以下のコマンドを実行してください。 [PC ~/out]$ perl genIVT.pl
IVT を追加する
パッドされた Linux カーネルイメージに IVT を追加します。以下のコマンドを実行してください。 [PC ~/out]$ cat Image_pad.bin ivt.bin > Image_pad_ivt.bin
デバイスツリーブロブのサイズを調べる
以下のコマンドを実行してください。 [PC ~]$ printf '0x%X\n' $(stat -c '%s' \
linux-[VERSION]/arch/arm64/boot/dts/freescale/armadillo_iotg_g4.dtb) 以下は結果の例です。 0xD112
csf_linux.txt を作る
以下のコマンドを実行して下さい。 [PC ~]$ cd csf
[PC ~/csf]$ vi csf_linux.txt 以下は csf_linux.txt のサンプルです。注釈のある行以外はそのまま利用してください。 [Header]
Version = 4.5
Hash Algorithm = sha256
Engine = CAAM
Engine Configuration = 0
Certificate Format = X509
Signature Format = CMS
[Install SRK]
File = "cst-3.3.1/crts/SRK_1_2_3_4_table.bin"
Source index = 0
[Install CSFK]
File = "cst-3.3.1/crts/CSF1_1_sha256_2048_65537_v3_usr_crt.pem"
[Authenticate CSF]
[Install Key]
Verification index = 0
Target index = 2
File = "cst-3.3.1/crts/IMG1_1_sha256_2048_65537_v3_usr_crt.pem"
[Authenticate Data]
Verification index = 2
Blocks = 0x40480000 0x00000000 0x01E80020 "out/Image_pad_ivt.bin", \
0x45000000 0x00000000 0xD112 "linux-[VERSION]/arch/arm64/boot/dts/freescale/armadillo_iotg_g4.dtb" |
Image_pad_ivt.bin のサイズを第3引数 (length) に入力する。ここでは 0x01E80020 の箇所。
| |
dtb のサイズを第3引数に入力する。ここでは 0xD112 の箇所。
|
CSF 設定ファイルから CSF ファイルを作ります。 csf_linux.bin を作ります。 [PC ~]$ ./cst-3.3.1/linux64/bin/cst -i csf/csf_linux.txt -o out/csf_linux.bin
Install SRK
Install CSFK
Authenticate CSF
Install key
Authenticate data
CSF Processed successfully and signed data available in out/csf_linux.bin 11.5.7.5. Linux カーネルイメージに CSF を追加するLinux カーネルイメージに CSF を追加することで署名が付加されることになります。 以下のコマンドを実行します。 [PC ~]$ cat out/Image_pad_ivt.bin out/csf_linux.bin > out/signed_Image 11.5.8. セキュアブート有効後の初回ファームウェアアップデートセキュアブートを有効にすると、既に書かれている署名されていないファームウェアでは基本的に起動ができなくなります。そのためファームウェアアップデートによって署名済みイメージを書き込む作業が必要になります。ただし、ファームウェアアップデートには注意が必要です。アップデート途中の電源断などが原因で Armadillo を再起動してしまうと、既に書かれていたファームウェアを起動することになるので起動に失敗してしまいます。そのため、セキュアブートを有効にした直後の書き込みは署名済みイメージが書かれた SD ブートを利用して eMMC を書き込みます。起動メディアを壊すことがないので再起動による再試行が可能です。 流れは以下の通りです。
署名イメージをつくる
リポジトリ alpine/build-rootfs を取得する
-
イメージを作る
-
イメージを microSD カードに書き込む
-
SD ブートでデバイスの eMMC を書き換える
PC 上で SD ブート用 microSD カードを作り、Armadillo に挿入して署名済みイメージを書いていきます。ここでは 「Alpine Linux ルートファイルシステムをビルドする」 で説明されているソースツリー alpine/build-rootfs にあるスクリプト build_image を利用します。
Linux カーネルイメージを参照するように変更する
以下のファイルを開きます。 [PC ~]$ vi ~/build-rootfs-[VERSION]/ax2/packages linux-at の行を消します。 : (省略)
dosfstools
atmark-x2-base
linux-at
crun
podman
: (省略)
Linux カーネルイメージとデバイスツリーを配置する
[PC ~]$ mkdir -p build-rootfs-[VERSION]/ax2/resources/boot
[PC ~]$ cp out/signed_Image build-rootfs-[VERSION]/ax2/resources/boot/Image
[PC ~]$ cp linux-[VERSION]/arch/arm64/boot/dts/freescale/armadillo_iotg_g4.dtb \
build-rootfs-[VERSION]/ax2/resources/boot/
ルートファイルシステムをビルドする
以下のコマンドを実行します。 [PC ~]$ cd build-rootfs-[VERSION]
[PC ~/build-rootfs-[VERSION]]$ sudo ./build_image.sh \
-B ../out/signed_imx-boot_armadillo_x2 成功すると以下の2つのファイルが生成されます。ファイル名に含まれる日付やバージョンはあくまで例です。 baseos-x2-3.14.3-at.1.20211124.img baseos-x2-3.14.3-at.1.20211124.tar.gz
イメージを作る
以下のコマンドを実行します。 [PC ~/build-rootfs-[VERSION]]$ sudo ./build_image.sh \
-B ../out/signed_imx-boot_armadillo_x2 \
--installer ./baseos-x2-[VERSION].img 成功すると以下のファイルが生成されます。ファイル名に含まれる日付やバージョンはあくまで例です。 baseos-x2-3.14.3-at.1.20211124-installer.img
SD ブート用 microSD カードをつくり、SD ブートする
「SDブートの活用」 を参考に baseos-x2-installer.img を microSD カードに書いて起動してください。このを microSD カードを利用すると SD ブートイメージのコピー (自分自身) を eMMC に書き込むように作られているので、セキュアブート用の署名付きイメージを書き込むことができます。最後にブートモードを戻して再起動すると署名済みイメージから起動するはずです。
Linux カーネルが立ち上がることを確認してください。
Linux カーネルまで立ち上がらない場合、uboot-imx のコマンドで HAB の状態を確認することができます。 Linux 起動まで正常な起動ログ : (省略)
Booting from mmc ...
## Checking Image at 40480000 ...
Unknown image format!
53522 bytes read in 22 ms (2.3 MiB/s)
Authenticate image from DDR location 0x40480000...
Secure boot enabled
HAB Configuration: 0xcc, HAB State: 0x99
No HAB Events Found!
## Flattened Device Tree blob at 45000000
Booting using the fdt blob at 0x45000000
Using Device Tree in place at 0000000045000000, end 0000000045010111
Starting kernel ...
: (省略) |
セキュアブートが有効な場合に表示されます
| |
問題がない場合はイベントが表示されません
|
ブートローダーに問題がある場合の起動ログ : (省略)
spl: ERROR: image authentication unsuccessful
### ERROR ### Please RESET the board ###
: (省略) Linux カーネルイメージに問題がある場合の起動ログ : (省略)
Authenticate image from DDR location 0x40480000...
bad magic magic=0x14 length=0xa1 version=0x0
bad length magic=0x14 length=0xa1 version=0x0
bad version magic=0x14 length=0xa1 version=0x0
Error: Invalid IVT structure
Allowed IVT structure:
IVT HDR = 0x4X2000D1
IVT ENTRY = 0xXXXXXXXX
IVT RSV1 = 0x0
IVT DCD = 0x0
IVT BOOT_DATA = 0xXXXXXXXX
IVT SELF = 0xXXXXXXXX
IVT CSF = 0xXXXXXXXX
IVT RSV2 = 0x0
Authenticate Image Fail, Please check
: (省略) |
認証に失敗しています
|
u-boot コマンドの hab_status 問題がない場合 u-boot=> hab_status
Secure boot enabled
HAB Configuration: 0xcc, HAB State: 0x99
No HAB Events Found! Linux カーネルイメージの署名確認で問題がある場合 u-boot=> hab_status
Secure boot disabled
HAB Configuration: 0xf0, HAB State: 0x66
--------- HAB Event 1 -----------------
event data:
0xdb 0x00 0x14 0x45 0x33 0x0c 0xa0 0x00
0x00 0x00 0x00 0x00 0x40 0x1f 0xdd 0xc0
0x00 0x00 0x00 0x20
STS = HAB_FAILURE (0x33)
RSN = HAB_INV_ASSERTION (0x0C)
CTX = HAB_CTX_ASSERT (0xA0)
ENG = HAB_ENG_ANY (0x00) 何らかのインシデント対応による鍵更新、また、鍵の定期更新などが必要な場合、その時点で利用している鍵を無効化して、別の鍵に切り替えることが可能です。ただし、その場合は複数 (i.MX 8M Plus の場合、最大4つ) の SRK が書かれていることが前提となります。 11.5.9.1. SRK の無効化 (revocation)ここでは SRK1 から SRK2 に変更する例を説明します。
csf_spl.txt に revocation のロックを解除するブロックを追加します
デフォルトでは eFuse の revoke レジスタはロックされているので書き込みできません。csf ファイルでロックを解除することができます。常にロックを解除すると攻撃者に悪用される可能性があるので通常時のセキュアブートではロックされるべきです。 csf_spl.txt を開いて、最後に Unlock ブロックを追加します。 [PC ~]$ vi csf/csf_spl.txt
: (省略)
[Unlock]
Engine = OCOTP
Features = SRK REVOKE
署名済みイメージを書き込む
「ブートローダーイメージを署名する」 を参考に署名済みイメージを生成して、イメージを書き込んでください。 -
再起動
Unlock を確認する
再起動時の uboot-imx のプロンプトを立ち上げてレジスタ値を確認します。以下のコマンドを実行してください。bit1 (SRK_REVOKE_LOCK) が落ちていると Unlock 状態です。 u-boot=> md 0x30350050 1
30350050: 00007dbc |
7dbc の bit 1 が経っていないので unlock 状態
|
SRK を無効化する
ビットフィールドはビットは 0 はじまりで、鍵の番号は 1 はじまり (1,2,3,4) になります。
bit0 が SRK1、bit1 が SRK2、bit2 が SRK3、bit3 が SRK4 です。 | |
---|
以下のコマンドはあくまで例なので、そのまま実行しないで下さい。 |
SRK1 を無効化する場合は以下のコマンドを実行してください。最終引数が無効化する鍵の設定値です。 u-boot=> fuse prog 9 3 1
ここでは SRK1 から SRK2 に変更する例を説明します。
SRK の変更
csf_spl.txt を開いて、[Install SRK] ブロックのインデックス (0,1,2,3) と [Install CSFK], [Install Key] のファイル番号(1,2,3,4) を目的のSRKへ変更する。 [PC ~]$ vi csf/csf_spl.txt
: (省略)
[Install SRK]
File = "~/cst-3.3.1/crts/SRK_1_2_3_4_table.bin"
Source index = 1
[Install CSFK]
File = "~/cst-3.3.1/crts/CSF2_1_sha256_2048_65537_v3_usr_crt.pem"
[Install Key]
File = "~/cst-3.3.1/crts/IMG2_1_sha256_2048_65537_v3_usr_crt.pem" |
SRK のインデックス (0,1,2,3) を変更先のインデックスに切り替える
| |
CSF ファイルの番号 (1,2,3,4) を変更先の番号に切り替える
| |
IMG ファイルの番号 (1,2,3,4) を変更先の番号に切り替える
|
再署名する
「ブートローダーイメージを署名する」 を参考に署名済みイメージを作成してください。
以下にブートローダーの署名済みイメージと展開先についての例を示します。緑色の部分が BootROM によって署名検証される部分、橙色の部分は SPL によって署名検証される部分になります。 Linux の署名済みイメージと展開先の例は以下のとおりです。水色の部分は u-boot によって署名検証される部分になります。 以下に SPL (Secondary Program Loader) のブートフローの概要を示します。点線で囲っている部分はセキュアブートで有効になる処理です。 u-boot のブートフローの概要は以下のとおりです。SPL と同様に点線で囲っている部分はセキュアブートで有効になる処理です。 | |
| | | |
| |