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