UEFI (Unified Extensible Firmware Interface) はシステムに付属するファームウエアと、システム内の全てのハードウエアコンポーネント、そしてオペレーティングシステムとの間に存在するインターフェイスを意味する用語です。
UEFI は現在の PC システムに順次取り入れられている仕組みで、従来の PC-BIOS を置き換える目的で作られています。たとえば UEFI では 64 ビットシステムを正しくサポートしているほか、最も重要な点として、 「Secure Boot」 (ファームウエアバージョン 2.3.1c もしくはそれ以降が必要) と呼ばれる仕組みにも対応しています。最終的には、全ての x86 プラットフォームで利用できるようになるはずのものです。
UEFI には、これらに加えて下記の利点が用意されています:
GUID Partition Table (GPT) を利用した、巨大なディスク (2 TiB 以上) からの起動に対応しています。
CPU に依存しないアーキテクチャとドライバに対応しています。
ネットワーク機能にも対応した柔軟な OS 起動前環境 (pre-OS) に対応しています。
CSM (互換性サポートモジュール; Compatibility Support Module) により、 PC-BIOS を疑似できるようになっています。これにより、古いオペレーティングシステムにも対応できます。
さらに詳しい情報については、 https://ja.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface をお読みください。下記の章では、 UEFI に関する一般的な説明ではなく、 openSUSE Leap ではこれらがどのように実装されているかを説明しています。
UEFI の世界では、起動処理時に不正なコードが紛れ込むことのないよう、信頼の鎖 (くさり) を構成して解決しています。このとき、 openSUSE Leap の用語で 「プラットフォーム」 は信頼の鎖の基礎となる存在ですが、これは一般にメインボードとそこに搭載されたファームウエアを意味します。これはハードウエアの製造元と言い換えることもできますので、ハードウエイの製造元からコンポーネントの製造元、そして OS の製造元へと信頼の鎖が繋がることになります。
信頼そのものは公開鍵認証の仕組みを利用しています。ハードウエアの製造元は、プラットフォーム鍵 (PK; Platform Key) をファームウエア内に配置し、これを信頼の鎖の基礎とします。オペレーティングシステムなどの製造元との信頼関係は、それらの鍵をプラットフォーム鍵で署名することによって成立させます。
最後にファームウエアは、それらの 「信頼済み」 鍵のいずれかで署名されたコードだけを実行することによって、セキュリティを成立させます。このコードには OS のブートローダのほか、 PCI Express カードやディスク内に配置されたいくつかのドライバ、そしてファームウエア更新そのものも含まれます。
Secure Boot を使用するには、まずファームウエアが信頼する鍵で OS ローダに署名し、 OS ローダが読み込むカーネルを信頼する必要があります。
鍵交換鍵 (KEK; Key Exchange Key) を UEFI の鍵データベースに追加することができます。この方法により、 PK で署名されている他の証明書を使用することができるようになります。
Microsoft 社の鍵交換鍵 (KEK) が既定でインストールされています。
Secure Boot の機能は UEFI/x86_64 環境にインストールする場合は、既定で有効化されます。具体的には、
ダイアログ内の タブにある に既定でチェックが入っています。ファームウエア側で Secure Boot を有効にしていれば起動を行うことができますし、無効化しても起動することができます。Secure Boot の機能を利用するには、パーティション方式を古いマスターブートレコード (MBR; Master Boot Record) 形式から、GUID パーティションテーブル (GPT; GUID Partition Table) に置き換える必要があります。 YaST がインストール時に EFI モードを検出すると、 GPT でパーティションを作成しようとします。また、 UEFI では、 FAT 形式でフォーマットされた EFI システムパーティション (ESP; EFI System Partition) 内に EFI プログラムを配置する必要があります。
さらに、 UEFI の Secure Boot を利用するには、ファームウエア側で信頼されている鍵で署名されたブートローダを使用する必要があります。また、この鍵はあらかじめ信頼されていなければなりません。
この信頼を得るには、 2 種類の方法があります。 1 つ目の方法は、ハードウエアの製造元に依頼して、 SUSE の鍵を信頼してもらう方法です。 SUSE ではブートローダに対して署名を付与しています。もう 1 つの方法は、 Microsoft 社の Windows ロゴ認証プログラムに申し込んでブートローダの証明を得て、 Microsoft 社から SUSE の署名鍵を認証してもらう (つまり、 KEK で署名してもらう) 方法です。現在は SUSE 社が UEFI 署名サービス (この場合は Microsoft 社) を介して、署名を付与してもらっています。
実装レイヤでは SUSE は、既定でインストールされる shim
ローダを使用しています。これは法的な問題を回避できる賢いソリューションであるだけでなく、証明書と署名の手順を非常に簡単にすることができます。 shim
ローダが行う処理は、 GRUB 2 のようなブートローダを読み込んで、それを検証するだけです。このブートローダは、 SUSE の鍵で署名されたカーネルのみを読み込むようになっています。
信頼済みのユーザという観点では、下記の 2 種類のユーザが存在します:
1 つ目は鍵の所有者です。プラットフォーム鍵 (PK) はほぼ全てのことが許可されます。鍵交換鍵 (KEK) は PK の変更を除き、 PK と同じ内容が許可されます。
2 つ目はマシンに対して物理的なアクセスのできるユーザです。このユーザはマシンを再起動することができるほか、 UEFI の設定を行うことができます。
UEFI では、これらのユーザの要件を満たすため、 2 種類の変数を提供しています:
1 つ目は 「認証済み変数」 と呼ばれるもので、起動処理 (起動サービス環境 (Boot Services Environment)) 内でも起動済みの OS 内でも、変更できる変数です。ただし、変数の値は古い値と同じ鍵で署名されている場合にのみ変更することができます。また、より高いシリアル番号の値を追記するか、もしくはより高いシリアル番号の値にのみ置き換えることができます。
2 つ目は 「起動サービスのみの変数」 と呼ばれるもので、起動処理中に実行される任意のコードからのみアクセスすることができます。起動処理が終わると、 OS の起動前にブートローダ側で ExitBootServices
を呼び出さなければなりません。その後、これらの変数にはアクセスできなくなりますので、 OS 側からもアクセスができなくなります。
UEFI 鍵リストは最初の種類のものであり、これによってオンラインでの更新や追加、鍵やドライバ/ファームウエアのフィンガープリントのブラックリストなどを行うことができます。また、 2 番目の 「起動サービスのみの変数」 では、 Secure Boot を安全かつオープンソースに適したやり方で実装し、それによって GPLv3 との互換性も確保することができています。
SUSE では shim
と呼ばれる、 SUSE と Microsoft が署名している小さくてシンプルな EFI ブートローダを使用しています。
これにより、 shim
が読み込みと実行ができるようになっています。
shim
を読み込んで実行すると、読み込むべきブートローダが信頼のできるものかどうかを確認しようとします。 既定の動作では、 shim
は独立した SUSE の内蔵署名を使用します。これに加えて shim
は、既定の SUSE 鍵を上書きする追加の鍵を 「登録」 します。下記では、この鍵を略して 「マシン所有者鍵」 (MOK) と呼んでいます。
あとはブートローダがカーネルを検証して起動し、カーネルが同様にモジュールを検証して読み込みます。
起動処理時に使用するカーネルやドライバ、もしくはその他のコンポーネントを入れ替えたい場合は、マシン所有者鍵 (MOKs) を使用する必要があります。これを行うには、 mokutils
と呼ばれるツールを利用します。
MOK の登録を行うには mokutil
と呼ばれるツールを使用します。要求は MokNew
と呼ばれる UEFI のランタイム (RT) 変数内に保存されます。次回以降の起動では shim
ブートローダが MokNew
を検出し、 MokManager
を読み込んでいくつかの選択肢を表示します。ここから , と選択していくことで、 MokList 内にキーを追加できるようになります。 MokNew
変数内にキーをコピーするには、 オプションをお使いください。
ディスクからのキーの登録は一般に、 grub2
の読み込みが失敗し、 MokManager に戻された場合に実施できます。まだ MokNew
が存在していない場合は、 UEFI パーティション内でキーを探すことができます。
下記の説明は、 https://ja.opensuse.org/openSUSE:UEFI#.E7.8B.AC.E8.87.AA.E3.81.AE.E3.82.AB.E3.83.BC.E3.83.8D.E3.83.AB.E3.81.AE.E8.B5.B7.E5.8B.95 をベースにしています。
Secure Boot は、独自にコンパイルしたカーネルを起動できないようにする仕組みではありません。自分の証明書で署名したあと、その証明書の発行者をファームウエアか MOK にインストールすることで、解決することができます。
まずは署名に使用する独自の X.509 鍵と証明書を作成します:
openssl req -new -x509 -newkey rsa:2048 -keyout key.asc \ -out cert.pem -nodes -days 666 -subj "/CN=$USER/"
証明書の作成方法について、詳しくは https://ja.opensuse.org/openSUSE:UEFI_%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E7%BD%B2%E5%90%8D%E3%83%84%E3%83%BC%E3%83%AB をお読みください。
鍵と証明書を PKCS#12 形式にパッケージ化します:
>
openssl pkcs12 -export -inkey key.asc -in cert.pem \
-name kernel_cert -out cert.p12
pesign で使用する NSS データベースを生成します:
>
certutil -d . -N
NSS データベース内に PKCS#12 に含まれる鍵と証明書を取り込みます:
>
pk12util -d . -i cert.p12
pesign
を利用して、新しい署名をカーネルに追加します:
>
pesign -n . -c kernel_cert -i arch/x86/boot/bzImage \
-o vmlinuz.signed -s
カーネルイメージに含まれる署名を一覧表示します:
>
pesign -n . -S -i vmlinuz.signed
あとは通常通り、 /boot ディレクトリ内にカーネルをインストールすることができます。ただし、カーネルには独自の証明書による署名が設定されているため、これをファームウエアか MOK に取り込む必要があります。
UEFI ファームウエアまたは MOK に取り込むため、証明書を DER 形式に変換します:
>
openssl x509 -in cert.pem -outform der -out cert.der
簡単にアクセスできるよう、 ESP に証明書をコピーします:
>
sudo
cp cert.der /boot/efi/
MOK を自動的に取り扱うには、 mokutil
を使用します。
証明書を MOK に取り込みます:
>
mokutil --root-pw --import cert.der
--root-pw
オプションを指定することで、 root
ユーザ経由でアクセスすることができます。
登録の準備ができた証明書の一覧を確認します:
>
mokutil --list-new
システムを再起動します。 shim
から MokManager が起動されるはずです。 root
のパスワードを入力して、 MOK の一覧内に証明書を取り込みます。
新しく取り込んだ鍵が登録されていることを確認します:
>
mokutil --list-enrolled
上記以外にも、 MOK を手作業で処理することもできます:
まずは再起動します。
GRUB 2 のメニューが表示されたら、 ' c
' キーを押します。
下記のように入力します:
chainloader $efibootdir/MokManager.efi boot
を選択します。
cert.der
ファイルを指定して Enter を押します。
後は表示された手順に従います。通常は 「0」 を押してから 「y」 を押すと、確認を完了することができます。
それ以外にも、ファームウエア側のメニューで、署名データベース内に新しい鍵を追加することができるものもあります。
Secure Boot が有効化されている場合、インストール時に非同梱ドライバ (openSUSE Leap には含まれていないドライバ) の追加を行うことはできません。 SolidDriver/PLDP 向けの署名鍵は、既定では信頼されていません。
Secure Boot が有効化されている場合、インストール時にサードパーティ製のドライバをインストールする方法が 2 種類用意されています。いずれも下記に注意してください:
インストールを行う前に、ファームウエアやシステム管理ツールを介して、ファームウエアデータベース内に必要な鍵を取り込んでおいてください。この設定は、使用しているハードウエアによって異なります。詳しくはハードウエアの製造元にお問い合わせください。
https://drivers.suse.com/ もしくはハードウエアの製造元が提供する起動可能な ISO を利用して、初回の起動時に必要な鍵を登録します。
起動可能な ISO を利用して MOK リスト内にドライバの鍵を登録するには、下記の手順を実施します:
空きの CD/DVD メディアに ISO イメージを書き込みます。
標準のインストールメディアを利用するか、もしくはネットワークのインストールサーバを利用してインストールを開始します。
ネットワーク経由でインストールする場合は、起動パラメータに install=
オプションで URL を指定します。
光学メディアからインストールを行う場合、インストールプログラムは最初にドライバキットから起動し、その後製品のインストールディスクを挿入してください。
initrd には更新済みのドライバが含まれていますので、それを利用してインストールすることができます。
詳しくは https://drivers.suse.com/doc/Usage/Secure_Boot_Certificate.html をお読みください。
Secure Boot モードで起動する場合、下記の機能が提供されます:
UEFI の既定の場所に対するブートローダのインストール、および EFI の起動項目に対する維持や復元の仕組み
UEFI 経由での再起動
従来の BIOS にフォールバックすることのない、 UEFI での Xen ハイパーバイザの起動
UEFI の IPv6 PXE 起動
UEFI ビデオモードサポート (UEFI 経由でカーネルがビデオモードを取得し、同じパラメータで KMS モードを設定する機能)
USB デバイス経由の UEFI 起動
openSUSE Leap 15.3 およびそれ以降のバージョンでは、 Kexec と Kdump は Secure Boot モードにも対応します。
Secure Boot モードでの起動時には、下記の制限事項が適用されます:
Secure Boot が容易に突破されないようにするため、 Secure Boot の動作中はいくつかのカーネル機能が無効化されます。
ブートローダ、カーネル、カーネルモジュールは、いずれも署名されていなければなりません。
ハイバネーション (suspend to disk) が無効化されます。
root ユーザであっても /dev/kmem
および /dev/mem
にアクセスできなくなります。
root ユーザであっても I/O ポートへのアクセスができなくなります。また、 X11 のグラフィカルドライバはカーネルドライバを使用しなければなりません。
sysfs を介した PCI BAR アクセスができなくなります。
ACPI の custom_method
が利用できなくなります。
asus-wmi モジュール向けの debugfs が利用できなくなります。
acpi_rsdp
がカーネルに対して何も影響を及ぼさなくなります。
https://uefi.org: UEFI の Web ページです。ここには最新の UEFI 仕様に関する情報が記載されています。
Olaf Kirch 氏および Vojtěch Pavlík 氏によるブログ投稿 (本章の内容は、この投稿をベースにしています):
https://ja.opensuse.org/openSUSE:UEFI openSUSE での UEFI