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

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

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

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

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

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

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

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

Формат

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

Формат блока схемы подписи APK 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 (variable-length: длина дополнительного атрибута — 4 байта)
        • ID - 0x3ba06f8c
        • value - структура доказательства ротации
    • minSDK (uint32) — дубликат значения minSDK в разделе подписанных данных — используется для пропуска проверки этой подписи, если текущая платформа находится вне диапазона. Должно соответствовать значению подписанных данных.
    • maxSDK (uint32) — дубликат значения maxSDK в разделе подписанных данных — используется для пропуска проверки этой подписи, если текущая платформа находится вне диапазона. Должно соответствовать значению подписанных данных.
    • последовательность signatures с префиксом длины:
      • signature algorithm ID (uint32)
      • signature с префиксом длины над signed data
    • public key с префиксом длины (SubjectPublicKeyInfo, форма ASN.1 DER)

Структуры «Доказательство ротации» и «доверенные старые сертификаты»

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

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

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

Структура данных самодоверенных старых сертификатов создается путем добавления флагов к каждому узлу, указывающих его членство и свойства в наборе. Например, может присутствовать флаг, указывающий, что сертификат подписи на данном узле является доверенным для получения разрешений на подпись Android. Этот флаг позволяет другим приложениям, подписанным старым сертификатом, по-прежнему получать разрешение на подпись, определенное приложением, подписанным новым сертификатом подписи. Поскольку весь атрибут подтверждения ротации находится в разделе подписанных данных поля 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, подписанный несколькими сертификатами, как имеющий уникальный идентификатор подписи, отдельный от входящих в него сертификатов. Таким образом, атрибут доказательства ротации в разделе подписанных данных образует ориентированный ациклический граф, который лучше рассматривать как односвязный список, где каждый набор подписывающих сторон для данной версии представляет один узел. Это усложняет структуру доказательства ротации (версия с несколькими подписантами ниже). В частности, заказ становится проблемой. Более того, больше невозможно подписывать 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

Множественные предки в структуре доказательства ротации

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

Проверка

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

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

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

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

  1. Найдите блок подписи APK и убедитесь, что:
    1. Два поля размера блока подписи APK содержат одно и то же значение.
    2. Сразу за ZIP Central Directory следует запись ZIP End of Central Directory.
    3. ZIP Конец центрального каталога не сопровождается дополнительными данными.
  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 существует атрибут подтверждения ротации, убедитесь, что структура действительна и что эта signer является последним сертификатом в списке.
  4. Проверка считается успешной, если в диапазоне текущей платформы найден ровно один signer и для этого signer шаг 3 выполнен успешно.

Проверка

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