В 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
вызывается на самом раннем этапе загрузки системы, должно затруднить использование этого времени.