Intel SGX / Open Enclave SDK
エンジニアの森田です。
先日、IETFにて策定中のTEEPプロトコルに関して、AIST塚本氏主催のハッカソンに参加してきました。 このハッカソンにはAIST, TRASIO, Secom, Roboc, Microsoft, Lepidumなど各方面からオンライン上で集まり、総勢10名が参加しました。 私は当日参加しただけで恐縮なのですが、事前にVPN、ビデオ会議といったインフラ整備を行い、当日はネットワークの疎通確認などからスタートする形で、初めての試みも多かった中、しっかり目標を達成できた素晴らしいハッカソンでした。
私は、参加者の一人であるDave Thaler氏が開発しているIntel Software Guard Execusion(Intel SGX)によるTEEP実装 をビルドし、動作検証する、という事に取り組みました。 実は、それまで私の使っているPCでIntel SGXを使ったプログラムのビルド/実行ができるという事を知らなかった(というかできないと思っていた)のですが、普通にIntel SGXに対応していたようです。
Dave氏のTEEP実装(現状Windowsのみがターゲット)ではEnclaveアプリケーション開発ツールとしてOpen Enclave SDKが使われているのですが、 今回の記事ではUbuntu上でOpen Enclave SDKを使い、Intel SGXを眺めてみたいと思います。 また、以前の記事で紹介したGlobal Platform APIベースのTrusted Application(TA)と、Enclaveアプリケーションの考え方の違いを掘り下げてみてみたいと思います。
Intel SGXについて
Intel Software Guard Extension(Intel SGX)とはハードウェアベースのメモリ暗号化によって重要なデータやコードをプロセスやOSから隔離し、セキュリティを強化する機能です。 以前の記事ではTrusted Execution Environment(TEE)のハードウェア実装としてARM TrustZoneが登場しましたが、Intel SGXはIntel CPUに実装されているTEE環境であると言えます。
Intel SGXのユースケースとしては鍵管理、コンテンツ保護など、セキュアなデータを扱う際に使われますが、特にクラウドサービスやエンタープライズでの利用が強調されています。
Intel SGXについての技術的な内容についてはCliffford氏によるQiita Intel SGX記事が詳しく、参考になります。
さて、ハードウェアによって隔離されたメモリ領域を作る、という点においてはIntel SGXとARM TrustZoneはTEEであるという意味では共通しているのですが、、 実際には想定する脅威、信頼の起点など、設計思想レベルでの違いも多く、ソフトウェアプログラマから見てもかなり差があります。 この点については後ほど詳しく見ていきたいと思います。
Enclaveとは
Intel SGXによって保護されるメモリ領域はEnclaveと呼ばれ、Enclave内のコードやデータは、プロセス内外からの攻撃から厳重に保護されます。 メモリ領域内は暗号的に保護されており、特にOSやハイパーバイザといった高い特権を持つプログラムからの盗み見、改竄といった脅威に対する安全を提供している事が特徴です。
まずEnclaveモデルの概念図を示します。 Enclaveはホストアプリケーションの内部に作成される隔離領域であり、Enclave内のデータやコードには限られた方法(ecall/ocall)でしかでアクセスできません。 またEnclaveとアクセスできるのはホストアプリケーションのみであり、OSであっても直接アクセスはできません、またEnclaveからOSに対して直接システムコールを呼び出すようなこともできません。

ARM TrustZoneとの差異
先程触れましたが、Intel SGXとARM TrustZoneには「ハードウェアによる隔離実行によりセキュリティを高める」という共通点はあるものの、異なる点もたくさんあります。 ハードウェア上の差異についてはこちらのスライドが参考になります。 特に以下の二つのハードウェア上の違いはソフトウェアの構成にも大きな影響を与えます。
- ARM TrustZoneがシステム起動時に一つの隔離実行環境が作成されるのに対して、Intel SGXが複数の隔離実行環境を動的に作成される
- ARM TrustZoneではすべての特権が利用可能であるのに対し、Intel SGXはEnclave内のコードを最も権限の低いユーザーモード(Ring 3)でしか実行できない
比較用にARM TrustZoneと相性のよいGlobal PlatformのTEEのモデルを示すと下の図のようになります。 この図を見てもらえるとわかるように、Global PlatformモデルではSecure WorldとNormal Worldの二つの世界に分かれ、 それぞれの世界にOS、アプリケーションが存在する、という前提があります。

Open Enclave SDK
Enclaveを利用したアプリケーションのための開発環境がIntelよりIntel SGX SDKとして提供されていますが、 今回注目するOpen Enclave SDKも同じくEnclaveアプリケーションを作成するための開発環境です。 Open Enclave SDKはIntel SGXに限らず、様々なTEEプラットフォーム(e.g. ARM TrustZone)に対してEnclaveアプリケーション開発環境を提供する事を目的としているようです。 現時点でIntel SGX以外のプラットフォームとして、Open Portable TEE OS(OP-TEE OS)のプレビューサポートが提供されています。
今回はOpen Enclave SDKの非常に単純なサンプルアプリケーションを眺める事で、 Enclaveアプリケーションの特徴を解説していきたいと思います。
以降、Open Enclave SDKを利用するための手順について、参考までに書いておきます。 基本的には公式のガイドに沿った方法ですが、本記事で説明するのはあくまでも私のマシン上でのインストール方法のみであり、 実際にはOSやCPUのIntel SGXサポート状況に依存して手順は大きく異なります。また、現時点でインストールできないマシン(CPU/マザーボード)も少なくないと思います。 読む必要がない方はEnclaveアプリケーションの特徴まで進んでください。
OS/SGXサポートの確認
筆者はUbuntu18.04の環境でOpen Enclave SDKをインストールしました。
uname -srvmo
Linux 5.3.0-42-generic #34~18.04.1-Ubuntu SMP Fri Feb 28 13:42:26 UTC 2020 x86_64 GNU/Linux
また、SGXハードのサポート状況によってもインストール方法が異なるので先に確認しておきます。 私の環境ではSGX1サポート有、SGX2サポート無、Launch Controlサポート無、という状況でした。
公式のツールではないようですが、SGXのサポート状況を知るにはこちらのツールが利用できました。このツールの使い方はこちらの記事で日本語で紹介されています。
SGXの有効化
まずはUEFI menuを起動してSGXを有効化します。 また本質的ではありませんが、Secure Bootをoffにしておきましょう。 これは後の作業でIntel SGX Driverのインストールが必要になりますが、Secure Bootがonの場合、ドライバに署名がついていないためインストールが失敗するからです。
Secure Bootをonの状態でIntel SGX Driverを利用するにはドライバに対してMachine-Owner Key(MOK)による署名を与える必要があります。
必要要件のインストール
git clone https://github.com/openenclave/openenclave
cd openenclave
sudo scripts/ansible/install-ansible.sh
ansible-playbook scripts/ansible/oe-contributors-setup-sgx1.yml
ビルド
mkdir build/
cd build/
cmake -DHAS_QUOTE_PROVIDER=OFF ..
make
インストール
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=~/openenclave-install ..
make install
本記事執筆時点で、cmakeのオプションとして2020/3/10に発表されたLVI脆弱性に対する緩和策を有効にするオプションが用意されていることが説明されています。 LVI脆弱性の緩和のためにパフォーマンスが大きく犠牲になると言われていることもあり、デフォルトではこのオプションは無効のようです。 今後、LVI脆弱性に対する洗練された対策が実現次第デフォルトで有効化されるなど、状況に応じて変わる可能性はあるかもしれません。
最後にlibsgx-launchというパッケージをインストールします。 理由は不明ですが、現時点では何故かこのパッケージは自動的にインストールされないようで、手動でインストールしました(参考issue)。
sudo apt-get install libsgx-launch
ここまできたら、以下のコマンドでテストを流してみましょう。 テストが通ればOpen Enclave SDKのインストール成功です。
ctest
サンプルのビルド/実行
ここではOpen Enclave SDKを使ってサンプルアプリケーションのビルドを行います。
まず、Open Enclave SDKのコマンド、ヘッダ等を環境変数の設定する必要があるのですが、 このあたりの設定を自動でやってくれるスクリプトがあるので使わせてもらいます。
source ~/openenc
lave-install/share/openenclave/openenclaverc
早速helloworldのサンプルをビルドして実行してみます。
cd ~/openenclave/samples/helloworld
make
make run
すると以下の様なメッセージが出力されるはずです。
host/helloworldhost ./enclave/helloworldenc.signed Hello world from the enclave Enclave called into host to print: Hello World!
Open Enclave SDKを使った標準的なビルド方法や、 今回ビルドしたhelloworldサンプルアプリケーションの作りや動作について、READMEに詳しく書かれています。 アプリケーションを作成するときには参考になると思います。
Enclaveアプリケーションの特徴
さて、ここではEnclaveアプリケーションの特徴について、サンプルコード、Global Platformとの比較を交えつつ紹介します。 今回紹介するのは以下の内容です。
- EDL/edger8r
- Enclave作成/呼出し方法
- Enclaveからのシステムコール
- Enclave同士の連携
EDL/edger8r
EnclaveプログラミングではEDLと呼ばれる独自の言語を利用し、Enclave内部とホストアプリケーションとの間のインターフェースを記述できます。
ホストアプリケーションからEnclave内の関数の呼出はecall、Enclave内からホストアプリケーションの関数の呼出はocallと呼ばれます。
サンプルコードのedlではecallとしてenclave_helloworld()
、ocallとしてhost_helloworld()
が定義されています。
OpenEnclave SDKではEDLをoeedger8r
と呼ばれるツールに渡す事でEnclaveとホストアプリケーションをブリッジするコードが生成される仕組みになっています(Intel SGX SDKでも同様の機能を持つツールがedger8r
として提供されています)。
サンプルコード中のビルド時にoeedger8r
によるコード生成が行われている事がわかると思います。
さて、EnclaveモデルとGlobal Platformモデルとの重要な違いはocallの存在です。 Global PlatformモデルではホストアプリケーションがTEEC APIを介してTAの処理を呼び出す事ができましたが、逆方向(TAからホストアプリケーション)への関数の呼出しは基本的にできません。
Enclave作成/呼出し方法
ホストアプリケーションがどのようにEnclave作成し、その内部の処理を呼び出すのかを見ていきたいと思います。
Enclaveのモデルではホストアプリケーションがそのプロセスの空間内に暗号的に保護された領域を作りだす、という形になります。
サンプルコードでは oe_create_helloworld_enclave()
という関数が呼び出れていますが、これもoeedger8r
によって生成される関数の一つで、Enclave領域の確保、作成を行います。
次に、edlにも記述したメインの処理であるenclave_helloworld()
を先程確保した領域を引数として与えて呼び出しています。
一方でGlobal Platformのモデルでは、システム起動時からNormal WorldとSecure Worldは分離されており、REE OS、TEE OSがそれぞれの空間で起動しています。 ホストアプリケーションからTrusted Applicationを指定はUUIDによって行われ、最終的なTrusted Applicationのメモリ割り当てや起動はTEE OSによって行われます。
Global Platform TEE APIのTA処理の呼出しであるInvokeCommand APIはインターフェースが大変汎用的に設計されている分、パラメータの受け渡しなどのコードが煩雑になりがちです。 アーキテクチャによる差異ではありませんが、edger8rやEDLといったツールが整備されているEnclaveアプリケーションでは、 関数呼び出しに近い形でEnclaveとホストアプリケーションのやり取りができますので、この点についてSDKとして優れているのではないかな、と個人的に感じます。
Enclaveからのシステムコール
基本的にEnclave内からはOSの機能に直接アクセスできません。 また、OSからも直接Enclave内の機能にアクセスできません。 ハードウェア的な観点から言っても、Intel SGXではEnclave内はユーザーモード(Ring 3)で実行され、システムコールは基本的に呼び出せないという事になっています。 従ってEnclaveからOSの機能を呼び出すときには、一度ocallによってホストアプリケーションに処理を移譲する必要があります。
一見、helloworldサンプルではシステムコールが発生するはずのfprintfをenclave内から直接呼び出しているように見えますが、 これは、Open Enclave SDKが一部のlibcの関数の呼出しをホスト側に移譲するコードをライブラリとして用意しており、実際のシステムコールはホストアプリケーション上で行われるようです。
OSが提供するシステムコールを利用できないEnclaveのモデルに対し、Global PlatformのモデルではTrusted World上にTEE OSが存在することが前提であり、 Trusted ApplicationはTEE OSが提供する機能は(主にGlobal Platform TEE APIを通して)そのまま利用できます。 Global Platform TEE APIではデータの永続化(Trusted Strage API)、周辺機器へのアクセス(Peripheral API)といった基本的な入出力についてサポートされます。
この観点において、Global Platformモデルでのセキュアアプリケーション開発はEnclaveモデルに比べてやりやすいといえるのではないでしょうか。
Enclave同士の連携
Enclaveは隔離されたメモリ領域であり、外部にアクセスする場合、ocallによってホストアプリケーションを経由する必要があります。 これは複数のEnclave領域を作成した場合に、Enclave同士が直接やりとりできない、という事を意味します。 また、間接的にやり取りするとしても、ホストアプリケーションに専用の実装が必要になります。
一方、Global PlatformのモデルではSecure WorldはOSや複数のアプリケーションを含む大きな世界であり、 TEE OSによって提供されるTEE API(Internal Clien API)を用いる事で、Trusted Applicationから別のTrusted Appliationの機能を呼び出す事ができます。 また、ホストアプリケーションから独立してTrusted Applicationを再利用できるといった利点もあります。
セキュアアプリケーション間の連携に関する制限の違いや、再利用性に関する考え方の違いは、 更新、削除といったセキュアアプリケーション自体のライフサイクルマネジメントにも影響を与えると思われます。
さいごに
本記事ではIntel SGXと、その開発環境であるOpen Encalve SDKについて紹介し、 Enclaveの概念について、Global Platform APIを使ったプログラミングモデルとの違いに注目しつつ、説明しました。
Intel SGX, ARM TrustZoneは両方ともTrusted Execution Environment(TEE)を実現する技術ですが、この概念はかなり広く、同じTEEと言っても実際のシステムはかなり違うものだという事を感じていただけたかと思います。
IETFのTEEP Working groupではTEE上のアプリケーションの更新、削除といったライフサイクル管理に関わるプロトコルが開発されています。 ここにおいても、ハードウェアアーキテクチャの違い、TEEのモデルの違いをどのように扱うかといった事は大きな課題になっているようです。
それぞれのアーキテクチャの良いところを活かせるようなプロトコルができるといいですね。