Проверка подписи загружаемых модулей в Genode

Цель

Реализовать прототип модуля init с функцией контроля целостности загружаемых модулей используя механизм электронной цифровой подписи (ЭЦП). Ознакомится с процессом загрузки ОС, принципами формирования ЭЦП и интегрировать полученные инструменты в систему сборки.

1. Общая информация

Для начала разберемся, что представляет собой ЭЦП [1]:

Электронная подпись предназначена для идентификации лица, подписавшего электронный документ, и является полноценной заменой (аналогом) собственноручной подписи в случаях, предусмотренных законом. Использование электронной подписи позволяет осуществить:
- Контроль целостности передаваемого документа: при любом случайном или преднамеренном изменении документа подпись станет недействительной, потому что вычислена она на основании исходного состояния документа и соответствует лишь ему.
- Защиту от изменений (подделки) документа: гарантия выявления подделки при контроле целостности делает подделывание нецелесообразным в большинстве случаев.
- Невозможность отказа от авторства. Так как создать корректную подпись можно, лишь зная закрытый ключ, а он известен только владельцу, он не может отказаться от своей подписи под документом.
- Доказательное подтверждение авторства документа: Так как создать корректную подпись можно, лишь зная закрытый ключ, а он известен только владельцу, он может доказать своё авторство подписи под документом. В зависимости от деталей определения документа могут быть подписаны такие поля, как «автор», «внесённые изменения», «метка времени» и т. д.

Для реализации ЭЦП наиболее часто используются асимметричные криптографические алгоритмы. Для подписи генерируются пара ключей: открытый и закрытый. Подпись и проверка выполняются в соответствие со следующей структурной схемой: By Acdx (Own work) [CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0) or GFDL (http://www.gnu.org/copyleft/fdl.html)], via Wikimedia Commons"

Исходя из этого к ключам предъявляются следующие требования:

В качестве алгоритмов используемых для ЭЦП в России рекомендуется применять ГОСТ Р 34.10-2012 [2] и ГОСТ Р 34/11-2012 [3] в качестве хеш-функции. В данной лабораторной работе рекомендованными алгоритмами являются ECDSA и SHA256 в качестве хеш-функции. В репозитории sss13 добавлены сторонние открытые библиотеки, реализующие данные алгоритмы micro-ecc [4] и SHA2 [5]. Открытый GOST engine из OpenSSL не использован по причине не возможности динамической линковки процесса init.

В качестве платформы будем использовать Fiasco.OC (base-foc) для архитектуры x86_32. На самом деле мы не будем добавлять никакого платформо-специфичного кода, но формирование загрузочного образа в системе сборки является платформо-зависимым.

Рассмотрим загрузку образа, построенного на базе Genode+Fiasco.OC более подробно:

  1. Загружается загрузчик, в нашем случае GRUB, все модули, указанные в конфигурационном файле загрузчика, загружаются в соответствии со спецификацией Multiboot. Управление передается модулю bootstrap.
  2. bootstrap выполняет часть операций необходимых для старта ядра, такие как:
    • сканирование доступной памяти;
    • перемещение модулей в памяти (sigma0 и root task должны быть расположены в определенных регионах, чтобы ядро при старте могло их запустить);
    • и непосредственно запуск ядра.
  3. Ядро выполняет необходимую инициализацию системы, запускает sigma0 и root task.
  4. Начинает выполняться модуль core (являющийся root task в Genode), который инициализирует сервисы Genode и запускает модуль init
  5. init последовательно загружает указанные в конфигурации модули (файл config) и запускает их выполнение.

Более подробно модуль init и создании процессов в Genode были рассмотрены в лекции “Genode Architecture”[6] прошлогодней летней школы и в статье “Configuring the init process of Genode”[7] в разделе документации на сайте Genode.

3. Порядок выполнения и рекомендации

  1. Для начала работы необходимо подготовить окружение:
    • форкнуть наш репозиторий на GitHub
    • переключиться на ветку sss13_lab
    • подготовить библиотеки:
      make prepare -C libport PKG=libc
      make prepare -C sss13

    В данном репозитории уже выполнена предварительная подготовка системы сборки и исходного кода. “Заготовка” утилиты для подписи с использованием рекомендованных библиотек находится в sss13/tools/signtools, там же находятся утилиты для добавления значения подписи в конфигурационный файл и генерации ключей.
    Оригинальный исходный код init находится в директориях os/src/init и os/include/init. Для данной работы заготовка исходного кода, скопирована в директории sss13/src/initsig и sss13/include/initsig. Этот исходный код будет использоваться в дальнейшем описании.

  2. Добавить расчет подписи для каждого исполняемого модуля и добавление полученного хеша в конфигурацию на этапе создания образа.
    Необходимо доработать утилиту для подписи sss13/tool/signtools/signfile.ccх[^8]. Эта утилита должна получать на входе имя файла с данными для подписи и имя файла с содержимым закрытыго ключа и выводить в stdout значение подписи в виде строки. Это значение при сборке, с помощью утилиты signfile.py будет вставлено в конфигурационный файл.
    Доступ к загруженным загрузчиком файлам для Genode осуществляется через ROM Session. Но для dataspace, относящегося к открытому файлу, невозможно получить реальный размер файла, размер dataspace всегда кратен размеру страницы памяти (4096 байт). Поэтому для получения хеша, размер файла должен быть дополнен нулями до размера кратного размеру страницы и затем вычислен хеш.
    Используя полученный хеш и закрытый ключ получить подпись. Подпись добавляется в конфигурационный файл на этапе сборки в виде <signature value="xxx">. Пример:
    <start name="timer">
    <resource name="RAM" quantum="20M" />
    <provides><service name="Timer" /></provides>
    <signature value="bc8d2e767f7da92b6216796eaff7ec3883597da0f751b5248baa1dae763a17bfc52b72280b3a74c49ba9c0e459adc3d72d0af58622a60440018d3f0713028650" />
    </start>

  3. Добавить проверку подписи в init
    Для начала рассмотрим исходный код модуля initsig более подробно. Модуль initsig (sss13/src/initsig/main.cc [9]) выполняет следующие действия:
    • инициализацию динамического линкера, если найден ld.lib.so (строки 154-157);
    • регистрацию сигнала, используемого для уведомления init-а об изменении конфигурации (строки 167-169);
    • определение роутинга сервисов (строки 178-186);
    • и создание потомков (строки 188-219), заканчивающееся параллельным стартом всех потомков;
    • оставшийся код отвечает за перезапуск потомков, в случае изменения конфигурации на лету.

    В данный код добавлена обработка исключения InitSig::Child::Signature_failed, которое должен генерировать класс InitSig::Child в случае каких-либо ошибок при проверке ЭЦП.
    За создание потомка отвечает класс InitSig::Child [10], который непосредственно создает процесс, именно в его конструктор стоит добавить проверку ЭЦП. Рассмотрим этот код и определим функционал, который необходимо реализовать:
    - получение значения сигнатуры из конфигурационного файла для данного модуля (строки 486-502);
    - конвертирование сигнатуры из строки в бинарный вид, пригодный для дальнейшего использование в проверке (необходимо реализовать, заготовка в строках 504-506);
    - получение указателя на данные модуля и его длину (необходимо реализовать, строки 508-510);
    - расчет хеша для данных загружаемого модуля (необходимо реализовать, строки 512-514);
    - проверка ЭЦП (необходимо реализовать, строки 522-523);
    - в случае успешной проверки ЭЦП производится создание нового модуля (строки 527-528).

    Открытый ключ в рамках этой лабораторной работы может быть просто вкомпилен в init (sss13/src/initsig/main.cc строка 19).

  4. Тестирование
    • подготовить сборочную директорию для платформы foc_x86_32 и перейти в нее;
    • подключить репозитории libport и sss13;
    • включить генерацию ЭЦП используя спек sign: echo 'SPECS += sign' >> etc/specs.conf;
    • собрать утилиты signtools: make -C ../sss13/tool/signtools
    • установить утилиты в директорию bin: PREFIX=`pwd`/bin make install -C ../sss13/tool/signtool
    • запустить скрипт lab.run: make run/lab;
    • убедиться что проверка подписей работает и подписи валидны;
    • изменить содержимое файла hackme, запустить руками и убедиться, что подпись не сходится:
      cd var/run/
      dhex lab/genode/hackme
      ../../../tool/create_iso iso ISO=lab
      qemu-system-i386 -no-kvm -m 64 -nographic -cdrom lab.iso
    • исправить подпись в конфигурации для измененного файла и проверить еще раз.
  5. Выводы
    Сделать выводы по работе, а именно, какие проблемы имеет эта реализация? Что нужно доработать, чтобы использовать такую реализацию в реальных применениях, какие еще могут быть варианты контроля целостности загружаемых модулей для Genode?

Ссылки

[1]: http://ru.wikipedia.org/wiki/Электронная_подпись
[2]: [http://ru.wikipedia.org/wiki/ГОСТ_Р34.10-2012](http://ru.wikipedia.org/wiki/ГОСТ_Р34.10-2012)
[3]: [http://ru.wikipedia.org/wiki/ГОСТ_Р34.11-2012](http://ru.wikipedia.org/wiki/ГОСТ_Р34.11-2012)
[4]: https://github.com/kmackay/micro-ecc
[5]: http://www.aarongifford.com/computers/sha.html
[6]: http://sss.ksyslabs.org/ru/prev/sss-12/genode-architecture/
[7]: http://genode.org/documentation/developer-resources/init
[8]: тут будет ссылка на гитхаб
[9]: тут будет ссылка на гитхаб
[10]: тут будет ссылка на гитхаб