No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
lisenblsh 74a5a47cf3 init
2026-09-30 21:28:34 +07:00
add_custom_cas.py init 2026-09-30 21:28:34 +07:00
README.md init 2026-09-30 21:28:34 +07:00

Сборка Firefox Android со встроенными CA-сертификатами

Инструкция по сборке Firefox для Android ARM64 из исходников Mozilla с добавлением собственных CA-сертификатов непосредственно во встроенное NSS-хранилище Firefox.

В результате Firefox будет доверять указанным CA без установки сертификатов в системное хранилище Android.

1. Требования

Рекомендуется использовать Linux x86_64.

Для работы понадобятся:

  • Git
  • Python 3
  • Perl
  • OpenSSL
  • Mercurial
  • необходимые пакеты для сборки Firefox
  • Android SDK/NDK
  • Java 17

Для Arch Linux:

sudo pacman -S --needed \
    git \
    mercurial \
    python \
    perl \
    openssl \
    base-devel \
    unzip \
    zip \
    yasm \
    nasm \
    ccache

Также должен быть доступен adb, если APK планируется устанавливать непосредственно на телефон:

sudo pacman -S --needed android-tools

2. Создание директории для исходников

В этой инструкции используется:

/mnt/games/firefox

Создаём её:

mkdir -p /mnt/games/firefox
cd /mnt/games/firefox

3. Получение исходников Firefox

Клонируем Mozilla Firefox:

git clone https://github.com/mozilla-firefox/firefox.git mozilla-central

Переходим в исходники:

cd /mnt/games/firefox/mozilla-central

Проверяем:

git status

4. Настройка Mozilla build environment

Создаём отдельную директорию для инструментов Mozilla:

mkdir -p /mnt/games/firefox/.mozbuild

Выставляем:

export MOZBUILD_STATE_PATH=/mnt/games/firefox/.mozbuild

Чтобы переменная сохранялась между сессиями shell:

echo 'export MOZBUILD_STATE_PATH=/mnt/games/firefox/.mozbuild' >> ~/.zshrc

Если используется bash:

echo 'export MOZBUILD_STATE_PATH=/mnt/games/firefox/.mozbuild' >> ~/.bashrc

После этого перезапустить shell или выполнить:

source ~/.zshrc

5. Создание mozconfig для Android ARM64

В директории исходников создаём:

cd /mnt/games/firefox/mozilla-central
nano mozconfig.android

Содержимое:

ac_add_options --enable-project=mobile/android
ac_add_options --target=aarch64

Выставляем этот конфиг:

export MOZCONFIG=/mnt/games/firefox/mozilla-central/mozconfig.android

Для постоянного использования:

echo 'export MOZCONFIG=/mnt/games/firefox/mozilla-central/mozconfig.android' >> ~/.zshrc

Проверить:

echo "$MOZCONFIG"

Должно быть:

/mnt/games/firefox/mozilla-central/mozconfig.android

6. Получение Android SDK, NDK и JDK

Firefox использует инструменты из .mozbuild.

Запускаем configure:

cd /mnt/games/firefox/mozilla-central
./mach configure

При первом запуске Mozilla build system автоматически установит необходимые инструменты.

После этого в .mozbuild должны появиться соответствующие компоненты, например:

/mnt/games/firefox/.mozbuild/android-sdk-linux
/mnt/games/firefox/.mozbuild/android-ndk-r30
/mnt/games/firefox/.mozbuild/jdk/

Проверить:

ls /mnt/games/firefox/.mozbuild

7. Проверка конфигурации

Повторно:

./mach configure

В выводе должно быть видно, что target — Android ARM64.

После успешного configure можно переходить к сборке.


8. Первая сборка Firefox

Собираем native-часть:

./mach build

Первая сборка может занимать значительное время и требует много дискового пространства.

После успешного завершения собираем Android debug APK:

./mach gradle fenix:assembleDebug

APK будет находиться примерно здесь:

obj-aarch64-unknown-linux-android/gradle/build/mobile/android/fenix/app/outputs/apk/debug/

Debug-сборку можно установить для проверки:

adb install -r \
    obj-aarch64-unknown-linux-android/gradle/build/mobile/android/fenix/app/outputs/apk/debug/*.apk

9. Подготовка собственных CA-сертификатов

Создаём отдельную директорию:

mkdir -p /mnt/games/firefox/certs

Помещаем туда сертификаты:

/mnt/games/firefox/certs/
├── rt_root_ca.cer
├── rt_sub_ca.cer
└── rt_sub_ca_2024.cer

Формат сертификатов должен быть PEM X.509.

Проверить:

file /mnt/games/firefox/certs/*.cer

Также можно проверить каждый сертификат:

openssl x509 \
    -in /mnt/games/firefox/certs/rt_root_ca.cer \
    -noout \
    -subject \
    -issuer \
    -serial

Для всех:

for cert in /mnt/games/firefox/certs/*.cer; do
    echo "===== $cert ====="
    openssl x509 \
        -in "$cert" \
        -noout \
        -subject \
        -issuer \
        -serial
done

10. Скрипт автоматического добавления CA в NSS

Firefox использует NSS для встроенного хранилища сертификатов.

Основной файл:

security/nss/lib/ckfw/builtins/certdata.txt

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

Создаём:

cd /mnt/games/firefox
nano add_custom_cas.py

Вставляем полный скрипт add_custom_cas.py из этой инструкции/проекта.

Скрипт должен находиться здесь:

/mnt/games/firefox/add_custom_cas.py

И использовать:

/mnt/games/firefox/certs/

как источник сертификатов.

Делаем его исполняемым:

chmod +x /mnt/games/firefox/add_custom_cas.py

11. Проверка сертификатов перед изменением Firefox

Сначала запускаем скрипт без --apply:

cd /mnt/games/firefox
./add_custom_cas.py

На этом этапе скрипт:

  1. находит все .cer;
  2. проверяет их через OpenSSL;
  3. определяет self-signed root;
  4. определяет intermediate CA;
  5. проверяет цепочку;
  6. конвертирует сертификаты в DER;
  7. генерирует NSS certdata.txt;
  8. проверяет результат через certdata.perl.

В конце должно быть:

Validating generated certdata.txt...
certdata.perl: OK

Dry run only. Nothing was modified.
Run with --apply to modify certdata.txt.

До этого момента исходники Firefox не изменяются.


12. Добавление CA в Firefox

Если dry-run завершился успешно:

cd /mnt/games/firefox
./add_custom_cas.py --apply

Скрипт добавит сертификаты в:

mozilla-central/security/nss/lib/ckfw/builtins/certdata.txt

При первом изменении создаётся backup:

certdata.txt.orig

13. Проверка внесённых изменений

Проверить ошибки форматирования:

git -C /mnt/games/firefox/mozilla-central diff --check

Посмотреть статистику:

git -C /mnt/games/firefox/mozilla-central diff --stat

Найти добавленный блок:

grep -n -A20 -B3 \
    'BEGIN CUSTOM FIREFOX CA' \
    /mnt/games/firefox/mozilla-central/security/nss/lib/ckfw/builtins/certdata.txt

В конце файла должен находиться блок:

# BEGIN CUSTOM FIREFOX CA
...
# END CUSTOM FIREFOX CA

14. Проверка trust-настроек

Root CA должен иметь:

CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR

Intermediate CA должны иметь:

CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_MUST_VERIFY_TRUST

Таким образом:

Russian Trusted Root CA
        │
        │ trusted
        ▼
Russian Trusted Sub CA
        │
        │ certificate chain
        ▼
Server certificate

Root является trust anchor.

Intermediate сертификаты добавляются в NSS для построения цепочки, но сами не становятся отдельными trust anchors.


15. Повторный запуск скрипта

Скрипт является идемпотентным.

Если выполнить:

./add_custom_cas.py --apply

повторно, он не должен создавать второй такой же блок.

Существующий блок:

# BEGIN CUSTOM FIREFOX CA
...
# END CUSTOM FIREFOX CA

будет заменён актуальным.

Это позволяет менять сертификаты в:

/mnt/games/firefox/certs/

и затем повторно запускать:

./add_custom_cas.py --apply

16. Сборка Firefox после добавления CA

После изменения certdata.txt:

cd /mnt/games/firefox/mozilla-central
./mach build

Затем собираем release APK:

./mach gradle fenix:assembleRelease

Готовый ARM64 APK:

obj-aarch64-unknown-linux-android/gradle/build/mobile/android/fenix/app/outputs/apk/release/fenix-arm64-v8a-release.apk

Полный путь:

/mnt/games/firefox/mozilla-central/obj-aarch64-unknown-linux-android/gradle/build/mobile/android/fenix/app/outputs/apk/release/fenix-arm64-v8a-release.apk

17. Проверка APK

Проверяем подпись:

$ANDROID_HOME/build-tools/*/apksigner verify --verbose \
    /mnt/games/firefox/mozilla-central/obj-aarch64-unknown-linux-android/gradle/build/mobile/android/fenix/app/outputs/apk/release/fenix-arm64-v8a-release.apk

Должно быть:

Verified using v2 scheme: true

Версия Android SDK build-tools может отличаться, поэтому при необходимости посмотреть:

ls "$ANDROID_HOME/build-tools"

18. Установка на Android

Подключаем устройство с включённым USB debugging.

Проверяем:

adb devices

Устанавливаем:

adb install -r \
    /mnt/games/firefox/mozilla-central/obj-aarch64-unknown-linux-android/gradle/build/mobile/android/fenix/app/outputs/apk/release/fenix-arm64-v8a-release.apk

19. Проверка работы custom CA

Открываем в собранном Firefox сайт, сертификат которого построен через добавленный CA.

Системный CA store Android при этом не требуется изменять.

Если сайт открывается без ошибки TLS, значит цепочка:

Firefox NSS
    │
    ├── Russian Trusted Root CA
    │       └── trusted
    │
    ├── Russian Trusted Sub CA
    │
    └── Russian Trusted Sub CA 2024

работает внутри самого Firefox.


20. Обновление сертификатов

При замене сертификатов:

rm /mnt/games/firefox/certs/*.cer

поместить новые .cer:

/mnt/games/firefox/certs/

Затем:

cd /mnt/games/firefox
./add_custom_cas.py

Если проверка успешна:

./add_custom_cas.py --apply

После этого:

cd /mnt/games/firefox/mozilla-central
./mach build
./mach gradle fenix:assembleRelease

21. Полный workflow после первоначальной настройки

Когда Firefox уже один раз сконфигурирован, обычный процесс выглядит так:

cd /mnt/games/firefox

# 1. Положить/обновить CA
ls certs/

# 2. Проверить сертификаты и будущий certdata
./add_custom_cas.py

# 3. Применить изменения
./add_custom_cas.py --apply

# 4. Проверить git diff
git -C mozilla-central diff --check

# 5. Собрать Firefox
cd mozilla-central
./mach build

# 6. Собрать release APK
./mach gradle fenix:assembleRelease

Готовый APK:

obj-aarch64-unknown-linux-android/gradle/build/mobile/android/fenix/app/outputs/apk/release/fenix-arm64-v8a-release.apk

22. Структура рабочего каталога

В итоге структура выглядит примерно так:

/mnt/games/firefox/
├── .mozbuild/
│   ├── android-sdk-linux/
│   ├── android-ndk-r30/
│   └── jdk/
│
├── certs/
│   ├── rt_root_ca.cer
│   ├── rt_sub_ca.cer
│   └── rt_sub_ca_2024.cer
│
├── add_custom_cas.py
│
└── mozilla-central/
    ├── mozconfig.android
    ├── security/
    │   └── nss/
    │       └── lib/
    │           └── ckfw/
    │               └── builtins/
    │                   ├── certdata.txt
    │                   └── certdata.txt.orig
    │
    └── obj-aarch64-unknown-linux-android/
        └── gradle/
            └── build/
                └── mobile/
                    └── android/
                        └── fenix/
                            └── app/
                                └── outputs/
                                    └── apk/
                                        └── release/
                                            └── fenix-arm64-v8a-release.apk

Примечания

Почему сертификаты добавляются именно в NSS

Firefox не обязан использовать системное Android-хранилище CA для своей проверки TLS. Встроенное NSS-хранилище позволяет добавить CA непосредственно в приложение.

Поэтому установка CA через настройки Android не требуется.

Почему root и intermediate обрабатываются по-разному

Root CA является доверенным якорем:

CKT_NSS_TRUSTED_DELEGATOR

Intermediate CA не является самостоятельным trust anchor:

CKT_NSS_MUST_VERIFY_TRUST

Это позволяет Firefox использовать intermediate при построении цепочки, не превращая его в отдельный корень доверия.

Почему нельзя просто добавить PEM-файл

certdata.txt — это не PEM-хранилище. NSS build system ожидает сертификаты и связанные с ними атрибуты в формате certdata.txt.

add_custom_cas.py автоматически:

PEM
 │
 ▼
DER
 │
 ├── subject
 ├── issuer
 ├── serial
 ├── SHA-1
 ├── MD5
 └── полный certificate DER
 │
 ▼
NSS certdata.txt
 │
 ▼
certdata.c
 │
 ▼
Firefox/NSS

Поэтому сертификаты не нужно вручную преобразовывать или вставлять огромными DER/octal-блоками.