Начиная с Android 12, модуль Android Runtime (ART) является основным модулем. Обновление модуля может потребовать перестроения артефактов предварительной компиляции (AOT) jar-файлов пути к загрузочному классу и системного сервера. Поскольку эти артефакты чувствительны к безопасности, в Android 12 используется функция, называемая подписью на устройстве, чтобы предотвратить подделку этих артефактов. На этой странице описана архитектура подписи на устройстве и ее взаимодействие с другими функциями безопасности Android.
Дизайн высокого уровня
Подписание на устройстве состоит из двух основных компонентов:
odrefresh
является частью модуля ART Mainline. Он отвечает за создание артефактов времени выполнения. Он сравнивает существующие артефакты с установленной версией модуля ART, jar-файлами пути к загрузочному классу и jar-файлами системного сервера, чтобы определить, обновлены ли они или нуждаются в восстановлении. Если их необходимо регенерировать,odrefresh
создаст их и сохранит.odsign
— это двоичный файл, являющийся частью платформы Android. Он запускается во время ранней загрузки, сразу после монтирования раздела/data
. Его основная обязанность — вызватьodrefresh
, чтобы проверить, нужно ли создавать или обновлять какие-либо артефакты. Для любых новых или обновленных артефактов, создаваемыхodrefresh
,odsign
вычисляет хеш-функцию. Результат такого вычисления хэша называется дайджестом файла . Для любых уже существующих артефактовodsign
проверяет, соответствуют ли дайджесты существующих артефактов дайджестам, вычисленнымodsign
ранее. Это гарантирует, что артефакты не были подделаны.
В случае ошибки, например, когда дайджест файла не совпадает, odrefresh
и odsign
удаляют все существующие артефакты в /data
и пытаются их восстановить. Если это не удается, система возвращается в режим JIT.
odrefresh
и odsign
защищены dm-verity
и являются частью цепочки проверенной загрузки Android.
Вычисление дайджестов файлов с помощью fs-verity
fs-verity — это функция ядра Linux, которая выполняет проверку данных файла на основе дерева Меркла. Включение fs-verity для файла приводит к тому, что файловая система строит дерево Меркла на основе данных файла с использованием хэшей SHA-256, сохраняет его в скрытом месте рядом с файлом и помечает файл как доступный только для чтения. fs-verity автоматически сверяет данные файла с деревом Меркла по требованию по мере их чтения. fs-verity делает корневой хэш дерева Меркла доступным в виде значения, называемого дайджестом файла fs-verity , а fs-verity гарантирует, что любые данные, считанные из файла, соответствуют этому дайджесту файла.
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, и Keystore откажется от операций, использующих этот ключ.
- Злоумышленники не могут создать новый ключ, поскольку к тому времени, когда у злоумышленника появляется возможность запустить вредоносный код, уровень загрузки превышает 30, а хранилище ключей отказывается создавать новый ключ с этим уровнем загрузки. Если злоумышленник создает новый ключ, не привязанный к уровню загрузки 30,
odsign
отклоняет его.
Хранилище ключей гарантирует правильное соблюдение уровня загрузки. В следующих разделах более подробно описано, как это делается для разных версий Keymaster.
Реализация Keymaster 4.0
Различные версии Keymaster по-разному реализуют ключи этапа загрузки. На устройствах с Keymaster 4.0 TEE/Strongbox Keymaster реализует реализацию следующим образом:
- При первой загрузке 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
извлекает компонент открытого ключа ключа подписи из хранилища ключей. Однако хранилище ключей не получает этот открытый ключ от TEE/SE, который содержит соответствующий закрытый ключ. Вместо этого он извлекает открытый ключ из собственной базы данных на диске. Это означает, что злоумышленник, скомпрометировавший файловую систему, может изменить базу данных хранилища ключей, чтобы она содержала открытый ключ, который является частью пары открытого/закрытого ключей, находящейся под его контролем.
Чтобы предотвратить эту атаку, odsign
создает дополнительный ключ HMAC с тем же уровнем загрузки, что и ключ подписи. Затем при создании ключа подписи odsign
использует этот ключ HMAC для создания подписи открытого ключа и сохраняет ее на диске. При последующих загрузках при получении открытого ключа ключа подписи он использует ключ HMAC для проверки соответствия подписи на диске подписи полученного открытого ключа. Если они совпадают, открытый ключ заслуживает доверия, поскольку ключ HMAC можно использовать только на ранних уровнях загрузки и, следовательно, он не может быть создан злоумышленником.
Начиная с Android 12, модуль Android Runtime (ART) является основным модулем. Обновление модуля может потребовать перестроения артефактов предварительной компиляции (AOT) jar-файлов пути к загрузочному классу и системного сервера. Поскольку эти артефакты чувствительны к безопасности, в Android 12 используется функция, называемая подписью на устройстве, чтобы предотвратить подделку этих артефактов. На этой странице описывается архитектура подписи на устройстве и ее взаимодействие с другими функциями безопасности Android.
Дизайн высокого уровня
Подписание на устройстве состоит из двух основных компонентов:
odrefresh
является частью модуля ART Mainline. Он отвечает за создание артефактов времени выполнения. Он сравнивает существующие артефакты с установленной версией модуля ART, jar-файлами пути к загрузочному классу и jar-файлами системного сервера, чтобы определить, обновлены ли они или нуждаются в восстановлении. Если их необходимо восстановить,odrefresh
создаст их и сохранит.odsign
— это двоичный файл, являющийся частью платформы Android. Он запускается во время ранней загрузки, сразу после монтирования раздела/data
. Его основная обязанность — вызватьodrefresh
, чтобы проверить, нужно ли создавать или обновлять какие-либо артефакты. Для любых новых или обновленных артефактов, создаваемыхodrefresh
,odsign
вычисляет хэш-функцию. Результат такого вычисления хэша называется дайджестом файла . Для любых уже существующих артефактовodsign
проверяет, соответствуют ли дайджесты существующих артефактов дайджестам, вычисленнымodsign
ранее. Это гарантирует, что артефакты не были подделаны.
В случае ошибки, например, когда дайджест файла не совпадает, odrefresh
и odsign
удаляют все существующие артефакты в /data
и пытаются их восстановить. Если это не удается, система возвращается в режим JIT.
odrefresh
и odsign
защищены dm-verity
и являются частью цепочки проверенной загрузки Android.
Вычисление дайджестов файлов с помощью fs-verity
fs-verity — это функция ядра Linux, которая выполняет проверку данных файла на основе дерева Меркла. Включение fs-verity для файла приводит к тому, что файловая система строит дерево Меркла на основе данных файла с использованием хэшей SHA-256, сохраняет его в скрытом месте рядом с файлом и помечает файл как доступный только для чтения. fs-verity автоматически сверяет данные файла с деревом Меркла по требованию по мере их чтения. fs-verity делает корневой хэш дерева Меркла доступным в виде значения, называемого дайджестом файла fs-verity , а fs-verity гарантирует, что любые данные, считанные из файла, соответствуют этому дайджесту файла.
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, и Keystore откажется от операций, использующих этот ключ.
- Злоумышленники не могут создать новый ключ, поскольку к тому моменту, когда у злоумышленника появляется возможность запустить вредоносный код, уровень загрузки превышает 30, а хранилище ключей отказывается создавать новый ключ с этим уровнем загрузки. Если злоумышленник создает новый ключ, не привязанный к уровню загрузки 30,
odsign
отклоняет его.
Хранилище ключей гарантирует правильное соблюдение уровня загрузки. В следующих разделах более подробно описано, как это делается для разных версий Keymaster.
Реализация Keymaster 4.0
Различные версии Keymaster по-разному реализуют ключи этапа загрузки. На устройствах с Keymaster 4.0 TEE/Strongbox Keymaster реализует реализацию следующим образом:
- При первой загрузке 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, может изменить базу данных хранилища ключей, чтобы создать собственный ключ MAX_USES_PER_BOOT=1
для подписи артефактов. Такая атака невозможна с реализациями Keymaster 4.1 и KeyMint 1.0, поскольку ключи EARLY_BOOT_ONLY
могут быть созданы только во время ранней загрузки.
Открытый компонент доверенных ключей подписи
odsign
извлекает компонент открытого ключа ключа подписи из хранилища ключей. Однако хранилище ключей не получает этот открытый ключ от TEE/SE, который содержит соответствующий закрытый ключ. Вместо этого он извлекает открытый ключ из собственной базы данных на диске. Это означает, что злоумышленник, скомпрометировавший файловую систему, может изменить базу данных хранилища ключей, чтобы она содержала открытый ключ, который является частью пары открытого/закрытого ключей, находящейся под его контролем.
Чтобы предотвратить эту атаку, odsign
создает дополнительный ключ HMAC с тем же уровнем загрузки, что и ключ подписи. Затем при создании ключа подписи odsign
использует этот ключ HMAC для создания подписи открытого ключа и сохраняет ее на диске. При последующих загрузках при получении открытого ключа ключа подписи он использует ключ HMAC для проверки соответствия подписи на диске подписи полученного открытого ключа. Если они совпадают, открытый ключ заслуживает доверия, поскольку ключ HMAC можно использовать только на ранних уровнях загрузки и, следовательно, он не может быть создан злоумышленником.