Привязка версии

В Keymaster 1 все ключи Keymaster были криптографически привязаны к корневому доверенному элементу устройства или к проверенному загрузочному ключу. В Keymaster 2 и 3 все ключи также привязаны к операционной системе и уровню исправлений образа системы. Это гарантирует, что злоумышленник, обнаруживший уязвимость в старой версии системы или программного обеспечения TEE, не сможет откатить устройство до уязвимой версии и использовать ключи, созданные с помощью более новой версии. Кроме того, когда ключ с определенной версией и уровнем исправлений используется на устройстве, которое было обновлено до более новой версии или уровня исправлений, ключ обновляется до того, как его можно будет использовать, а предыдущая версия ключа становится недействительной. Таким образом, по мере обновления устройства ключи *перемещаются* вместе с устройством, но любой возврат устройства к предыдущей версии делает ключи непригодными для использования.

Для поддержки модульной структуры Treble и разрыва связи между system.img и boot.img, Keymaster 4 изменил модель привязки версий ключей, предоставив отдельные уровни патчей для каждого раздела. Это позволяет обновлять каждый раздел независимо, сохраняя при этом защиту от отката.

Для реализации этой привязки версий доверенному приложению KeyMint (TA) необходим способ безопасного получения текущей версии ОС и уровней исправлений, а также гарантия того, что получаемая информация соответствует всей информации о работающей системе.

  • Устройства с Android Verified Boot (AVB) могут помещать все уровни исправлений и версию системы в vbmeta, чтобы загрузчик мог предоставить их Keymaster. Для связанных разделов информация о версии раздела находится в связанном vbmeta. В общем случае информация о версии должна находиться в vbmeta struct , содержащей данные проверки (хеш или хеш-дерево) для данного раздела.
  • На устройствах без AVB:
    • Для реализации Verified Boot необходимо предоставить загрузчику хэш метаданных версии, чтобы загрузчик мог передать этот хэш Keymaster.
    • boot.img может продолжать хранить информацию об уровне исправлений в заголовке.
    • system.img может продолжать хранить уровень исправлений и версию ОС в свойствах, доступных только для чтения.
    • vendor.img уровень исправлений хранится в свойстве только для чтения ro.vendor.build.version.security_patch .
    • Загрузчик может предоставить Keymaster хэш всех данных, проверенных Verified Boot.
  • В Android 9 используйте следующие теги для указания информации о версии для следующих разделов:
    • VENDOR_PATCH_LEVEL : раздел vendor
    • BOOT_PATCH_LEVEL : boot раздел
    • OS_PATCH_LEVEL и OS_VERSION : system раздел. ( OS_VERSION удален из заголовка boot.img .)
  • Реализации Keymaster должны обрабатывать все уровни патчей независимо. Ключи считаются пригодными для использования, если вся информация о версии соответствует значениям, связанным с ключом, и IKeymaster::upgradeDevice() выполняет обновление до более высокого уровня патчей при необходимости.

Изменения HAL

Для поддержки привязки версий и аттестации версий в Android 7.1 были добавлены теги Tag::OS_VERSION и Tag::OS_PATCHLEVEL , а также методы configure и upgradeKey . Теги версий автоматически добавляются реализациями Keymaster 2+ ко всем вновь сгенерированным (или обновленным) ключам. Кроме того, любая попытка использовать ключ, версия или уровень исправлений которого не соответствуют текущей версии или уровню исправлений системы, будет отклонена с ErrorCode::KEY_REQUIRES_UPGRADE .

Tag::OS_VERSION — это значение UINT , представляющее основную, дополнительную и субдополнительную части версии системы Android в формате MMmmss, где MM — основная версия, mm — дополнительная версия, а ss — субдополнительная версия. Например, версия 6.1.2 будет представлена ​​как 060102.

Tag::OS_PATCHLEVEL — это значение UINT , представляющее год и месяц последнего обновления системы в формате YYYYMM, где YYYY — четырехзначный год, а MM — двузначный месяц. Например, март 2016 года будет представлен как 201603.

UpgradeKey

Для обеспечения возможности обновления ключей до новой версии ОС и уровня исправлений образа системы, в Android 7.1 в HAL был добавлен метод upgradeKey :

Ключница 3

    upgradeKey(vec keyBlobToUpgrade, vec upgradeParams)
        generates(ErrorCode error, vec upgradedKeyBlob);

Ключница 2

keymaster_error_t (*upgrade_key)(const struct keymaster2_device* dev,
    const keymaster_key_blob_t* key_to_upgrade,
    const keymaster_key_param_set_t* upgrade_params,
    keymaster_key_blob_t* upgraded_key);
  • dev — это структура устройства.
  • keyBlobToUpgrade — это ключ, который необходимо обновить.
  • Параметр upgradeParams необходим для обновления ключа. К ним относятся Tag::APPLICATION_ID и Tag::APPLICATION_DATA , которые необходимы для расшифровки блока ключа, если они были предоставлены во время генерации.
  • upgradedKeyBlob является выходным параметром, используемым для возврата нового двоичного объекта ключа.

Если upgradeKey вызывается с ключом, который не может быть проанализирован или является недействительным по другим причинам, он возвращает ErrorCode::INVALID_KEY_BLOB . Если он вызывается с ключом, уровень исправлений которого выше текущего системного значения, он возвращает ErrorCode::INVALID_ARGUMENT . Если он вызывается с ключом, версия ОС которого выше текущего системного значения, и системное значение не равно нулю, он возвращает ErrorCode::INVALID_ARGUMENT . Допускается обновление версии ОС с ненулевого значения до нуля. В случае ошибок при взаимодействии с защищенной средой, метод возвращает соответствующее значение ошибки (например, ErrorCode::SECURE_HW_ACCESS_DENIED , ErrorCode::SECURE_HW_BUSY ). В противном случае он возвращает ErrorCode::OK и возвращает новый ключ в upgradedKeyBlob .

keyBlobToUpgrade остается действительным после вызова upgradeKey и теоретически может быть использован повторно, если устройство будет понижено в версии. На практике хранилище ключей обычно вызывает deleteKey для объекта keyBlobToUpgrade вскоре после вызова upgradeKey . Если бы keyBlobToUpgrade имел тег Tag::ROLLBACK_RESISTANT , то upgradedKeyBlob также должен был бы иметь его (и должен быть устойчив к откату).

Безопасная конфигурация

Для реализации привязки версий Keymaster TA необходим способ безопасного получения текущей версии ОС и уровня исправлений (информации о версии), а также для обеспечения того, чтобы получаемая информация строго соответствовала информации о работающей системе.

Для обеспечения безопасной передачи информации о версии в TA в заголовок образа загрузки добавлено поле OS_VERSION . Скрипт сборки образа загрузки автоматически заполняет это поле. Производителям оборудования и разработчикам Keymaster TA необходимо совместно модифицировать загрузчики устройств, чтобы извлекать информацию о версии из образа загрузки и передавать ее в TA до загрузки небезопасной системы. Это гарантирует, что злоумышленники не смогут помешать предоставлению информации о версии в TA.

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

keymaster_error_t (*configure)(const struct keymaster2_device* dev,
  const keymaster_key_param_set_t* params);

Аргумент params содержит Tag::OS_VERSION и Tag::OS_PATCHLEVEL . Этот метод вызывается клиентами keymaster2 после открытия HAL, но до вызова каких-либо других методов. Если перед configure вызывается какой-либо другой метод, TA возвращает ErrorCode::KEYMASTER_NOT_CONFIGURED .

При первом вызове configure после загрузки устройства необходимо проверить, соответствует ли предоставленная информация о версии той, что была предоставлена ​​загрузчиком. Если информация о версии не совпадает, configure возвращает ErrorCode::INVALID_ARGUMENT , и все остальные методы Keymaster продолжают возвращать ErrorCode::KEYMASTER_NOT_CONFIGURED . Если информация совпадает, configure возвращает ErrorCode::OK , и другие методы Keymaster начинают работать в обычном режиме.

Последующие вызовы функции configure возвращают то же значение, что и первый вызов, и не изменяют состояние Keymaster.

Поскольку configure вызывается системой, содержимое которой она призвана проверять, у злоумышленника остается узкое окно возможностей для компрометации образа системы и принуждения его к предоставлению информации о версии, соответствующей загрузочному образу, но не являющейся фактической версией системы. Сочетание проверки загрузочного образа, проверки содержимого образа системы с помощью dm-verity и того факта, что configure вызывается на очень ранней стадии загрузки системы, должно затруднить использование этого окна возможностей.