Все ссылки в этом документе относятся к Secure Boot V1 (схема безопасной загрузки, основанная на AES). Для ESP32 Revision 3 и далее предпочтительнее использовать схему безопасной загрузки Secure Boot V2 (см. документацию [2] для ESP32 Revision 3 или ESP32-S2).
Технология Secure Boot гарантирует, что на чипе можно будет запустить только Ваш код. Данные загружаются из flash и проверяются при каждом сбросе/включении питания.
Secure Boot отделяется от функции шифрования памяти SPI flash (Flash Encryption), и можно использовать безопасную загрузку без шифрования содержимого flash. Однако для безопасного рабочего окружения Secure Boot и Flash Encryption должны использоваться одновременно (см. далее раздел "Secure Boot и Flash Encryption").
Важное замечание: разрешение техники Secure Boot ограничивает возможности для будущих обновлений используемого чипа ESP32. Внимательно прочитайте этот документ, чтобы разобраться в последствиях включения безопасной загрузки.
Что происходит при безопасной загрузке:
• Большинство данных сохраняются в памяти flash. Доступ к flash не нужно защищать от физического доступа, чтобы работала функция Secure Boot, поскольку критические данные сохраняются в битах Efuse внутри чипа, и эти данные программно недоступны [3, 4]. • Efuse используются для сохранения ключа загрузки в efuse BLOCK2 (secure bootloader key). Также прошивается один бит Efuse (ABS_DONE_0, в него записывается 1) для необратимого разрешения Secure Boot на чипе. Более подробно про eFuse см. ESP32 Technical Reference Manual -> eFuse Controller (eFuse) [PDF]. • Чтобы разобраться в процессе Secure Boot, полезно сначала разобраться в стандартном процессе загрузки ESP-IDF [5, 6]. • Обе стадии процесса загрузки (загрузка и запуск загрузчика второй стадии и последующая загрузка таблицы разделов и приложения) проверяются процессом Secure Boot в цепочке доверия ("chain of trust" relationship).
[Обзор процесса Secure Boot]
Ниже показан процесс безопасной загрузки, как он работает на верхнем уровне. Пошаговые инструкции по запуску безопасной загрузки приведены далее в разделе "Как разрешить Secure Boot". Дополнительные подробности процесса объясняются в разделе "Технические подробности Secure Boot".
1. Опции для разрешения Secure Boot предоставляются в меню конфигурации проекта ESP-IDF, в разделе "Secure Boot Configuration" (описание меню конфигурации см. в [7]).
2. По умолчанию Secure Boot подписывается образы и данные таблицы разделов во время процесса сборки. Опция конфигурации "Secure boot private signing key" это путь до файла (в формате PEM) с парой ECDSA-ключей (public/private key).
3. Образ загрузчика второй стадии (software bootloader) собирается средой разработки ESP-IDF, когда разрешена поддержка безопасной загрузки, вместе с публичным ключом (сигнатура проверки) кода загрузчика. Этот образ программного загрузчика прошивается в SPI flash со смещением 0x1000.
Примечание: под "программным загрузчиком" (software bootloader) имеется в виду загрузчик второго уровня, см. [5].
4. При первой загрузке программный загрузчик следует следующей процедуре для разрешения Secure Boot:
• Аппаратная поддержка безопасной загрузки генерирует защищенный ключ загрузки устройства (device secure bootloader key, он генерируется на основе аппаратного генератора случайных чисел RNG, и затем сохраняется в область efuse, защищенную от записи), и цифровую подпись (secure digest). Эта подпись вычисляется от ключа, IV, и от содержимого образа загрузчика. • Цифровая подпись прошивается в SPI flash со смещением 0x0. • В зависимости от конфигурации Secure Boot прошиваются efuse для запрета JTAG и интерпретатора ROM BASIC (строго рекомендуется включить эти опции защиты). • Загрузчик необратимо разрешает Secure Boot путем прошивки ABS_DONE_0 efuse. После этого software bootloader становится защищенным (чип сможет загрузиться только в том случае, когда образ загрузчика соответствует цифровой подписи).
5. При последующих загрузках ROM bootloader видит, что прошит Secure Boot efuse, считывает цифровую подпись с адреса 0x0, и использует процедуру аппаратной поддержки Secure Boot для проверки загруженной подписи с вычисленным значением. Если подпись не совпала, то процесс загрузки остановится. Подпись и её сравнение выполняется полностью аппаратно, и вычисленную подпись невозможно прочитать программно. Дополнительную информацию см. далее в секции "Аппаратная поддержка Secure Boot".
6. Когда запускается режим Secure Boot, программный загрузчик (software bootloader) использует ключ подписи (secure boot signing key, публичный ключ, который встроен в код самого программного загрузчика, и поэтому он был также проверен как часть образа загрузчика), чтобы проверить подпись, прикрепленную ко всем последующим таблицам разделов и образам приложения перед тем, как они будут загружены.
[Ключи шифрования]
Во время процесса Secure Boot испльзуются следующие ключи:
• "secure bootloader key" это 256-разрядный ключ AES, который сохранен в Efuse block 2. Пользователю не надо предоставлять этот ключ, потому что загрузчик может генерировать этот ключ самостоятельно с помощью внутреннего аппаратного генератора случайных чисел RNG (опционально можно предоставить этот ключ, см. далее раздел "Перепрошиваемый программный загрузчик"). Хранение этого ключа в Efuse обеспечивает защиту от чтения и записи ключа (обеспечение защиты ПО) до момента разрешения Secure Boot.
- По умолчанию применена "None" схема кодирования Efuse Block 2, и 256 бит ключа сохранены в этот блок. На некоторых устройствах ESP32 схема кодирования устанавливается на 3/4 Encoding (CODING_SCHEME efuse установлен в значение 1), и 192-битный ключ должен сохраняться в этот блок. Дополнительную информацию см. в ESP32 Technical Reference Manual -> eFuse Controller (eFuse) > System Parameter coding_scheme [PDF]. Алгоритм шифрования во всех случаях работает с ключом 256 бит, при этом 192-битные ключи расширяются путем повтора некоторых бит.
• "secure boot signing key" это стандартная ECDSA пара ключей public/private (см. секцию "Алгоритм подписи образа") в формате PEM.
- Публичный ключ из этой пары (предназначенный для проверки подписи, но не для её создания) компилируется в тело software bootloader, и используется для проверки загрузки второй стадии (таблица разделов, образ приложения) перед продолжением загрузки. Этот публичный ключ можно свободно распространять по открытым каналам, его не нужно сохранять в секрете. - Приватный ключ из этой пары должен сохраняться в секрете, и любой, кто имеет к нему доступ, может выполнить аутентификацию для любого загрузчика, который был сконфигурирован для Secure Boot и соответствующего публичного ключа.
[Размер программного загрузчика]
Разрешение secure boot и/или шифрования flash увеличивают размер загрузчика, что может потребовать обновления (увеличения) значения смещения таблицы разделов, см. раздел "Размер загрузчика" документации [5].
[Как разрешить Secure Boot]
1. Откройте меню конфигурации проекта [7], перейдите в раздел "Secure Boot Configuration" и выберите опцию "One-time Flash" (однократное программирование). Доступна альтернатива для перепрошиваемого загрузчика, см. далее раздел "Перепрошиваемый программный загрузчик".
2. Выберите имя файла для ключа подписи Secure Boot. Эта опция появится после того, как разрешена конфигурация Secure Boot. Файл может быть в любом месте в вашей системе. Относительный путь строится относительно корневого каталога проекта. Этот файл пока не существует.
3. Установите другие опции menuconfig (по мере необходимости). Уделите в частности внимание опциям "Bootloader Config", поскольку прошить загрузчик можно будет только однократно. После этого выйдите из menuconfig и сохраните свою конфигурацию.
4. При первом запуске make, если ключ подписи не найден, то отобразится сообщение об ошибке, что нужно выполнить команду espsecure.py generate_signing_key для генерации ключа подписи.
Важные замечания: ключ подписи, сгенерированный таким способом, будет использовать самый лучший источник генерации случайных числе в операционной системе, и выделенную инсталляцию Python (/dev/urandom на OSX/Linux и CryptGenRandom() на Windows). Если этот источник случайных чисел нестойкий, то приватный ключ будет ненадежным. Для целей производства рекомендуется генерировать пару ключей с использованием openssl или другой программы, соответствующую индустриальным стандартам. Подробности см. далее в разделе "Генерация Secure Boot Signing Key".
5. Запустите команду idf.py bootloader, чтобы выполнить сборку для загрузчика с разрешенной конфигурацией secure boot. Вывод сборки будет содержать приглашения для команды прошивки, используется esptool.py write_flash.
6. Когда Вы готовы прошить загрузчик, запустите указанную команду (Вы должны будете ввести её самостоятельно, этот шаг make не выполняет), и затем подождите завершения прошивки. Помните, что это прошивка однократная, после этого загрузчик поменять будет невозможно!
7. Запустите idf.py flash для сборки и прошивки таблицы раздела и только что собранного образа приложения. Образ приложения будет подписан ключом, который был сгенерирован на шаге 4.
Замечание: idf.py flash не прошивает загрузчик, если разрешена конфигурация Secure Boot.
8. Сбросьте устройство ESP32, и оно запустит программный загрузчик, который был прошит на шаге 6. Программный загрузчик разрешит Secure Boot на чипе, затем проверит сигнатуру образа приложения и после успешной проверки загрузит и запустит его. В последовательной консоли Вы должны наблюдать вывод ESP32 для проверки разрешения Secure Boot, и что не было ошибок из-за сборки конфигурации.
Замечания: безопасная загрузка будет разрешена только после прошивки корректной таблицы разделов и образа приложения. Это необходимо для предотвращения аварийных ситуаций до полной настройки системы. Если устройство ESP32 было сброшено, или был сбой по питанию во время первой загрузки, то процесс запустится снова при следующей загрузке.
9. При последующих загрузках аппаратура Secure Boot будет проверять, что программный загрузчик не был изменен (с помощью secure bootloader key) и затем программный загрузчик будет проверять подписанную таблицу разделов и образ приложения (используя публичную часть secure boot signing key).
[Перепрошиваемый программный загрузчик]
Рекомендуется сконфигурировать однократную прошивку загрузчика (опция "Secure Boot: One-Time Flash") для устройств, находящихся в производстве. В режиме однократной прошивки загрузчика каждое устройство получит уникальный ключ, который будет храниться только внутри этого устройства, и больше нигде.
Однако также существует альтернативный режим Secure Boot: Reflashable (CONFIG_SECURE_BOOTLOADER_MODE -> SECURE_BOOTLOADER_REFLASHABLE). Этот режим позволяет предоставить двоичный файл ключа, используемый в качестве secure bootloader key. Если Вы владеете этим файлом, то можете генерировать новые образы загрузчика и загрузочные подписи Secure Boot для него.
В процессе сборки ESP-IDF этот файл 256-битного ключа получается из ECDSA app signing key, генерируемого пользователем (см. далее раздел "Генерация Secure Boot Signing Key"). Этот приватный ключ SHA-256 используется как секретный ключ secure bootloader key в efuse (он применяется как есть для схемы кодирования None, либо обрезается до 192 бит, когда используется схема кодирования 3/4). Это удобно, поскольку нужно только сгенерировать/защитить один приватный ключ.
Замечание: несмотря на наличие возможности перепрошивки загрузчика, строго рекомендуется не генерировать один secure boot key и прошивать в процессе производства его копию в каждое устройство. Для производства лучше использовать опцию однократной прошивки (One-Time Flash).
Чтобы разрешить использование пререпрошиваемого загрузчика:
1. В меню конфигурации проекта [7] выберите "Bootloader Config" -> CONFIG_SECURE_BOOT -> CONFIG_SECURE_BOOT_V1_ENABLED -> CONFIG_SECURE_BOOTLOADER_MODE -> Reflashable.
2. Если необходимо, установите CONFIG_SECURE_BOOTLOADER_KEY_ENCODING, основываясь на схеме кодирования, используемой в Вашем устройстве. Схема кодирования показывается в строке Features, когда esptool.py подключается к чипу, или в результатах вывода команды espefuse.py summary.
3. Выполните шаги, показанные ниже в разделе "Генерация Secure Boot Signing Key", чтобы сгенерировать ключ подписи. Путь для сгенерированного файла должен быть указан в меню "Secure Boot Configuration".
4. Запустите команду idf.py bootloader. Будет создан двоичный файл ключа, полученный из приватного ключа, используемого для подписи. Будут выведены результаты двух прошивок - первый набор шагов включает результат команды espefuse.py burn_key secure_boot_v1 path_to/secure-bootloader-key-xxx.bin, которая используется для записи в efuse ключа загрузчика (прошивка этого ключа однократная). Второй набор шагов может использоваться для перепрошивки загрузчика с предварительно сгенерированной подписью (она генерируется во время процесса сборки).
5. Далее продолжайте выполнять действия, начиная с шага 6 описанного выше процесса разрешения однократно прошиваемого загрузчика (раздел "Как разрешить Secure Boot"), чтобы прошить загрузчик и разрешить Secure Boot. Наблюдайте за логом консоли чтобы убедиться, что не было ошибок в конфигурации Secure Boot.
[Генерация Secure Boot Signing Key]
Система сборки выведет приглашение для ввода команды с целью генерации нового ключа подписи (signing key) через команду espsecure.py generate_signing_key. Эта генерация использует библиотеку python-ecdsa, которая в свою очередь использует в качестве источника случайных чисел os.urandom() из библиотек Python.
Надежность ключа подписи пропорциональна (a) качеству генератора случайных чисел, и (b) корректности используемого алгоритма шифрования. Для устройств, находящихся в производстве, рекомендуется использовать генерацию ключей подписи на основе качественного генератора энтропии, применяя лучшие на сегодняшний день утилиты генерации ключей EC.
Например, для генерации ключа подписи с помощью openssl, используйте команду:
openssl ecparam -name prime256v1 -genkey -noout -out my_secure_boot_signing_key.pem
Помните, что безопасность Secure Boot зависит от надежности хранения в секрете приватной части ключа подписи.
[Дистанционная подпись образов]
Для сборок процесса производства хорошей практикой будет использовать удаленный сервер подписи (remote signing server) вместо того, чтобы держать ключ подписи в компьютере, на котором выполняется сборка (которая является конфигурацией безопасной загрузки ESP-IDF по умолчанию). Утилита командной строки espsecure.py на удаленной системе может использоваться при подписи образов приложения и данных таблицы разделов для Secure Boot.
Чтобы использовать удаленную подпись, запретите опцию "Sign binaries during build". Приватный signing key не обязательно должен присутствовать в системе сборки. Однако публичный ключ (сигнатура проверки) нужен, потому что он компилируется в тело загрузчика (и может использоваться для проверки сигнатур образа при обновлениях OTA [8]).
Чтобы получить публичный ключ из приватного ключа, выполните команду:
espsecure.py extract_public_key --keyfile PRIVATE_SIGNING_KEY PUBLIC_VERIFICATION_KEY
Для сборки защищенного загрузчика в menuconfig (опция "Secure boot public signature verification key") необходимо указать путь к ключу проверки публичной подписи.
После того, как была выполнена сборка образа приложения и таблицы разделов, система сборки напечатает шаги для выполнения подписи с помощью утилиты espsecure.py:
espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY BINARY_FILE
Эта команда присоединит подпись образа к существующему двоичному файлу. Вы можете использовать аргумент –output, чтобы записать пописанный двоичный код в отдельный файл:
espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY --output SIGNED_BINARY_FILE BINARY_FILE
[Рекомендуемая практика использования Secure Boot]
• Генерируйте ключ подписи на системе, где присутствует качественный источник энтропии (надежный генератор случайных чисел). • Сохраняйте ключ подписи приватным в течение всего времени жизни устройств. Утечка этого ключа скомпрометирует систему Secure Boot. • Не позволяйте сторонним лицам вмешиваться в любые аспекты генерации ключа или процесса подписи с использованием espsecure.py. Оба этих процесса уязвимы по времени или для сторонних атак. • Разрешите все опции безопасности в конфигурации Secure Boot. Это включает шифрование flash, запрет JTAG, запрет интерпретатора BASIC ROM, и запрет доступа к зашифрованной flash-памяти загрузчика UART. • Используйте Secure Boot в комбинации с flash encryption, чтобы предотвратить локальное чтение содержимого памяти flash.
[Технические подробности Secure Boot]
Следующие разделы содержат низкоуровневые справочные описания различных элементов безопасной загрузки.
Аппаратная поддержка Secure Boot. Первая стадия проверки Secure Boot (проверка тела software bootloader) осуществляется аппаратно. Аппаратная поддержка Secure Boot чипа ESP32 может выполнять 3 базовые операции:
1. Генерация случайной последовательности байт с помощью аппаратного генератора случайных чисел RNG. 2. Генерация цифровой подписи для данных (обычно для образа загрузчика из flash), используя ключ, сохраненный в Efuse block 2 (см. [3, 4]). Ключ в Efuse защищен от чтения/записи, и его чтение недоступно со стороны программы (см. далее секцию "Алгоритм цифровой подписи защищенного загрузчика"). Цифровая подпись может быть прочитана программно только если не прошит Efuse ABS_DONE_0 (т. е. его значение осталось в лог. 0). 3. Генерация цифровой подписи из данных (обычно из образа загрузчика, находящегося в SPI flash), используя тот же алгоритм, как на шаге 2, и сравнение её с предварительно вычисленной подписью, предоставленной в буфере (она обычно находится в SPI flash со смещением 0x0). Аппаратура вернет результат сравнения true/false, не предоставляя для программы доступ к подписи. Эта функция доступна даже когда прошит Efuse ABS_DONE_0.
Алгоритм цифровой подписи защищенного загрузчика. Начиная с "образа" двоичных данных на входе, этот алгоритм генерирует на выходе цифровую подпись. Эта подпись иногда в документации аппаратуры называется как "abstract".
Для Python-версии этого алгоритма см. утилиту espsecure.py tool, которая находится в каталоге components/esptool_py (команда digest_secure_bootloader).
Элементы, помеченные символам (^), должны соответствовать аппаратным, а не криптографическим ограничениям.
1. Считывается ключ AES из efuse block 2, в обратном порядке байт. Если для efuse установлена схема кодирования 3/4 Encoding, то 192 бита расширяются до 256 бит с использования алгоритма, описанного в [9]. 2. К образу добавляется префикс из 128 байт случайно сгенерированного IV. 3. Если длина образа не делится нацело на 128, то образ дополняется байтами 0xFF (^). 4. Для каждых 16 байт открытого текста входного образа: - Реверсирование порядка байт входного блока открытого текста (^). - Применение AES256 в режиме ECB для блока открытого текста. - Реверсирование порядка байт блока зашифрованного текста (ciphertext). (^) - Добавление ciphertext к общему выводу. 5. Перестановка байт в каждом слове из 4 байт ciphertext (^). 6. Вычисление SHA-512 от ciphertext.
Выходная подпись содержит 192 байта данных: 128 байт IV, за которым идет 64 байта подписи SHA-512.
Алгоритм подписи образа. Применяется детерминированный алгоритм ECDSA, как указано стандартом RFC 6979.
• Кривая NIST256p (openssl называет эту кривую "prime256v1", также она иногда называется secp256r1). • Хеш-функция SHA256. • Формат для хранения ключа PEM. В загрузчике публичный ключ (для проверки подписи) прошивается как 64 сырых байта. • Подпись образа состоит из 68 байт - 4 байта слова версии (в настоящий момент нули), за которыми идут 64 байта данных подписи. Эти 68 байт добавляются к образу приложения или данным таблицы разделов.
Запуск команд вручную. Технология Secure Boot интегрирована в систему сборки ESP-IDF, которая автоматически подписывает образ приложения, если разрешена конфигурация Secure Boot. Команда idf.py bootloader будет формировать подпись загрузчика (bootloader digest), если для этого сконфигурирована конфигурация проекта (menuconfig).
Однако есть возможность использовать утилиту espsecure.py для генерации отдельных сигнатур и подписей.
Для подписи двоичного образа:
espsecure.py sign_data --keyfile ./my_signing_key.pem --output ./image_signed.bin
image-unsigned.bin
Здесь keyfile это файл в формате PEM, содержащий приватный ключ подписи (ECDSA private signing key).
Для генерации подписи загрузчика:
espsecure.py digest_secure_bootloader --keyfile ./securebootkey.bin --output
./bootloader-digest.bin build/bootloader/bootloader.bin
Здесь keyfile это 32 сырых байта ключа безопасной загрузки (secure boot key) для устройства.
Вывод команды espsecure.py digest_secure_bootloader command это один файл, который содержит подпись, так и добавленный к ней загрузчик. Для прошивки этого файла в устройство:
esptool.py write_flash 0x0 bootloader-digest.bin
[Secure Boot и Flash Encryption]
Если Secure Boot используется без Flash Encryption, то есть возможность запустить атаку взлома типа "time-of-check to time-of-use", где содержимое flash подменяется после того, как образ проверен и запущен. Таким образом, рекомендуется одновременно включить обе эти опции защиты.
[Проверка подписи приложения без Hardware Secure Boot]
Целостность приложений можно проверить без разрешения опции аппаратной проверки загрузки (hardware secure boot). Эта опция использует ту же самую схему подписи приложения, как и hardware secure boot, однако в отличие от hardware secure boot она не защищает загрузчик от физического обновления. Это означает, что устройство может быть защищено от доступа через удаленный доступ по сети, но не будет защищено от физического локального доступа. В сравнении с аппаратным Secure Boot эта опция намного проще для реализации. Пошаговые инструкции см. далее в секции выше в разделе "Как разрешить проверку подписанного приложения".
Приложение может быть проверено при обновлении, и опционально при загрузке.
• Проверка при обновлении (опция Verification on update): когда это разрешено, подпись автоматически проверяется всякий раз, когда для OTA-обновления [8] используется esp_ota_ops.h API. Если разрешена функция hardware secure boot, то эта опция всегда разрешена и не может быть запрещена. Если функция hardware secure boot не разрешена, то эта опция все еще добавит значимую защиту от атак по сети, предотвращая спуфинг обновлений OTA. • Проверка при загрузке (опция Verification on boot): когда это разрешено, в загрузчик будет скомпилирован код для проверки подписи приложения перед тем, как оно будет загружено. Если разрешена функция hardware secure boot, то эта опция всегда разрешена и не может быть запрещена. Если функция hardware secure boot не разрешена, то эта опция не добавляет защищенности, так что большинство пользователей оставят эту опцию запрещенной.
Как разрешить проверку подписанного приложения:
1. Откройте меню конфигурации проекта -> Security features -> разрешите CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT.
2. Может быть разрешена опция "Bootloader verifies app signatures", которая обеспечивает проверку загрузчиком образа приложения.
3. По умолчанию при выборе опции "Require signed app images" будет разрешена опция "Sign binaries during build", что приведет к подписи двоичных файлов, которая будет выполняться как часть процесса сборки. Файл с именем "Secure boot private signing key" будет использоваться для подписи образа.
4. Если запретить опцию "Sign binaries during build", то в "Secure boot public signature verification key" понадобится ввести путь до файла публичного ключа, используемого для проверки подписанных образов. В этом случае приватный ключ подписи должен быть сгенерирован инструкциями, описанными выше в разделе "Генерация Secure Boot Signing Key". Проверочный публичный ключ и подписанный образ должен быть сгенерирован инструкциями, описанными выше в разделе "Дистанционная подпись образов".
[Дополнительные возможности]
Отладка JTAG. По умолчанию, когда разрешена конфигурация Secure Boot, отладка JTAG через eFuse запрещается. Загрузчик прошивает этот eFuse во время первой загрузки, одновременно с прошивкой eFuse, который разрешает Secure Boot.
См. "JTAG with Flash Encryption or Secure Boot" в советах [10] для дополнительной информации по использованию отладки JTAG, когда разрешена конфигурация Secure Boot, или разрешена проверка подписанного приложения.
[Словарик]
OTA Over The Air, технология загрузки (обновления) по радиоканалу.
PEM Privacy Enhanced Mail, текстовый файл, содержащий сертификат подписи или ключ шифрования в виде ASCII-текста.
[Ссылки]
1. ESP32 Secure Boot site:docs.espressif.com. 2. ESP32 Secure Boot V2. 3. ESP32: контроллер eFuse. 4. ESP32 eFuse Manager. 5. ESP32 Bootloader. 6. ESP32: процесс запуска приложения. 7. Конфигурация проекта ESP-IDF. 8. ESP32: обновление по радиоканалу (OTA). 9. ESP32 Flash Encryption site:docs.espressif.com. 10. ESP32 Tips and Quirks site:docs.espressif.com. |