wolfBoot:セキュアブートの汎用フレームワーク

wolfBoot は、あらゆる種類の組み込みシステム向けのユニバーサルなセキュア ブートローダーです。

当初は 32 ビット マイクロコントローラを対象にしていましたが、今やさまざまなシステムやアーキテクチャにセキュアなブート ソリューションを実装するための完全なフレームワークへと成長しました。

これは主に wolfBoot の持つモジュール性と柔軟性によるものであり、これにより、特殊なユースケースにも再構成して適応することが簡単にできます。 以下では、実際のユースケースで扱ったカスタマイズ例をご紹介します。

外部デバイスに格納されたイメージで更新するケース

最も典型的なカスタマイズ例がこのタイプです。 wolfBoot は、外部ストレージ デバイスとして抽象化できるデバイスを扱うための”ext_flash”インターフェースを提供しています。 ext_flash は、特定のストレージ デバイスのコンテンツにアクセスするために、以下の関数呼び出しを実装するドライバーに wolfBoot を接続するインターフェイスです:

ext_flash_lock()

ext_flash_write()

ext_flash_read()

ext_flash_erase()

ext_flash_unlock()

マイクロプロセッサ ベースの組み込みシステムでは、多くの場合、「外部」ストレージデバイスが唯一のソリューションであり、さまざまなサポートデバイス (USB、SD、eMMC、SSD など) のカーネル イメージにアクセスするには特定のドライバーが必要です。 マイクロコントローラ アーキテクチャは、多くの場合、永続的なストレージとして使用できる外部 NOR SPI/QSPI フラッシュ メモリを統合しますが、通常はその上でコードを実行することはできません。

wolfBoot には、複数タイプの SPIフラッシュ メモリ チップを直接サポートするための追加レイヤーを持っています。 SPIサポートも ext_flash API インターフェイスの上に実装され、別のレベルの抽象化を提供します。 この場合、SPIコントローラーを使用して新しいターゲットに移植するには、次の単一の SPI 転送関数を実装するだけで済み、SPIレイヤーは必要な関数をリンクして、このインターフェイスを介してフラッシュにアクセスします:

spi_init()

spi_cs_on()

spi_cs_off()

spi_read()

spi_write()

spi_release()

SPIアクセスは、wolfBoot で利用できる例の 1 つにすぎず、サポートを任意の不揮発性メモリに拡張することができます。

近隣システムからオンデマンドでダウンロードしたイメージで更新するケース

wolfBoot にはストレージ デバイスと内部フラッシュ メモリへのアクセス以外の、ネットワーク スタックや通信機能を含めないという設計上の選択を行いました。この選択により、攻撃界面が非常に小さくなるのでセキュリティの観点から利点があり、さらに安全性の観点からもすべての構造とコード フローを簡単に追跡して予測可能に保つことができます。

ブート段階で他のシステムとの通信が必要となるケースがあります。フラッシュ メモリを分割して更新イメージ用のパーティションを確保することを避け、そのイメージを別の場所に保存している場合がそのケースです。このような場合には、隣接システムからファームウェア イメージを取得するために、wolfBoot が通信チャネル (通常はUARTやSPIなどのシリアル バスを介して)を開く必要があります。実際、このようなケースは、wolfBoot が非対称マルチプロセッサ システムまたは複数の異種コアを備えた一般的なシステムでブート手順を保護している場合に、かなり一般的な要件です。

wolfBoot からリモート コンテンツにアクセスするための推奨される方法は、仮想アドレス可能なメモリ空間を抽象化するカスタム ext_flash ドライバーを定義することです。 wolfBoot のコードベースには、提供された uart_flash_server POSIX アプリケーションに接続するクライアント エンドポイントを実行する ext_uart ドライバーのサンプルプログラムが含まれています。このドライバーは署名付与および暗号化されたファイルをエクスポートしてwolfBoot が処理およびステージングできるようにします。 EXT_UART は、外部フラッシュのサポートを物理ストレージのサポートと仮想アドレス空間にマップされた抽象化ストレージの両方に拡張できるモードの 1 つです。

サードパーティの鍵プロビジョニングを使用するケース

鍵プロビジョニングとは、メインの秘密鍵を生成、保存、および使用してファームウェア イメージに署名するプロセスのことです。このプロセスにはサード パーティのツールおよびそのツールを使った生成物が関係することもあります。 wolfBootの柔軟性のおかげで、一つのプロセスの中でサードパーティーの鍵ツールが署名プロセス内で生成した鍵(公開されたフォーマットで)とインポートした鍵の両方を扱うことができます。 公開鍵は実行時に wolfBoot によってすべて利用可能でアクセス可能でなければなりませんが、秘密鍵は各認証ファームウェアのヘッダーに署名するために使用されます。 実際の署名操作は、フェーズを分割して、マニフェスト ヘッダー構築処理から分離することができます。この方法では、署名は外部ツールによって実行され、wolfBootはイメージ更新操作中に秘密鍵にアクセスする必要はありません。 署名手順をカスタマイズする可能性の詳細については、wolfBoot 署名ツールのドキュメントを参照してください。

安全な保管庫へ鍵を格納するケース

ファームウェアの認証に使用される公開鍵を永続メモリの安全な書き込み保護領域に格納することは、適切なセキュア ブート メカニズムにとって最も重要なセキュリティ要件です。多くの場合、書き込み保護された領域から wolfBoot を実行し、鍵をブートローダ コードとともに C 配列に保存するだけで十分です。これは、wolfBoot に実装されているデフォルトのメカニズムです。

keygen ツールが公開鍵を生成またはインポートすると、実行時に署名検証に必要な公開鍵のローカル アーカイブの 二つのコピーが、二つの異なる形式で作成されます。ブートローダ イメージに組み込まれる C 配列 (keystore.c) と、同じ構造をバイナリ形式で含むバイナリ ファイル (keystore.der)です。

keystore.c 以外は、keystore.der のコンテンツを専用の安全なストレージまたは書き込み保護されたストレージだけに保管することができます。その為には安全な保管庫にアクセスするためのドライバーが必要となります。このドライバーは公開鍵、それらのサイズ、およびそれらの許可マスクを取得するための三つの関数をエクスポートする API を提供する必要があります。キーストアに別途の抽象化レイヤーを使用して、従来のセキュア エレメントや TPM の相互作用を超えてカスタマイズできるインターフェイスが提供され、実行時に鍵を処理するためのより複雑な構造を設計できます。キーストア構造に関する詳細情報は、wolfBoot ドキュメント ページで入手できます。

パーティション/イメージと鍵の組み合わせが必要なケース

複数ステージを持つブート レイアウトは非常に複雑になる可能性があります。弊社開発チームは、さまざまなレベルのアクセス許可を持つ一連のパーティションとファームウェア イメージを含むブート プロセスを初めて設計したときに、多くのことを学びました。それ以来、公開鍵の特定のサブセットで認証されたファームウェアを使用して、複数のアクターがパーティションの 1 つのサブセットのみを更新できるシナリオに何度か対処してきました。

セキュア ブートローダーと 二つのパーティションを備えた組み込みデバイスのシナリオを考えてみましょう。二つのパーティションの一つは「システム」パーティションで、おそらくTEE(Trusted Execution Environment)からセキュアモードで実行します。もう一つは「アプリケーション」パーティションで、登録されたユーザーによってアップロードされたコンフィギュレーション可能なソフトウェアを保持しています。この登録ユーザーはデバイスを所有しアクセス権を持っています。このケースでは、二つの鍵ペアが必要です。ユーザーは署名済みのアプリケーション更新イメージだけをアプリケーションパーティションにアップロード可能であり、一方製造者はシステムソフトウエアを更新できなければなりません(必要であればブートローダーも)。この2段階の権限では二つの別々の鍵ペアが必要となります。一つ目はユーザーに関連付けられ二 つ目の鍵ペア(一つ目より多くの権限を持つ)は製造者が保持する必要があります。

最新の wolfBoot は、キーストア構造のおかげで、最大 15 のターゲット パーティションをサポートし、それぞれを、キーストアの 一つまたは複数の公開鍵を使用して認証できます。 wolfBoot のファームウェア パッケージは、ファームウェアのインストール先パーティションを示す 0 ~ 15 の識別番号 (id) に常に関連付けられています。上記のシナリオでは、「システム」には id=1 が割り当てられ、「アプリケーション」ソフトウェアには id=2 が関連付けられます。 wolfBoot は自己更新手順、つまり wolfBoot 自体の新しい (署名された) バージョンを含む更新パッケージ用に id=0 を予約しています。 このメカニズムにより、更新メカニズムはすべての更新の一時ストレージとして同じ更新パーティションを使用できます。これは、wolfBoot が受信パッケージを解析し、マニフェスト ヘッダーを解析して、正しい鍵を使用してパッケージを処理するためです。前述のキーストア内の公開鍵オブジェクト要素には、各鍵を単一のターゲット パーティション ID に関連付けるビット マスクが含まれています。

非セキュアなブートを行うケース

wolfBoot は、公開鍵アルゴリズムと鍵サイズのさまざまな組み合わせをサポートしています。 ただし、場合によっては、ファームウェアの認証が必須ではありません。 SIGN=NONE でコンパイルすると、wolfBoot は適切に動作します。署名検証部分のみを除外し、他のすべての機能を維持して更新を容易にし、失敗した場合はロールバックし、転送後に SHA を使用してファームウェア イメージの整合性を検証します。 つまり、wolfBoot は非セキュアなブートローダーとして使用でき、フットプリントは数 KB で、起動時間への影響はほとんどありません。 リソースと CPU サイクルが限られている非常に小規模な低電力システムで特に役立ちます。

ライブラリとしてwolfBootを利用するケース

当社のユーザーの多くは、古い製品やデバイスをアップグレードし、以前のバージョンのレガシー ソフトウェアを再利用しながら、通常はセキュア ブート ソリューションの追加を意味するセキュリティ要件に対応しています。

新しいブートローダーをゼロから開始することは、開発およびテストの観点から見れば過小評価されることが多いですが、多くの開発チームは、何年にもわたって現場で維持および展開されてきた既存のソリューションに依存しています。一部のカスタム ブートローダー ソリューションにはネットワーク通信が含まれており、独自のプロトコルやデータ リンクを使用する場合があり、通常の wolfBoot に統合するには多大な労力が必要になります。一方、これらのレガシー ソリューションのほとんどには、暗号化セキュア ブートを実装するために必要なセキュリティ機能がありません。

このため、wolfBoot をライブラリとして構築できる手段も提供しています。ビルドアップ、ステージング、特定のハードウェア アクセス、カスタマイズされたフローを含むブートローダーの実装全体を提供する代わりに、「ライブラリとしての wolfBoot」はどこにでも完全に移植可能であり、マニフェスト ヘッダーの解析、バージョン管理のチェック、ロードまたはマップされたイメージの検証を行うための簡単なインターフェイスを提供します。提供されたキーストアに対する整合性と信頼性のためにメモリ内に。ホスト上の主要なツールは、完全な wolfBoot インストールの場合とまったく同じ方法で使用できます。フォーマットは同じままで、ハードウェアやアーキテクチャから完全に独立しているためです。 wolfBoot をライブラリとして使用する方法の詳細については、ライブラリ API に関するドキュメント ページを確認してください。

wolfBootのソースコードとドキュメントは弊社ダウンロードページからあるいはGitHubから取得できます。

原文:https://www.wolfssl.com/customized-ad-hoc-secure-boot-wolfboot/