Skip to content

Instantly share code, notes, and snippets.

@sysraccoon
Last active February 2, 2026 06:25
Show Gist options
  • Select an option

  • Save sysraccoon/d3169c9ac557ef0a12aa5aab1b3c883a to your computer and use it in GitHub Desktop.

Select an option

Save sysraccoon/d3169c9ac557ef0a12aa5aab1b3c883a to your computer and use it in GitHub Desktop.
Certificate installation to Android system store

Manual certificate installation to Android system store (root required!)

Automated solution described here. Below I describe manual steps that reproduce application inner logic.

Generate new pem certificate (skip if already exists)

$ openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem

Tip

For mitmproxy you can use certificate from ~/.mitmproxy/mitmproxy-ca-cert.pem
If you want generate new certificate add extensions critical and keyCertSign as described here:

openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem -addext keyUsage=critical,keyCertSign
cat key.pem cert.pem > mitmproxy-ca.pem
mitmproxy --set confdir=$(pwd)

Prepare certificate

Android work with PEM certificates that named as $hash.0 where $hash is md5 based hash that can be generate via openssl with -subject_hash_old option:

$ openssl x509 -inform PEM -subject_hash_old -noout -in cert.pem
e210c8c4
$ cp cert.pem e210c8c4.0

All certificates in system store also contains additional information. SSL would work without that, but for consistency we can add it to our file:

$ openssl x509 -inform PEM -text -fingerprint -noout -in cert.pem >> e210c8c4.0

Push prepared certificate somewhere on android device

$ adb push e210c8c4.0 /data/local/tmp/e210c8c4.0

Permanent certificate installation (Android 9 or older)

Before Android 10, permanent installation of a certificate is possible by remounting the root directory in read-write mode. These changes may require a device reboot.

$ adb shell su

mount -o rw,remount,rw /system # or '/' itself
mv /data/local/tmp/e210c8c4.0 /system/etc/security/cacerts/
chmod 644 /system/etc/security/cacerts/e210c8c4.0
mount -o ro,remount,ro /system # or '/' itself
reboot

Temporary certificate installation (Android 10-13)

Starting with Android 10, the root system is available in read-only mode. To install a certificate, need remounting /system/etc/security/cacerts directory in tmpfs with a preliminary copy of all existing certificates. After a reboot, the changes will be reset.

$ adb shell su

mkdir -p -m 700 /data/local/tmp/cacerts
cp /system/etc/security/cacerts/* /data/local/tmp/cacerts/
mount -t tmpfs tmpfs /system/etc/security/cacerts/
cp /data/local/tmp/cacerts/* /system/etc/security/cacerts/
mv /data/local/tmp/e210c8c4.0 /system/etc/security/cacerts/
chmod 644 /system/etc/security/cacerts/e210c8c4.0
chcon u:object_r:system_file:s0 /system/etc/security/cacerts/*

Temporary certificate installation (Android 14 or newer)

Original post

Starting with Android 14, all certificates available in /apex/com.android.conscrypt/cacerts, but this folder is available in read-only mode. Remounting them as tmpfs don't actually work. We should change filesystem inside zygote (and zygote childs) namespace.

Do same steps as for Android 10, but copy certs from /apex/com.android.conscrypt/cacerts/* instead of /system/etc/security/cacerts/*

$ adb shell su

mkdir -p -m 700 /data/local/tmp/cacerts
cp /apex/com.android.conscrypt/cacerts/* /data/local/tmp/cacerts/
mount -t tmpfs tmpfs /system/etc/security/cacerts/
cp /data/local/tmp/cacerts/* /system/etc/security/cacerts/
mv /data/local/tmp/e210c8c4.0 /system/etc/security/cacerts/
chmod 644 /system/etc/security/cacerts/e210c8c4.0
chcon u:object_r:system_file:s0 /system/etc/security/cacerts/*

Perform bind mount inside zygote (and child) processes

$ adb shell su

ZYGOTE_PID=$(pidof zygote || true)
ZYGOTE64_PID=$(pidof zygote64 || true)
for Z_PID in "$ZYGOTE_PID" "$ZYGOTE64_PID"; do
    if [ -n "$Z_PID" ]; then
        nsenter --mount=/proc/$Z_PID/ns/mnt -- \
            /bin/mount --bind /system/etc/security/cacerts /apex/com.android.conscrypt/cacerts
    fi
done
APP_PIDS=$(
    echo "$ZYGOTE_PID $ZYGOTE64_PID" | \
    xargs -n1 ps -o 'PID' -P | \
    grep -v PID
)
for PID in $APP_PIDS; do
    nsenter --mount=/proc/$PID/ns/mnt -- \
        /bin/mount --bind /system/etc/security/cacerts /apex/com.android.conscrypt/cacerts &
done
wait
@misyltoad
Copy link

chmod 644 /system/etc/security/cacerts/

This should be

chmod 644 /system/etc/security/cacerts/e210c8c4.0

To unbreak what this does:

mount -o rw,remount,rw /system # or '/' itself
chmod 755 /system/etc/security/cacerts/
mount -o ro,remount,ro /system # or '/' itself
reboot

@sysraccoon
Copy link
Author

@misyltoad Fixed the guide, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment