Схема подписи APK v3

Android 9 поддерживает ротацию ключей APK , что дает приложениям возможность изменять свой ключ подписи в рамках обновления APK. Чтобы ротация была практичной, APK-файлы должны указывать уровни доверия между новым и старым ключом подписи. Для поддержки ротации ключей мы обновили схему подписи APK с версии 2 до версии 3, чтобы можно было использовать новые и старые ключи. V3 добавляет информацию о поддерживаемых версиях SDK и структуру подтверждения ротации в блок подписи APK.

Блок подписи APK

Для обеспечения обратной совместимости с форматом APK v1 подписи APK v2 и v3 хранятся внутри блока подписи APK, расположенного непосредственно перед центральным каталогом ZIP.

Формат блока подписи APK v3 такой же, как и v2 . Подпись v3 APK хранится в виде пары идентификатор-значение с идентификатором 0xf05368c0.

Блокировка схемы подписи APK v3

Схема v3 очень похожа на схему v2 . Он имеет тот же общий формат и поддерживает те же идентификаторы алгоритмов подписи , размеры ключей и кривые EC.

Однако схема v3 добавляет информацию о поддерживаемых версиях SDK и структуру подтверждения ротации.

Формат

Блок APK Signature Scheme v3 хранится внутри блока подписи APK под идентификатором 0xf05368c0 .

Формат блока APK Signature Scheme v3 соответствует формату v2:

  • последовательность с префиксом длины signer стороны с префиксом длины:
    • signed data с префиксом длины:
      • последовательность digests с префиксом длины:
        • signature algorithm ID (4 байта)
        • digest (с префиксом длины)
      • последовательность certificates X.509 с префиксом длины:
        • certificate X.509 с префиксом длины (форма ASN.1 DER)
      • minSDK (uint32) — эту подписывающую сторону следует игнорировать, если версия платформы ниже этого номера.
      • maxSDK (uint32) — эту подписывающую сторону следует игнорировать, если версия платформы выше этого числа.
      • последовательность additional attributes с префиксом длины:
        • ID (uint32)
        • value (переменная-длина: длина дополнительного атрибута - 4 байта)
        • ID - 0x3ba06f8c
        • value - Структура Proof-of-Rotation
    • minSDK (uint32) — дубликат значения minSDK в разделе подписанных данных — используется для пропуска проверки этой подписи, если текущая платформа не находится в диапазоне. Должно соответствовать значению данных со знаком.
    • maxSDK (uint32) — дубликат значения maxSDK в разделе подписанных данных — используется для пропуска проверки этой подписи, если текущая платформа не находится в диапазоне. Должно соответствовать значению данных со знаком.
    • последовательность signatures с префиксом длины:
      • signature algorithm ID (uint32)
      • signature с префиксом длины над signed data
    • public key с префиксом длины (SubjectPublicKeyInfo, форма ASN.1 DER)

Структуры Proof-of-Rotation и самонадежных старых сертификатов

Структура подтверждения ротации позволяет приложениям менять свой сертификат подписи без блокировки в других приложениях, с которыми они взаимодействуют. Для этого сигнатуры приложений содержат две новые части данных:

  • утверждение для третьих лиц, что сертификату подписи приложения можно доверять везде, где доверяют его предшественникам
  • старые сертификаты подписи приложения, которым само приложение все еще доверяет

Атрибут подтверждения ротации в разделе подписанных данных состоит из односвязного списка, в котором каждый узел содержит сертификат подписи, используемый для подписи предыдущих версий приложения. Этот атрибут предназначен для содержания концептуальных структур данных proof-of-rotation и self-trusted-old-certs. Список упорядочен по версии с самым старым сертификатом подписи, соответствующим корневому узлу. Структура данных, подтверждающая ротацию, строится за счет того, что сертификат в каждом узле подписывает следующий в списке, и, таким образом, каждый новый ключ наполняется свидетельством того, что ему следует доверять так же, как и старому ключу (ключам).

Структура данных самонадежных старых сертификатов строится путем добавления флагов к каждому узлу, указывающих на его принадлежность и свойства в наборе. Например, может присутствовать флаг, указывающий, что сертификат подписи на данном узле является доверенным для получения разрешений подписи Android. Этот флаг позволяет другим приложениям, подписанным старым сертификатом, по-прежнему получать разрешение подписи, определенное приложением, подписанным новым сертификатом подписи. Поскольку весь атрибут proof-of-rotation находится в разделе подписанных данных поля signer v3, он защищен ключом, используемым для подписи содержащего apk.

Этот формат исключает использование нескольких ключей подписи и объединение сертификатов подписи разных предков в один (несколько начальных узлов к общему приемнику).

Формат

Доказательство ротации хранится внутри блока APK Signature Scheme v3 под идентификатором 0x3ba06f8c . Его формат:

  • последовательность levels с префиксом длины:
    • signed data с префиксом длины (по предыдущему сертификату - если существует)
      • certificate X.509 с префиксом длины (форма ASN.1 DER)
      • signature algorithm ID (uint32) — алгоритм, используемый сертификатом на предыдущем уровне
    • flags (uint32) — флаги, указывающие, должен ли этот сертификат находиться в структуре self-trusted-old-certs и для каких операций.
    • signature algorithm ID (uint32) - должен совпадать с идентификатором из раздела подписанных данных следующего уровня.
    • signature с префиксом длины над указанными выше signed data

Несколько сертификатов

Android в настоящее время рассматривает APK, подписанный с несколькими сертификатами, как имеющий уникальное удостоверение подписи, отдельное от входящих в него сертификатов. Таким образом, атрибут proof-of-rotation в разделе подписанных данных формирует ориентированный ациклический граф, который лучше рассматривать как односвязный список, в котором каждый набор подписывающих для данной версии представляет один узел. Это добавляет дополнительную сложность структуре доказательства ротации (версия с несколькими подписчиками ниже). В частности, заказ становится проблемой. Более того, больше невозможно подписывать APK независимо, потому что в структуре подтверждения ротации старые сертификаты подписи должны подписывать новый набор сертификатов, а не подписывать их один за другим. Например, APK, подписанный ключом A, который хочет быть подписан двумя новыми ключами B и C, не может позволить подписавшему B просто включить подпись A или B, потому что это другое удостоверение подписи, чем B и C. Это будет означают, что подписавшие должны координировать свои действия перед созданием такой структуры.

Атрибут подтверждения ротации нескольких подписывающих сторон

  • последовательность sets с префиксом длины:
    • signed data (по предыдущему набору - если есть)
      • последовательность certificates с префиксом длины
        • certificate X.509 с префиксом длины (форма ASN.1 DER)
      • Последовательность signature algorithm IDs (uint32) — по одному для каждого сертификата из предыдущего набора в том же порядке.
    • flags (uint32) — флаги, указывающие, должен ли этот набор сертификатов находиться в структуре self-trusted-old-certs и для каких операций.
    • последовательность signatures с префиксом длины:
      • signature algorithm ID (uint32) - должен совпадать с идентификатором из раздела подписанных данных
      • signature с префиксом длины над указанными выше signed data

Несколько предков в структуре proof-of-rotation

Схема v3 также не поддерживает смену двух разных ключей на один и тот же ключ подписи для одного и того же приложения. Это отличается от случая приобретения, когда приобретающая компания хотела бы переместить приобретенное приложение, чтобы использовать его ключ подписи для совместного использования разрешений. Приобретение рассматривается как поддерживаемый вариант использования, поскольку новое приложение будет отличаться по имени пакета и может содержать собственную структуру подтверждения ротации. Неподдерживаемый случай, когда одно и то же приложение имеет два разных пути для получения одного и того же сертификата, нарушает многие предположения, сделанные в схеме ротации ключей.

Проверка

В Android 9 и более поздних версиях APK можно проверить в соответствии со схемой подписи APK v3, v2 или v1. Старые платформы игнорируют подписи v3 и пытаются проверить подписи v2, а затем v1.

Процесс проверки подписи APK

Рисунок 1. Процесс проверки подписи APK

Проверка схемы подписи APK v3

  1. Найдите блок подписи APK и убедитесь, что:
    1. Два поля размера блока подписи APK содержат одно и то же значение.
    2. За ZIP-файлом центрального каталога сразу же следует ZIP-конец записи центрального каталога.
    3. ZIP End of Central Directory не сопровождается дополнительными данными.
  2. Найдите первый блок схемы подписи APK v3 внутри блока подписи APK. Если присутствует блок v3, перейдите к шагу 3. В противном случае вернитесь к проверке APK с использованием схемы v2 .
  3. Для каждой signer стороны в блоке APK Signature Scheme v3 с минимальной и максимальной версией SDK, соответствующей текущей платформе:
    1. Выберите signature algorithm ID подписи из signatures . Порядок прочности зависит от каждой версии реализации/платформы.
    2. Сверьте соответствующую signature из signatures с signed data используя public key . (Теперь безопасно анализировать signed data .)
    3. Убедитесь, что минимальная и максимальная версии SDK в подписанных данных соответствуют версиям, указанным для signer .
    4. Убедитесь, что упорядоченный список идентификаторов алгоритмов подписи в digests и signatures идентичен. (Это сделано для предотвращения удаления/добавления подписи.)
    5. Вычислите дайджест содержимого APK , используя тот же алгоритм дайджеста, что и алгоритм дайджеста, используемый алгоритмом подписи.
    6. Убедитесь, что вычисленный дайджест идентичен соответствующему digest из digests .
    7. Убедитесь, что SubjectPublicKeyInfo первого certificate certificates идентичен public key .
    8. Если для signer существует атрибут proof-of-rotation, убедитесь, что структура действительна и этот signer является последним сертификатом в списке.
  4. Проверка завершается успешно, если в диапазоне текущей платформы найдено ровно одно signer лицо и шаг 3 для этого signer выполнен успешно.

Проверка

Чтобы убедиться, что ваше устройство правильно поддерживает v3, запустите тесты PkgInstallSignatureVerificationTest.java CTS в cts/hostsidetests/appsecurity/src/android/appsecurity/cts/ .