GitHub – AktivCo/rutoken-uefi-apdu-samples: Пример по работе с токенами и смарт-картами Рутокен из UEFI-модуля

GitHub - AktivCo/rutoken-uefi-apdu-samples: Пример по работе с токенами и смарт-картами Рутокен из UEFI-модуля Электронная цифровая подпись

Описание проекта

Этот проект содержит пример по работе с токенами и смарт-картами Рутокен из UEFI-модуля. Для взаимодействия со смарт-картами используется UEFI Smart Card Reader Protocol, представленный в спецификации UEFI версии 2.5.

Токен на таблетке — это пробник. Если пробы прошли успешно, то можно собрать нормальное устройство для повседневного пользования. Продвинутый эмбеддер нарисует

, изготовит её в JLCPCB, и получит массу удовольствия в виде кучки плат.

Если же нужно собрать пару ключей, то дешевле использовать ST-Link-свисток от наших друзей. На плате есть (почти) всё что нужно. Подойдёт любой контроллер, 103-й оригинал или один из его клонов.

Вот срисовал схему, может кому пригодится:

GitHub - AktivCo/rutoken-uefi-apdu-samples: Пример по работе с токенами и смарт-картами Рутокен из UEFI-модуля
Замечания по схеме:

  • не показаны второстепенные компоненты (блокирующие конденсаторы, стабилизатор 3,3В, разъём USB);
  • микросхема DD2 — логический элемент-повторитель с выходом ОК (УГО перерисовывать было лень); его назначение — формировать крутые срезы на линии SWIM; вместо DD2 может быть установлен нолик R1;
  • на плате Mini ST-Link одной из старых версий (зелёная ниже по тексту) DD2 не предусмотрена, порт PB11 подключен к PB8, а PB14 наоборот, висит в воздухе;
  • цепи UART_RT/UART_TX/TDO/TDI/SWO/NRST/JRST в свистке не подключены; используются в полноценных реализациях ST-Link`а;
  • всегда думал, что вход BOOT0 нельзя оставлять неподключенным; однако здесь он почему-то висит в воздухе, и тем не менее всё работает. На зелёной плате (старой версии) установлен резистор 10к.

Вспомнил. В одном проекте на основе STM32F407 (да, тот самый, который видеосигнал делать умеет) висящий BOOT0 отобрал у меня кучу нервов и времени, пока искал причину непонятных спорадических глюков…

Наш донор со снятыми штанами:

Загрузка файла

Запуск

Для модулей, решающих прикладные задачи, стандартным методом внедрения в процесс загрузки компьютера является модификация глобальных NVRAM-переменных (см. 3 Boot Manager Unified Extensible Firmware Interface Specification 2.6). Для запуска UEFI-приложения, в частности, требуется создание переменной Boot#### и внесение имени этой переменной в список загрузки, заданный в переменной BootOrder.

Поскольку пример предполагается использовать в целях ознакомления, его запуск предлагается выполнять вручную из UEFI Shell. Ниже описаны также и альтернативные методы запуска.

Запуск с помощью ovmf в системе linux

Находясь в корневой директории выполните следующие действия:

  1. Для настройки BaseTools и переменных окружения выполните команды:
  2. Для сборки образа OVMF выполните следующую команду:

    Данная последовательность команд соберет образ OVMF компилятором GCC версии >=5.0 (список поддерживаемых
    идентификаторов находится в файле edk2/Conf/tools_def.txt) для архитектуры x86-64. Собранный образ OVMF
    будут находиться по пути Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd.

  3. Создайте рабочую директорию и директорию, в которую поместятся собранные файлы драйвера и примеров:
  4. Скопируйте файлы OVMF_CODE.fd и OVMF_VARS.fd из директории собранного OVMF образа в директорию run-ovmf:
  5. Поместите файлы драйвера и примеров в директорию hda-contents
  6. Запустите OVMF образ в qemu, предварительно указав путь до директории, содержащей собранные драйвер и примеры, например:
    sudo qemu-system-x86_64 -L . --hda fat:rw:hda-contents 
    -drive if=pflash,format=raw,unit=0,readonly=on,file=OVMF_CODE.fd 
    -drive if=pflash,format=raw,unit=1,readonly=off,file=OVMF_VARS.fd 
    -net none -usb -device qemu-xhci,id=xhci 
    -device usb-host,bus=xhci.0,vendorid=0x0a89,productid=0x0030
    

    Данная команда запустит OVMF образ, предоставив виртуальной машине доступ на чтение и запись к директории hda-contents.
    При запуске виртуальной машины будет создано устройство виртуального USB контроллера, к которому будет подключено
    прокинутое с хоста USB устройство, указанное в параметрах vendorid и productid.

  7. Перейдите в раздел, который содержит файлы исполняемых образов. Например, если файлы содержатся в разделе fs0, перейти в него можно командой
  8. Загрузите Smart Card Reader драйвер с помощью команды

    При удачной загрузке драйвер будет присутствовать в выводе команды drivers.

  9. Запустите пример:

Запуск с помощью uefi shell

  1. Подготовить загрузочный раздел UEFI Shell (например, используя USB носитель). Для этого требуется:
    1. Предварительно отформатировать загрузочный раздел, использовав FAT32 в качестве целевого формата файловой системы
    2. Создать в корне раздела директории, имеющие следующую структуру:
    1. Загрузить UEFI Shell, переименовать
      его в bootx64.efi и поместить в директорию /EFI/boot
    2. Загрузить исполняемые образы Smart Card Reader драйвера и примеров в произвольную директорию внутри раздела
  2. Выполнить загрузку с UEFI Shell раздела:
    1. Если активирована функция Secure Boot, её требуется отключить в настройках UEFI
    2. После отключения Secure Boot, возможно выполнить загрузку в UEFI Shell, выбрав содержащий UEFI Shell раздел
      в списке загрузочных разделов, предлагаемых настройками UEFI
  3. Перейти в раздел, который содержит файлы исполняемых образов. Например, если файлы содержатся в разделе fs0,
    перейти в него можно командой
  4. Загрузить Smart Card Reader драйвер с помощью команды:

    При удачной загрузке драйвер будет присутствовать в выводе команды drivers.

  5. Запустить пример:

Инструменты и оборудование

Без микроскопа и паяльника с тонким жалом здесь делать нечего. Чтобы не ловить бегающую по столу плату, нужен держатель плат. Фен тоже лишним не будет.

Использование uefi smart card reader protocol

Использование UEFI Smart Card Reader Protocol осложнено тем, что в спецификации UEFI он появился только в версии 2.5, и некоторые прошивки UEFI все еще не содержат реализации этого протокола.

Существует opensource-реализация UEFI Smart Card Reader Protocol в виде отдельного драйвера, выполненная LudovicRousseau. Реализация драйвера не проходила тщательного аудита кода и не была принята в кодовую базу проекта edk2, в основном, из-за неготовности мейнтейнеров проекта edk2 вносить в проект компоненты, лицензированные под LGPL.

Код драйвера с небольшими исправлениями сборки и обновленной зависимостью от EDK II размещен для ознакомления в репозитории AktivCo/uefi-smartcard-reader-driver. Эта версия драйвера может быть использована для запуска UEFI-модулей, взаимодействующих со смарт-картами, в UEFI-средах, где отсутствует встроенная реализация UEFI Smart Card Reader Protocol.

Конфигурация и сборка

В репозитории проекта используются сабмодули. Перед сборкой, пожалуйста, убедитесь, что исходный код проекта скачан полностью. Для скачивания сабмодулей достаточно выполнить следующую команду из корневой директории проекта:

Для сборки проекта используется окружение EDK II. Для сборки проекта должны быть выполнены предусловия, включающие в себя установку инструментов для сборки. В частности, для сборки потребуется компилятор (GCC или Clang), Python, NASM.

Настройка конфигурации железа

Библиотеке chopstx нужно сказать, какой используется контроллер, как настроить тактирование, к каким портам подключены светодиод и кнопка. Штатно файлы конфигурации хранятся в файлах chopstxboardboard-*.h. Для сборки проекта расположение нужного файла указывается в makefile.

Форк проекта с моими доработками здесь, ветка blue_pill_btn. В makefile добавил конфигурации для указанных выше трёх плат:

  • Blue Pill: кнопка к PB8 и на землю; светодиод анодом к питанию, катодом к PC13;
  • Black Pill: кнопка к PС13 и на землю; светодиод анодом к питанию, катодом к PB12;
  • ST-Link-v2 mini: сенсорная кнопка к PA2 (активный низкий); светодиод анодом к питанию, катодом к PB12.

Проект подготовлен к сборке в Эклипсе.

План работ:

  • установить зелёный светодиод (штатные — красный и синий — моветон, да и светят вбок в маленькую дырочку, их плохо видно);
  • установить сенсорную кнопку;
  • установить разъём для подключения отладчика/программатора (опционально).

Механическая кнопка на практике оказалась неудобной. Нажатие требует неслабого усилия, которое передаётся на USB-разъём и постепенно убивает его. Поэтому сенсорный датчик лучше.

После сборки доработать напильником

Кроме собственно программы, в память микроконтроллера нужно залить сертификат и его приватный ключ. Это всё хранится в памяти Flash начиная с адреса 0x0800F400.

Распределение памяти (STM32F103) следующее:

  • 0x08000000-F3FF — код (реально около 28кб);
  • 0x0800F400-F7FF — сертификат; в начале страницы размещается структура-указатель attestation_cert (см. файл empty-attestation-cert.c);
  • 0x0800F800-FBFF — приватный ключ; 32 байта и для надёжности его хэш, ещё 32 байта;
  • 0x0800FС00-FFFF — счётчик аутентификаций.

Сертификат

можно создать собственный, или использовать прилагаемый. Если в строке параметров сборки указать ключ CUSTOM_ATTESTATION_CERT, то будут выполнены скрипты из папки srccert, которые создадут новый сертификат, и закинут его в файл certificates.c. Если ключ CUSTOM_ATTESTATION_CERT не указать, то будет использован дефолтный (пустой) файл empty-attestation-cert.c, а сертификат придётся записать в память микроконтроллера при помощи скрипта certcerttool или программатором.

Поскольку сертификат напрямую не привязан к аппаратному железу, то его можно интегрировать в прошивку. Что я и сделал. Пользуйтесь на здоровье. В прошивки (что в приложении к статье) вставлен сертификат, прилагаемый к оригинальному проекту. Действителен до 2029-03-07, срока годности вполне достаточно.

Приватный ключ. Это секрет (32 байта), который отвечает за «уникальность» ключа и используется в криптографических алгоритмах. Ключ защищается его sha256-отпечатком. Отпечаток проверяется во время инициализации устройства (при подаче питания). Если ошибка — ключ будет создан заново. Заодно обнулится счётчик аутентификаций.

Приватный ключ можно также подготовить вручную и внедрить его в прошивку. Это можно сделать при помощи питонячьего скрипта inject_key.py (достаёт бинарник из u2f.elf) или inject_key_bin.py (работает с бинарником u2f.bin). Однако надо внимательно проверить результат.

Счётчик хранится в верхней странице памяти Flash. Для увеличения ресурса в памяти реализован кольцевой буфер, страница памяти будет очищена после достижения его границы. Теоретический ресурс составит 1024/4*10k = 2560 килоциклов. На наш век хватит.

Кстати, ходят слухи о массовом море ключей JaCarta. Причиной вполне может быть ограниченный ресурс Flash-памяти.

Счётчик обнуляется при создании нового приватного ключа. Если для записи приватного ключа использован скрипт inject_key*.py, то начальное значение счётчика также может быть записано этим скриптом. Если прошивка собрана без опции ENFORCE_DEBUG_LOCK=1, то счётчик можно поправиль вручную при помощи программатора: очистить страницу памяти FC00-FFFF (записать FF), а в начало (по адресу FC00) поместить 4-байтное начальное значение (младший байт первый).

Чтобы поддержать ваше желание собрать безопасный ключ, предлагаю готовые прошивки для трёх приведенных выше аппаратных платформ. Каждая прошивка собрана в двух исполнениях:

  • с автоматическим локом, суффикс “_lock”;
  • без включения защиты кристалла, суффикс “_nolock”.

Первый вариант прошивки после первого старта включает защиту от чтения. Второй вариант этого не делает, оставляя возможность подключения программатора и чтения памяти. Незалоченный чип позволяет клонировать ключ. Что при желании можно сделать (см. далее).

В прошивку уже встроен сертификат. Приватный ключ отсутствует, он будет создан автоматически при первом включении.

Почти готово

Итак, подключаем программатор, полностью очищаем память микроконтроллера, записываем нашу прошивку. Отключаем программатор. Перезапускаем токен по питанию. При первом включении будет создан секретный ключ и обнулён счётчик. После чего токен готов к работе.

Прошивка -lock при первом включении лочится и зависает. Нужно перезапустить токен по питанию. Также пару раз зависал во время первой аутентификации (возможно не смог очистить страницу памяти со счётчиком). Почему это происходит, не разбирался. В дальнейшем во время эксплуатации проблем не возникало.

Проверить работоспособность ключа можно на демо-сайте Юбикея. Там же можно посмотреть протокол обмена между ключом и сервером.

Во время регистрации ключа Виндовз предложит свои услуги (Windows Hello). Отказаться, два раз нажать ОК, и когда замигает светодиод, нажать юзер-кнопку на ключе.

GitHub - AktivCo/rutoken-uefi-apdu-samples: Пример по работе с токенами и смарт-картами Рутокен из UEFI-модуля
Подтвердить физическое присутствие можно и заранее. Сначала нажать на юзер-кнопку, а потом в течение 10 сек. успеть выполнить процедуру регистрации/аутентификации.

Рутокен m2m

IoT повышает качество жизни людей и помогает многим компаниям адаптировать свой бизнес к современным реалиям. Вместе с тем рынок IoT работает на стыке различных технологий, являя миру новые, ранее не применявшиеся решения. Поэтому крайне важно уделять внимание безопасности, т. к. игнорирование и откладывание решения этого вопроса может дорого обойтись.

Устранение последствий вторжения всегда на порядки дороже, чем затраты на внедрение решений по безопасности. С новыми возможностями индустрии IoT приходят и новые риски, которые лучше нивелировать на начальной стадии проекта.

Сборка

Сборка прошивки — пожалуй самая трудоёмкая задача для неопытного юзера. В

есть подробная инструкция по сборке на Linux. Как обычно принято в opensourse, только хардкор, через make-файл, с привлечением скриптов на баше и пайтоне. Несколько готовых прошивок предлагается в разделе

Чтобы компилятор не нагружать поиском подходящего файла конфигурации (из списка chopstxboard*.h), перед сборкой проекта создаётся ссылка srcboard.h на нужный файл конфигурации утилитой ln (из комплекта busybox). И компилятор использует именно этот файл-ссылку.

После смены цели (target) ссылку board.h нужно обязательно удалить командой make distclean, чтобы создать новую на актуальный файл конфигурации. В Виндовз ссылку можно создать в файловой системе NTFS. А в FAT32 — нет, проект не соберётся. В последнем случае нужно руками скопировать нужный chopstxboardboard-*.h в src и переименовать его в board.h. И чуть поправить makefile.

Вполне реально собрать проект и в любимой IDE Eclipse GCC-ARM. Дополнительно потребуются утилиты cp/ln/mkdir из комплекта busybox. А также руки из правильного места, и традиционные танцы с бубном.

Сборка в linux (gcc)

Для настройки среды сборки, воспользуйтесь инструкциями по ссылке.

Для операционных систем, основанных на Debian, ожидается, что данная команда установит все необходиные инструменты:

Для сборки используется компилятор gcc. Тестирование сборки производилось компиляторами gcc 4.8.

Каждый шаг сборки выполняется из корневой директории проекта.

  1. Выполнить сборку BaseTools проекта edk2:

  2. Настроить BaseTools и переменные окружения:

  3. Выполнить сборку UEFI-модуля примера:

Исполняемый модуль примера доступен по пути ${WORKSPACE}/Build/RutokenSamplesPkg/RELEASE_GCC5/X64/RutokenGetTokenID.efi.

Сборка в windows (clang)

Перед сборкой требуется установить инструменты:

  1. Python версии 3.7 или выше
  2. NASM – инструкция по настройке
  3. ASL – инструкция по настройке
  4. Clang.

Для сборки используется компилятор clang. Тестирование сборки производилось компиляторами clang 9 и clang 11.

Каждый шаг сборки выполняется в командной строке из корневой директории проекта.

  1. Настроить переменные окружения:

  2. Выполнить сборку BaseTools проекта edk2:

  3. Выполнить сборку UEFI-модуля примера:

Исполняемый модуль примера доступен по пути ${WORKSPACE}/Build/RutokenSamplesPkg/RELEASE_CLANGPDB/X64/RutokenGetTokenID.efi.

Установка примера в качестве загрузчика в ovmf

Для настройки автоматической загрузки драйвера и автоматического выполнения примера как основного загрузчика необходимо добавить информацию об этих модулях в UEFI-переменные Boot####, Driver####, BootOrder, DriverOrder. Выполнить это можно из среды UEFI Shell, которая загружается при выполнении шагов 1 — 7 предыдущей инструкции, после чего выполнить:

  1. Настроить автоматическую загрузку драйвера:
  2. Настроить автоматический запуск примера, как первого исполняемого загрузчика:
  3. Завершить работу qemu.

Записи, ассоциированные с драйвером SmartCardReader.efi и загрузчиком RutokenGetTokenID.efi были записаны в NVRAM-переменные, которые сохраняются между запусками qemu в файле OVMF_VARS.fd. Для повторного запуска, при котором произойдет автоматическая загрузка драйвера и автоматическое выполнение примера, можно использовать команду:

sudo qemu-system-x86_64 -L . --hda fat:rw:hda-contents 
-drive if=pflash,format=raw,unit=0,readonly=on,file=OVMF_CODE.fd 
-drive if=pflash,format=raw,unit=1,readonly=off,file=OVMF_VARS.fd 
-net none -usb -device qemu-xhci,id=xhci 
-device usb-host,bus=xhci.0,vendorid=0x0a89,productid=0x0030

Шаг второй

Зачистить маску в указанных местах и перерезать две дорожки. Дорожка, которая идёт к выводу 15 (цепь SWCLK), будет использована для подключения емкостного контакта. К контакту 5V будет припаян светодиод.

Шаг первый

Отпаять разъём IDC. Брутальные электронщики выкусывают пластмассу и поочерёдно отпаивают контакты. Но мы используем недеструктивный метод. Зазор между платой и выводами позволяет поочерёдно освободить все контакты разъёма при помощи обычного паяльника и стального лезвия от бритвы. Разъём сохраняется для будущих поделок:

Шаг пятый

Перевернуть плату, припаять перемычку для светодиода и полоску из медной фольги. Площадку 3V3 отрезать от питания. Лепесток загнуть на обратную сторону платы. Это будет емкостной сенсор. Также рекомендуется подрезать выводы кварцевого резонатора, чтобы их не коротнуло на корпус.

В итоге получаем вот такую фитоняшку:

С торца имеем SWD-разъём, сенсор и светодиод. После успешного проведения испытаний свисток можно аккуратно замотать каптоновым скотчем. Для защиты от грази, статики, и чтобы плата не выпадала из корпуса. Или напечатать на 3D-принтере крышку-затычку. Или корпус целиком.

Шаг третий

С обратной стороны снять R11 и R12 (фото ниже). На позицию R12 становить конденсатор 100-1000 пФ. Если чувствительность емкостного датчика окажется слишком высокой, установить на место R11 конденсатор 0-50 пФ (см. даташит TTP223).

Шаг четвёртый

Устанавливаем TTP223, разъём программирования (если нужен), светодиод, паяем провода. Светодиод 0805 или 1206, цвет по своему вкусу. Мне нравится зелёный. Все выводы TTP223 кроме 2 и 5 чуть приподнять. Вывод 4 соединить с 5-м (чтобы задать низкий активный уровень при обнаружении пальца).

Кстати, есть простой способ, как зажать короткий отрезок провода МГТФ. Думаю, о нём все знают. Но на всякий случай оставлю это здесь (чёрная штука — обычный китайский пинцет):

Нужно сделать примерно так:

GitHub - AktivCo/rutoken-uefi-apdu-samples: Пример по работе с токенами и смарт-картами Рутокен из UEFI-модуля
Разъём программирования опциональный. Если дальнейших экспериментов не планируется, для программирования можно временно подпаяться с обратной стороны.

Для подключения по SWD предпочитаю разъём PBS1.27-5:

  • 1 — GND
  • 2 — SWDIO
  • 3 — SWCLK
  • 4 — SWDIO
  • 5 — GND

Компактный. Разъём-перевёртыш, не нужно искать ключ. Если при подключении ответную часть чуть наклонить, первым соединяется земля. В серийном изделии разъём можно не устанавливать, для однократного подключения достаточно отверстий. Сплошные плюсы.

Читайте также:  3 Easy Ways to Use a Voxal Voice Changer - wikiHow
Оцените статью
ЭЦП Эксперт
Добавить комментарий

Adblock
detector