Начиная с Android 12, модуль Android Runtime (ART) является модулем основной ветки . Обновление модуля может потребовать пересборки артефактов предварительной компиляции (AOT) JAR-файлов bootclasspath и системного сервера. Поскольку эти артефакты чувствительны к безопасности, Android 12 использует функцию, называемую подписью на устройстве, чтобы предотвратить их изменение. На этой странице рассматривается архитектура подписи на устройстве и ее взаимодействие с другими функциями безопасности Android.
Проектирование высокого уровня
Подписание документов непосредственно на устройстве состоит из двух основных компонентов:
odrefreshявляется частью модуля ART Mainline. Он отвечает за генерацию артефактов среды выполнения. Он проверяет существующие артефакты на соответствие установленной версии модуля ART, jar-файлам из bootclasspath и jar-файлам системного сервера, чтобы определить, являются ли они актуальными или нуждаются в перегенерации. Если требуется перегенерация,odrefreshсоздает их и сохраняет.odsign— это исполняемый файл, являющийся частью платформы Android. Он запускается на ранней стадии загрузки, сразу после монтирования раздела/data. Его основная задача — вызыватьodrefreshдля проверки необходимости генерации или обновления каких-либо артефактов. Для любых новых или обновленных артефактов, сгенерированныхodrefresh,odsignвычисляет хеш-функцию. Результат такого вычисления хеша называется дайджестом файла . Для любых уже существующих артефактовodsignпроверяет, совпадают ли дайджесты существующих артефактов с дайджестами, вычисленными ранееodsign. Это гарантирует, что артефакты не были изменены.
В случае ошибок, например, когда дайджест файла не совпадает, odrefresh и odsign удаляют все существующие артефакты в /data и пытаются сгенерировать их заново. Если это не удаётся, система переключается в режим JIT-компиляции.
odrefresh и odsign защищены dm-verity и являются частью цепочки Verified Boot в Android.
Вычисление дайджестов файлов с помощью fs-verity
fs-verity is a feature of the Linux kernel that does Merkle tree based verification of file data. Enabling fs-verity on a file causes the file system to build a Merkle tree over the file's data using SHA-256 hashes, store it in a hidden location alongside the file, and mark the file as read-only. fs-verity automatically verifies the file's data against the Merkle tree on demand as it's read. fs-verity makes the root hash of the Merkle tree available as a value called the fs-verity file digest , and fs-verity ensures that any data read from the file is consistent with this file digest.
odsign использует fs-verity для повышения производительности загрузки за счет оптимизации криптографической аутентификации скомпилированных на устройстве артефактов во время загрузки. При генерации артефакта odsign включает для него fs-verity. При проверке артефакта odsign проверяет дайджест файла fs-verity, а не полный хеш файла. Это устраняет необходимость чтения и хеширования полных данных артефакта во время загрузки. Вместо этого данные артефакта хешируются по запросу fs-verity по мере их использования, блок за блоком.
На устройствах, ядро которых не поддерживает fs-verity, odsign использует вычисление дайджестов файлов в пользовательском пространстве. odsign использует тот же алгоритм хеширования на основе дерева Меркла, что и fs-verity, поэтому дайджесты в обоих случаях одинаковы. fs-verity требуется на всех устройствах, выпущенных с Android 11 и выше.
Хранение дайджестов файлов
odsign хранит дайджесты файлов артефактов в отдельном файле с именем odsign.info . Чтобы гарантировать сохранность odsign.info odsign.info он подписывается ключом подписи, обладающим важными свойствами безопасности. В частности, ключ может быть сгенерирован и использован только на ранней стадии загрузки, когда выполняется только доверенный код; подробности см. в разделе «Доверенные ключи подписи» .
Проверка дайджестов файлов
При каждой загрузке, если odrefresh определяет, что существующие артефакты актуальны, odsign проверяет, не были ли файлы изменены с момента их создания. odsign делает это, проверяя дайджесты файлов. Сначала он проверяет подпись odsign.info . Если подпись действительна, то odsign проверяет, соответствует ли дайджест каждого файла соответствующему дайджесту в odsign.info .
Доверенные ключи подписи
В Android 12 появилась новая функция хранилища ключей, называемая ключами этапа загрузки, которая решает следующие проблемы безопасности:
- Что мешает злоумышленнику использовать наш ключ подписи для подписи собственной версии
odsign.info? - Что мешает злоумышленнику сгенерировать собственный ключ подписи и использовать его для подписи собственной версии
odsign.info?
Ключи, активируемые на этапе загрузки, разделяют цикл загрузки Android на уровни и криптографически связывают создание и использование ключа с определенным уровнем. odsign создает свой ключ подписи на раннем уровне, когда выполняется только доверенный код, защищенный с помощью dm-verity .
Уровни загрузки нумеруются от 0 до магического числа 1000000000. Во время процесса загрузки Android вы можете повысить уровень загрузки, установив системное свойство в файле init.rc Например, следующий код устанавливает уровень загрузки на 10:
setprop keystore.boot_level 10
Пользователи Keystore могут создавать ключи, привязанные к определенному уровню загрузки. Например, если вы создадите ключ для уровня загрузки 10, то этот ключ можно будет использовать только тогда, когда устройство находится в режиме загрузки 10.
odsign использует уровень загрузки 30, и создаваемый им ключ подписи привязан к этому уровню загрузки. Перед использованием ключа для подписи артефактов odsign проверяет, привязан ли ключ к уровню загрузки 30.
Это предотвращает две атаки, описанные ранее в этом разделе:
- Злоумышленники не могут использовать сгенерированный ключ, потому что к тому моменту, когда у злоумышленника появляется возможность запустить вредоносный код, уровень загрузки повышается выше 30, и хранилище ключей отклоняет операции, использующие этот ключ.
- Злоумышленники не могут создать новый ключ, потому что к тому моменту, когда у злоумышленника появляется возможность запустить вредоносный код, уровень загрузки повышается выше 30, и Keystore отказывается создавать новый ключ с этим уровнем загрузки. Если злоумышленник создаст новый ключ, не привязанный к уровню загрузки 30,
odsignего отклонит.
Keystore обеспечивает корректное применение уровня загрузки. В следующих разделах более подробно описано, как это делается для различных версий KeyMint (ранее Keymaster).
Внедрение Keymaster 4.0
Разные версии Keymaster по-разному обрабатывают реализацию ключей на этапе загрузки. На устройствах с Keymaster 4.0 TEE/StrongBox реализация происходит следующим образом:
- При первой загрузке Keystore создает симметричный ключ K0 с тегом
MAX_USES_PER_BOOT, установленным в1Это означает, что ключ можно использовать только один раз за загрузку. - В процессе загрузки, если уровень загрузки повышается, новый ключ для этого уровня загрузки может быть сгенерирован из K0 с помощью функции HKDF:
Ki+i=HKDF(Ki, "some_fixed_string"). Например, если вы переходите с уровня загрузки 0 на уровень загрузки 10, функция HKDF вызывается 10 раз для получения K10 из K0. При изменении уровня загрузки ключ для предыдущего уровня загрузки удаляется из памяти, и ключи, связанные с предыдущими уровнями загрузки, становятся недоступны.
Ключ K0 имеет значение
MAX_USES_PER_BOOT=1. Это означает, что использовать этот ключ позже во время загрузки также невозможно, поскольку всегда происходит как минимум один переход между уровнями загрузки (к последнему уровню загрузки).
Когда клиент хранилища ключей, такой как odsign запрашивает создание ключа на уровне загрузки i , его двоичные данные шифруются ключом Ki . Поскольку Ki недоступен после уровня загрузки i , этот ключ не может быть создан или расшифрован на более поздних этапах загрузки.
Реализация Keymaster 4.1 и KeyMint 1.0
Реализации Keymaster 4.1 и KeyMint 1.0 в значительной степени идентичны реализации Keymaster 4.0. Главное отличие заключается в том, что K0 — это не ключ с параметром MAX_USES_PER_BOOT , а ключ EARLY_BOOT_ONLY , который был введен в Keymaster 4.1. Ключ EARLY_BOOT_ONLY может использоваться только на ранних этапах загрузки, когда не выполняется ненадежный код. Это обеспечивает дополнительный уровень защиты: в реализации Keymaster 4.0 злоумышленник, скомпрометировавший файловую систему и SELinux, может изменить базу данных Keystore, чтобы создать свой собственный ключ MAX_USES_PER_BOOT=1 для подписи артефактов. Такая атака невозможна в реализациях Keymaster 4.1 и KeyMint 1.0, поскольку ключи EARLY_BOOT_ONLY могут быть созданы только на ранних этапах загрузки.
Открытый компонент доверенных ключей подписи
odsign извлекает компонент открытого ключа подписи из хранилища ключей (Keystore). Однако Keystore не извлекает этот открытый ключ из TEE/SE, в котором хранится соответствующий закрытый ключ. Вместо этого он извлекает открытый ключ из своей собственной базы данных на диске. Это означает, что злоумышленник, скомпрометировавший файловую систему, может изменить базу данных Keystore, чтобы она содержала открытый ключ, являющийся частью пары открытого/закрытого ключей, находящихся под его контролем.
Чтобы предотвратить эту атаку, odsign создает дополнительный HMAC-ключ с тем же уровнем загрузки, что и ключ подписи. Затем, при создании ключа подписи, odsign использует этот HMAC-ключ для создания подписи открытого ключа и сохраняет ее на диске. При последующих загрузках, при получении открытого ключа подписи, он использует HMAC-ключ для проверки соответствия подписи на диске подписи полученного открытого ключа. Если они совпадают, открытый ключ является надежным, поскольку HMAC-ключ может использоваться только на ранних уровнях загрузки и, следовательно, не мог быть создан злоумышленником.