LoginSignup
22
19

More than 5 years have passed since last update.

ArchLinux にSecure Boot を導入する

Last updated at Posted at 2016-08-29

Secure Boot について

Secure Boot とはOS 起動時にそのローダーがマシン(ファームウェア)にとって信頼のある署名がされている場合のみローダーを実行し、信頼出来ない不正なローダーは実行はされないようにする機能のことです。
この機能を使用することにより、知らないうちにあなたが使用しているPC のUSB やHDD、SSD に悪意のあるOS イメージが入ったものが装着されていた場合にそれを起動してしまうのを防いだり、前回OS 起動時にローダが書き換えられて悪意のあるイメージを起動させようとした攻撃に対処することができます。

今回はSecure Boot を導入するにあたって、Think Pad T460s を使用しました。

Boot 時の概略図

Secure Boot は以下のコンポーネントから構成されます。
Linux_SecureBoot0001.png

  • Secure boot を構成する秘密鍵一覧
    秘密鍵 役割
    Platform Key (PK) db とdbx を編集するための鍵。一般的にはハードウェアベンダから提供(OEM)される。
    Key Exchange Key (KEK) PK とKEK を編集するための鍵。
    Authorized DB (db) 信頼のおけるbootloader の検証を行うための証明書とハッシュ値。複数もありうる。例えばMicrosoft Windows Production CA など。
    Unauthorized DB (dbx) 不適切なbootloader を検証するための証明書とハッシュ。複数もありうる。一般的に呼ばれるCertificate Revocation List(CRL) と似たもの。

Secure boot がbootloader を検証して安全にOS を起動するまでの処理シーケンスは次のように図示することができます。
下図のboot シーケンスは既にPK を使用してdb 及びdbx の設定が完了していることが前提になります。
Linux_SecureBoot0000.png

shim

shim は自己CA 証明書を格納したfirst stage boot loader でで、GRUB 2 やELILO などのboot loader をロードすることが役割です(今回はGRUB 2 を使用しますので、GRUB 2 についてのみ記述します)。
このCA 証明書はGRUB 2 boot loader の署名を検証するために使用されます。
そしてGRUB 2 は後ほどkernel の署名を検証するためにshim の処理をcall back します。

TODO: 今回実施したArch Linux でSecure boot を実現する方法では、shim を使用しているのか否か、もしくは他のpreloader を 使っているのかどうか確認することができませんでした。情報求む...。

Secure boot 環境構築

secure boot の概要を説明したので、ここからはArch Linux でsecure boot を行うための手順を説明していきます。

パッケージのインストール

secure boot を実現するためにArch Linux で必要なパッケージをインストールします。

必要なパッケージのインストール
# pacman -S sbsigntools
# pacman -S openssl

署名用の鍵の作成

openssl コマンドを使用してPK, KEK, db に署名を行うための鍵を生成します。

openssl(RSA)
# openssl genrsa -out my-arch-linux.key 2048
# openssl req -new -x509 -sha256 -subj '/CN=my-arch-linux' -key my-arch-linux.key -out my-arch-linux.pem
# openssl x509 -in my-arch-linux.pem -inform PEM -out my-arch-linux.der -outform DER

uuidgen を使用して鍵の所有者を表すためのGUID を作成します。

# guid=$(uuidgen)
# echo $guid

次にEFI_SIGNATURE_LIST (署名リスト)を作成していきましょう。
ここで登録されるmy-arch-linux.der の署名は自己署名となります。

# sbsiglist --owner $guid --type x509 --output my-arch-linux.der.siglist my-arch-linux.der

sbvarsign コマンドを使用して各鍵情報、変数とその値に対して署名を行っていきます。

PKKEKdbのsignedupdateを作成する
for n in PK KEK db
do
    sbvarsign --key my-arch-linux.key --cert my-arch-linux.pem --output my-arch-linux.der.siglist.$n.signed $n my-arch-linux.der.siglist
done

次にkeystore を作成していきます。

# mkdir -p /etc/secureboot/keys/{PK,KEK,db,dbx}
# cp *.PK.signed /etc/secureboot/keys/PK/
# cp *.KEK.signed /etc/secureboot/keys/KEK/
# cp *.db.signed /etc/secureboot/keys/db/

sbkeysync コマンドを使用してfirmware の鍵データベースと情報を同期させます。
上記で/etc/secureboot/keys ディレクトリ配下に鍵を作成しましたが、これ以外のディレクトリを使用したい場合はsbkeysync コマンドのオプションに--keystore and/or --no-default-keystores オプションを加えて実行してください。

まずは--dry-run オプションを付けて、テストモードで実行してみましょう。

sbkeysync(dry-run)
# sbkeysync --verbose --pk --dry-run

結果に問題無いようであれば、今度は--dry-run オプションを外してコマンドを実行します(firemware 上の鍵DB が更新されま すので、覚悟を決めてください…)。
ここで注意していただきたいのは、firmware によってはこのコマンドを実行することで、自動的にset up モードからsecure boot 強制モードへ移行してしまうものがあるそうです。
そのため、やっぱりsecure boot をoff にしたい場合の保険の意味も込めて、事前にお使いのコンピュータのfirmware の設定画面からsecure boot をOFF にする方法やPK を削除する方法があることを確認しておいてください。

sbkeysync
# sbkeysync --verbose --pk

... 以下のようなエラーが出た ...
New keys in filesystem:
 /etc/secureboot/keys/db/my-arch-linux.der.siglist.db.signed
 /etc/secureboot/keys/KEK/my-arch-linux.der.siglist.KEK.signed
 /etc/secureboot/keys/PK/my-arch-linux.der.siglist.PK.signed
Inserting key update /etc/secureboot/keys/db/my-arch-linux.der.siglist.db.signed into db
Can't create key file /sys/firmware/efi/efivars/db-d719b2cb-3d3a-4596-a3bc-dad00e67656f: Permission denied
Error syncing keystore file /etc/secureboot/keys/db/my-arch-linux.der.siglist.db.signed
Inserting key update /etc/secureboot/keys/KEK/my-arch-linux.der.siglist.KEK.signed into KEK
Can't create key file /sys/firmware/efi/efivars/KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c: Permission denied
Error syncing keystore file /etc/secureboot/keys/KEK/my-arch-linux.der.siglist.KEK.signed

--dry-run モードで成功しても実際に同期しようとすると失敗しました。
原因はUEFI のsecure boot モードがsetup モードになっていないためでした。
お使いのマシンによってエラーになったり、ならなかったりは異なってくると思いますので、次の対応はあくまで参考程度にとど めておいてください。

secure boot モードをsetup モードへ変更するために、一旦マシンを再起動し、Lenovo セットアップ画面メニューから設定を変更し、再度OS を起動させます。

Lenovoのセットアップ画面から...
Security
  -> Secure Boot
    -> Reset to Setup Mode [Enter]
    -> Clear All Secure Boot Keys [Enter]

// "Reset to Setup Mode" でEnter キーを押してSetup Mode をリセット
// 念のため"Clear All Secure Boot Keys" でもEnter キーを押下してすべての鍵をリセット

bootloader に署名を行う

bootloader に署名を行います。
今回はノートPC 上で既に起動しているArch Linux のbootloader に対して署名を行います。

実際、重要なLinux システムを想定したSecure Boot を行う場合は、署名を行うbootloader(OS) と鍵を管理するOS は別の物であ ることがセキュリティ上は好ましいでが、今回は動作確認目的なので、そのようなことは気にせずに署名を行っていきます。

bootloaderに署名を行う
# sbsign --key my-arch-linux.key --cert my-arch-linux.pem --output grubx64.efi /boot/efi/EFI/arch/grubx64.efi
# cp /boot/efi/EFI/arch/grubx64.efi{,.bak}
# cp grubx64.efi /boot/efi/EFI/arch/

Secure Boot モードで起動する

bootloader への署名も完了したら、マシンを再起動し、ハードウェアのセットアップ画面からSecure Boot モードがON になって いることを確認します。

// Lenovo のセットアップ画面から...
Security
  -> Secure Boot
    -> Secure Boot [Enabled]

Secure Boot モードがON になっていることを確認したら、そのままOS のboot プロセスへ進み、正常にLinux が起動できれば成功です。

正しくSecure Boot モードでLinux が起動しているかどうかを確認したい場合は、USB メモリに他のLinux イメージを入れてUSB から起動させてみてください。
その時にUSB にインストールした署名が行われていない、もしくは署名検証にパスできずに起動に失敗すれば、Secure Boot の動 作として正常に運転していることが確認できます。

setup モード(もしくはSecure Boot モードOFF)へ切り戻しする

Secure Boot モードをリセットしたい、もしくはSecure Boot モードを無効にしたい場合は以下の手順を実施します。

方法1: ハードウェアベンダのセットアップ画面からSecure Boot モードをOFF にする

今回検証に使用したLenovo T460s のように、ハードウェア側のセットアップ画面にSecure Boot を設定するメニューがある場合は、そちらからOFF にすることができます。

// Lenovo のセットアップ画面から...
Security
  -> Secure Boot
    -> Reset to Setup Mode [Enter]   // Enter を押下する
    -> Clear All Secure Boot Keys [Enter] // Enter を押下する

更にSecure Boot モードをOFF にしたい場合は"Secure Boot" もDisabled に設定します。

// Lenovo のセットアップ画面から...
Security
  -> Secure Boot
    -> Secure Boot [Disabled]

方法2: コマンドラインからfirmware 上のメモリを書き換える

(この方法を実施しても戻らないfirmware があるようです。実行は自己責任でおねがいします...)
コマンドラインからsetup モードへ切り戻しをしたい場合、以下のような手順で空っぽのPK を上書きしてあげることで行うことができます。

# : > empty
# sbvarsign --key my-arch-linux.key --cert my-arch-linux.pem --attrs NON_VOLATILE,BOOTSERVICE_ACCESS,RUNTIME_ACCESS --include-attrs --output empty.PK.signed PK empty
# dd bs=4K if=empty.PK.signed of=/sys/firmware/efi/efivars/PK-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx は使っている環境ごとに異なる)

備忘録: 署名ECDSA 秘密鍵で作成する場合

最後に...本手順は以上で終了ですが、ECDSA でも署名が行うことができるかどうかについてテストをしてみました。
結果から先にいうと、今回自分が使用したハードウェアでは、ECDSA な秘密鍵を使った方法は実施不能でした。
備忘録。2016/08 現在、ECDSA にて登録しようとしても、firmware と情報の同期を行うときにエラーが発生して登録することができません。
お使いのハードウェア環境によっても変わってくる可能性があるため、あくまで参考程度にしておいてください。

openssl(ECDSA)
# openssl ecparam -list_curves
...
secp521r1
...

# openssl ecparam -out my-arch-linux.key -name secp521r1 -genkey
# openssl ecparam -out my-arch-linux.key -name prime256v1 -genkey
# openssl ecparam -out my-arch-linux.key -name secp384r1 -genkey

# openssl req -new -x509 -sha256 -subj '/CN=my-arch-linux' -key my-arch-linux.key -out my-arch-linux.pem
# openssl x509 -in my-arch-linux.pem -inform PEM -out my-arch-linux.der -outform DER

楕円曲線としてメジャーどころであるprime256v1, secp384r1, secp521r1 あたりを試してみたがどれもダメ。

prime256v1,secp384r1,secp521r1
Inserting key update /etc/secureboot/keys/db/my-arch-linux.der.siglist.db.signed into db
Error writing key update: Invalid argument
Error syncing keystore file /etc/secureboot/keys/db/my-arch-linux.der.siglist.db.signed
Inserting key update /etc/secureboot/keys/KEK/my-arch-linux.der.siglist.KEK.signed into KEK
Error writing key update: Invalid argument
Error syncing keystore file /etc/secureboot/keys/KEK/my-arch-linux.der.siglist.KEK.signed

参考

22
19
8

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
19