この記事では、主にWindowsとLinuxを使うことを想定しつつ、セキュアブートの基本的な仕組みと周辺のソフトウェア、セキュアブートとTPMの有効性などについて説明する。
セキュアブートとは
セキュアブートは、従来のLegacy BIOSに変わる新しいファームウェア規格であるUEFIの一部として定められた機能で、起動(ブート)にあたってOS等の正当性を検証し、不正なプログラムの起動を防ぐものである。
UEFIにはブートの順番などさまざまな情報が変数(EFI変数、UEFI変数などと呼ばれる)として保持されており、UEFI BIOSメニューから、あるいはLinuxではefivarやmokutil(後述)やefibootmgr(後述)といったコマンドで閲覧・操作できる(UEFIの実装、あるいは変数によって、できないものもある)。
このうち、セキュアブートで主要な役目を果たすEFI変数は以下の4つである。
- db(Signature database)…信頼できるソフトウェアの署名を保持する。
- dbx(Forbidden Signature Database)…禁止されたソフトウェアの署名を保持する。実用的には、正当なバイナリとして一度はリリースされたものの脆弱であると判明したものの起動を防止するために用いられる。
これらに従って、起動するバイナリ(ファイル)をUEFIファームウェアが検証する。
https://uefi.org/specs/UEFI/2.10/03_Boot_Manager.html#globally-defined-variablesに予約されたEFI変数名の一覧があるようだが、dbとdbxはここに含まれておらず、https://uefi.org/specs/UEFI/2.10/32_Secure_Boot_and_Driver_Signing.htmlで説明されている。なぜかはわからなかった。
署名、鍵、ハッシュ
上ではやや省略して書いたが、dbとdbxにはハッシュ、鍵、署名のいずれも登録することができる。
- 鍵については、ファイルに署名が付いていて、その署名に使われた公開鍵と一致するものがデータベースにあるかどうかを見る。
- 複数のファイルに一致しうる。おそらく最も一般的に使われる。
- 署名については、ファイルについている署名それ自体と一致するものがデータベースにあるかどうかを見る。
- 署名とはハッシュを公開鍵で暗号化したものなので、やはり単一のefiファイルに対してのみ一致する。内容としては同じファイルでも署名に使った鍵が違ったり、逆に署名に使った鍵は同じでも別のファイルだったりしたら一致しないことになる。はず。
- 基本的には鍵を使う方法がメインになるので、今後は「ハッシュや署名がdbのものと一致するバイナリ」も含めて「db内の鍵で署名されたバイナリ」と呼ぶなど適宜サボった表記にする。
- 単一ファイルを対象とする「ハッシュ」「署名」については、dbxで使うのに便利そう。
- セキュリティホールが見つかった大量のイメージのハッシュがdbxに追加されているため次第に容量が足りなくなってきており、対策としてSBATというものが導入された。https://github.com/rhboot/shim/blob/main/SBAT.md や https://mjg59.dreamwidth.org/70348.html を参照。
後述のMOK(・MOKx)についても概ね似たような動作と考えてよいだろう。
ブートローダーなどについて
UEFIファームウェアがブートローダーと呼ばれる小さなEFIプログラムを起動し、そこから大きなOS全体が読み込まれていくという大まかな過程はWindowsでもLinuxでも同じである(Legacy BIOS時代も似たような流れ)。この部分はある程度既知とする。
参考
全体にわたり、Arch Wikiのhttps://wiki.archlinux.jp/index.php/Unified_Extensible_Firmware_Interfaceとhttps://wiki.archlinux.jp/index.php/Unified_Extensible_Firmware_Interface/セキュアブートは参考になる。ただし内容が多く、Arch独自の内容も含まれているので、いきなりこちらを読むのは難しそう。
Windowsでのセキュアブート
近年発売されるPCはほとんどセキュアブートに対応しており、Windows 11ではセキュアブートが必須要件として追加された。セキュアブート対応のWindows機には、Microsoftによるいくつかの鍵がもともと入っているので、ここではそれらを紹介する。
以下、「2023」と付いている新しい版のほうの名前で記載しているが、旧バージョンにあたる「2011」版もあり、これは2026年6月あるいは10月に署名の期限が切れる(とはいえ、ただちにPCが使えなくなるわけではない(はず))。
- 以下3つはdbに格納されている。
参考
更新の流れ
- 参考 https://note.com/dreamy_snail1789/n/n842ea9969718 長い記事だが、初心者にもわかりやすく書かれている。
古いWindows機には「2011」版の鍵しか入っていないが、有効期限が2026年に切れるため、更新が必要になる。基本的には、Windows Updateによって勝手に更新されるはず。2025年11月時点で筆者の(2023年よりは前に買った)ノートPCでは既に更新されていた(確認のためのコマンドは上記参考サイトにある)。
Microsoftのサポートページによると、具体的な流れとしては、
- DBに「Microsoft Corporation UEFI CA 2011」(3rd Party CA)がある場合、 「Microsoft Option ROM UEFI CA 2023」と「Microsoft UEFI CA 2023」をDBに追加
となる。
参考サイトでは、古い鍵を無効化(DBxに登録)するコマンドも書かれている。順番としては2より後のどこかで行うことになる。Windows Updateで更新した場合にこれが(どこで)行われるかは不明。
ところで、参考サイトに書かれている通り、一部PCではベンダー側の不手際により、まともなPKが入っておらず、Windows Updateでの更新ができない。この不具合は「PKFail」と呼ばれる。ちなみに筆者が持っている中華製のミニPC(TRIGKEY G4, BeeLink Mini S-12 Pro)はどちらもPKFailの状態になっていた。
これを修正するには、PKごと入れ替える必要がある。これについては次項で説明する。
Linuxでのセキュアブート: 独自の鍵を使う
では次に、Windows以外のOSをセキュアブートすることを考える。といっても、WindowsとmacOS(そもそもApple製以外のデバイスで動かすことを想定していない)を除くPC向けのOSというとほとんどはLinuxになるので、ここではLinuxを想定して書く。Linux以外のOSであっても、基本的な考え方は同じである。
このための方法としては、「独自の鍵を使う」「Microsoftの鍵を維持する」の2通りがある。この項では、まず独自の鍵を使う方法について述べる。
独自の鍵を使うというのは、つまり自分で作った好き勝手な鍵をdbに入れるということである。そんなことに対してMicrosoftやPCベンダーが署名してくれるはずがない。そうすると、セキュアブートの仕組み上、最上位のPKごと自分で作った鍵に置き換える必要がある。また、その上で改めてMicrosoftのKEKやdbを(自分のPKで適宜署名しつつ)追加することで、Windowsもデュアルブートできるようになる。
この内容はArch Wikiや、ブートローダーrEFIndの開発者Rod Smith(Roderick W. Smith)氏のこのページにかなり詳しく書いてある。
また前項の参考サイトで紹介されている「Mosby」は、この操作を勝手に(わりと安全に)やってくれる。筆者もこれで中華製ミニPCのPKFailを修正できた。Archなどで使われるsbctlも同様のツールである。
Arch Wikiでも何度か「文鎮化する可能性があります」と警告されている通り、この方法はそれなりにリスクを伴う。Microsoftを信頼できないと考えるならともかく、ただ単にWindows入りPCでセキュアブート有効のまま普通にLinuxを使いたいだけなら、次項の方法のほうが安全で楽である。
- ちなみに筆者はArch Wikiで言及されていたLenovo ThinkPad X1 Yoga Gen 5で、前述の「PCR7」関連エラーを修正するためにいくつかの鍵を削除したことがあった。記憶が正しければ、作業の過程で、「Microsoft Corporation KEK CA 2011」「Microsoft Windows Production PCA 2011」「Microsoft Corporation UEFI CA 2011」「Microsoft UEFI CA 2023」については一度以上削除操作をしたが、幸い文鎮化することはなかった(前述の通り結果的には「Microsoft Corporation UEFI CA 2011」のみの削除で十分だった)。Windowsがブートしない状態になったことはあった。LenovoやThinkPadと名前のつく鍵は一度も削除操作はしなかった。
Linuxでのセキュアブート: Microsoftの鍵を維持する
次に、Windowsが入ったPCにおいて、Microsoft(とPCベンダー)の鍵を維持して、つまりPK, KEK, dbに手を加えずに、Linuxをセキュアブートする場合について考える。こちらも引き続き、Linux以外にも応用できる内容である。
前述の通りLinuxはWindowsでない3rd PartyのOSなので、それを起動するためのブートローダーには先ほどの「Microsoft UEFI CA 2023」(あるいは2011版)が付いていなければならない。最近の「Secured-Core PC」などではBIOSメニューからこの鍵を有効に設定する必要がある。
あとはLinuxのブートローダーがこの鍵で署名されていればよい。しかし、Linux側からすると、ブートローダー(主にGRUB)の仕様を少しでも変更するたびにMicrosoftに署名をもらいに行くのは手間である。
そこで使われるソフトウェアがshimである。shimというのは「(薄い)詰め木」といったような意味の英単語で、コンピュータ用語としては薄い互換性レイヤーのようなもの全般を指す。例えばpyenvでは.pyenv/shims/といったフォルダに「python」などといった名前のラッパースクリプトが配置され、それらが場合に応じて適切なバージョンのpythonを選んで起動させる。
セキュアブートにおけるshimも、これと似たようなもので、shimx64.efiというようなファイル名を持ち、適切に署名されたgrubx64.efi(このパスはハードコードされているが、署名さえ正当であればGRUBでなくてもよい)を起動するだけの小さなブートローダーである。また、GRUBがカーネルを起動する際にも同様に(詳しくは後述するが、shimに依頼する形で)カーネルの署名を検証する。shimはMatthew Garrett氏によって開発され、現在のソースコードはRed Hat(Red Hat Bootloader Team)のリポジトリ https://github.com/rhboot/shimにある。
各ディストリビューションの開発者(UbuntuであればCanonical、など)は、自分たちが作成した鍵を埋め込んでshimをビルドする。その後は、それをMicrosoftに見せて署名してもらう、という手続きになる…と思うのが普通だろう。ところがshimについては、Microsoft自身が確認するのではなくRed Hat側にレビュー手続きを外部委託したような形になっており、https://github.com/rhboot/shim-reviewというレポジトリでレビューが行われ、それをMicrosoftがそのまま追認するという流れになる(出典: https://learn.microsoft.com/ja-jp/windows-hardware/drivers/dashboard/file-signing-reqs)。
- このへんの参考文献
- https://www.cybertrust.co.jp/blog/linux-oss/linux/uefi-secureboot-and-boot.html
- エンドユーザーにとって大きな影響はなさそうだが、2025年10月から新たなガイドラインが適用される([UPDATED]: Microsoft UEFI Signing Requirements | Microsoft Community Hub)。shim-reviewでも言及されている。
- もちろんこれがセキュリティ対策として成り立つのは各ディストリビューション開発者の信用があってこそであり、悪意のあるバイナリにCanonicalが署名する(あるいは秘密鍵が漏洩して悪意のある攻撃者がそれを行う)ようなことが絶対にないとは言えない。Let’s Encryptがサイトの所有者以外にSSLの秘密鍵をばらまくようなことが絶対にないとは言えないのと同じである。
- 2025年11月18日現在、利用可能なほとんどすべてのLinuxのshimは未だに2011版で署名されているが、10月頃から2023鍵での署名が始まったという情報がある。見つけたものでは唯一、数日前にリリースされたばかりのRed Hat Enterprise Linux 10.1において、aarch64版のshimがMicrosoft UEFI CA 2023で署名されている。Ubuntu 26.04が出る頃には2023版で署名されたshimが普及していることを期待したい。
- 追記更新: https://fedoraproject.org/wiki/Test_Day:2026-01-12_Multi-signed_shim において、テスト用として2023版で署名されたshimがダウンロード可能になった。手元でも実際に2023版だけをdbに入れて起動できることを確認した。
- ちなみに、GRUB2に直接署名せずshimを使うのは、署名の回数を減らすためという以外に、Microsoftによる署名の規則によってGPLライセンスのソフトウェアに署名できないという問題も一因となっているようである。
実例を見てみよう。例えば、UbuntuのshimはEFIパーティションの/EFI/ubuntu/shimx64.efiに配置されており、sbverify --list shimx64.efiとすると、前述の通り「Microsoft Corporation UEFI CA 2011」(あるいは将来的には2023版)で署名されていることがわかる。同じディレクトリにあるgrubx64.efiを見ると、「Canonical Ltd. Secure Boot Signing」といったCanonicalのキーで署名されている。また、カーネルについても、pesign -S -i vmlinuz-6.8.0-87-genericなどとすると、GRUBと同じような鍵で署名されていることがわかる。sbverifyとpesignはそれぞれaptでインストールできる。
shimとほぼ同等のLinux向けブートローダーとしてLinux FoundationによるPreLoaderというのもあるが、開発は停止している。shimの初出は2012年頃なのに対してPreLoaderは2013年2月頃とみられるが、Microsoftによる署名済みバイナリのリリースはおそらくこの一度のみで、これは前述の「2011」版の鍵で署名されているため2026年中には使えなくなる。
- https://www.rodsbooks.com/efi-bootloaders/secureboot.html Rod Smith氏のこのページによると、PreLoaderの開発者であるJames Bottomley氏は、PreLoaderの主な目的は「Linux のセキュアブートのデモンストレーションと Microsoft の署名プロセスのテスト」であり、shimが普及しているので今後PreLoaderの新たな署名済みバイナリをリリースする予定はない、としている。
MOKについて
MOKはMachine Owner Keyの略で、UEFI自体の仕様ではなく、shimおよびPreLoaderで使用できる独自機能である。shimを使っているセキュアブート機にNVIDIAのドライバを導入するとき、再起動時に表示される殺風景な青い画面にパスワードを入れた記憶があるかもしれないが、それがMOK機能である。
MOKとは、マシンを所有するユーザーが鍵を登録することで、その鍵で署名された任意のバイナリをセキュアブート環境で使えるようにしてくれる機能である。MokListやMokNewなどの「Mok」で始まる(予約されていない)EFI変数を使用して動作する(MOKという名前の変数はない)。
Machine Owner 「Key」という名前ではあるが、MokListには鍵とハッシュのいずれも登録することができる(署名は不可)(「署名、鍵、ハッシュ」の項目も参照)。最初期のshimは鍵のみに対応していた。ハッシュは各バイナリごとに別々に生成する必要がある一方で、バイナリに署名するのが難しい・面倒な状況(カーネルが読み取り専用イメージにあるなど)で役立つ(これはdbについても言えることである)。
- 鍵のほうだけを「MOK」と呼ぶ場合もあるかもしれないが、それほど厳密に考えなくても大丈夫そう。現実的には鍵を使う場合のほうが多いだろう。
- ちなみにPreLoaderも一応MOKに対応しているようだが、ハッシュしか使えない。また、古いので、一部機能がうまく動作しない可能性もありそう。 https://www.reddit.com/r/linuxquestions/comments/s4s00g/mokconsistency_between_shim_and_preloader/
- dbに対するdbxと同様に、MOKにもMOKxというブラックリスト機能がある。
MOKの基本
mokutilコマンドで閲覧・操作(鍵登録要求など)が可能。mokutilはPKなど他のEFI変数を読んだり単にセキュアブートが有効かどうか確認したりするのにも使える。
mokutilで鍵の登録を要求するには以下のようにする。
sudo mokutil --import /path/to/mok.der
このコマンドは、次回再起動時に一度のみ使用するパスワードを聞いてくるので、設定する。そして、再起動時に出てくる青い画面で「Enroll MOK」「Yes」などと選んで先ほどのパスワードを入力すると、無事にMOKが登録される。このように「あのとき確かに登録要求を行ったまさにその鍵」であることを確認することだけがこのパスワードの役目である。従って、複雑で長いパスワードは必要ない。多分。
「Enroll MOK」の画面を提供しているのは、shimx64.efiと同じディレクトリにあるmmx64.efi(64bit環境の場合)で、このmmというのはMokManagerの略である。
MOKに登録されている鍵を一覧するには以下のようにする。
mokutil list-enrolled
ここには上記のようにimportされた鍵に加え、shimに埋め込まれた鍵も表示される。従って、mokutil --reset(と再起動)でMOKの鍵を全て消去すると、この鍵だけが表示される。
起動中のOSの中だけでMOK登録を完結させることはできず、必ずUEFIレベルでの操作が必要、というのがMOKのセキュリティの根幹である。逆に、起動中のOSにはアクセスできなくても、UEFIレベルの操作が可能であれば、mmx64.efiを直接呼ぶことでMOKを編集することができる。
MOKのよくある使い方
Ubuntu系で独自カーネルモジュールのためにMOKを利用する際の典型的な操作は以下のようである。
まず、
sudo update-secureboot-policy --new-key
により、/var/lib/shim-signed/mok/にMOK.derとMOK.privが生成される。次に、
sudo update-secureboot-policy --enroll-key
によりmokutil --importが内部的に呼び出される。再起動後にやることは同じである。
また、nvidia-XXX-dkmsパッケージや、Ubuntu系ディストリビューションのインストール時の「サードパーティ製ソフトウェアをインストールする」でも上記のupdate-secureboot-policyと同じようなことが行われている。従ってあまり意識していないのにMOKを使っていたということもよくある。
- この種の独自カーネルモジュールとしてよく使われるのは、NVIDIA以外だと、Broadcomのネットワークドライバ、VirtualboxやVMwareの仮想化ドライバなどがある。
update-secureboot-policyはUbuntu系のコマンドで、他のDebian系やRHEL系などでは使えない。それらの場合は別のコマンドを使うか、opensslコマンドなどで自分でキーを作成する必要があるかもしれない。
カーネルモジュールへの署名はkmodsignというコマンドを使用するが、ここもdkmsがやってくれるため、直接使う機会はあまり多くないだろう。
また、ブートローダー等のEFIバイナリや(カーネルモジュールではなく)カーネル本体への署名ではkmodsignではなくsbsignという別のコマンドを使う。この際は証明書のフォーマットが異なっており、DER(バイナリ)ではなくPEM(「-----BEGIN CERTIFICATE-----」のような行で始まる)を使う(privのほうはそのままでよい)。双方の変換はopensslコマンドで簡単にできる。
sbsign向けの証明書の作成ではupdate-secureboot-policyではなく最初から独自の鍵をopensslコマンドで作る方法が案内されていることがほとんどだが、https://wiki.debian.org/ja/SecureBootなどを見る限りupdate-secureboot-policyで作られた鍵をsbsign用に流用しても間違いではないように思われる。
- 追記訂正: grub2 - Can't load self-signed kernel with Secure Boot on: "bad shim signature" - Unix & Linux Stack Exchangeに書いてある通り、Extended Key Usageが(
openssl x509 -in MOK.pem -text -nooutなどとして確認できる)が1.3.6.1.4.1.2312.16.1.2に設定されている鍵は、shimにおいてはカーネルモジュール署名用とみなされるため(?)、これでEFIバイナリに署名してもbad shim signatureになってしまう。update-secureboot-policyで作成される鍵はこれになっているようなので、(shimの検証を通す目的としては)この鍵をsbsignで使うことはできない。
shimやPreLoaderによる他バイナリの起動
- 参考(後でさらに詳しく扱う): ValdikSS氏によるSuper UEFIinSecureBoot Diskと、その解説(いずれも2019年頃)
ここからしばらくshimやPreLoader関連の技術的にこみいった内容を扱う。筆者自身も理解の怪しいところがあるので、適宜参考リンクも辿ってほしい。
まず、shimによる他バイナリ(EFIバイナリ)の起動について扱う。
前述の通り、shimは各ディストリビューション作成者による埋め込み鍵を持っており、この鍵で署名されたEFIバイナリであればshimは実行を許可する。これとは別に、MOK(ハッシュ含む)によって正当性が検証できるEFIバイナリの実行もshimは許可する。
この「shimが認めたバイナリを起動する」という部分が厄介である。というのも、EFI内部から他のEFIを呼び出すのはLoadImageやStartImageといったUEFI関数を使うのが普通で、これらは通常のセキュアブートによる検証(db, dbxとの照合)を行う。従って、普通にLoadImageやStartImageを使うだけでは、Canonical鍵やMOKなどで署名されたバイナリを起動することはできない。
そこでshimは、LoadImage/StartImageにかわるような独自のEFIローダーを実装している(イメージとしては動的ライブラリを実行するような感じ?)。この部分に関しては作者自身によるこの解説が最も詳しい(LoadImageが使えない理由もコメント欄で説明されている)。この解説は2012年のものなので少し古いが、2025年現在も、handle_image関数がpe.cに存続しており、README.mdの冒頭にも「… then shim will relocate and execute the binary.」との記述があるので、この部分は変わっていないのではないかと思われる。Rod Smith氏のこの回答もこれに沿った内容である。
- この影響か、通常実行できるはずの一部のEFIバイナリはshimからの実行に失敗する場合がある。例えば前述のMosbyなどがそうである。一旦UEFI Shellを起動してその中から実行するなどすれば問題ない。
一方PreLoaderは、 ValdikSS氏によれば、少し違ったアプローチを採用しており、LoadImage/StartImageの内部で使われてセキュアブート鍵による検証を行うUEFIの関数であるFileAuthenticationとFileAuthenticationStateをフックして動作を上書き(dbだけでなくMOKも見るように変更)することで、MOKで署名されたバイナリをLoadImage/StartImageで実行可能にしている(これも前述のRod Smith氏の回答で言及されている)。2025年現在でもlib/security_policy.cでそのコードを確認することができる。
- Rod Smith氏によると、このPreLoaderの方式は一部機種で動作しない場合があるとのこと(“some computers may lack the features needed by PreLoader to insert itself in this way”)。
実はこのsecurity_policy.cは2013年9月のこのコミットによりshimにも導入されているのだが、ValdikSS氏が「disabled by default」と書いてある通り、このコミット以降はOVERRIDE_SECURITY_POLICYを設定しないと動作しない。
さらにその後のshimの変更を見ていく。
2013年10月のこのコミットではreplacements.cにExitBootServices()とStartImage()(その後LoadImage(), Exit()も)に対するフックが追加されているが、これらはセキュリティの緩和(MOKの許容)ではなくむしろ強化が目的のようで(詳細は未調査だがSuper UEFIinSecureBoot DiskのREADME.md参照)、その後しばらく2024年頃まで同じような状況が続く。
しかし、近年大きな動きがあり、2025年2月のhttps://github.com/rhboot/shim/commit/bb114a3b92a96875dc71e5e4925bedba5c02f958やその後のhttps://github.com/rhboot/shim/pull/748を経て、どうやらshimはStartImage()やLoadImage()をフックして独自のEFIローダー(shim_load_image()関数など)を呼び出す仕様に変更されたように見える。バージョンとしては16.1からのようで、READMEにも追記された。これは、PreLoaderのようにFileAuthenticationとFileAuthenticationStateを置き換えるのとは少し異なるものの、同等の使い勝手が実現されることになる。ちなみに、PreLoader由来のsecurity_policy.cについては2024年頃にかけてのこのissueで議論されており、いずれ削除されそうである。
- 2021年のこのissueも関係ありそう?
GRUBによる他バイナリの起動
shimからGRUBを呼び出すまではできたとして、GRUBも場合によってdb鍵で署名されていない他のEFI(Unified Kernel Imageなど)を起動する必要がある。ここでもやはり、(16.0以前のshimを使うことを想定すると)LoadImage/StartImageの通常の呼び出しではブロックされる。
従ってGRUBでもshimと同じようにカスタムのEFIローダーが実装されている(ValdikSS氏解説)。というより、GRUBはshimよりもずっと古くからあるので(GRUB2のリリースはちょうどshimと同じくらい)、GRUBのEFIローダーのコードがshimに使われている可能性もありそうだが、そこまでは調べていない。
- ValdikSS氏はGRUB2の実装について述べている箇所で、PreLoaderのようにフックを使ったほうがいいのではないか?としているが、shimとの比較なのかGRUB2との比較なのかはっきりしない(この記事ではshimのEFIローダーに関する言及はない)。
また、GRUBがカーネルやEFIイメージをロードする際には、GRUB側からshimの検証関数を呼ぶようになっている(EFIイメージのロードに関する情報は少ないが、ValdikSS氏のページに「…as well as the validation code of the loaded files via shim…」と書かれた箇所がある)。
その他に、従来GRUBに備わっていたinsmodなどの機能も、任意コードの実行につながるため無効にされている。
これらの対策をすることで、GRUBを署名した鍵を埋め込んだshimが、信頼されたコードしか呼べないセキュアなものとしてMicrosoftの署名を受けられる、というわけである。
- ところで、Rod Smith氏のページには、「…that program can launch follow-on Shim/MOK-signed programs only if the boot loader is designed to "talk" to Shim.」「rEFIt can't "talk" to Shim, and so can't launch follow-on boot loaders and kernels that are signed only with MOKs.」など、「shimと連携しないローダー(
grubx64.efiに配置することを想定)はMOKで署名されたものを起動できない」というような趣旨の説明がある(この文が書かれた正確な時期はわからないが2018年よりは前と思われる)。これはあまり釈然としない。というのも、まさにGRUBがやっているように独自のEFIローダーを実装するなどすれば、shimと連携せずとも任意コードの実行はつねに可能だからである。おそらくここでの意図は、「セキュアブートの趣旨に従って、shimに署名鍵を埋め込んでもらえるような安全なブートローダーを作るなら、それはshimと連携するようなものにならざるを得ない」ということなのではないだろうか。
前述のshim16.1での実装変更により、将来的にはGRUB側もシンプルにLoadImage/StartImageを呼ぶような実装になりそうだが、見た感じさすがにまだ着手されていないように思われる。
shimと組み合わせずにGRUB2を使う際は、shim_lockというものを無効にする(grub-installに--disable-shim-lockを付ける)と、カーネル等をロードする際にshimの関数を呼ぶことはなくなり、insmodなども普通に使えるようになる。そのかわりこのときのGRUBイメージにはshimが許可してくれるような署名は付かないので、「独自の鍵を使う」の項目、あるいは次項で説明するような方法を使う必要がある。
MOKを利用したセキュアブートの回避
- 参考: 前述の、Super UEFIinSecureBoot Diskと、その解説
MOKにより署名されたEFIバイナリを実行できるというshimやPreloaderの機能は、セキュアブートのある種の「抜け穴」となる。そもそも、最も単純には、自分で作成した好き勝手なEFIバイナリにMOKで署名し、grubx64.efiに配置してshim経由で実行させることができる。しかし前述の通り、このEFIバイナリから任意のEFIバイナリをLoadImage/StartImageで呼ぶことはできず、不便である。
そこで、「Super-UEFIinSecureBoot-Disk」では、FileAuthenticationとFileAuthenticationStateを無条件の関数にカスタマイズしたPreLoaderを「好き勝手なEFIバイナリ」の部分に使っている。さらにその内側で再びGRUB2(grubx64_real.efi)を呼ぶことで通常の(セキュアブート無しの)GRUB2のような使い勝手にしている。(そのPCでの)初回起動時のみmmx64.efiが呼び出され、Enroll操作が必要になる。
この「Super-UEFIinSecureBoot-Disk」はリポジトリでは”proof-of-concept (not actively maintained or enhanced)”とされているものの、.isoや.imgから直接ブートできるUSBを作成するツールであるVentoyの内部で使用されていることから、今後も何らかの形で生き続けるだろう。
また、サイト後半にある「Silent UEFIinSecureBoot Disk」(ただしおそらくセキュリティ上の懸念からか、バイナリは公開されていない)はさらに進んでいて、Microsoftに署名されたものの脆弱性のあるGRUB2(Kasperskyのレスキューソフトウェアで使われていた)を使い、MOK操作無しでも完全にセキュアブートを迂回できるようになっている。サイトの最後で予測されている通り、このKaspersky GRUB2はdbxに追加されたものの、副作用もあったようで、現在のWindowsでどうなっているかは不明。
その脆弱性というのは、前述のinsmodがブロックされていなかったことである。
- https://wiki.archlinux.jp/index.php/GRUB#Shim-lockに、「GRUB バージョン 2.06.r261.g2f4430cc0 から、セキュアブートモードで insmod を使ってモジュールをロードすることは許可されなくなりました」との記載があるので、KasperskyのGRUB2はこれより前のバージョンをベースにしていたのかもしれない。
実装では、このmodファイルの中に、前項で説明したようなEFIローダーのコード(と、ヘッダ解析などshimに含まれる一部のコード)をそのまま移植している。このローダーを用いてさっきのカスタムPreLoaderを呼べば、あとは同じである。なお、modファイルの中に直接カスタムPreLoaderの内容を書くことでも実現できそうだが、おそらくGRUB由来のコードをGRUB内で使い回すほうが実装しやすいという判断によるものであろう。
追記: shim 16.1以降に対応したセキュアブート回避用ローダーを作ってみた
ところで、前述の変更によるものなのか、Super-UEFIinSecureBoot-Diskに含まれるshimを16.1のものに変更するとうまく動かないことがわかった。しかしそのかわり、shim 16.1を改変して、LoadImage/StartImageに伴う検証をすべて無効化すれば、前述のカスタムPreLoaderと同じことができることもわかった。ただし、別の(正規の)shimからこの「カスタムshim」が呼び出された場合、この「カスタムshim」からは既にフックされた(db・MOKの検証が含まれた)LoadImage/StartImageしか見えていないはずなのに、それを迂回して任意のEFIを起動できるというのは、なぜなのか不明である。
ソースコード・バイナリはGitHub - ge9/shim-insecure: UEFI shim loaderに公開してある。実際にこれをSuper-UEFIinSecureBoot-DiskのカスタムPreLoaderのかわりに使うことで、以降のEFI起動が無制限に可能になることも確認できた。
MOKとセキュリティ
前述の通り、MOKを使えば、実質的にセキュアブートが無効化されたような状態にすることもできてしまう。物理アクセスを持ったユーザーがMOKの画面を操作するのはそれだけ重大なことであり、慎重に行うべきものだということである。Microsoftとしても、MOK画面が一種のセキュリティ警告として働き、かつ不具合なく実装されていることを前提にshimへの署名を行っているということになる。
このような事情から、MOKに新たな鍵を登録する際は、出来るだけ他のソフトウェアを起動せずに必要最小限の操作だけを行い、すぐに再起動して登録を完了すべきかもしれない。それ以外のタイミングでMOKの画面が出たら、セキュアブートが危機に晒されていると気づくことができる。
また当然ながら、MOKの秘密鍵のほうは厳格に管理する必要がある。
各ディストリビューションの対応状況
ここまで述べたように、Microsoftの3rd Party鍵でLinuxをセキュアブートするには、ディストリビューション制作側が適切に署名したカーネル・GRUB・shimを提供する必要がある。
企業が管理している有名どころのディストリビューションは、大抵対応している。例えば、Debian, Ubuntu, RHEL, CentOS Stream, Fedora, openSUSEなどである。またこれらと同じカーネルを使った派生ディストリビューション(Linux MintやAlma Linuxなど)も対応している。MX Linuxは、通常版はセキュアブートをサポートしているが、AHS (Advanced Hardware Support)版は独自カーネルであるためサポートしていない。
一方で、コミュニティ管理の独自ディストリビューション(Arch系、Slackware系、Gentoo、NixOSなど)ではサポートされていない。これらにshim-signedというようなパッケージがあったとしても、それはUbuntuなどからのバイナリコピーであり、MOKを使わないとカーネルを起動してくれない。
また、例えばUbuntuとFedoraのshimでは異なる鍵を使っているため、Fedoraのos-proberがUbuntuを検出してGRUBメニューに追加したとしても、Fedora側のshimにはCanonicalの鍵は入っていないのでカーネルの起動は拒否されることに注意が必要である。
TPM
TPM(Trusted Platform Module)は、独立のハードウェアチップとして(discrete TPM)、またはCPU内部に(firmware TPM)搭載される部品で、暗号演算と記憶の機能をもつ。バージョンとしては主に1.2と2.0があり、暗号の強さ、鍵の階層に(結構大きな)違いがある。
TPMはセキュアブートとは違って起動時だけでなくPCの通常動作中にも使われる部品で、PC周辺機器やPC以外の組み込み機器とも協働するものである。
ここでは起動時のUEFIとの連携についてのみ扱う。とはいえ実際のところこれがTPMの用途として最も有名なものであろう。
このときに主要な役割を果たすのはPCR(Platform Configuration Register)というメモリ(レジスタ)である。番号付けられていて、大抵は「PCR0」から「PCR23」までの24個ある。
TPMは、周辺機器の構成の情報、あるいは起動に使われるEFIバイナリのハッシュ値などを受け取り(測定)、PCRに保存する。PCR0がUEFIの種類、PCR4がEFIバイナリのパス、PCR7がセキュアブート関連の設定、など番号によって役割が定められている。
BitLockerやLUKSなどのディスク暗号化においては、PCR0, 2, 4, 7, 11などの値に変動がなければ(セキュアブートの無効化や起動するバイナリの変更がなければ)、TPMが暗号化キーを渡し、パスフレーズ等の入力なしで復号が行われる。
UEFI側を改ざんするなど、TPMに対しては様々な攻撃が考えられ、Intel Boot GuardやAMD Platform Secure Bootのような保護技術の有無によっても安全性は変動する。
TPMによるディスク暗号化はほとんどの場合セキュアブートと併用されるが、バイナリのハッシュを測定すること自体はセキュアブートがなくても可能であるようにも思える。このことはhttps://security.stackexchange.com/questions/261028/tpm-use-without-secure-bootなどで議論されているが、筆者には分からなかった。
TPMの詳細な解説は少なく、筆者もこれ以上のことはあまり理解していない。
- 参考
TPM・セキュアブートの効果
TPM・セキュアブートは互いに連携して機能することからそれぞれのセキュリティ的な利点がやや分かりづらいところがあり、特にセキュアブートはLinuxまわりでよくトラブルの元になることからMicrosoftが他OSを排除するための陰謀かのように言われることも多い。
ここでは、実際にこの2つがどのようにセキュリティに役立つかを具体的に考えてみる。
なお、当然ながら結論としてはこの2つはそれぞれ一定の効果があるセキュリティ対策であり、またマシンの正規ユーザーにとって防護壁にはなっても障害物になることはほとんどないというのはこの記事を読めばわかるはずである。巷のLinux関連の情報では、カーネルモジュール関連等のトラブルの解決策としてセキュアブートの無効化が提案されていることも依然として多いが、この記事の筆者としてはセキュアブートを有効にした上で解決することを強く推奨する。
OS起動中の攻撃からの防御
まず、攻撃対象のOSが起動している間にOSの内部から行われる攻撃について考える。よく言われているように、この状況ではTPMによるディスク暗号化は無意味なので、セキュアブートについてだけ考えればよい。
単純な改ざん
これは、セキュアブートが対処すべき(かつ対処可能な)問題の最も原始的なものである。
例えば起動中のWindowsの内部からwinload.efi(これはC:\Windows\System32にある)やbootmgfw.efi(Cドライブではなく、EFIシステムパーティションにある)を改ざんして悪意あるプログラムを仕込むことは、(たとえ管理者権限さえ無かったとしても)Windowsにしかるべき脆弱性があれば可能である。Linuxでも同様のことが言える。
起動中のWindowsやLinuxの内部への侵入が完了しているのになぜわざわざブートシーケンスをいじるような回りくどいことをするのだろう?と思うかもしれないが、PCの起動の根幹であるブートシーケンスをいじればアンチウイルスソフトさえも自由に制御できてしまう(可能性がある)ため、成功した場合の利益が大きい。もちろんbootmgfw.efiに書き込むような怪しい動作をした時点で検出されてしまえば無意味だが、そうならない可能性は常に存在する。
一方で、セキュアブートがあればこの改ざんを確実に検知することができ、起動時のエラーという形でユーザーは保護される。
偽のWindowsの起動
3rd Party UEFI CAが有効なWindows機について考えてみよう。
管理者権限があれば(あるいは無くても適切な脆弱性があれば)、起動中のWindowsからブートの順番を変えることは可能である。さらに、別のパーティションを作成してそこに勝手にLinuxなどのOSをインストールすることも可能かもしれない。そうすれば、次回再起動したときにはWindowsではなくそのLinuxが起動する状態にできる。
このLinuxのログイン画面表示までの動作を、Windowsと見分けがつかないデザインにすることを考える。筆者は詳しくないが、セキュアブートに対応しているUbuntuやLinux Mintをベースにスプラッシュイメージやデスクトップ環境などを変更すれば、そこまで難しくないだろう。
そうすると、PCのユーザーは、次回そのPCを起動したときに、出現した画面をいつものWindowsのものと誤認し、パスワードを入力してしまうかもしれない。あとは適当にエラー画面を表示して再起動させてもいいし、デスクトップの背景なども偽装してさらなる情報窃取を狙ってもよい。。
この攻撃が成立してしまうのは、3rd Party UEFI CAが有効になっているためである。3rd Party UEFI CAを有効にするというのは、多くのLinuxディストリビューションが障害なく起動するようになるということなので、一定のリスクがある。Linuxを使わないのであれば、3rd Party UEFI CAを無効にしておいた方がよい。
これに対し、「独自の鍵を使う」の手法は、「自分が本当に使いたいと思っているLinux」のみを起動可能にしてくれるという点でセキュアである。
他のOSの起動中の攻撃からの防御
次に、同じマシンに、攻撃対象のものとは別の(基本的には信頼して使っている)OSがインストールされていて、そこで悪意のあるプログラムが動作するものの、(起動順の変更などOS側からでも可能な操作を除き)UEFIにはアクセスされない、という場合を考える。
先ほどと同様にセキュアブートは引き続き有用である。
加えてこの場合は、攻撃対象のOSが起動していないため、TPMによるディスク暗号化が重要な対策になる。というのも、セキュアブートはブートの根幹であるブートローダー・カーネルは検証するものの、その先のシステムライブラリなど(Linuxなら/usr以下など)は関知しないため、暗号化されていないファイルシステムに入っていれば他OSから簡単に改ざんできてしまうからである。
また、ディスク暗号化があれば、攻撃対象のOSの中身は一切見えないため、先ほどの「偽のWindows」攻撃は(Windows内で攻撃が発生した場合と比べて)それほど心配しなくてもよくなる。使用者としてはWindowsを起動していつも通りのロック画面が表示されたならそれはおそらくいつも使っている本物のWindowsだろうと信じることができるし、そうでなかった場合には何か悪いことが起こっていると気づくことができる。
UEFIにアクセスできる攻撃者からの防御
さらに、攻撃者がUEFIファームウェアにアクセスできる場合を考える。これは(エンタープライズ向けサーバーなどはさておき)一般的には物理アクセスと同義である。しかしここでは、あくまでPCのケースを開けずにできる攻撃についてのみ考える。この想定にどれほどの意味があるかはわからないが、攻撃にかけられる時間が短い場合や、学校のように攻撃者の知識・技術・悪意がそれほど高度でない場合や、蓋を開けたことを検知して自爆するシステムがある場合などを考えれば、全く無意味というわけでもないだろう。
この際は、まずUEFIをパスワード保護することが最重要の対策になる。そうすれば、攻撃者ができることは前項と同じ範囲内にとどまる。
UEFIをパスワード保護しない場合、セキュアブートはUEFI BIOSから無効にしたり別のPKをインストールしたりできるので一切意味がないことになる。一方でTPMはセキュアブートの有効無効や鍵それ自体を判定して復号を拒否できるので、依然として効果的である(前述の通りTPMによるディスク暗号化にセキュアブートが必要なのかは筆者にはわからないが、必要なのであればその意味でセキュアブートにしておいた意味があったということにはなる(次項でも同じ))。逆にTPMがなければ、ブートプロセスまで含めてあらゆる種類の攻撃が可能になる。
攻撃者は攻撃対象OSのロック画面までは(普通に起動することにより)確認できるので「偽のWindows」攻撃は前項よりも少し成立しやすくなる。しかしデスクトップ背景などはわからないので、使用者としてはログイン後にいつもと違うことが起きたら攻撃に気づける可能性が高い。
物理アクセスを持つ攻撃者からの防御
最後に、攻撃者が完全な物理アクセスを持っている場合について考える。
まず、一度攻撃されたかもしれないPCをもう一度安全に使いたいという目的で考えてみよう。この場合、セキュアブートにはほぼ効果がない。というのも、UEFIファームウェアにアクセスできる攻撃者からセキュアブートそれ自体を守る唯一の手段であるUEFIパスワードは、(機種にもよるようだが)CMOSを自然放電・ショートさせることでリセットできる場合があるからである。あるいはUEFIファームウェア部分だけ交換できるかもしれないし、それが無理ならハードディスクを取り出して別のマシンにつないでしまえばよい。
TPMについては、引き続き有用である。ただし、物理的な手段があればTPMとUEFIファームウェアの間の通信が見られる可能性が全くないわけではない。また、正規の起動後に電源を強制遮断してメモリを読み出すコールドブート攻撃によっても暗号化キーはリスクに晒される。
その他にも、物理アクセスがあれば、あまりにも多くの種類の攻撃(ハードウェア型キーロガーなど)が可能になってしまう。要するに物理アクセスは危険すぎてどうしようもないので、誰かがいじったかもしれないPCは使わないのが唯一確実な対策である。
- ちなみに、所有者の不在時に物理アクセスを通じてPCの動作を不正に変更するような攻撃は「悪意あるメイド攻撃(evil maid attack)」などと呼ばれる。
次に、主に盗難を想定し、不正に操作されたPCを再び使うことは諦めるにしても、内部のデータは保護したい、という場合を考える。ただし、後述の「パスワード・USBキー等を使ってデータを保護する」のような方法は使えない(余計な認証操作無しでOS全体を暗号化したい)とする。
この場合有用なのはTPMだけであり、これがTPMの最も典型的な使用例である。とはいえ先ほどと同様、物理的手段で迂回される可能性はある。セキュアブートは認証情報の供給源ではないため、対策にはならない。
セキュアブート・TPMがなくても可能な対策
パスワード・USBキー等を使ってデータを保護する
OSの起動中の何らかのタイミングで、パスワードやUSBキー等を使って暗号化を解除することで、PCのデータを保護する、という方法もある。この場合、セキュアブートやTPMには関係なく盗難への対策になる。もちろん、パスワードは十分に強力なものである必要があり、USBキーを紛失してはいけない。
この手法は、ユーザーフォルダのデータを保護する際には特に有用である。というのも、ユーザーのログイン時にはパスワード等を使用するため、これを暗号化に利用すれば入力操作を余分に増やすことなくシームレスに復号が可能だからである。画面ロック時にいちいち暗号化するようにすれば、(初回ログイン後の画面ロック時に盗難された場合の)コールドブート攻撃への対策にもなる(ただしパフォーマンスの問題がある)。
例えばLinuxのecryptfsには、通常のログインパスワードを利用して、ログインと同時にフォルダの暗号化を解除する機能がある。WindowsのDPAPI(データ保護API)やEFS(Windows Proのみ)にも同等の効果がある。
一方で、ログイン前に使用されるファイル(OS本体のファイル)を余分な入力操作なしに保護するにはセキュアブートやTPMが必要ということになる。