Укрощаем UEFI SecureBoot
Данные обещания надо выполнять, тем более, если они сделаны сначала в заключительной части опуса о безопасности UEFI, а потом повторены со сцены ZeroNights 2015, поэтому сегодня поговорим о том, как заставить UEFI SecureBoot работать не на благо Microsoft, как это чаще всего настроено по умолчанию, а на благо нас с вами.
Если вам интересно, как сгенерировать свои обственные ключи для SecureBoot, как установить их вместо стандартных (или вместе с ними), как подписать ваш любимый EFI-загрузчик, как запретить загрузку неподписанного или подписанного чужими ключами кода, как выглядит интерфейс для настройки SecureBoot у AMI, Insyde и Phoenix и почему это, по большому счету, совершенно не важно — добро пожаловать под кат, но опасайтесь большого количества картинок и длинных консольных команд.
Введение
О том, как устроен и работает SecureBoot, я уже рассказывал в начале пятой части вышеупомянутого опуса, повторяться смысла не вижу. Если вы не в курсе, о чем весь этот UEFI SecureBoot вообще, кто такие PK, KEK, db и dbx, и почему с точки зрения SecureBoot по умолчанию хозяином вашей системы является производитель UEFI, а единственным авторизованным пользователем является Microsoft — смело проследуйте туда, мы вас тут пока подождем.
С ликбезом закончили, теперь к делу. Несмотря на то, что про создание своих ключей и настройку SecureBoot написано за три последних года с десяток отличных статей (ссылки на часть из которых приведены в разделе Литература), воз и ныне там. Основная проблема с информацией о настройке SecureBoot даже в англоязычном сегменте сети (не говоря уже о рунете) — большая часть статей, текстов и постов обрывается на «вот у нас теперь есть ключи в формате EFI Signature List, добавьте их зависимым от вашего вендора прошивки способом и готово». При этом сами вендоры не торопятся описывать меню настройки SecureBoot ни в документации на свои платформы для OEM’ов, ни в мануалах на конечные системы, в результате пользователь теряется на незнакомой местности и либо отключает SecureBoot, мешающий загружать его любимую OpenBSD (или что там у него), либо оставляет его на настройках по умолчанию (а чего, Windows грузится же). Именно этот последний шаг я и попытаюсь описать более подробно, но не в ущерб остальным необходимым шагам.
Тестовая конфигурация
Специально для этой статьи я достал из закромов пару не самых новых ноутбуков с прошивками на платформах Phoenix SCT и Insyde H2O, а также совершенно новую плату congatec (разработкой прошивки для которой я занят в данный момент) на платформе AMI AptioV. Встречайте, наши тестовые стенды:
1. AMI, они же »треугольные»: congatec conga-TR3 @ conga-TEVAL, AMD RX-216GD (Merlin Falcon), AMI AptioV (UEFI 2.4)
2. Insyde, они же »квадратные»: Acer Aspire R14 R3–471T (Quanta ZQX), Intel Core i3–4030U (Ivy Bridge), Insyde H2O (UEFI 2.3.1C)
3. Phoenix, они же »полукруглые»: Dell Vostro 3360 (Quanta V07), Intel Core i7–3537U (Ivy Bridge), Phoenix SCT (UEFI 2.3.1C)
Об интерфейсах для настройки SecureBoot
На всех вышеперечисленных системах производитель заявляет о поддержке технологии UEFI SecureBoot, но интерфейс для ее настройки сильно отличается между системами. К счастью, это не очень большая проблема, поскольку для настройки SecureBoot на совместимых со спецификацией UEFI 2.3.1C (и более новых) прошивках никакого интерфейса в Setup, кроме возможности удаления текущего PK (т.е. перевода SecureBoot в так называемый Setup Mode) не требуется, а после этого можно использовать любое EFI-приложение, способное вызвать UEFI-сервис gRS→SetVariable с предоставленными пользователем данными, в том числе утилиту KeyTool.efi из пакета efitools, которая специально для управления ключами и предназначена, осталось только научиться ей пользоваться.
Тем не менее, если удобный интерфейс для настройки присутствует (у AMI он, на мой взгляд, даже удобнее KeyTool’а) — можно воспользоваться им, так что рассказывать про эти самые интерфейсы все равно придется.
Готовим плацдарм
Начнем с лирического отступления о наличии нужного софта для разных ОС. Несмотря на то, что Microsoft является одним из разработчиков технологии, в открытом доступе до сих пор отсутствуют нормальные средства для работы с ней из Windows (ключи можно сгенерировать утилитой MakeCert из Windows SDK, а для всего остального предлагается использовать HSM третьих лиц за большие деньги). Я подумывал сначала взять и написать нужную утилиту на Qt, но потому решил, что ключи и подписи каждый день генерировать не нужно, а на пару раз хватит и существующих решений. Можете попробовать переубедить меня в комментариях, если хотите.
В общем, для всего нижеперечисленного вам понадобится Linux (который можно запустить с LiveUSB, если он у вас не установлен). Для него существует целых два набора утилит для работы с SecureBoot: efitools/sbsigntool и EFIKeyGen/pesign. У меня есть положительный опыт работы с первым набором, поэтому речь пойдет именно о нем.
В итоге, кроме Linux, нам понадобятся несколько вещей:
1. Пакет openssl и одноименная утилита из него для генерирования ключевых пар и преобразования сертификатов из DER в PEM.
2. Пакет efitools, а точнее утилиты cert-to-efi-sig-list, sign-efi-sig-list для преобразования сертификатов в формат ESL и подписи файлов в этом формате, и KeyTool.efi для управления ключами системы, находящейся в SetupMode.
3. Пакет sbsigntool, а точнее утилита sbsign для подписи исполняемых файлов UEFI (т.е. загрузчиков, DXE-драйверов, OptionROM’ов и приложений для UEFI Shell) вашим ключем.
Загрузите Linux, установите вышеуказанные пакеты, откройте терминал в домашней директории и переходите к следующему шагу.
Генерируем собственные ключи для SecureBoot
Как обычно, есть несколько способов сделать что-либо, и чем мощнее используемый инструмент, тем таких способов больше. OpenSSL же как инструмент развит настолько, что кажется, что он умеет делать вообще всё, а если почитать к нему man — то и абсолютно всё остальное. Поэтому в этой статье я ограничусь непосредственной генерацией ключевых файлов, а танцы вокруг создания собственного CA оставлю на самостоятельное изучение.Генерируем ключевые пары
Ключей понадобится сгенерировать три штуки: PK, KEK и ISK.
Начнем с PK, для генерации которого нужно выполнить следующее
openssl req -new -x509 -newkey rsa:2048 -sha256 -days 365 -subj "/CN=Platform Key" -keyout PK.key -out PK.pem
после чего ввести и подтвердить пароль, который потом спросят при попытке подписи чего-либо получившимся закрытым ключом.
Командой выше мы просим OpenSSL сгенерировать нам ключевую пару RSA2048/SHA256 со сроком действия на один год, под названием Platform Key, с выводом закрытого ключа в файл PK.key, а открытого — в файл PK.pem. Если добавить -nodes, то для подписи этой ключевой парой не нужен будет пароль, но здесь мы этого делать не станем — с паролем хоть ненамного, но безопаснее.
Таким же образом генерируем ключевые пары для KEK и ISK, пароли при этом советую вводить разные:
openssl req -new -x509 -newkey rsa:2048 -sha256 -days 365 -subj "/CN=Key Exchange Key" -keyout KEK.key -out KEK.pem
openssl req -new -x509 -newkey rsa:2048 -sha256 -days 365 -subj "/CN=Image Signing Key" -keyout ISK.key -out ISK.pem
Конвертируем открытые ключи в формат ESL
Теперь нужно сконвертировать открытые ключи из формата PEM в понятный UEFI SecureBoot формат ESL. Этот бинарный формат описан в спецификации UEFI (раздел 30.4.1 в текущей версии 2.5) и интересен тем, что файлы в нем можно соединять друг с другом конкатенацией, и этот факт нам еще пригодится.
cert-to-efi-sig-list -g "$(uuidgen)" PK.pem PK.esl
cert-to-efi-sig-list -g "$(uuidgen)" KEK.pem KEK.esl
cert-to-efi-sig-list -g "$(uuidgen)" ISK.pem ISK.esl
Ключ -g добавляет к сгенерированному ESL-файлу GUID, в нашем случае — случайный, полученый запуском утилиты uuidgen и использованием ее вывода. Если этой утилиты у вас нет — придумывайте GUIDы сами или оставьте значение по умолчанию.Подписываем ESL-файлы Для правильно работы SecureBoot необходимо, чтобы PK был подписан сам собой, KEK подписан PK, а хранилища db и dbx — сответственно KEK. При этом PK не может быть несколько, а вот ситуация с несколькими KEK хоть и встречается в дикой природе, но я все же настоятельно рекомендую удалить предустановленный ключ Microsoft из KEK по простой причине — db и dbx могут быть подписаны любым ключом из хранилища KEK, т.е. если ключ MS оттуда не удалить, то у MS будет возможность управлять содержимым db и dbx, т.е. добавлять любые новые ключи или хеши в список доверенной загрузки и удалять из него существующие. На мой взгляд, это немного слишком, и если мы берем управление ключами в свои руки, то нужно делать это до конца.
openssl x509 -in MicCorKEKCA2011_2011-06-24.crt -inform DER -out MsKEK.pem -outform PEM
затем сконвертировать полученный PEM в ESL командой
cert-to-efi-sig-list -g "$(uuidgen)" MsKEK.pem MsKEK.esl
после чего добавить получившийся файл к нашему файлу KEK.esl командой
cat KEK.esl MsKEK.esl > KEK.esl
Теперь Microsoft такой же авторизованный пользователь вашей платформы, как и вы сами, с чем я вас и поздравляю.
С другой стороны, если вы не хотите терять возможность загрузки Windows и подписанных ключом Microsoft исполняемых компонентов (к примеру, GOP-драйверов внешних видеокарт и PXE-драйверов внешних сетевых карточек), то к нашему ISK.esl надо будет добавить еще пару ключей — ключ Microsoft Windows Production CA 2011, которым MS подписывает собственные загрузчики и ключ Microsoft UEFI driver signing CA, которым подписываются компоненты третьих сторон (именно им, кстати, подписан загрузчик Shim, с помощью которого теперь стартуют разные дистрибутивы Linux, поддерживающие SecureBoot из коробки).
Последовательность та же, что и под спойлером выше. Конвертируем из DER в PEM, затем из PEM в ESL, затем добавляем к db.esl, который в конце концов надо будет подписать любым ключом из KEK:
openssl x509 -in MicWinProPCA2011_2011-10-19.crt -inform DER -out MsWin.pem -outform PEM
openssl x509 -in MicCorUEFCA2011_2011-06-27.crt -inform DER -out UEFI.pem -outform PEM
cert-to-efi-sig-list -g "$(uuidgen)" MsWin.pem MsWin.esl
cert-to-efi-sig-list -g "$(uuidgen)" UEFI.pem UEFI.esl
cat ISK.esl MsWin.esl UEFI.esl > db.esl
Теперь подписываем PK самим собой:
sign-efi-sig-list -k PK.key -c PK.pem PK PK.esl PK.auth
Подписываем KEK.esl ключем PK:
sign-efi-sig-list -k PK.key -c PK.pem KEK KEK.esl KEK.auth
Подписываем db.esl ключем KEK:
sign-efi-sig-list -k KEK.key -c KEK.pem db db.esl db.auth
Если еще не надоело, можно добавить чего-нибудь еще в db или создать хранилище dbx, нужные команды вы теперь знаете, все дальнейшее — на ваше усмотрение.Подписываем загрузчик
Осталось подписать какой-нибудь исполняемый файл ключом ISK, чтобы проверить работу SecureBoot после добавления ваших ключей. Для тестов я советую подписать утилиту RU.efi, она графическая и яркая, и даже издалека видно, запустилась она или нет. На самом деле, утилита эта чрезвычайно мощная и ей можно натворить добрых и не очень немало дел, поэтому после тестов лучше всего будет её удалить, и в дальнейшем подписывать только загрузчики.
В любом случае, подписываются исполняемые файлы вот такой командой:
sbsign --key ISK.key --cert ISK.pem --output bootx64.efi RU.efi
Здесь я заодно переименовал исполняемый файл в bootx64.efi, который нужно положить в директорию /EFI/BOOT тестового USB-носителя с ФС FAT32. Для 32-битных UEFI (избавь вас рандом от работы с ними) используйте bootia32.efi и RU32.efi.
В результате вот этого всего у вас получились три файла .auth, которые нужно будет записать «как есть» в NVRAM-переменные db, KEK и PK, причем именно в таком порядке. Скопируйте все три файла в корень другого USB-носителя с ФС FAT32, на котором в качестве /EFI/BOOT/bootx64.efi выступит /use/share/efitools/efi/KeyTool.efi (скопируйте его еще и в корень, на всякий случай) и ваш «набор укротителя SecureBoot» готов.
Укрощение строптивого
Начинается все одинаково: вставляем нашу флешку с ключами и KeyTool’ом в свободный USB-порт, включием машину, заходим в BIOS Setup.
Здесь, прежде чем заниматься настройкой SecureBoot, нужно отключить CSM, а с ним — и легаси-загрузку, с которыми наша технология не совместима. Также обязательно поставьте на вход в BIOS Setup пароль подлиннее, иначе можно будет обойти SecureBoot просто отключив его, для чего на некоторых системах с IPMI и/или AMT даже физическое присутсвие не потребуется.AMI AptioV
У большинства прошивок, основанных на коде AMI, управление технологией SecureBoot находится на вкладке Security, у меня это управление выглядит так:
Заходим в меню Key Management (раньше оно было на той же вкладке, сейчас его выделили в отдельное) и видим там следующее:
Выбираем нужную нам переменную, после чего сначала предлагают выбрать между установкой нового ключа и добавлением к уже имеющимся, выбираем первое:
Теперь предлагается либо установить значение по умолчанию, либо загрузить собственное из файла, выбираем последнее:
Далее нужно устройство и файл на нем, а затем выбрать формат этого файла, в нашем случае это Authenticated Variable:
Затем нужно подтвердить обновление файла, и если все до этого шло хорошо, в результате получим лаконичное сообщение:
Повторяем то же самое для KEK и PK, и получам на выходе вот такое состояние:
Все верно, у нас есть единственный PK, всего один ключ в KEK и три ключа в db, возвращаемся в предыдущее меню кнопкой Esc и включаем SecureBoot:
Готово, сохраняем настройки и выходим с перезагрузкой, после чего пытаемся загрузиться с нашей флешки и видим вот такую картину:
Отлично, неподписанные загрузчики идут лесом, осталось проверить подписанный. Вставляем другую флешку, перезагружаемся и видим что-то такое:
Вот теперь можно сказать, что SecureBoot работает как надо.
Если у вашего AMI UEFI такого интерфейса для добавления ключей нет, то вам подойдет другой способ, о котором далее.Insyde H2O
Здесь все несколько хуже, чем в предыдущем случае. Никакого интерфейса для добавления собственных ключей нет, и возможностей настройки SecureBoot предлагается всего три: либо удалить все переменные разом, переведя SecureBoot в Setup Mode, либо выбрать исполняемый файл, хеш которого будет добавлен в db, и его можно будет запускать даже в том случае, если он не подписан вообще, либо вернуться к стандартным ключам, в качестве которых на этой машине выступают PK от Acer, по ключу от Acer и MS в KEK и куча всякого от Acer и MS в db.
Впрочем, нет интерфейса — ну и черт с ним, у нас для этого KeyTool есть, главное, что в Setup Mode перейти можно. Интересно, что BIOS Setup не дает включить SecureBoot, если пароль Supervisor Password не установлен, поэтому устанавливаем сначала его, затем выполняем стирание ключей:
После чего на соседней вкладке Boot выбираем режим загрузки UEFI и включаем SecureBoot:
Т.к. фотографии у меня посреди ночи получаются невыносимо отвратительными, то скриншоты KeyTool'а я сделаю на предыдущей системе, и придется вам поверить в то, что на этой все выглядит точно также (мамой клянусь!).
Загружаемся с нашего носителя в KeyTool, и видим примерно следующее:
Выбираем Edit Keys, попадаем в меню выбора хранилища:
Там сначала выбираем db, затем Replace Keys, затем наше USB-устройство, а затем и файл:
Нажимаем Enter и без всяких сообщений об успехе нам снова показывают меню выбора хранилища. Повторяем то же самое сначала для KEK, а затем и для PK, после выходим в главное меню двойным нажатием на Esc. Выключаем машину, включаем заново, пытаемся загрузить KeyTool снова и видим такую картину (которую я утащил из дампа прошивки, ее фото на глянцевом экране еще кошмарнее, чем предыдущие):
Ну вот, одна часть SecureBoot’а работает, другая проверяется запуском подписанного нами RU.efi и тоже работает. У меня на этой системе Windows 8 установлена в UEFI-режиме, так вот — работает и она, Microsoft с сертификатом не подвели.Phoenix SCT
Здесь возможностей еще меньше, и во всем меню Secure Boot Configuration на вкладке Security всего два пункта: возврат к стандартным ключам и удаление всех ключей с переводом системы в SetupMode, нам нужно как раз второе:
Затем на вкладке Boot нужно выбрать тип загрузки UEFI, включить SecureBoot, и создать загрузочную запись для KeyTool'а, иначе на этой платформе его запустить не получится:
Нажимаем Yes, выходим с сохранением изменений, перезагружаемся, нажимаем при загрузке F12, чтобы попасть в загрузочное меню, оттуда выбираем KeyTool, работа с которым описана выше. После добавления ключей и перезагрузки попытка повторного запуска KeyTool'а заканчивается вот так:
При этом установленный на той же машине Linux продолжает исправно загружаться, как и подписанная нами RU.efi, так что SecureBoot можно признать работоспособным.
Заключение
В итоге, благодаря утилитам с открытым кодом, удалось завести SecureBoot на системах с UEFI трех различных вендоров, сгенерировать свои собственные ключи и подписать ими нужные нам исполняемые файлы. Теперь загрузка платформы целиком в наших руках, но только в случае, если пароль на BIOS стойкий и не хранится открытым текстом, как у некоторых, а в реализации SecureBoot нет каких-либо известных (или еще неизвестных) дыр. Сам по себе SecureBoot — не панацея от буткитов, но с ним ситуация с безопасной загрузкой все равно намного лучше, чем без него.
Надеюсь, что материал вам поможет, и спасибо за то, что прочитали эту портянку.
Литература
Managing EFI Bootloaders for Linux: Controlling SecureBoot.
AltLinux UEFI SecureBoot mini-HOWTO.
Booting a self-signed Linux kernel.
Sakaki’s EFI Install Guide: Configuring SecureBoot.
Ubuntu Security Team: SecureBoot.
Owning your Windows 8 UEFI Platform.
MinnowBoard Max: Quickstart UEFI Secure Boot.
Windows 8.1 Secure Boot Key Creation and Management Guidance.