UEFIの機能の一つに、
あなたのブートローダーとカーネルを見守るセキュアブート
「セキュアブート
セキュアブートが機能しているかどうかは、dmesgコマンドの内容で確認できます
$ dmesg | grep Secure [ 0.000000] Secure boot enabled
セキュアブートの仕組み
Ubuntuのセキュアブート対応を解説する前に、
セキュアブートを有効化すると、
- Platform Key (PK)
- Key Exchange Key (KEK)
- db/
dbx
「Platform Key」
「Key Exchange Key」
「db」
セキュアブートによる起動の流れ
UEFIファームウェアの実装の一つであるOVMFを参考に、DxeImageVerificationHandler()において、
- 実行するバイナリから署名データを取り出す
- 署名データがない場合はバイナリのSHA256ハッシュを計算する
- dbxにハッシュもしくは署名データ、
署名した人の公開鍵のいずれかが存在したら実行を拒否する - dbにハッシュもしくは署名データ、
署名した人の公開鍵のいずれかが存在したら実行を許可する
つまりセキュアブートが有効化された環境で起動時に参照するUEFI変数はdbxとdbのみです。この変数が正しく設定されていれば、
UEFIの実行バイナリはMicrosoft Windowsと同じPE/fileコマンドを使えば、
$ file /usr/lib/shim/shim.efi.signed /usr/lib/shim/shim.efi.signed: PE32+ executable (EFI application) x86-64 (stripped to external PDB), for MS Windows
UEFI変数の追加や更新
セキュアブートにはdb/EFI_)
$ hd /sys/firmware/efi/efivars/PK-* | head 00000000 27 00 00 00 a1 59 c0 a5 e4 94 a7 4a 87 b5 ab 15 |'....Y.....J....| 00000010 5c 2b f0 72 75 04 00 00 00 00 00 00 59 04 00 00 |\+.ru.......Y...| 00000020 74 24 86 16 a3 fc 52 46 86 1f 93 30 80 10 25 e7 |t$....RF...0..%.| 00000030 30 82 04 45 30 82 03 2d a0 03 02 01 02 02 09 00 |0..E0..-........|
たとえば上記のPK変数の例だと
0010 0111 = 0x27
^- NVRAM領域に保存する
^- Boot Service後も読み込み可能にする
^- Boot Service後も書き込み可能にする
^- Hardware Error Record用の変数である
^- 書き込み時にカウンタベースの認証が必要
^- 書き込み時に時刻ベースの認証が必要
^- 書き込み時に既存のデータの後ろに追記する
このうち
PK変数は
まずPK変数が空の状態を考えてみます。この状態はSetup Modeと呼ばれ
一般的にセキュアブート対応のPCを購入した場合、
KEKやPKの秘密鍵を持っていない状態でdb/
- PK変数に空のデータを書き込む
- プラットフォーム固有のPK変数クリア機能を実行する
PK変数に空のデータを書き込む場合は、
このようにセキュアブートに関するUEFI変数の更新には、
Ubuntuにおける鍵の取り扱い
セキュアブートとその鍵の扱いを見てきました。今度はWindwos PCにUbuntuをインストールした時に、
ベンダーがUbuntuを最初からインストールしているマシンであれば、
これまで何度か言及しているように、
- Microsoft Windows Production PCA 2011
(PCAファイルへのリンク) - Microsoft Corporation UEFI CA 2011
(UEFI CAファイルへのリンク)
PCAはWindowsのOSローダーの署名に使われている証明書です。これに対してUEFI CAのほうは、
shimはGRUBなどの他のブートローダーの署名を検証した上で起動するだけのブートローダーです。Microsoftによる署名処理を少なくするために、efbootmgrコマンドで確認できます。
$ efibootmgr -v | grep ubuntu Boot000B* ubuntu HD(1,GPT,49f2bf87-652c-4787-a801-59b4ea5dcbb2,0x800,0x100000)/File(\EFI\ubuntu\shimx64.efi) $ sudo ls /boot/efi/EFI/ubuntu/ MokManager.efi fw fwupx64.efi grub.cfg grubx64.efi shimx64.efi
UEFIのシステムパーティションにshimx64.が存在します。このshimローダーには、
まとめると、
- UEFIファームウェアはセキュアブートが有効になっているか確認する
- Ubuntuシステムで起動するUEFIアプリケーションを確認する
( shimx64.)efi shimx64.がdbx変数にある証明書・efi 署名・ ハッシュのいずれかに一致しないか確認する shimx64.がdb変数にある証明書・efi 署名・ ハッシュのいずれかに一致するか確認する - このとき
「Microsoft Corporation UEFI CA 2011」 で署名されていることがわかるので shimx64.を実行するefi - shimは埋め込まれた証明書である
「Canonical Ltd. Master Certificate Authority」 を用いて次のブートローダーを検証する - 次のブートローダーである
grubx64.が上記の証明書で署名されているならefi grubx64.を実行するefi - カーネルが署名済みならGRUBはshimに埋め込まれた
「Canonical Ltd. Master Certificate Authority」 を用いて次のカーネルを検証する - カーネルが上記の証明書で署名されているならカーネルを起動する
MicrosftのUEFI CAで署名されたshimローダーさえあれば、
ちなみにカーネルのキーリングには、keyctlコマンドを使えば、
$ sudo keyctl list %:.system_keyring 5 keys in keyring: 315799008: ---lswrv 0 0 asymmetric: Hewlett-Packard Company: HP UEFI Secure Boot 2013 DB key: 1d7cf2c2b92673f69c8ee1ec7063967ab9b62bec 128458387: ---lswrv 0 0 asymmetric: Build time autogenerated kernel key: d76179dc6bbadd817ec29258d181eadabda602cb 304050812: ---lswrv 0 0 asymmetric: Canonical Ltd. Master Certificate Authority: ad91990bc22ab1f517048c23b6655a268e345a63 376509249: ---lswrv 0 0 asymmetric: Microsoft Corporation UEFI CA 2011: 13adbf4309bd82709c8cd54f316ed522988a1bd4 132391469: ---lswrv 0 0 asymmetric: Microsoft Windows Production PCA 2011: a92902398e16c49778cd90f99e4f9ae17c55af53
PCベンダーであるヒューレットパッカードの鍵、
実際に署名を検証してみる
最後に、
db変数から鍵を取り出す
まずdb変数から鍵リストを取り出し、
$ mkdir tmpsb && cd $_ $ cp /sys/firmware/efi/efivars/db-* db $ hd db | head -n 4 00000000 27 00 00 00 a1 59 c0 a5 e4 94 a7 4a 87 b5 ab 15 |'....Y.....J....| 00000010 5c 2b f0 72 a8 05 00 00 00 00 00 00 8c 05 00 00 |\+.r............| 00000020 31 6b a9 f5 a0 db aa 4f a4 2a 7a 0c 98 32 76 8e |1k.....O.*z..2v.| 00000030 30 82 05 78 30 82 04 60 a0 03 02 01 02 02 10 56 |0..x0..`.......V|
db変数は複数の鍵リストを束ねたものとして保存されます。鍵リストは次のようなフォーマットになっています。
typedef struct _EFI_SIGNATURE_DATA {
EFI_GUID SignatureOwner;
UINT8 SignatureData[...];
} EFI_SIGNATURE_DATA;
typedef struct _EFI_SIGNATURE_LIST {
EFI_GUID SignatureType;
UINT32 SignatureListSize;
UINT32 SignatureHeaderSize;
UINT32 SignatureSize;
UINT8 SignatureHeader[SignatureHeaderSize];
EFI_SIGNATURE_DATA Signatures[...][SignatureSize];
} EFI_SIGNATURE_LIST;
最初の4バイトは前述したとおり変数の属性です。以降の鍵リストの最初の部分を上記にしたがって解析してみましょう。
SignatureType = EFI_CERT_X509_GUID(a5c059a1-94e4-4aa7-87b5ab155c2bf072) SignatureListSize = 0x5a8 SignatureHeaderSize = 0x0 SignatureSize = 0x58c SignatureHeader = (なし) SignatureOwner = f5a96b31-dba0-4faa-a42a7a0c9832768e SginatureData = [0x30 .. (0x30 + 0x58c - 0x10)] = [0x30 .. 0x5ac]
SignatureSizeには16バイトのSignatureOwnerが含まれているため、SignatureDataはその分を引いています。では、
$ hd -s 0x5a0 db | head -n 4 000005a0 eb c9 36 54 97 a7 54 61 0c 34 60 40 a1 59 c0 a5 |..6T..Ta.4`@.Y..| 000005b0 e4 94 a7 4a 87 b5 ab 15 5c 2b f0 72 07 06 00 00 |...J....\+.r....| 000005c0 00 00 00 00 eb 05 00 00 bd 9a fa 77 59 03 32 4d |...........wY.2M| 000005d0 bd 60 28 f4 e7 8f 78 4b 30 82 05 d7 30 82 03 bf |.`(...xK0...0...|
0x5acあたりから再びEFI_らしきものが始まっています。よって再び解析してみます。
SignatureType = EFI_CERT_X509_GUID(a5c059a1-94e4-4aa7-87b5ab155c2bf072) SignatureListSize = 0x607 SignatureHeaderSize = 0x0 SignatureSize = 0x5eb SignatureHeader = (なし) SignatureOwner = 77fa9abd-0359-4d32-bd6028f4e78f784b SginatureData = [0x5d8 .. (0x5d8 + 0x5eb - 0x10)] = [0x5d8 .. 0xbb3]
$ hd -s 0xbb0 db | head -n 4 00000bb0 1c 59 7e a1 59 c0 a5 e4 94 a7 4a 87 b5 ab 15 5c |.Y~.Y.....J....\| 00000bc0 2b f0 72 40 06 00 00 00 00 00 00 24 06 00 00 bd |+.r@.......$....| 00000bd0 9a fa 77 59 03 32 4d bd 60 28 f4 e7 8f 78 4b 30 |..wY.2M.`(...xK0| 00000be0 82 06 10 30 82 03 f8 a0 03 02 01 02 02 0a 61 08 |...0..........a.|
さらにEFI_らしきものが始まっているようです。
SignatureType = EFI_CERT_X509_GUID(a5c059a1-94e4-4aa7-87b5ab155c2bf072) SignatureListSize = 0x640 SignatureHeaderSize = 0x0 SignatureSize = 0x624 SignatureHeader = (なし) SignatureOwner = 77fa9abd-0359-4d32-bd6028f4e78f784b SginatureData = [0xbdf .. (0xbdf + 0x624 - 0x10)] = [0xbdf .. 0x11f3]
ここまでで、ddコマンドで取り出しましょう。
$ dd if=db of=db1.der bs=1 skip=$((0x30)) count=$((0x57c)) $ dd if=db of=db2.der bs=1 skip=$((0x5d8)) count=$((0x5db)) $ dd if=db of=db3.der bs=1 skip=$((0xbdf)) count=$((0x614))
SignatureTypeからいずれの鍵もDERエンコードされたX.opensslコマンドを使ってこの証明書の内容を確認できます。
$ openssl x509 -inform der -in db1.der -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
56:74:a7:03:ef:39:09:10:8b:1f:47:53:68:73:6d:6d
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, O=Hewlett-Packard Company, CN=Hewlett-Packard Printing Device Infrastructure CA
Validity
Not Before: Aug 23 00:00:00 2013 GMT
Not After : Aug 23 23:59:59 2033 GMT
Subject: O=Hewlett-Packard Company, OU=Long Lived CodeSigning Certificate, CN=HP UEFI Secure Boot 2013 DB key
(後略)
$ openssl x509 -inform der -in db2.der -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
61:07:76:56:00:00:00:00:00:08
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Root Certificate Authority 2010
Validity
Not Before: Oct 19 18:41:42 2011 GMT
Not After : Oct 19 18:51:42 2026 GMT
Subject: C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Windows Production PCA 2011
(後略)
$ openssl x509 -inform der -in db3.der -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
61:08:d3:c4:00:00:00:00:00:04
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation Third Party Marketplace Root
Validity
Not Before: Jun 27 21:22:45 2011 GMT
Not After : Jun 27 21:32:45 2026 GMT
Subject: C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation UEFI CA 2011
(後略)
MicrosoftのPCA、
shimバイナリの署名を検証する
今度はdb変数の鍵を使って、shimx64.はdb変数にあるMicrosoftのUEFI CAdb3.)/usr/です。署名の検証は、sbverifyコマンドを使うと便利です。ただsbverifyはPEM形式しか受け付けてくれないのでdb3.をPEMに変更してから使用します。
$ openssl x509 -inform der -in db3.der -out db3.pem $ sbverify --cert db3.pem /usr/lib/shim/shim.efi.signed warning: data remaining[1170360 vs 1289424]: gaps between PE/COFF sections? Signature verification OK
警告は、
GRUBバイナリとLinuxカーネルの署名を検証する
GRUBバイナリとLinuxカーネルは、
$ apt source shim
$ openssl x509 -inform der -in shim-0.8/debian/canonical-uefi-ca.der -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 13348991040521802343 (0xb94124a0182c9267)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=GB, ST=Isle of Man, L=Douglas, O=Canonical Ltd., CN=Canonical Ltd. Master Certificate Authority
Validity
Not Before: Apr 12 11:12:51 2012 GMT
Not After : Apr 11 11:12:51 2042 GMT
Subject: C=GB, ST=Isle of Man, L=Douglas, O=Canonical Ltd., CN=Canonical Ltd. Master Certificate Authority
あとはこれを、sbverifyコマンドの--detachオプションで署名部分を別途指定する必要があります。
$ openssl x509 -inform der -in shim-0.8/debian/canonical-uefi-ca.der -out canonical.pem $ sbverify --cert canonical.pem /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed Signature verification OK $ sudo sbverify --cert canonical.pem \ --detach /usr/lib/linux/vmlinuz-`uname -r`.efi.signature /boot/vmlinuz-`uname -r` Signature verification OK
このようにセキュアブートは、shimx64.を指定しているかといった点を確認してみてください。