Архитектура подписи на устройстве

Начиная с 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 реализует реализацию следующим образом:

  1. При первой загрузке Keystore создает симметричный ключ K0 с тегом MAX_USES_PER_BOOT , установленным в 1 . Это означает, что ключ можно использовать только один раз за загрузку.
  2. Если во время загрузки уровень загрузки увеличивается, новый ключ для этого уровня загрузки может быть сгенерирован из K0 с помощью функции HKDF: Ki+i=HKDF(Ki, "some_fixed_string") . Например, если вы переходите с уровня загрузки 0 на уровень загрузки 10, HKDF вызывается 10 раз для получения K10 из K0.
  3. При изменении уровня загрузки ключ предыдущего уровня загрузки стирается из памяти, и ключи, связанные с предыдущими уровнями загрузки, больше не доступны.

    Ключ 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 реализует реализацию следующим образом:

  1. При первой загрузке Keystore создает симметричный ключ K0 с тегом MAX_USES_PER_BOOT , установленным в 1 . Это означает, что ключ можно использовать только один раз за загрузку.
  2. Если во время загрузки уровень загрузки повышен, новый ключ для этого уровня загрузки может быть сгенерирован из K0 с помощью функции HKDF: Ki+i=HKDF(Ki, "some_fixed_string") . Например, если вы переходите с уровня загрузки 0 на уровень загрузки 10, HKDF вызывается 10 раз для получения K10 из K0.
  3. При изменении уровня загрузки ключ предыдущего уровня загрузки стирается из памяти, и ключи, связанные с предыдущими уровнями загрузки, больше не доступны.

    Ключ 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 можно использовать только на ранних уровнях загрузки и, следовательно, он не может быть создан злоумышленником.