IoT Security 05 · セキュアブートとチェーンオブトラスト

Chapter 05

セキュアブートとチェーンオブトラスト

この章がなぜ必要なのか——ファームウェアの完全性は、全対策の前提だから.

どんなに立派な暗号を使っていても、 攻撃者が自分のファームウェアを起動できるなら、すべて無意味である。 鍵は読まれるし、TLS は無効化されるし、ログは偽造される。

だから 02 章で見たとおり、Tampering(改ざん)への対策が最優先になる。 その中核がセキュアブートである。

この章で使う既出の用語(定義は各リンク先). 可用性(01 章 4 節)、セキュアブート(02 章 3 節)、RSS(04 章 2 節)、ハッシュ(04 章 4 節)、署名検証(04 章 4 節)

1. 基本の仕組み

セキュアブートの流れ電源投入ブート ROM(Immutable RoT)1OTP から ROTPK のハッシュを読む2イメージ添付の公開鍵をハッシュして照合3その公開鍵でイメージの署名を検証4OK なら実行、NG なら停止/リカバリ第 2 段:ブートローダ / Updatable RoT同じことを次段に対して行う第 3 段:アプリケーション起動完了ここだけは更新できない= 最小限にする
各段が次段を検証してから制御を渡す。ROM は焼き切りなので、そこにバグがあると回収不能になる

「検証してから実行する」を繰り返す。 これがチェーンオブトラストである。

セキュアブートを段階実行する

各段で何が検証され、どこで失敗するとどうなるかを確かめられる。

2. 署名の中身

ファームウェアイメージは、典型的にはこういう構造になっている。

署名付きイメージの構造ヘッダマジック番号・バージョン・サイズ・ロードアドレス・アルゴリズム識別子セキュリティバージョン番号(SVN)ロールバック防止に使う(13 章)公開鍵(または鍵の識別子)OTP のハッシュと照合するペイロード(実際のコード)署名 = Sign( 秘密鍵, Hash(ヘッダ + ペイロード) )署名の対象に「ヘッダ」を含めることが重要。含めないとサイズや SVN を書き換えられる
ヘッダを署名対象から外した実装は実際に存在した。何を署名しているかを必ず確認する

検証手順

検証の中身 — どこでハードウェアに繋がっているかイメージヘッダ + コードハッシュ計算SHA-256署名検証公開鍵で復号して比較添付の公開鍵ハッシュして OTP と照合OTPROTPKハッシュここが「信頼の起点」添付された公開鍵をそのまま信じてはいけない。必ずシリコンに焼かれたハッシュと突き合わせる。この照合を飛ばすと、攻撃者は自分の鍵で署名したイメージを通せてしまう
署名検証そのものより、「どの公開鍵を信じるか」の決め方が本質。OTP のハッシュ照合が要になる
順処理失敗したら
1ヘッダのマジックとサイズを検証不正なイメージ。停止
2公開鍵のハッシュを OTP の値と照合鍵が違う。停止(最重要)
3ペイロード全体のハッシュを計算—
4署名を検証(公開鍵とハッシュで)改ざんまたは偽造。停止
5SVN が現在値以上か確認ロールバック攻撃。停止(13 章)
6実行—

手順 2 を飛ばす実装ミスが、実際に存在する.

「イメージに添付された公開鍵で署名を検証する」だけでは、まったく意味がない。 攻撃者は自分の鍵ペアを作り、自分の秘密鍵で署名し、自分の公開鍵を添付すればよい。

必ず「添付された公開鍵が、OTP に焼いた正規の鍵か」を確認すること。 これがチェーンを地面(RoT)に繋ぎ止める唯一の釘である。

3. 署名アルゴリズムの選択

アルゴリズム署名サイズ公開鍵サイズ検証速度備考
RSA-2048256 B256 B速い現在では最低限。長期には非推奨
RSA-3072384 B384 Bやや遅いRSA を使うならこれ以上
RSA-4096512 B512 B遅い高セキュリティ
ECDSA P-25664 B64 B中サイズが小さい。組み込み向き
ECDSA P-38496 B96 B遅めより高強度
EdDSA (Ed25519)64 B32 B速い実装が事故りにくい
ML-DSA (Dilithium)約 2.4 KB〜約 1.3 KB〜中耐量子。NIST 標準(FIPS 204)
SLH-DSA (SPHINCS+)約 8〜30 KB32 B遅い耐量子・ハッシュベース。FIPS 205
LMS / XMSS数 KB小速いステートフルハッシュ署名。NIST SP 800-208

なぜ検証速度が問題になるのか.

セキュアブートは毎回の起動時に走る。 起動時間の要求が厳しい機器(自動車の ECU は数十 ms で起動を求められることがある)では、 検証時間が製品要件を決める。

ハードウェアアクセラレータ(PKA / CASPER / SCE など)があるかどうかで、 10 倍以上の差が出る。08 章と 17 章〜21 章で各社の状況を見る。

耐量子への移行

暗号学的に意味のある量子計算機が実現すると、RSA と ECC は破られる。

事情内容
署名は「今」の問題ではない通信の暗号と違い、将来解読される心配はない(署名は機密性を持たない)
だが機器の寿命が長いと問題になる20 年動く機器の RoT が RSA だと、途中で破られる可能性がある
ブート ROM は変えられないImmutable RoT のアルゴリズムは選び直せない(04 章)

LMS / XMSS は既に一部のベンダが採用している。 ハッシュ関数だけで作られているので、量子計算機に対しても安全性が保たれる。 ただしステートフル——同じ鍵で同じ状態を 2 回使うと破綻する——ので、 署名側(工場・CI)の鍵管理が難しい。

実務的な指針.

4. 起動失敗時の設計

「検証に失敗したらどうするか」は、セキュリティと可用性のトレードオフである。

方針動作長所短所
完全停止 (brick)何も起動しない最も安全文鎮化。回収コスト
リカバリモードROM のリカバリ(USB/UART)で書き直せる復旧できるリカバリ経路が攻撃面になる
前バージョンへ戻す (A/B)もう一方の面から起動可用性が高いロールバック攻撃に注意(13 章)
限定機能で起動安全機能だけ動かす産業機器向け実装が複雑

リカバリモードは慎重に設計すること.

「ブートに失敗したら USB から書き込める」は便利だが、 攻撃者がわざとブートを失敗させてリカバリモードに入れるなら、 セキュアブートの意味がなくなる。

対策:

ウォッチドッグとの組み合わせ

/* 典型的な A/B ブートの制御 */
if (boot_count[active_slot] > MAX_BOOT_ATTEMPTS) {
    /* 何度やっても起動しきらない → もう一方の面へ */
    switch_to_other_slot();
}
boot_count[active_slot]++;
/* アプリケーションが「正常起動した」と確認したらクリアする */

「起動した」と「正常に動いている」は違う。 アプリケーションが自己診断を通って初めてカウンタをクリアする設計にすると、 起動はするが機能しない状態からも復帰できる。

5. 測定ブート(Measured Boot)との違い

セキュアブートと名前が似ていて混同されやすい仕組みに、測定ブートがある。 まず定義から。

測定ブートとは、起動の各段階で「これから実行するコードのハッシュ(=測定値)」を 計算し、書き換えできない場所に記録しながら起動していく方式である。 計測はするが、止めない。「実際に何が動いたか」の証拠を残すことが目的になる。

記録先には専用のレジスタを使う。代表が TPM の PCR(Platform Configuration Register) で、 上書きができず、

\[ \text{PCR} \leftarrow H(\text{PCR} \parallel \text{測定値}) \]

という「これまでの値と連結してハッシュ」する操作(extend)でしか更新できない。 だから起動後にマルウェアが「都合のよい値」に書き換えることはできない。 TPM を積まない MCU では、同じ性質を持つセキュアレジスタ(一方向にしか書けないレジスタ)で代用する。

この記録を 04 章のアテステーションでサーバに署名付きで報告すると、 「この機器でいま何が動いているか」を外部から検証できる。

セキュアブートとの違いを並べると:

セキュアブート測定ブート
やること検証して、ダメなら止めるハッシュを記録する(止めない)
目的不正なコードを実行させない何が動いているかを後から証明する
必要なもの署名検証、OTP の鍵ハッシュ格納先(TPM の PCR、セキュアレジスタ)
判断する主体機器自身リモートの検証者(アテステーション)
セキュアブートと測定ブートは目的が違うセキュアブート検証 → NG なら停止する機器の中で判断が完結する改ざんされたコードは動かない起動できない=現地で文鎮化する危険もある測定ブートハッシュを記録 → そのまま起動する判定は後からサーバが行う(04 章)改ざんされていても動きはする「動くが隔離される」運用ができる
止めるか、記録するか。両方を組み合わせて「起動はするが、サービスは受けられない」設計にすることも多い

両方使うのが理想である.

セキュアブートだけだと、「正規に署名された古い脆弱なバージョン」が動いていても 機器自身は気づけない。サーバ側で SVN を見て弾くことができるのが測定ブートの価値である。

6. XIP と外部フラッシュの扱い

MCU の場合、コードの置き場所によって難しさが変わる。

構成セキュアブートの難しさ
内部フラッシュのみ最も簡単。バスが外に出ない
外部フラッシュ → 内部 RAM にロードして実行検証してからコピー、コピー後に書き込み禁止
外部フラッシュを XIP(直接実行)最も難しい。実行中ずっとバスが露出

XIP の対策

対策内容各社の名称
オンザフライ復号フラッシュの内容を暗号化し、読むたびに復号するST: OTFDEC、NXP: PRINCE / BEE / OTFAD、Espressif: Flash Encryption
オンザフライ認証復号に加えて完全性も検証する対応する SoC は限られる
初回検証 + 実行時保護起動時に全体を検証し、以後は書き込みを禁止MPU / メモリ保護コントローラ

暗号化だけでは完全性を守れない、という点を繰り返し強調しておく.

AES-CTR や AES-XTS でフラッシュを暗号化しても、 攻撃者が暗号文をランダムに書き換えれば、復号結果もランダムに変わる。 それが命令として実行されると、予測不能な動作になる。

「ランダムなので攻撃に使えない」と思うかもしれないが、 何度も試して、都合のよい動作になる書き換えを探すことができる。 04 章で見たとおり、攻撃者は試行回数に制限がない。

完全性が要るなら、MAC か認証付き暗号(AEAD)が必要である。 ただしフラッシュに MAC を持つとオーバーヘッドが大きく、 XIP でこれをやるにはハードウェア支援が要る。対応品種は限られる。

7. 実装上の落とし穴

落とし穴何が起きるか対策
公開鍵を OTP と照合していない攻撃者の鍵で署名した偽物が通る必ず照合する(本章 2 節)
ハッシュの範囲がヘッダを含まないヘッダのロードアドレスを書き換えられるヘッダも署名対象に含める
サイズフィールドを信じてしまうバッファオーバーフロー上限を固定値で検査してから使う
検証と実行の間に隙があるTOCTOU(04 章)検証後に書き込み禁止/DMA 禁止
タイミング依存の比較ハッシュ比較でタイミング攻撃定時間比較を使う
フォールト 1 回で通る分岐電圧グリッチで検証をスキップ(10 章)二重チェック、ランダム遅延
エラー処理で分岐が抜ける失敗時に fall-through して起動デフォルトは「失敗」にする

安全な書き方の例

/* 悪い例: フォールト 1 回でスキップされる */
if (verify_signature(img) != OK) {
    halt();
}
jump_to(img);            /* ← グリッチで上の if を飛ばされたら実行される */

/* 良い例: デフォルトを失敗にして、二重に確認する */
volatile uint32_t v1 = MAGIC_FAIL, v2 = MAGIC_FAIL;

v1 = verify_signature(img);
random_delay();                          /* タイミングを揺らす */
v2 = verify_signature(img);              /* 二重検証 */

if (v1 != MAGIC_OK) halt();
if (v2 != MAGIC_OK) halt();
if (v1 != v2)       halt();
if ((v1 ^ v2) != 0) halt();              /* 冗長な確認 */

jump_to(img);

なぜここまでやるのか.

10 章で見るとおり、電圧グリッチによる分岐スキップは数万円の機材でできる。 単一の if に全体の安全性を賭けるのは危険すぎる。

MAGIC_OK に 0x5A5A5A5A のようなハミング距離の大きい値を使うのも定石である。 ビット反転が 1 個起きても、成功値にならない。

8. 各社の実装との対応(先取り)

概念STNXPEspressif章
Immutable RoTブート ROM + RSSROM の HAB/AHABブート ROM18〜20
ROTPK の保管オプションバイト / OTPSRK ハッシュを eFuse にeFuse の Secure Boot 鍵ダイジェスト18〜20
Updatable RoTSBSFU / TF-MMCUboot / TF-Mブートローダ(第 2 段)18〜20
外部フラッシュ暗号化OTFDECPRINCE / BEE / OTFADFlash Encryption18〜20
署名アルゴリズムECDSA / RSARSA / ECDSARSA-PSS 3072 / ECDSA18〜20

汎用のブートローダとしては、MCUboot が事実上の標準になりつつある。

特徴内容
出自Zephyr / Apache Mynewt から。現在は独立プロジェクト
対応多数の MCU、Zephyr / FreeRTOS / ベアメタル
機能署名検証、A/B スワップ、ロールバック防止、暗号化イメージ
署名RSA-2048/3072、ECDSA P-256、Ed25519

自作するより MCUboot を使うことを強く推奨する.

セキュアブートは「一見簡単だが、細部で必ず事故る」領域である。 上の落とし穴の表を見れば分かるとおり、罠が多すぎる。

広く使われている実装は、それだけ多くの目でレビューされ、 実際の攻撃で見つかった問題が修正されている。そこに乗るのが合理的である。

9. この章のまとめ

ポイント内容
仕組み検証してから実行を繰り返す。RoT から地面に繋がる
最重要の手順添付された公開鍵を OTP のハッシュと照合する。ここを飛ばすと無意味
アルゴリズム今なら ECDSA P-256 / RSA-3072。長寿命機器は PQC 移行を想定
検証速度毎起動に走る。ハードウェアアクセラレータの有無で 10 倍差
起動失敗時停止/リカバリ/A-B 切替。リカバリ経路も署名検証する
測定ブートとの違いセキュアブートは止める、測定ブートは記録して後で判定
XIP最も難しい。暗号化は機密性のみ。完全性には MAC/AEAD が要る
実装の要点デフォルトを失敗に、二重検証、定時間比較、フォールト対策
実装の選択MCUboot を使う。自作は罠が多すぎる

次章では、この全体の要——鍵をどこに、どう保管するかを扱う。