Ubuntu Weekly Recipe

第444回Ubuntuにおけるセキュアブートの仕組み

UEFIの機能の一つに、検証されたブートローダーやOSのみを起動する「セキュアブート」という仕組みが存在します。今回はセキュアブートが有効化された環境について説明し、Ubuntuがどのように起動するのかを紹介します。

あなたのブートローダーとカーネルを見守るセキュアブート

「セキュアブート(Secure Boot⁠⁠」はUEFIで定義されているプロトコルの一つで、UEFIファームウェアに保存された「鍵」で検証できたバイナリのみを起動する仕組みです。この仕組みを使うことで、検証されていないブートローダーやカーネル、その他のEFIアプリケーションの不用意な起動を「ある程度」防ぐことができます。検証済みのOSだけ起動するようにしておけば、UEFIファームウェアへの不正なアクセスも防ぐことができるのです。

セキュアブートが機能しているかどうかは、Ubuntuであればdmesgコマンドの内容で確認できます[1]⁠。次のように「Secure boot enabled」と表示されていたら、有効化されています。無効化されている場合は、何も表示されません。

$ dmesg | grep Secure
[    0.000000] Secure boot enabled

セキュアブートの仕組み

Ubuntuのセキュアブート対応を解説する前に、セキュアブートの仕組みについて簡単に説明しておきましょう。今回の記事ではUEFI Specification 2.6を元に説明します。注釈にいくつかセクションタイトルを付けていますが、UEFIのバージョンによってはセクション番号が異なることもありますので、その点は注意してください。

セキュアブートを有効化すると、UEFIファームウェアはあらかじめ登録されていた「公開鍵証明書」※2やハッシュ値を用いて、実行しようとしているバイナリが正当なものであるかどうかを検証します。この時に使われる「鍵」がどこに保存されているかというと、第441回にも出てきたNVRAM領域です。さらにNVRAM変数を安全に更新するための鍵も必要です[3]⁠。鍵は用途に応じていくつかのUEFI変数[4]に保存されます。

  • Platform Key (PK)
  • Key Exchange Key (KEK)
  • db/dbx

「Platform Key」変数は、そのプラットフォーム(マシン)のオーナーの鍵を保存する変数です。この変数に鍵として保存されている証明書と対になる秘密鍵を保持しているオーナーのみが、後述のKEK変数を更新できます。市販されているPCなら大抵の場合、PK変数にはPCベンダーが作成した鍵が保存されています。当然のことながら一般ユーザーはPCベンダーの秘密鍵を持っていないはずなので、PCベンダーの秘密鍵で署名されたKEK変数を更新することはできません。KEK変数を更新したいならPK変数を削除し、独自のPlatform Keyを作成した上で、0から各種変数を設定し直す必要があります。

「Key Exchange Key」変数は、db/dbxの更新に使用する鍵を保存する変数です。複数の鍵を登録可能です。市販されているPCならたいていの場合、KEK変数にはOSベンダーが作成した鍵が保存されています。また、プラットフォームによってはPKと同じくPCベンダーが作成した鍵も一緒に保存されている場合があります。つまりdb/dbxの更新をするなら、やはりOSベンダーやPCベンダーの秘密鍵を持っている必要があります。

「db」変数と「dbx」変数はそれぞれ「署名データベース」「失効した署名データベース」であり、実行バイナリの署名を検証する際の鍵や署名そのもの、もしくは実行バイナリのハッシュを保存する変数です[5]⁠。セキュアブートを起動するときは、基本的にこのdbやdbxの内容を参照してバイナリイメージの検証を行います。市販されているPCならOSベンダーの鍵に加えて、他にもいくつかの鍵が入っている場合もあります。

セキュアブートによる起動の流れ

UEFIファームウェアの実装の一つであるOVMFを参考に、セキュアブートの大まかな流れを見ていきましょう。OVMFではDxeImageVerificationHandler()において、署名の検証を行っています。

  1. 実行するバイナリから署名データを取り出す
  2. 署名データがない場合はバイナリのSHA256ハッシュを計算する
  3. dbxにハッシュもしくは署名データ、署名した人の公開鍵のいずれかが存在したら実行を拒否する
  4. dbにハッシュもしくは署名データ、署名した人の公開鍵のいずれかが存在したら実行を許可する

つまりセキュアブートが有効化された環境で起動時に参照するUEFI変数はdbxとdbのみです。この変数が正しく設定されていれば、バイナリを起動できることになります。ちなみにバイナリが未署名の場合も、そのハッシュ値が登録されていれば実行は可能です。しかしながら、バイナリの内容が変わる度にUEFI変数を更新しなくてはならないため、頻繁に更新が行われるようなOSの起動にはあまり使われません。

UEFIの実行バイナリはMicrosoft Windowsと同じPE/COFF形式です。このバイナリのPEヘッダーのOptional Data Directoryの5番目には「The Attribute Certificate Table」へのアドレスが入っています。このアドレスの先に、署名データが存在するわけです[6]⁠。大抵の場合はバイナリの末尾です。fileコマンドを使えば、PE/COFF形式かどうかわかります[7]⁠。PE形式ならファイルの末尾の方にあるバイナリデータの息遣いを感じて、X.509形式っぽい文字列が見えてきたなら署名済みと判断できることでしょう。

$ 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/dbxといったUEFI変数の内容が関わってきます。また、この変数を更新するためにはPK/KEK変数に登録した公開鍵証明書と対になる秘密鍵が必要です。言い換えると、これらの変数が簡単に変更できてしまうと、セキュアブートがセキュアではなくなってしまいます。そのためUEFI変数の属性には「書き込み時に認証が必要かどうか」のビットが存在し、そのビットが立っている場合は特定の認証処理を経て認証されないとセキュリティ違反EFI_SECURITY_VIOLATIONと判定します。

$ 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変数の例だと[8]⁠、属性フィールドの値は「0x00000027」です。個々のビットは次のような意味をもっています[9]⁠。

0010 0111 = 0x27
        ^- NVRAM領域に保存する
       ^- Boot Service後も読み込み可能にする
      ^- Boot Service後も書き込み可能にする
     ^- Hardware Error Record用の変数である
   ^- 書き込み時にカウンタベースの認証が必要
  ^- 書き込み時に時刻ベースの認証が必要
 ^- 書き込み時に既存のデータの後ろに追記する

このうち「認証が必要」なビットが立っている変数がセキュアブートポリシーを持った変数です。カウンタベースか時刻ベースかは認証方法の違いで、現在の仕様では、認証時に更新するかどうかの判断基準としてタイムスタンプを使用する時刻ベースのほうが推奨されています[10]⁠。

PK変数は「NVRAM領域に保存され⁠⁠、⁠Boot Service後(OSなどから)も読み書き可能で⁠⁠、⁠書き込み時に時刻ベースの認証が必要」であることがわかります。なお上記のPKの値だと、最初の4バイトが属性で、次の16バイトが鍵の種類を示すGUIDになります。さらに4バイトごとに鍵リスト全体のサイズ(0x0475⁠⁠、鍵ヘッダーのサイズ(0x0000⁠⁠、鍵のサイズ(0x0459)です。上記の例では鍵ヘッダーのサイズが0なので鍵ヘッダーはなく、次の16バイトがその鍵の所有者のGUIDとなります。そして、0x00000030番地から鍵の種類にあわせた形式(今回の例だとDERエンコードされたX.509証明書)のデータが始まります。

まずPK変数が空の状態を考えてみます。この状態はSetup Modeと呼ばれ[11]⁠、セキュアブートもオフになります(UEFI変数の「SetupMode」に1が、⁠SecureBoot」に0がセットされます⁠⁠。Setup Modeの時、セキュアブートポリシーを持った変数であっても認証自体をスキップします[12]⁠。よってPlatform Keyの登録(Enroll)が可能です。Platform KeyをEnrollすると自動的に「User Mode」に移行します。User Modeになると、セキュアブートポリシーを持ったUEFI変数の書き込み時に認証が行われるようになります。また、Runtime Service[13]ではない時は、セキュアブートがオンになります。Runtime Serviceの場合は、次回起動時からセキュアブートが有効化されます[14]⁠。

一般的にセキュアブート対応のPCを購入した場合、最初からUser Modeになっています。このためdb/dbx変数を更新する場合はKEK変数の鍵に対応した秘密鍵で認証する必要がありますし、KEK変数を更新する場合はPK変数の鍵に対応した秘密鍵で認証する必要があります。この認証処理は、セキュアブートがオンかオフかに関わらず、User Modeである時は常に行われます[15]⁠。

KEKやPKの秘密鍵を持っていない状態でdb/dbxを更新したいとなると、Setup Modeに戻って認証をスキップするしかありません。しかしSetup Modeに戻ってしまうということは、PK/KEKの値に関係なくセキュアブートポリシー変数を変更できてしまうということで、PK/KEKを利用した「Chain of trust」が途切れてしまうことになります。つまり設定済みのPKやKEKが信頼できないということです。そこでPlatform Keyを削除することで、Setup Modeに戻る仕組みになっています。Platform Keyを削除する方法は次の2つです[16]⁠。

  • PK変数に空のデータを書き込む
  • プラットフォーム固有のPK変数クリア機能を実行する

PK変数に空のデータを書き込む場合は、当然のことながら認証を行う必要があります。つまりPlatform Keyの秘密鍵が必要です。よって一般的な利用者にとって、後者が唯一の方法になります。大抵のUEFIファームウェアであれば、Platform Keyを削除する仕組みが備わっていることでしょう。ものによっては「Setup ModeにするUI」によって、Platform Keyを削除するかもしれません。たとえばOVMFの場合は「Secure Boot Configuration」「Customize Secure Boot」「Customized」にした上で、⁠Custom Secure Boot Options」「PK Options」から「Delete Pk」を選択します[17]⁠。

このようにセキュアブートに関するUEFI変数の更新には、さまざまな手続きが必要なのです。

Ubuntuにおける鍵の取り扱い

セキュアブートとその鍵の扱いを見てきました。今度はWindwos PCにUbuntuをインストールした時に、セキュアブートを有効にしたUbuntuのブートシーケンスにおいてこれらの鍵がどのように使われているかを見ていきましょう[18]⁠。

ベンダーがUbuntuを最初からインストールしているマシンであれば、UbuntuのブートローダーであるGRUBやOSであるLinuxカーネルを起動するための鍵をあらかじめEnrollしてくれているはずです。しかしながら、今のUbuntuはUbuntuがプリインストールされていないマシンであっても、鍵を入れかえることなくセキュアブートを有効化できます。これはどういうことでしょうか。

これまで何度か言及しているように、PK変数やKEK変数、db/dbx変数はいずれもPCベンダーもしくはOSベンダー(Microsoft)の秘密鍵を持っていないと書き換えはできません。つまりGRUBやLinuxカーネルはdb変数に登録されている鍵で検証可能な、署名済みバイナリである必要があります。そこでUbuntu(やFedora)は、GRUBより一段前にMicrosoftの鍵で署名されたshimブートローダーをはさむ方法を採用しました。もともとMicrosoftはdb用に2つの鍵を持っています。

PCAはWindowsのOSローダーの署名に使われている証明書です。これに対してUEFI CAのほうは、サードパーティーのベンダー向けにMicrosoftが提供しているUEFIファームウェアの署名サービスで使われる鍵です。サードパーティのベンダーがUEFIバイナリを作成しMicrosoftに送付すると、Microsoft側でバイナリを検証した上でUEFI CAで署名したバイナリを作成してくれます。このサービスで作成したUEFIバイナリを使えば、UEFI CAインストール済みのWindowsマシンでも独自のバイナリを実行できるというわけです[19]⁠。

shimはGRUBなどの他のブートローダーの署名を検証した上で起動するだけのブートローダーです。Microsoftによる署名処理を少なくするために、できる限りシンプルに作られています。shim自体はshimパッケージで提供されていますが、UEFI CAで署名済みのバイナリはshim-signedパッケージに入っています。UEFIシステム上にUbuntuをインストールした時は、このshimローダーを最初に起動するようにUEFI変数を設定します。ちなみに、起動関連のUEFI変数は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.efiが存在します。このshimローダーには、Canonicalの証明書が埋め込まれています。shimローダーから起動するGRUBやさらにその先のカーネルは、このCanonicalの証明書で正当性を検証することで、shim以降の安全性を確保しているのです。当然のことながらshimに証明書を埋め込むということは、その秘密鍵が流出してしまうと何でも起動できてしまうということです。Microsoftがshimに署名をする場合は、埋め込まれる証明書の厳密な管理が求められています

まとめると、セキュアブートが有効化されている環境において、Ubuntu 16.04 LTSの起動時には次のような手順で検証が行われます。

  1. UEFIファームウェアはセキュアブートが有効になっているか確認する
  2. Ubuntuシステムで起動するUEFIアプリケーションを確認するshimx64.efi
  3. shimx64.efiがdbx変数にある証明書・署名・ハッシュのいずれかに一致しないか確認する
  4. shimx64.efiがdb変数にある証明書・署名・ハッシュのいずれかに一致するか確認する
  5. このとき「Microsoft Corporation UEFI CA 2011」で署名されていることがわかるのでshimx64.efiを実行する
  6. shimは埋め込まれた証明書である「Canonical Ltd. Master Certificate Authority」を用いて次のブートローダーを検証する
  7. 次のブートローダーであるgrubx64.efiが上記の証明書で署名されているならgrubx64.efiを実行する
  8. カーネルが署名済みならGRUBはshimに埋め込まれた「Canonical Ltd. Master Certificate Authority」を用いて次のカーネルを検証する
  9. カーネルが上記の証明書で署名されているならカーネルを起動する

MicrosftのUEFI CAで署名されたshimローダーさえあれば、あとはCanonical側の鍵を使うだけでGRUBやカーネルの更新時も、Microsoftによる承認を待つことなく新しいパッケージをリリースできるのです。

ちなみにカーネルのキーリングには、セキュアブート関連の鍵も保存されています。keyutilsパッケージのkeyctlコマンドを使えば、鍵の一覧を確認できます。たとえばヒューレットパッカードのPCだと、次のような結果になります。

$ 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ベンダーであるヒューレットパッカードの鍵、WindowsのベンダーであるMicrosoftの鍵に加えて、Canonicalの鍵も追加されていることがわかります。ちなみに「Build time autogenerated kernel key」はカーネルパッケージのビルド時に自動生成された鍵です。モジュールの検証に使われます[20]⁠。

実際に署名を検証してみる

最後に、ここまで取り上げてきたパーツを組み合わせて、手作業で署名を検証する手順を紹介します。

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_SIGNATURE_LISTらしきものが始まっています。よって再び解析してみます。

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_SIGNATURE_LISTらしきものが始まっているようです。

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.509証明書ですので、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、UEFI CAについては、Microsoftのサイトからダウンロードできるファイルと同じです。

shimバイナリの署名を検証する

今度はdb変数の鍵を使って、UEFIバイナリの署名を検証します。⁠Ubuntuにおける鍵の取り扱い」でも述べたように、shimx64.efiはdb変数にあるMicrosoftのUEFI CAdb3.derを用いて署名を検証します。このEFIバイナリの実体は/usr/lib/shim/shim.efi.signedです。署名の検証は、sbsigntoolパッケージのsbverifyコマンドを使うと便利です。ただsbverifyはPEM形式しか受け付けてくれないのでdb3.derを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

警告は、PE/COFFのセクション解析時に「署名部分までのオフセット+署名サイズ(1170360⁠⁠」が「バイナリイメージのサイズ(1289424⁠⁠」より小さかったことを示しています。おそらくPE/COFFのいくつかのセクションが読み飛ばされただけだと思いますので、ここでは気にしなくても問題ないでしょう。

GRUBバイナリとLinuxカーネルの署名を検証する

GRUBバイナリとLinuxカーネルは、Canonicalの証明書を用いて署名を検証します。しかしながら、この証明書はPK/KEK/db変数などには保存されておらず、shimバイナリに埋め込まれています。そこで、shimパッケージのソースパッケージをダウンロードして、証明書を取り出します。

$ 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

あとはこれを、PEM形式に変換したうえで検証するだけです。なお、カーネルはバイナリ部分と署名部分が分離しています。そのため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

このようにセキュアブートは、複数の「鍵」を用いて安全性を確保しています。もしUEFIシステムにインストールしたUbuntuがセキュアブートを有効にするとうまく動かない場合は、本記事の情報をもとに必要な鍵(特にMicrosoft UEFI CA)が足りているか、必要なパッケージ(shim-signedやgrub-efi-ARCH-signedなど)がインストールされているか、UEFIのブートオプションでshimx64.efiを指定しているかといった点を確認してみてください。

おすすめ記事

記事・ニュース一覧