android – Как установить доверенный сертификат ЦС на Android-устройство? –

android - Как установить доверенный сертификат ЦС на Android-устройство? - Сертификаты

Введение сертификата безопасности оказалось тестом. что говорит о сертификате закон и как его удалить с различных устройств?

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

6 августа в Комитете национальной безопасности заявили об успешном завершении тестирования сертификата безопасности. Национальный координационный центр информационной безопасности выявил более 8 млн фактов вирусной активности и 130 тысяч кибератак на государственные органы и частные компании, также были выявлены факты кибершпионажа в отношении ряда государственных органов.

Было объявлено, что казахстанцы могут удалять национальные сертификаты безопасности Qaznet Trust Network со своих устройств. Informburo.kz рассказывает, значит ли это, что власти отказались от идеи контролировать казахстанский интернет и как удалить пресловутый сертификат со своего устройства.

А это законно?

В Законе “О связи” от 2021 года есть пункт, касающийся национального сертификата безопасности. После того, как казахстанцев попросили установить сертификат, в социальных сетях было много высказываний о том, почему четыре года с момента принятия Закона “О связи” на этот пункт не обращали внимания.

В законе сказано следующее:

“Операторы междугородной и (или) международной телефонной связи обязаны:

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

При этом закон не даёт операторам право ограничивать доступ к интернету тем, кто не установил на своё устройство национальный сертификат безопасности. Как поясняли представители компаний, операторы обязаны уведомлять своих абонентов о необходимости установки сертификата, который выпускает Национальный удостоверяющий центр РК. и предоставлять к нему доступ.

Также закон не обязывает казахстанцев устанавливать национальный сертификат на свои устройства, чтобы получить доступ к интернету.

Если я удалю сертификат, то будут ли за мной следить?

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

Согласно статье 26 Закона “О связи” операторы обязаны весь трафик пропускать через систему централизованного управления сетями телекоммуникаций РК. Также представители Министерства цифрового развития, оборонной и аэрокосмической промышленности в Казахстане сказали, что действует промежуточная система, которая позволяет вмешиваться в поток данных и считывать его, для чего и нужна централизация всех потоков. Сертификат безопасности – часть промежуточной системы. В основном он необходим для удобства управления трафиком, так как он позволяет получать его в незашифрованном виде.

Если на вашем устройстве нет национального сертификата, то государство всё равно может перехватывать ваш трафик, просто он будет в зашифрованном виде.

Больше никаких сертификатов?

На сегодняшний день государство приостановило внедрение национального сертификата безопасности, но это не значит, что в следующий раз подобное “тестирование” на проведут на территории всего государства по нескольким причинам:

Как удалить сертификат из iOS?

У устройств iPhone, iPad или iPod touch, которые работают на операционной системе iOS, одинаковый алгоритм удаления ненужных сертификатов. При этом система позволяет отключить сертификат, не удаляя его с устройства.

Отключить сертификат Qaznet Trust Network:

  1. Откройте “Настройки“, кликнув на значок с шестирёнками.
  2. Прокрутите вниз до пункта “Основные” и нажмите на него (значок с одной большой шестирёнкой).
  3. В появившемся меню нажмите на первую строчку “Об этом устройстве“.
  4. Прокрутите меню до конца и нажмите на последнюю строчку “Доверие сертификатов”.
  5. В появившемся списке нажмите на зелёный переключатель “Qaznet Trust Network“. Переключатель окрасится в серый, если он уже такого цвета, значит, сертификат на вашем устройстве не был включён.

Удалить сертификат Qaznet Trust Network:

  1. Откройте “Настройки” (значок с шестирёнками).
  2. Прокрутите вниз до пункта “Основные” и нажмите на него (значок с одной большой шестирёнкой).
  3. Найдите внизу появившегося меню пункт “Профиль” и нажмите на него.
  4. В открывшемся списке выберите профиль под названием “Qaznet Trust Network“.
  5. Затем нажмите большую красную кнопку “Удалить профиль”.
  6. Устройство потребует ввода пароля безопасности, если он установлен. Введите пароль к устройству и нажмите кнопку “Удалить”.
  7. Перезагрузите устройство.

Удаление сертификата безопасности Qaznet Trust Network (IOS).

Как удалить сертификат с устройства на Android?

Устройства. работающие на платформе Android. могут иметь разные оболочки, так как каждый производитель может переделывать её на свой лад, поэтому меню могут выглядеть по-разному, но логика процесса удаления сертификата должна быть схожей для всех гаджетов.

Удалить сертификат Qaznet Trust Network:

  1. Зайдите в настройки устройства.
  2. Найдите и нажмите на строчку “Расширенные настройки“.
  3. В появившемся меню выберите пункт “Конфинедциальность“.
  4. В разделе “Хранилище учётных данных” нажмите на строчку “Надёжные сертификаты“.
  5. В подпункте “Пользователь” найдите и нажмите на сертификат под названием “Qaznet Trust Network“.
  6. В появившемся меню должна быть кнопка “Удалить” нажимайте на неё, а затем на кнопку “Ок“.
  7. Вернитесь обратно в раздел “Конфиденциальность“, найдите в разделе “Хранилище учётных данных” подпункт “Учётные данные пользователя” и нажмите на него.
  8. В появившемся списке найдите и нажмите на строчку QCA или Qaznet Trust Network.
  9. В появившемся окне “Учётные данные” нажмите на кнопку “Удалить“.
  10. Перезагрузите устройство.

Удаление сертификата безопасности Qaznet Trust Network (Andriod).

Как удалить сертификат из windows?

Независимо от того, через какой браузер вы устанавливали сертификат безопасности, его можно удалить одним способом.

Для начала вам нужно зайти в “Панель управления“:

Чтобы удалить сертификат Qaznet Trust Network из Wbindows:

  1. В “Панели управления” нажмите на меню “Сеть и интернет“.
  2. Под пунктом “Свойства браузера” найдите строчку “Управление настройками браузера“. Нажмите на неё.
  3. В появившемся меню “Свойства интернета” выберите вкладку “Содержание” и нажмите на кнопку “Сертификаты“.
  4. В меню “Сертификаты” вам нужна вкладка “Промежуточные центры сертификации“.
  5. В появившемся списке выберите строчку под названием Qaznet Trust Network, затем нажмите на кнопку “Удалить“.

Как удалить сертификат из macos?

Устройства под управлением MacOS независимо от версий обычно имеют схожую логику меню. Вне зависимости от того, старой или новой операционной системой вы пользуетесь, чтобы найти расположение сертификата безопасности, запустите приложение “Связка ключей”.

Как найти приложение “Связка ключей”:

  • В меню “Программы” откройте вкладку “Утилиты” и найдите в списке “Связка ключей
  • Запустите “Launchpad” – значок в виде ракеты в нижней панели. Откройте папку “Другие” и в ней найдите “Связка ключей“.

Как удалить сертификат Qaznet Trust Network из MacOS:

  1. Запустите приложение “Связка ключей“.
  2. В нижнем левом разделе “Категория” выберите строчку “Сертификаты”.
  3. В центральном разделе появится список, в котором вам необходимо найти строчку “Qaznet Trust Network”.
  4. Нажмите дважды на сертификат и в появившемся подменю выберите строчку “Удалить “Qaznet Trust Network”.

Я всё сделал по инструкции. как проверить, что сертификат больше не работает?

Чтобы проверить, действует ли национальный сертификат безопасности на вашем устройстве или нет, зайдите на сайт check.qca.kz. Если он ещё работает, то вы увидите надпись “Сертификат безопасности успешно установлен”, в ином случае появится предупреждение “Это подключение не защищено”.

4 метода обхода верификации ssl-сертификатов в android

Прошли те времена, когда мобильные приложения мужественно игнорировали все ошибки, связанные с SSL, и позволяли перехватывать и модифицировать трафик.

Автор: Cody Wass

Прошли те времена, когда мобильные приложения мужественно игнорировали все ошибки, связанные с SSL, и позволяли перехватывать и модифицировать трафик. Современные приложения, как минимум, проверяют цепочки сертификатов на валидность и принадлежность к достоверному центру сертификации. Мы, пентестеры, ставим перед собой задачу «убедить» приложение, что сертификат надежный с целью выполнения атаки типа «человек посередине» и последующего изменения трафика. В этой статье будут рассмотрены следующие техники обхода проверок SSL-сертификатов в Android:

  • Добавление сертификатов в хранилище достоверных сертификатов.
  • Перезапись упакованных сертификатов.
  • Использование скрипта Frida для обхода проверок SSL-сертификатов.
  • Изменение кода проверки сертификата.

Некоторые из вышеуказанных техник – простые, другие – более сложные в реализации. Мы рассмотрим каждый из этих методов без особого углубления в специфические детали.

Зачем нужна MITM-атака на SSL

Чтобы просматривать и изменять вызовы веб-службы, используемой мобильным приложением, нам понадобится промежуточный прокси сервер для перехвата, созданный при помощи утилит навроде BurpSuite или ZAP. При перехвате SSL-трафика SSL-соединение прерывается на стороне прокси-сервера. Сертификат, отсылаемый прокси-сервером, анализируется мобильным приложением, как если бы прокси был оконечной точкой веб-службы. По умолчанию самоподписанный сертификат, генерируемые утилитами наподобие Burp, не будет принадлежать проверенной достоверной цепочке. Если сертификат нельзя проверить на достоверность, большинство мобильных будут обрывать соединение вместо того, чтобы подключаться и работать в потенциально незащищенном канале. Техники, представленные ниже, предназначены для одной цели – убедить мобильное приложение, что сертификат, отправляемый прокси-сервером, является достоверным.

Техника 1 – Добавление сертификата в хранилище пользовательских сертификатов

Самый простой способ избежать SSL-ошибок – обзавестись валидным и надежным сертификатом. Эта задача решается относительно просто, если вы сможете установить достоверный сертификат на устройство. Если операционная система доверяет вашему центру сертификации, то будет доверять и сертификату, подписанному центром сертификации.

В Android есть два встроенных хранилища сертификатов, которые отслеживают, каким центрам сертификации доверяет операционная система: системное хранилище (хранит предустановленные сертификаты) и пользовательское хранилище (хранит сертификаты, добавленные пользователями).

Выдержка с сайта developer.android.com:

По умолчанию безопасные соединения (использующие протоколы TLS, HTTPS и им подобные) во всех приложениях доверяют предустановленным системным сертификатам. В Android 6.0 (API level 23) и более ранних версиях по умолчанию также считаются достоверными сертификаты, добавленные пользователями. Приложение может настраивать свои собственные соединения на уровне приложения (base-config) и на уровне домена (domain-config).

Сей факт означает, что, если мы имеем дело с приложением, которое работает в Android 6.0 и более ранних версиях, то можно просто добавить сертификат в пользовательское хранилище. Когда приложение пытается проверить достоверность цепочки для нашего сертификата, то обнаружит, что наш центр сертификации связан с достоверным хранилищем и, следовательно, будет доверять нашему сертификату. В более новых версиях приложение не будет доверять хранилищу пользовательских сертификатов. Чтобы решить эту проблему, нужно прописать такой уровень API и версию Android, чтобы приложение стало доверять пользовательским центрам сертификации. Мы будем редактировать атрибут «platformBuildVersionCode» элемента «manifest» в файле AndroidManifest.xml.

<manifest xmlns:android=”http://schemas.android.com/apk/res/android&quot; package=”com.test.app” platformBuildVersionCode=”25″ platformBuildVersionName=”7.1.1″>

В коде выше в строке «platformBuildVersionCode=25» нужно поменять значение 25 на 23, а в строке platformBuildVersionName=”7.1.1″ значение 7.1.1 на 6.0.

<manifest xmlns:android=”http://schemas.android.com/apk/res/android&quot; package=”com.test.app” platformBuildVersionCode=”23″ platformBuildVersionName=”6.0“>

После переупаковки приложения с обновленным файлом AndroidManifest.xml, доверие пользовательским центрам сертификации будет восстановлено.

Если требуется запуск на конкретной версии платформы, мы можем определить тэг trust-anchors в файле «/res/xml/network_security_config.xml». Например, следующий файл (https://developer.android.com/training/articles/security-config.html) определяет новый достоверный сертификат, который должен храниться по адресу /res/raw/my_ca.

 <?xml version="1.0"  encoding="utf-8"?>
  <network-security-config>
  <base-config>
  <trust-anchors>
  <certificates src="@raw/my_ca"/>
  </trust-anchors>
  </base-config> 
</network-security-config>

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

Техника 2 – Перезапись упакованного сертификата

Если после установки сертификата в пользовательское хранилище, изменении в настройках версии Android и успешном прохождении проверок при просмотре других ресурсов, защищенных протоколом SSL, все равно возникают ошибки, значит, разработчики внедрили дополнительные условия, которым должны удовлетворять достоверные центры сертификации. Если не забыли, в предыдущей технике внутри тэга trust-anchors добавлялся новый путь к сертификату. Подобный трюк может использоваться разработчиками для защиты приложений от перехвата SSL.

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

android - Как установить доверенный сертификат ЦС на Android-устройство? -
Рисунок 1: Перечень сертификатов, используемых приложением

Если открыть пакет приложения при помощи, например, APK Studio, то можно сразу увидеть перечень привязанных сертификатов. На картинке выше сертификаты находятся в папке «assets». Замена явно бросающегося в глаза сертификата UniversalRootCA позволит нам подсунуть приложению наш сертификат.

Техника 3 – Подключение к функциям через фреймворк Frida

Если установки собственного сертификата недостаточно для успешного перехвата SSL-трафика, скорее всего, в приложении используются техники навроде SSL pinning или дополнительная SSL-валидация. В этом случае нужно блокировать проверки через непосредственное подключение к соответствующим функциям. Ранее эта техника была доступна для реализации только на устройствах с правами суперпользователя. Однако на данный момент при помощи библиотеки Frida Gadget можно работать с приложением и получить доступ к полному функционалу фреймворка Frida без прав суперпользователя.

Если вы уже выполняли пентесты мобильных приложений, то, вероятно, знакомы с этим фреймворком. Описание всей функциональности Frida выходит за рамки этой статьи, но если говорить в общем, то этот фреймворк позволяет изменять логику работы приложения во время выполнения. Обычно Frida работает как отдельное приложение и требует прав суперпользователя на устройстве. Если у нас нет прав суперпользователя, мы можем инжектировать в пакет приложения динамическую библиотеку Frida Gadget, содержащую большую часть функционала фреймворка Frida. Эта библиотека загружается во время выполнения приложения и позволяет вносить изменения в код.
Чтобы загрузить Frida Gadget, нужно распаковать APK, вставить динамическую библиотеку, отредактировать smali-код так, чтобы динамическая библиотека вызывалась самой первой, а затем переупаковать и установить пакет. Весь этот процесс хорошо задокументирован Джоном Козиракисом (John Kozyrakis). Вначале лучше пройти все этапы вручную, чтобы лучше понять, как работает эта технология. Чтобы сэкономить время, существует утилита – Objection, которая автоматизирует весь вышеупомянутый процесс. Требуется лишь указание целевого пакета, над которым нужно выполнить манипуляции.

 C:  >objection patchapk -s test_app.apk
  No  architecture specified. Determining it using `adb`...
  Detected  target device architecture as: armeabi-v7a
  Github  FridaGadget is v10.6.28, local is v10.6.13. Updating...
  Downloading  armeabi-v7a library to  C:.objectionandroidarmeabi-v7alibfrida-gadget.so.xz...
  Unpacking  C:.objectionandroidarmeabi-v7alibfrida-gadget.so.xz...
  Cleaning up  downloaded archives...
  Using Gadget  version: 10.6.28
  Unpacking  test_app.apk
  App already  has android.permission.INTERNET
  Reading  smali from:  C:Temptmp8dxqks1u.apktempsmalicom/test/app/TestMainActivity.smali
  Injecting  loadLibrary call at line: 10
  Writing  patched smali back to: C:Temptmp8dxqks1u.apktempsmalicom/test/app/TestMainActivity.smali
  Creating  library path: C:Temptmp8dxqks1u.apktemplibarmeabi-v7a
  Copying  Frida gadget to libs path...
  Rebuilding  the APK with the frida-gadget loaded...
  Built new  APK with injected loadLibrary and frida-gadget
  Signing new  APK.
  jar signed.
  Signed the  new APK
  Performing  zipalign
  Zipaling  completed
  Copying  final apk from  C:UserscwassAppDataLocalTemptmp8dxqks1u.apktemp.aligned.objection.apk to  current directory...
Cleaning up  temp files...

После завершения в нашей рабочей директории должен появиться файл «test_app.objection.apk». По умолчанию утилита objection добавляет постфикс «.objection» к имени пакета. Далее мы можем установить этот пакет так же, как и любой другой APK, при помощи команды adb install test_app.objection.apk. После того как измененный пакет установлен на целевом устройстве, во время запуска приложение должно встать на паузу на начальном экране. В этот момент мы можем подключиться к серверу Frida, который отслеживает наше устройство:

C:>frida-ps -U
PID Name
—- ——
6383 Gadget

C:>frida -U gadget
____
/ _ | Frida 10.3.14 – A world-class dynamic instrumentation framework
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about ‘object’
. . . . exit/quit -> Exit
. . . .
. . . . More info at http://www.frida.re/docs/home/

[Motorola Moto G (5) Plus::gadget]-> Java.available
true

Alternatively, Objection supports interaction with the listening Frida server by using the ‘explore’ command:

C:>objection explore
___| |_ |_|___ ___| |_|_|___ ___
| . | . | | | -_| _| _| | . | |
|___|___|_| |___|___|_| |_|___|_|_|
|___|(object)inject(ion) v1.2.2

Runtime Mobile Exploration
by: @leonjza from @sensepost

[tab] for command suggestions
com.test.app on (motorola: 7.0) [usb] # android hooking search classes TrustManager
android.security.net.config.RootTrustManager
android.app.trust.ITrustManager$Stub$Proxy
android.app.trust.ITrustManager
android.security.net.config.NetworkSecurityTrustManager
android.security.net.config.RootTrustManagerFactorySpi
android.app.trust.TrustManager
android.app.trust.ITrustManager$Stub
com.android.org.conscrypt.TrustManagerImpl
com.android.org.conscrypt.TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker
com.android.org.conscrypt.TrustManagerImpl$TrustAnchorComparator
com.android.org.conscrypt.TrustManagerFactoryImpl
javax.net.ssl.TrustManagerFactory$1
javax.net.ssl.TrustManager
javax.net.ssl.TrustManagerFactory
javax.net.ssl.X509TrustManager
javax.net.ssl.TrustManagerFactorySpi
javax.net.ssl.X509ExtendedTrustManager
[Ljavax.net.ssl.TrustManager;

Теперь вы можете воспользоваться функцией для обхода технологии SSL pinning:

com.test.app on (motorola: 7.0) [usb] # android sslpinning disable
Job: 2f633f86-f252-4a57-958e-6b46ac8d69d1 – Starting
[6b46ac8d69d1] [android-ssl-pinning-bypass] Custom, Empty TrustManager ready
Job: 2f633f86-f252-4a57-958e-6b46ac8d69d1 – Started

Техника 4 – Реверс-инжиниринг кода верификации сертификата

Возможен такой случай, когда разработчик использует собственные SSL-библиотеки вместо системных для верификации сертификата. В этой ситуации нам нужно распаковать пакет, сконвертировать smali-код в Java-код и найти функции, отвечающие за проверку сертификата.

Если использовать «dex2jar», синтаксис будет следующим:

C:>d2j-dex2jar.bat “C:test_app.apk”
dex2jar C:test_app.apk -> .test_app-dex2jar.jar

Полученный файл .jar должен быть пригоден для открытия в вашей любимой утилите для исследования Java-приложений (например, JD-GUI).

После того как вы нашли функции, отвечающие за проверку сертификата, можно либо полностью пропатчить код, либо подцепиться к нужной функции при помощи Frida. Чтобы сэкономить время и не пересобирать полностью приложение, эффективнее подцепиться к функциям, отвечающим за проверку сертификата. Шаги, описанные в предыдущей технике, позволят подключиться к приложению, и далее вы можете либо подцепиться к функции при помощи утилит фреймворка Frida, либо при помощи приложения Objection.

Заключение

Техники, описанные в этой статье, позволяют перехватывать SSL-трафик и обходить некоторые наиболее распространенные защиты, используемые разработчиками. Кроме того, я кратко рассказал об утилите Objection и фреймворке Frida. Обход технологии SSL pinning и других защит лишь небольшая часть возможностей, которые позволяют реализовать эти инструменты.

Надеюсь, мне удалось на доступном языке рассказать о техниках, которые могут быть пригодны для оценки безопасности мобильных Android-приложений и демонстрируют важность наличия нескольких способов проведения подобного рода исследований.

Поиск trustmanager

Архитектура шифрования Java (JCA) – очень гибкая архитектура, и ее общая структура выглядит следующим образом:

Приложения Java получают доступ к службам шифрования через уровень интерфейса. В состав уровня интерфейса входят JAAS (Java Authentication Authorization Service, Java Authentication and Authorization API), JSSE (Java Secure Socket Extension, Java Secure Socket Extension)

JCA также определяет набор интерфейсов поставщика услуг шифрования, напримерjavax.net.ssl.SSLContextSpi с участием javax.net.ssl.TrustManagerFactorySpi Подождите. Разработчики служб шифрования реализуют эти интерфейсы и передаютjava.security.Security Предоставленный интерфейс зарегистрирован в структуре JCA.

Для системы AndroidTrustManagerFactory Регистрация службы шифрования находится наActivityThread изhandleBindApplication() Соответствующий код (находится вframeworks/base/core/java/android/app/ActivityThread.java)следующим образом:

        // Install the Network Security Config Provider. This must happen before the application
        // code is loaded to prevent issues with instances of TLS objects being created before
        // the provider is installed.
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "NetworkSecurityConfigProvider.install");
        NetworkSecurityConfigProvider.install(appContext);
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

NetworkSecurityConfigProvider Определение класса (находится вframeworks/base/core/java/android/security/net/config/NetworkSecurityConfigProvider.java)следующим образом:

package android.security.net.config;

import android.content.Context;
import java.security.Security;
import java.security.Provider;

/** @hide */publicfinalclassNetworkSecurityConfigProviderextendsProvider {privatestaticfinal String PREFIX =
            NetworkSecurityConfigProvider.class.getPackage().getName()   ".";

    publicNetworkSecurityConfigProvider() {
        super("AndroidNSSP", 1.0, "Android Network Security Policy Provider");
        put("TrustManagerFactory.PKIX", PREFIX   "RootTrustManagerFactorySpi");
        put("Alg.Alias.TrustManagerFactory.X509", "PKIX");
    }

    publicstaticvoidinstall(Context context) {
        ApplicationConfig config = new ApplicationConfig(new ManifestConfigSource(context));
        ApplicationConfig.setDefaultInstance(config);
        int pos = Security.insertProviderAt(new NetworkSecurityConfigProvider(), 1);
        if (pos != 1) {
            thrownew RuntimeException("Failed to install provider as highest priority provider."
                      " Provider was installed at position "   pos);
        }
        libcore.net.NetworkSecurityPolicy.setInstance(new ConfigNetworkSecurityPolicy(config));
    }
}

ВNetworkSecurityConfigProvider.install() В методе передайтеSecurity.insertProviderAt() БудетNetworkSecurityConfigProvider Зарегистрирован в рамках JCA. Из NetworkSecurityConfigProvider Конструктор видит, что онandroid.security.net.config.RootTrustManagerFactorySpi Внесите в структуру JCA.

android.security.net.config.RootTrustManagerFactorySpi Определение (находится вframeworks/base/core/java/android/security/net/config/RootTrustManagerFactorySpi.java)следующим образом:

package android.security.net.config;

import android.util.Pair;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidParameterException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.util.Set;
import javax.net.ssl.ManagerFactoryParameters;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.TrustManagerFactorySpi;

import com.android.internal.annotations.VisibleForTesting;

/** @hide */publicclassRootTrustManagerFactorySpiextendsTrustManagerFactorySpi {private ApplicationConfig mApplicationConfig;
    private NetworkSecurityConfig mConfig;

    @OverridepublicvoidengineInit(ManagerFactoryParameters spec)
            throws InvalidAlgorithmParameterException {
        if (!(spec instanceof ApplicationConfigParameters)) {
            thrownew InvalidAlgorithmParameterException("Unsupported spec: "    spec   ". Only "
                      ApplicationConfigParameters.class.getName()   " supported");

        }
        mApplicationConfig = ((ApplicationConfigParameters) spec).config;
    }

    @OverridepublicvoidengineInit(KeyStore ks) throws KeyStoreException {
        if (ks != null) {
            mApplicationConfig = new ApplicationConfig(new KeyStoreConfigSource(ks));
        } else {
            mApplicationConfig = ApplicationConfig.getDefaultInstance();
        }
    }

    @Overridepublic TrustManager[] engineGetTrustManagers() {
        if (mApplicationConfig == null) {
            thrownew IllegalStateException("TrustManagerFactory not initialized");
        }
        returnnew TrustManager[] { mApplicationConfig.getTrustManager() };
    }

    @VisibleForTestingpublicstaticfinalclassApplicationConfigParametersimplementsManagerFactoryParameters {publicfinal ApplicationConfig config;
        publicApplicationConfigParameters(ApplicationConfig config) {
            this.config = config;
        }
    }
}

RootTrustManagerFactorySpi изTrustManager Из ApplicationConfig,ApplicationConfig СреднийTrustManager Связанный код (находится вframeworks/base/core/java/android/security/net/config/ApplicationConfig.java)следующим образом:

publicfinalclassApplicationConfig {privatestatic ApplicationConfig sInstance;
    privatestatic Object sLock = new Object();

    private Set<Pair<Domain, NetworkSecurityConfig>> mConfigs;
    private NetworkSecurityConfig mDefaultConfig;
    private X509TrustManager mTrustManager;
. . . . . .
    /**
     * Returns the {@link X509TrustManager} that implements the checking of trust anchors and
     * certificate pinning based on this configuration.
     */public X509TrustManager getTrustManager() {
        ensureInitialized();
        return mTrustManager;
    }
. . . . . .
    privatevoidensureInitialized() {
        synchronized(mLock) {
            if (mInitialized) {
                return;
            }
            mConfigs = mConfigSource.getPerDomainConfigs();
            mDefaultConfig = mConfigSource.getDefaultConfig();
            mConfigSource = null;
            mTrustManager = new RootTrustManager(this);
            mInitialized = true;
        }
    }

ApplicationConfig изTrustManager Да RootTrustManager。

Давайте посмотрим на уровень интерфейса JCAjavax.net.ssl.TrustManagerFactory Определение:

Проверка легальности цепочки сертификатов

Каким образом корневое хранилище сертификатов используется для процесса проверки сертификата при подтверждении связи SSL / TLS с корневым хранилищем сертификатов?

Срок действия сертификата определяется стандартной библиотекой Java.javax.net.ssl.SSLSocket ВstartHandshake() Метод завершен. Для системы AndroidSSLSocket Эта реализация, основанная на реализации библиотеки OpenSSL, реализованаexternal/conscrypt Модуль предоставлен,SSLSocket Реализуется какOpenSSLSocketImpl Класс (находится вexternal/conscrypt/src/main/java/org/conscrypt/OpenSSLSocketImpl.java)。

OpenSSLSocketImpl.startHandshake() Подтверждение SSL / TLS – чрезвычайно деликатный процесс. Мы пропускаем подробный процесс установления связи и сосредотачиваемся на части проверки сертификата.

OpenSSLSocketImpl.startHandshake() ПроходятNativeCrypto Класс (находится вexternal/conscrypt/src/main/java/org/conscrypt/NativeCrypto.java) Статический метод локального слояSSL_do_handshake() Метод выполняет операцию рукопожатия:

/**
     * Returns the sslSessionNativePointer of the negotiated session. If this is
     * a server negotiation, supplying the {@code alpnProtocols} will enable
     * ALPN negotiation.
     */publicstaticnativelongSSL_do_handshake(long sslNativePointer,
                                               FileDescriptor fd,
                                               SSLHandshakeCallbacks shc,
                                               int timeoutMillis,
                                               boolean client_mode,
                                               byte[] npnProtocols,
                                               byte[] alpnProtocols)
        throws SSLException, SocketTimeoutException, CertificateException;

NativeCrypto Класс определяет набор обратных вызовов, которые будут вызываться кодом OpenSSL C / C , связанным с рукопожатием SSL на локальном уровне.SSLHandshakeCallbacks,над SSL_do_handshake() В методе этот набор обратных вызовов передается на локальный уровень в качестве параметров.

SSLHandshakeCallbacks Это определяется следующим образом:

/**
     * A collection of callbacks from the native OpenSSL code that are
     * related to the SSL handshake initiated by SSL_do_handshake.
     */publicinterfaceSSLHandshakeCallbacks {/**
         * Verify that we trust the certificate chain is trusted.
         *
         * @param sslSessionNativePtr pointer to a reference of the SSL_SESSION
         * @param certificateChainRefs chain of X.509 certificate references
         * @param authMethod auth algorithm name
         *
         * @throws CertificateException if the certificate is untrusted
         */publicvoidverifyCertificateChain(long sslSessionNativePtr, long[] certificateChainRefs,
                String authMethod) throws CertificateException;

        /**
         * Called on an SSL client when the server requests (or
         * requires a certificate). The client can respond by using
         * SSL_use_certificate and SSL_use_PrivateKey to set a
         * certificate if has an appropriate one available, similar to
         * how the server provides its certificate.
         *
         * @param keyTypes key types supported by the server,
         * convertible to strings with #keyType
         * @param asn1DerEncodedX500Principals CAs known to the server
         */publicvoidclientCertificateRequested(byte[] keyTypes,
                                               byte[][] asn1DerEncodedX500Principals)
            throws CertificateEncodingException, SSLException;

        /**
         * Gets the key to be used in client mode for this connection in Pre-Shared Key (PSK) key
         * exchange.
         *
         * @param identityHint PSK identity hint provided by the server or {@code null} if no hint
         *        provided.
         * @param identity buffer to be populated with PSK identity (NULL-terminated modified UTF-8)
         *        by this method. This identity will be provided to the server.
         * @param key buffer to be populated with key material by this method.
         *
         * @return number of bytes this method stored in the {@code key} buffer or {@code 0} if an
         *         error occurred in which case the handshake will be aborted.
         */publicintclientPSKKeyRequested(String identityHint, byte[] identity, byte[] key);

        /**
         * Gets the key to be used in server mode for this connection in Pre-Shared Key (PSK) key
         * exchange.
         *
         * @param identityHint PSK identity hint provided by this server to the client or
         *        {@code null} if no hint was provided.
         * @param identity PSK identity provided by the client.
         * @param key buffer to be populated with key material by this method.
         *
         * @return number of bytes this method stored in the {@code key} buffer or {@code 0} if an
         *         error occurred in which case the handshake will be aborted.
         */publicintserverPSKKeyRequested(String identityHint, String identity, byte[] key);

        /**
         * Called when SSL state changes. This could be handshake completion.
         */publicvoidonSSLStateChange(long sslSessionNativePtr, int type, int val);
    }

среди нихverifyCertificateChain()Обратный вызов используется для проверки сертификата сервера. Система Android использует этот обратный вызов для подключения модуля управления библиотекой корневых сертификатов с подтверждением связи SSL / TLS и проверкой подлинности базового OpenSSL.

SSLHandshakeCallbacks Обратный звонок отOpenSSLSocketImpl достичь,verifyCertificateChain() Реализация следующая:

@SuppressWarnings("unused") @OverridepublicvoidverifyCertificateChain(long sslSessionNativePtr, long[] certRefs, String authMethod)
            throws CertificateException {
        try {
            X509TrustManager x509tm = sslParameters.getX509TrustManager();
            if (x509tm == null) {
                thrownew CertificateException("No X.509 TrustManager");
            }
            if (certRefs == null || certRefs.length == 0) {
                thrownew SSLException("Peer sent no certificate");
            }
            OpenSSLX509Certificate[] peerCertChain = new OpenSSLX509Certificate[certRefs.length];
            for (int i = 0; i < certRefs.length; i  ) {
                peerCertChain[i] = new OpenSSLX509Certificate(certRefs[i]);
            }

            
            handshakeSession = new OpenSSLSessionImpl(sslSessionNativePtr, null, peerCertChain,
                    getHostnameOrIP(), getPort(), null);

            boolean client = sslParameters.getUseClientMode();
            if (client) {
                Platform.checkServerTrusted(x509tm, peerCertChain, authMethod, this);
                if (sslParameters.isCTVerificationEnabled(getHostname())) {
                    byte[] tlsData = NativeCrypto.SSL_get_signed_cert_timestamp_list(
                                        sslNativePointer);
                    byte[] ocspData = NativeCrypto.SSL_get_ocsp_response(sslNativePointer);

                    CTVerifier ctVerifier = sslParameters.getCTVerifier();
                    CTVerificationResult result =
                        ctVerifier.verifySignedCertificateTimestamps(peerCertChain, tlsData, ocspData);

                    if (result.getValidSCTs().size() == 0) {
                        thrownew CertificateException("No valid SCT found");
                    }
                }
            } else {
                String authType = peerCertChain[0].getPublicKey().getAlgorithm();
                Platform.checkClientTrusted(x509tm, peerCertChain, authType, this);
            }
        } catch (CertificateException e) {
            throw e;
        } catch (Exception e) {
            thrownew CertificateException(e);
        } finally {
            
            handshakeSession = null;
        }
    }

OpenSSLSocketImpl изverifyCertificateChain() Из sslParameters ПолучитьX509TrustManagerА потом вPlatform.checkServerTrusted() (com.android.org.conscrypt.Platform,роды external/conscrypt/src/compat/java/org/conscrypt/Platform.java) При выполнении проверки действительности сертификата на стороне сервера:

publicstaticvoidcheckServerTrusted(X509TrustManager tm, X509Certificate[] chain,
            String authType, OpenSSLSocketImpl socket) throws CertificateException {
        if (!checkTrusted("checkServerTrusted", tm, chain, authType, Socket.class, socket)
                && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class,
                                 socket.getHandshakeSession().getPeerHost())) {
            tm.checkServerTrusted(chain, authType);
        }
    }

Platform.checkServerTrusted() ВыполняяX509TrustManager изcheckServerTrusted() Метод выполняет проверку действительности сертификата.

X509TrustManager Из OpenSSLSocketImpl изsslParameters, ЧтоsslParameters Откуда это?OpenSSLSocketImpl изsslParameters Передано создателем объекта:

publicclassOpenSSLSocketImplextendsjavax.net.ssl.SSLSocketimplementsNativeCrypto.SSLHandshakeCallbacks, SSLParametersImpl.AliasChooser,
        SSLParametersImpl.PSKCallbacks {
. . . . . .
    privatefinal SSLParametersImpl sslParameters;
. . . . . .
    protectedOpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException {
        this.socket = this;
        this.peerHostname = null;
        this.peerPort = -1;
        this.autoClose = false;
        this.sslParameters = sslParameters;
    }

    protectedOpenSSLSocketImpl(String hostname, int port, SSLParametersImpl sslParameters)
            throws IOException {
        super(hostname, port);
        this.socket = this;
        this.peerHostname = hostname;
        this.peerPort = port;
        this.autoClose = false;
        this.sslParameters = sslParameters;
    }

    protectedOpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters)
            throws IOException {
        super(address, port);
        this.socket = this;
        this.peerHostname = null;
        this.peerPort = -1;
        this.autoClose = false;
        this.sslParameters = sslParameters;
    }


    protectedOpenSSLSocketImpl(String hostname, int port,
                                InetAddress clientAddress, int clientPort,
                                SSLParametersImpl sslParameters) throws IOException {
        super(hostname, port, clientAddress, clientPort);
        this.socket = this;
        this.peerHostname = hostname;
        this.peerPort = port;
        this.autoClose = false;
        this.sslParameters = sslParameters;
    }

    protectedOpenSSLSocketImpl(InetAddress address, int port,
                                InetAddress clientAddress, int clientPort,
                                SSLParametersImpl sslParameters) throws IOException {
        super(address, port, clientAddress, clientPort);
        this.socket = this;
        this.peerHostname = null;
        this.peerPort = -1;
        this.autoClose = false;
        this.sslParameters = sslParameters;
    }

    /**
     * Create an SSL socket that wraps another socket. Invoked by
     * OpenSSLSocketImplWrapper constructor.
     */protectedOpenSSLSocketImpl(Socket socket, String hostname, int port,
            boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
        this.socket = socket;
        this.peerHostname = hostname;
        this.peerPort = port;
        this.autoClose = autoClose;
        this.sslParameters = sslParameters;

        
    }

Другими словами,OpenSSLSocketImpl изsslParameters Из javax.net.ssl.SSLSocketFactory,который OpenSSLSocketFactoryImpl。OpenSSLSocketFactoryImpl Определение (находится вexternal/conscrypt/src/main/java/org/conscrypt/OpenSSLSocketFactoryImpl.java)следующим образом:

package org.conscrypt;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;

publicclassOpenSSLSocketFactoryImplextendsjavax.net.ssl.SSLSocketFactory {privatefinal SSLParametersImpl sslParameters;
    privatefinal IOException instantiationException;

    publicOpenSSLSocketFactoryImpl() {
        SSLParametersImpl sslParametersLocal = null;
        IOException instantiationExceptionLocal = null;
        try {
            sslParametersLocal = SSLParametersImpl.getDefault();
        } catch (KeyManagementException e) {
            instantiationExceptionLocal = new IOException("Delayed instantiation exception:");
            instantiationExceptionLocal.initCause(e);
        }
        this.sslParameters = sslParametersLocal;
        this.instantiationException = instantiationExceptionLocal;
    }

    publicOpenSSLSocketFactoryImpl(SSLParametersImpl sslParameters) {
        this.sslParameters = sslParameters;
        this.instantiationException = null;
    }

    @Overridepublic String[] getDefaultCipherSuites() {
        return sslParameters.getEnabledCipherSuites();
    }

    @Overridepublic String[] getSupportedCipherSuites() {
        return NativeCrypto.getSupportedCipherSuites();
    }

    @Overridepublic Socket createSocket() throws IOException {
        if (instantiationException != null) {
            throw instantiationException;
        }
        returnnew OpenSSLSocketImpl((SSLParametersImpl) sslParameters.clone());
    }

    @Overridepublic Socket createSocket(String hostname, int port) throws IOException, UnknownHostException {
        returnnew OpenSSLSocketImpl(hostname, port, (SSLParametersImpl) sslParameters.clone());
    }

    @Overridepublic Socket createSocket(String hostname, int port, InetAddress localHost, int localPort)
            throws IOException, UnknownHostException {
        returnnew OpenSSLSocketImpl(hostname,
                                     port,
                                     localHost,
                                     localPort,
                                     (SSLParametersImpl) sslParameters.clone());
    }

    @Overridepublic Socket createSocket(InetAddress address, int port) throws IOException {
        returnnew OpenSSLSocketImpl(address, port, (SSLParametersImpl) sslParameters.clone());
    }

    @Overridepublic Socket createSocket(InetAddress address,
                               int port,
                               InetAddress localAddress,
                               int localPort)
            throws IOException {
        returnnew OpenSSLSocketImpl(address,
                                     port,
                                     localAddress,
                                     localPort,
                                     (SSLParametersImpl) sslParameters.clone());
    }

    @Overridepublic Socket createSocket(Socket s, String hostname, int port, boolean autoClose)
            throws IOException {
        returnnew OpenSSLSocketImplWrapper(s,
                                            hostname,
                                            port,
                                            autoClose,
                                            (SSLParametersImpl) sslParameters.clone());
    }
}

OpenSSLSocketImpl Основная ответственность – установить параметры SSL / TLS.SSLParametersImpl Придерживайтесь SSLSocket. В основном смотрите по умолчаниюSSLParametersImpl изX509TrustManager Что находится (находится вexternal/conscrypt/src/main/java/org/conscrypt/SSLParametersImpl.java ):

/**
     * Initializes the parameters. Naturally this constructor is used
     * in SSLContextImpl.engineInit method which directly passes its
     * parameters. In other words this constructor holds all
     * the functionality provided by SSLContext.init method.
     * See {@link javax.net.ssl.SSLContext#init(KeyManager[],TrustManager[],
     * SecureRandom)} for more information
     */protectedSSLParametersImpl(KeyManager[] kms, TrustManager[] tms,
            SecureRandom sr, ClientSessionContext clientSessionContext,
            ServerSessionContext serverSessionContext, String[] protocols)
            throws KeyManagementException {
        this.serverSessionContext = serverSessionContext;
        this.clientSessionContext = clientSessionContext;

        if (kms == null) {
            x509KeyManager = getDefaultX509KeyManager();
            
            pskKeyManager = null;
        } else {
            x509KeyManager = findFirstX509KeyManager(kms);
            pskKeyManager = findFirstPSKKeyManager(kms);
        }

        if (tms == null) {
            x509TrustManager = getDefaultX509TrustManager();
        } else {
            x509TrustManager = findFirstX509TrustManager(tms);
        }

        
        secureRandom = sr;

        
        enabledProtocols = NativeCrypto.checkEnabledProtocols(
                protocols == null ? NativeCrypto.DEFAULT_PROTOCOLS : protocols).clone();
        boolean x509CipherSuitesNeeded = (x509KeyManager != null) || (x509TrustManager != null);
        boolean pskCipherSuitesNeeded = pskKeyManager != null;
        enabledCipherSuites = getDefaultCipherSuites(
                x509CipherSuitesNeeded, pskCipherSuitesNeeded);
    }

    protectedstatic SSLParametersImpl getDefault() throws KeyManagementException {
        SSLParametersImpl result = defaultParameters;
        if (result == null) {
            
            defaultParameters = result = new SSLParametersImpl(null,
                                                               null,
                                                               null,
                                                               new ClientSessionContext(),
                                                               new ServerSessionContext(),
                                                               null);
        }
        return (SSLParametersImpl) result.clone();
    }
 . . . . . . 
    /**
     * @return X.509 trust manager or {@code null} for none.
     */protected X509TrustManager getX509TrustManager() {
        return x509TrustManager;
    }
 . . . . . . 
    /**
     * Gets the default X.509 trust manager.
     * <p>
     * TODO: Move this to a published API under dalvik.system.
     */publicstatic X509TrustManager getDefaultX509TrustManager()
            throws KeyManagementException {
        X509TrustManager result = defaultX509TrustManager;
        if (result == null) {
            
            defaultX509TrustManager = result = createDefaultX509TrustManager();
        }
        return result;
    }

    privatestatic X509TrustManager createDefaultX509TrustManager()
            throws KeyManagementException {
        try {
            String algorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
            tmf.init((KeyStore) null);
            TrustManager[] tms = tmf.getTrustManagers();
            X509TrustManager trustManager = findFirstX509TrustManager(tms);
            if (trustManager == null) {
                thrownew KeyManagementException(
                        "No X509TrustManager in among default TrustManagers: "
                                  Arrays.toString(tms));
            }
            return trustManager;
        } catch (NoSuchAlgorithmException e) {
            thrownew KeyManagementException(e);
        } catch (KeyStoreException e) {
            thrownew KeyManagementException(e);
        }
    }

БудетcreateDefaultX509TrustManager() Скопируйте код в наше приложение, как показано ниже:

private X509TrustManager systemDefaultTrustManager() {
            try {
                TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                        TrustManagerFactory.getDefaultAlgorithm());
                trustManagerFactory.init((KeyStore) null);
                TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
                if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
                    thrownew IllegalStateException("Unexpected default trust managers:"
                              Arrays.toString(trustManagers));
                }
                return (X509TrustManager) trustManagers[0];
            } catch (GeneralSecurityException e) {
                thrownew AssertionError(); 
            }
        }

Прервите точку во время выполнения приложения и подтвердите системное значение по умолчанию с помощью Android StudioX509TrustManager Что это такое, подтвердить несложно, этоandroid.security.net.config.RootTrustManager。android.security.net.config.

Про сертификаты:  сертификат ЦС что это и с чем его едят? - MIUI общее - Xiaomi Community - Xiaomi
Оцените статью
Мой сертификат
Добавить комментарий