Сертификаты минцифры в Firefox Nightly на Android: через adb, без рута
Posted on Сб 15 августа 2026 in misc
Понадобилось, чтобы сертификату минцифры доверял только Firefox Nightly, а не весь Android.
GeckoView читает /data/local/tmp/
Поднимаем Marionette
geckoview-config.yaml:
args:
- --marionette
- --remote-allow-system-access
prefs:
marionette.port: 2828
adb shell am set-debug-app --persistent org.mozilla.fenix
adb push geckoview-config.yaml \
/data/local/tmp/org.mozilla.fenix-geckoview-config.yaml
adb shell chmod 644 /data/local/tmp/org.mozilla.fenix-geckoview-config.yaml
adb shell am force-stop org.mozilla.fenix
adb shell monkey -p org.mozilla.fenix -c android.intent.category.LAUNCHER 1
adb forward tcp:2828 tcp:2828
Кладём сертификаты в cert9.db
Marionette в chrome-контексте даёт привилегированный JS, дальше всё делает nsIX509CertDB. Флаг "C,," для корня, которому доверяем по SSL, ",," для промежуточных: доверия им не надо, они нужны только чтобы собралась цепочка.
Протокол простой, длина:json поверх TCP, клиент пишется за пять минут:
use v5.36;
use IO::Socket::INET;
use MIME::Base64 'encode_base64';
use JSON::PP;
my $s = IO::Socket::INET->new('127.0.0.1:2828') or die $@;
my $j = JSON::PP->new->canonical;
my $id = 0;
sub pkt {
my ($len, $buf, $c) = ('', '');
$len .= $c while sysread($s, $c, 1) and $c ne ':';
$buf .= $c
while length $buf < $len and sysread $s, $c, $len - length $buf;
$j->decode($buf);
}
sub cmd ($name, $params = {}) {
my $body = $j->encode([0, ++$id, $name, $params]);
print {$s} length($body) . ":$body";
my $r = pkt();
die "$name: " . $j->encode($r->[2]) . "\n" if defined $r->[2];
$r->[3];
}
my @certs = map {
my ($file, $trust) = split /=/, $_, 2;
open my $fh, '-|', qw(openssl x509 -outform DER -in), $file
or die "$file: $!";
binmode $fh;
[ encode_base64(do { local $/; <$fh> }, ''), $trust // 'C,,' ];
} @ARGV;
pkt();
cmd 'WebDriver:NewSession';
cmd 'Marionette:SetContext', { value => 'chrome' };
say JSON::PP->new->pretty->canonical->encode(cmd 'WebDriver:ExecuteScript', {
script => q{
const cid = "@mozilla.org/security/x509certdb;1";
const db = Cc[cid].getService(Ci.nsIX509CertDB);
return arguments[0].map(([b64, trust]) => {
try {
const c = db.addCertFromBase64(b64, trust);
return { ok: true, subject: c.subjectName };
} catch (e) {
return { ok: false, error: String(e) };
}
});
},
args => [ \@certs ],
});
cmd 'WebDriver:DeleteSession';
устанавливем:
perl fenix-cert.pl \
russian_trusted_root_ca_pem.crt=C,, \
russian_trusted_sub_ca_pem.crt=,, \
russian_trusted_sub_ca_2024_pem.crt=,,
# cleanup
adb shell rm -f /data/local/tmp/org.mozilla.fenix-geckoview-config.yaml
adb shell am clear-debug-app
adb forward --remove tcp:2828
adb shell am force-stop org.mozilla.fenix
Проверено на Pixel 5, Android 14, Firefox Nightly 156.0a1.