Chapter 05
セキュアブートとチェーンオブトラスト
この章がなぜ必要なのか——ファームウェアの完全性は、全対策の前提だから.
どんなに立派な暗号を使っていても、 攻撃者が自分のファームウェアを起動できるなら、すべて無意味である。 鍵は読まれるし、TLS は無効化されるし、ログは偽造される。
だから 02 章で見たとおり、Tampering(改ざん)への対策が最優先になる。 その中核がセキュアブートである。
この章で使う既出の用語(定義は各リンク先). 可用性(01 章 4 節)、セキュアブート(02 章 3 節)、RSS(04 章 2 節)、ハッシュ(04 章 4 節)、署名検証(04 章 4 節)
1. 基本の仕組み
「検証してから実行する」を繰り返す。 これがチェーンオブトラストである。
セキュアブートを段階実行する
各段で何が検証され、どこで失敗するとどうなるかを確かめられる。
2. 署名の中身
ファームウェアイメージは、典型的にはこういう構造になっている。
検証手順
| 順 | 処理 | 失敗したら |
|---|---|---|
| 1 | ヘッダのマジックとサイズを検証 | 不正なイメージ。停止 |
| 2 | 公開鍵のハッシュを OTP の値と照合 | 鍵が違う。停止(最重要) |
| 3 | ペイロード全体のハッシュを計算 | — |
| 4 | 署名を検証(公開鍵とハッシュで) | 改ざんまたは偽造。停止 |
| 5 | SVN が現在値以上か確認 | ロールバック攻撃。停止(13 章) |
| 6 | 実行 | — |
手順 2 を飛ばす実装ミスが、実際に存在する.
「イメージに添付された公開鍵で署名を検証する」だけでは、まったく意味がない。 攻撃者は自分の鍵ペアを作り、自分の秘密鍵で署名し、自分の公開鍵を添付すればよい。
必ず「添付された公開鍵が、OTP に焼いた正規の鍵か」を確認すること。 これがチェーンを地面(RoT)に繋ぎ止める唯一の釘である。
3. 署名アルゴリズムの選択
| アルゴリズム | 署名サイズ | 公開鍵サイズ | 検証速度 | 備考 |
|---|---|---|---|---|
| RSA-2048 | 256 B | 256 B | 速い | 現在では最低限。長期には非推奨 |
| RSA-3072 | 384 B | 384 B | やや遅い | RSA を使うならこれ以上 |
| RSA-4096 | 512 B | 512 B | 遅い | 高セキュリティ |
| ECDSA P-256 | 64 B | 64 B | 中 | サイズが小さい。組み込み向き |
| ECDSA P-384 | 96 B | 96 B | 遅め | より高強度 |
| EdDSA (Ed25519) | 64 B | 32 B | 速い | 実装が事故りにくい |
| ML-DSA (Dilithium) | 約 2.4 KB〜 | 約 1.3 KB〜 | 中 | 耐量子。NIST 標準(FIPS 204) |
| SLH-DSA (SPHINCS+) | 約 8〜30 KB | 32 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)の鍵管理が難しい。
実務的な指針.
- 今日設計するなら ECDSA P-256 か RSA-3072 が現実的
- Immutable RoT が複数アルゴリズムに対応しているチップを選ぶと将来が楽
- Updatable RoT で PQC に対応するという 2 段構えを想定しておく(04 章)
- ハイブリッド署名(古典 + PQC の両方を検証)という移行手法もある
4. 起動失敗時の設計
「検証に失敗したらどうするか」は、セキュリティと可用性のトレードオフである。
| 方針 | 動作 | 長所 | 短所 |
|---|---|---|---|
| 完全停止 (brick) | 何も起動しない | 最も安全 | 文鎮化。回収コスト |
| リカバリモード | ROM のリカバリ(USB/UART)で書き直せる | 復旧できる | リカバリ経路が攻撃面になる |
| 前バージョンへ戻す (A/B) | もう一方の面から起動 | 可用性が高い | ロールバック攻撃に注意(13 章) |
| 限定機能で起動 | 安全機能だけ動かす | 産業機器向け | 実装が複雑 |
リカバリモードは慎重に設計すること.
「ブートに失敗したら USB から書き込める」は便利だが、 攻撃者がわざとブートを失敗させてリカバリモードに入れるなら、 セキュアブートの意味がなくなる。
対策:
- リカバリで書き込むイメージも署名検証する(必須)
- リカバリモードへの入り方を制限する(特定の GPIO パターンなど)
- 量産品ではリカバリモードを OTP で無効化する(14 章)
ウォッチドッグとの組み合わせ
/* 典型的な 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) で、 上書きができず、
という「これまでの値と連結してハッシュ」する操作(extend)でしか更新できない。 だから起動後にマルウェアが「都合のよい値」に書き換えることはできない。 TPM を積まない MCU では、同じ性質を持つセキュアレジスタ(一方向にしか書けないレジスタ)で代用する。
この記録を 04 章のアテステーションでサーバに署名付きで報告すると、 「この機器でいま何が動いているか」を外部から検証できる。
セキュアブートとの違いを並べると:
| セキュアブート | 測定ブート | |
|---|---|---|
| やること | 検証して、ダメなら止める | ハッシュを記録する(止めない) |
| 目的 | 不正なコードを実行させない | 何が動いているかを後から証明する |
| 必要なもの | 署名検証、OTP の鍵 | ハッシュ格納先(TPM の PCR、セキュアレジスタ) |
| 判断する主体 | 機器自身 | リモートの検証者(アテステーション) |
両方使うのが理想である.
- セキュアブートで明らかな改ざんを止める
- 測定ブートで実際に何が動いているかをサーバに報告する(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. 各社の実装との対応(先取り)
| 概念 | ST | NXP | Espressif | 章 |
|---|---|---|---|---|
| Immutable RoT | ブート ROM + RSS | ROM の HAB/AHAB | ブート ROM | 18〜20 |
| ROTPK の保管 | オプションバイト / OTP | SRK ハッシュを eFuse に | eFuse の Secure Boot 鍵ダイジェスト | 18〜20 |
| Updatable RoT | SBSFU / TF-M | MCUboot / TF-M | ブートローダ(第 2 段) | 18〜20 |
| 外部フラッシュ暗号化 | OTFDEC | PRINCE / BEE / OTFAD | Flash Encryption | 18〜20 |
| 署名アルゴリズム | ECDSA / RSA | RSA / ECDSA | RSA-PSS 3072 / ECDSA | 18〜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 を使う。自作は罠が多すぎる |
次章では、この全体の要——鍵をどこに、どう保管するかを扱う。