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(с префиксом длины)
 
-  
-  Последовательность certificatesX.509 с префиксом длины:-  certificateX.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 v3 под идентификатором 0x3ba06f8c . Его формат:
-  последовательность levelsс префиксом длины:-  signed dataс префиксом длины (по предыдущему сертификату - если существует)-  certificateX.509 с префиксом длины (форма ASN.1 DER)
-  signature algorithm ID(uint32) — алгоритм, используемый сертификатом на предыдущем уровне
 
-  
-  flags(uint32) — флаги, указывающие, должен ли этот сертификат находиться в структуре self-trusted-old-certs и для каких операций.
-  signature algorithm ID(uint32) — должен совпадать с идентификатором из раздела подписанных данных на следующем уровне.
-  signatureс префиксом длины поверхsigned data
 
-  
Несколько сертификатов
Несколько подписантов не поддерживаются, и Google Play не публикует приложения, подписанные несколькими сертификатами.
Проверка
В Android 9 и более поздних версиях APK-файлы можно проверять в соответствии со схемой подписи APK v3, v2 или v1. Старые платформы игнорируют подписи v3 и пытаются проверить подписи v2, а затем v1.

Рисунок 1. Процесс проверки подписи APK
Проверка схемы подписи APK v3
-  Найдите блок подписи APK и убедитесь, что:- Два поля размера блока подписи APK содержат одно и то же значение.
- Сразу за ZIP Central Directory следует запись ZIP End of Central Directory.
- ZIP Конец центрального каталога не сопровождается дополнительными данными.
 
- Найдите первый блок схемы подписи APK v3 внутри блока подписи APK. Если блок v3 присутствует, перейдите к шагу 3. В противном случае вернитесь к проверке APK по схеме v2 .
-  Для каждого signerв блоке схемы подписи APK v3 с минимальной и максимальной версией SDK, соответствующей текущей платформе:-  Выберите самый надежный signature algorithm IDизsignatures. Порядок прочности зависит от каждой версии реализации/платформы.
-  Проверьте соответствующую signatureизsignaturesпротивsigned dataс помощьюpublic key. (Теперь можно безопасно анализироватьsigned data.)
-  Убедитесь, что минимальная и максимальная версии SDK в подписанных данных совпадают с указанными для signer.
-  Убедитесь, что упорядоченный список идентификаторов алгоритмов подписи в digestsиsignaturesидентичен. (Это сделано для предотвращения удаления/добавления подписи.)
- Вычислите дайджест содержимого APK, используя тот же алгоритм дайджеста, что и алгоритм дайджеста, используемый алгоритмом подписи.
-  Убедитесь, что вычисленный дайджест идентичен соответствующему digestизdigests.
-  Убедитесь, что subjectPublicKeyInfo первого certificatecertificatesидентиченpublic key.
-  Если для signerсуществует атрибут подтверждения ротации, убедитесь, что структура действительна и что этаsignerявляется последним сертификатом в списке.
 
-  Выберите самый надежный 
-  Проверка считается успешной, если в диапазоне текущей платформы найден ровно один signerи для этогоsignerшаг 3 выполнен успешно.
Валидация
 Чтобы проверить, правильно ли ваше устройство поддерживает версию 3, запустите CTS-тесты PkgInstallSignatureVerificationTest.java в cts/hostsidetests/appsecurity/src/android/appsecurity/cts/ .
