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

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

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

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

  • Устройства с Android Verified Boot (AVB) могут сохранять все уровни патчей и версию системы в vbmeta, чтобы загрузчик мог предоставить их Keymaster. Для связанных разделов информация о версии хранится в связанной vbmeta. Как правило, информация о версии должна храниться в vbmeta struct , содержащей данные проверки (хэш или хэш-дерево) для данного раздела.
  • На устройствах без AVB:
    • Проверенные реализации загрузки должны предоставить хэш метаданных версии загрузчику, чтобы загрузчик мог предоставить хэш Keymaster.
    • boot.img может продолжать хранить уровень патча в заголовке
    • system.img может продолжать хранить уровень исправления и версию ОС в свойствах, доступных только для чтения.
    • vendor.img сохраняет уровень исправления в свойстве только для чтения ro.vendor.build.version.security_patch .
    • Загрузчик может предоставить хэш всех данных, проверенных Verified Boot, в Keymaster.
  • В 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 . Скрипт сборки загрузочного образа автоматически заполняет это поле. OEM-производителям и разработчикам 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 вызывается на самом раннем этапе загрузки системы, должно затруднить использование этого времени.