Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Это самый ответственный и нетривиальный этап разработки загружаемого кода. Суть его заключается в том, что разработчику нужно решить, какой именно код будет выполняться в электронном ключе.
Код должен быть устроен таким образом, чтобы выполнять определенную конечную задачу, которая в общем виде выглядит так:

  • Получение буфера с входными данными
  • Вычисления над данными из этого буфера
  • Возврат буфера с выходными данными

Существует целый ряд требований к этому коду, налагающих достаточно серьезные ограничения на выбор. Требования условно можно разделить на несколько типов:

...

Загружаемый код должен быть достаточно сложным, чтобы брутфорс или иные (более эффективные и продвинутые) методы анализа черных ящиков не сделали возможным создания эмулятора в короткое время.
Этот код должен отсутствовать в более ранних версиях приложения. Несоблюдение этого условия делает возможным сравнение версий приложения и нахождение перенесенного кода для внедрения его в эмулятор.

...

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

...

Код, размещаемый в электронном ключе, не должен:

  • Содержать вызовов API, которые нельзя было бы перенестив электронный ключ, или иметь внешние зависимости
  • Использовать потоки ввода-вывода
  • Использовать вывод на консоль
  • Использовать динамическое распределение памяти

Коду, исполняемому внутри ключа, доступны лишь стандартные библиотеки С и функции для работы с электронным ключом.
Ключи Guardant Code позволяют исполнять алгоритмы до 20 тысяч строк кода на С (до 60 тысяч строк в моделях ключей с увеличенным размером памяти). Соответственно, размер кода должен укладываться в эти пределы.

...

Несмотря на то, что для процессоров CORTEX-M3 существуют компиляторы многих языков программирования, эффективнее всего использовать язык C, а точнее его подмножество, основой для которого является стандарт ANSI C.
Требование соблюдения стандарта связано с тем, что первоначальная разработка и отладка загружаемого кода может выполняться с использованием различных компиляторов. Т. е. предполагается, что код разрабатывается в привычной интегрированной среде, а затем компилируется для использования в Guardant Code. Поэтому для разработки загружаемого кода пригодятся навыки кроссплатформенного программирования.
Код перед загрузкой в ключ должен быть скомпилирован. Поскольку система команд процессора архитектуры CORTEX-M3, используемого в ключе, отличается от системы команд x86-совместимых процессоров, для работы потребуется компилятор, способный генерировать двоичный код, совместимый с архитектурой CORTEX-M3.
Для компиляции загружаемого кода можно применять как коммерческие средства, так и распространяемые под различными «свободными» лицензиями. К последним можно отнести GCC (включая различные решения на его основе, такие как YAGARTO).
Большинство средств разработки, распространяемых под свободными лицензиями, рассчитаны на работу под Linux. Тем не менее, существуют решения и для Windows. Кроме того, есть возможность использовать средства разработки, предназначенные для Linux под операционными системами семейства Windows, применяя для их запуска Cygwin или MinGW.
Примеры и makefile, входящие в комплект разработчика Guardant, рассчитаны на использование компилятора GCC и инструментария YAGARTO, как на самый доступный вариант.
Хотя для большинства высокоуровневых языков программирования перенос кода на С достаточно несложен, но альтернативно, можно использовать и другие языки программирования высокого уровня, для которых есть компилятор CORTEX-M3. Однако в данном документе эта возможность не описывается.

...

При разработке загружаемого кода с большой вероятностью может возникнуть необходимость обращаться к ресурсам ключа, находящимся в области EEPROM (защищенным ячейкам, алгоритмам), или к таймеру. Поэтому был разработан специальный интерфейс прикладного программирования Guardant Code API (см. Справочную систему Guardant API, файл GrdAPI.chm) Библиотека этого API содержит большинство функций Guardant API, адаптированных для использования из среды загружаемого кода.
Основной нюанс при работе с Guardant Code API состоит в том, что хэндл защищенного контейнера в загружаемом коде теряет смысл, поскольку этот код, во-первых, имеет доступ только к одному ключу, а во-вторых, не существует ситуации конкурентного доступа к ресурсам ключа из разных потоков одного приложения и из разных приложений.
Вместе с тем, функциям внутренного API загружаемого кода передается параметр типа HANDLE. Это сделано для соблюдения единообразия и удобства отладки загружаемого кода.
Guardant Code API поддерживает основные функции Guardant API, связанные с хранением данных и работой с алгоритмами.
Кроме того, в API загружаемого кода существует возможность вызывать криптографические алгоритмы, не используя дескрипторы, а напрямую, подобно тому, как в Guardant API вызываются программно-реализованные алгоритмы. Для этого вместо числового имени ячейки, содержащей дескриптор, указывается специальное зарезервированное имя алгоритма.
Если в загружаемом коде присутствуют функции Guardant API (например, в ключ переносится алгоритм, который раньше защищался ключами Guardant), то для большинства этих функций существуют аналоги в Guardant Code API, и портирование будет заключаться в смене префикса c GrdXXX на GcaXXX или GccaXXX.

Название функции

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

GcaCrash()

Инициировать ошибку среды исполнения Guardant Code

GcaExit()

Выйти из загружаемого кода. В вызывающее приложение передается код возврата

GcaLedOn()

Включить светодиодный индикатор

GcaLedOff()

Выключить светодиодный индикатор

GcaRead()

Прочитать данные из EEPROM, аналогично GrdRead()

GcaWrite()

Записать данные в EEPROM, аналогично GrdWrite()

GcaPI_Read()

Прочитать данные из защищенной ячейки, аналогично GrdPI_Read()

GcaPI_Update()

Изменить данные защищенной ячейки, аналогично GrdPI_Update()

GcaPI_GetTimeLimit()

Получить время жизни защищенной ячейки, аналогично GrdPI_GetTimeLimit(). Для Guardant Code Time

GcaPI_GetCounter()

Получить значение счетчика оставшихся выполнений алгоритма, аналогично GrdPI_GetCounter()

GcaGetTime()

Получить текущее время из RTC ключа, аналогично GrdGetTime(). Для Guardant Code Time

GcaGetRTCQuality()

Проверить валидность значения RTC, аналогично GrdGetRTCQuality(). Для Guardant Code Time

GcaGetLastError()

Получить последний код ошибки, аналогично GrdGetLastError(). Возвращает код ошибки, которая произошла при последнем вызове функции Guardant Code API

GccaCryptEx()

Шифровать данные симметричным алгоритмом, аналогично GrdCryptEx(). Для программного алгоритма AES128 требуется другой размер контекста. Контекст должен быть выровнен по границе в 4 байта (warning) применением макроса ALIGNED

GccaSign()

Вычислить ЭЦП, аналогично GrdSign(). Присутствует дополнительный параметр – ключ подписи и вариант вызова, работающий в обход таблицы дескрипторов

GccaVerifySign()

Проверить ЭЦП, аналогично GrdVerifySign()

GccaGenerateKeyPair()

Генерировать ключевую пару для алгоритма ЭЦП ECC160

GccaHash()

Вычислить хэш-функцию, аналогично GrdHash()

GccaGetRandom()

Генерировать случайное однобайтовое число

GcaSetTimeout

Установить разрешенное время работы загружаемого кода

GcaCodeGetInfo

Запросить информацию из дескриптора загружаемого кода

GcaCodeRun

Выполнить код из другого участка загружаемого кода

...

Загружаемый код, в отличие от ячеек с данными и дескрипторов аппаратных алгоритмов, хранится в другой области памяти ключа, для которой используются иные принципы адресации. Поэтому для загрузки кода в память ключа, его выполнения и других операций существуют специальные функции Guardant API.
Для записи в ключ загружаемый код преобразуется в файл специального формата GCEXE (Guardant Code Executable), обеспечивающего защиту от подделки, подмены и анализа. Эта защита обеспечивается шифрованием криптостойкими алгоритмами и ЭЦП. Такая защита делает возможным безопасное обновление загружаемого кода в ключе, в том числе при пересылке файлов по открытым каналам и через сети общего пользования.
Файл формата GCEXE генерируется на основе данных дескриптора загружаемого кода, скомпилированного кода и map-файла утилитой программирования ключей GrdUtil.exe. Однажды сгенерированный файл может быть использован для записи в тиражируемые ключи той же утилитой. Если предпродажное программирование осуществляется при помощи собственных специально разработанных инструментов, файл с загружаемым кодом может быть записан в ключ при помощи функции GrdCodeLoad().
Список сервисных функций Guardant API:

Название функции

Код доступа

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

GrdCodeGetInfo

Private Read

Получить информацию из дескриптора загружаемого кода

GrdCodeLoad

Private Read

Записать GCEXE-файл, содержащий загружаемый код, во Flash-память ключа

GrdCodeRun

Private Read

Выполнить загружаемый код

GrdSetDriverMode

Private Read

Задать USB-режим работы ключа

...

Компиляция загружаемого кода

Anchor
_Toc244330131
_Toc244330131
Инсталляция и настройка компилятора GCC

...