httptoolkit-server icon indicating copy to clipboard operation
httptoolkit-server copied to clipboard

Certificate injection failure in Android 14

Open MHBdev2 opened this issue 3 months ago • 2 comments

I'm using Android 14 and want to inject a custom CA certificate The device is rooted using magisk, so for a smooth operation that will be performed every restart, I put the following code in service.sh

API=`getprop ro.build.version.sdk`
if [ "$API" -ge 33 ]; then
while [ "$(getprop sys.boot_completed)" != 1 ];
do
   sleep 1
done
if [ -d "/apex/com.android.conscrypt/cacerts" ]; then
     cp /apex/com.android.conscrypt/cacerts/* /data/local/tmp/htk-ca-copy/
else
     cp /system/etc/security/cacerts/* /data/local/tmp/htk-ca-copy/
fi

# Create the in-memory mount on top of the system certs folder
su -mm -c mount -t tmpfs tmpfs /system/etc/security/cacerts

# Copy the existing certs back into the tmpfs mount, so we keep trusting them
mv /data/local/tmp/htk-ca-copy/* /system/etc/security/cacerts/

# Copy our new cert in, so we trust that too
cp /system/etc/cacustom/* /system/etc/security/cacerts/

# Update the perms & selinux context labels, so everything is as readable as before
chown root:root /system/etc/security/cacerts/*
chmod 644 /system/etc/security/cacerts/*
chcon u:object_r:system_file:s0 /system/etc/security/cacerts/*

echo 'System cacerts setup completed'

           # Create a separate temp directory, to hold the current certificates
             # Without this, when we add the mount we can't read the current certs anymore.

             # Deal with the APEX overrides in Android 14+, which need injecting into each namespace:
             if [ -d "/apex/com.android.conscrypt/cacerts" ]; then
              

                 # When the APEX manages cacerts, we need to mount them at that path too. We can't do
                 # this globally as APEX mounts are name-spaced per process, so we need to inject a
                 # bind mount for this directory into every mount namespace.

                 # First we get the Zygote process(es), which launch each app
                 ZYGOTE_PID=$(pidof zygote || true)
                 ZYGOTE64_PID=$(pidof zygote64 || true)
                 Z_PIDS="$ZYGOTE_PID $ZYGOTE64_PID"
                 # N.b. some devices appear to have both, some have >1 of each (!)

                 # Apps inherit the Zygote's mounts at startup, so we inject here to ensure everything is new
                 # started apps will see these certs straight away:
                 for Z_PID in $Z_PIDS; 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

              

                 # Then we inject the mount into all already running apps, so they see these certs immediately.

                 # Get the PID of every process whose parent is one of the Zygotes:
                 APP_PIDS=$(
                     echo $Z_PIDS | \
                     xargs -n1 ps -o 'PID' -P | \
                     grep -v PID
                 )

                 # Inject into the mount namespace of each of those apps:
                 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 # Launched in parallel - wait for completion here

               
             fi

It really seems that the personalized certificates enter the system but after a few seconds the device crashes (restarts) This is the log at the moment of the crash

 !@*** FATAL EXCEPTION IN SYSTEM PROCESS: pool-246-thread-1
                                                                                                    java.lang.AssertionError
                                                                                                    	at com.android.okhttp.OkHttpClient.getDefaultSSLSocketFactory(OkHttpClient.java:649)
                                                                                                    	at com.android.okhttp.OkHttpClient.copyWithDefaults(OkHttpClient.java:605)
                                                                                                    	at com.android.okhttp.OkUrlFactory.open(OkUrlFactory.java:63)
                                                                                                    	at com.android.okhttp.OkUrlFactory.open(OkUrlFactory.java:58)
                                                                                                    	at com.android.okhttp.HttpHandler.openConnection(HttpHandler.java:56)
                                                                                                    	at java.net.URL.openConnection(URL.java:1006)
                                                                                                    	at com.android.server.location.gnss.GnssPsdsDownloader.doDownload(GnssPsdsDownloader.java:165)
                                                                                                    	at com.android.server.location.gnss.GnssPsdsDownloader.doDownloadWithTrafficAccounted(GnssPsdsDownloader.java:152)
                                                                                                    	at com.android.server.location.gnss.GnssPsdsDownloader.downloadPsdsData(GnssPsdsDownloader.java:129)
                                                                                                    	at com.android.server.location.gnss.GnssLocationProvider.lambda$handleDownloadPsdsData$6(GnssLocationProvider.java:909)
                                                                                                    	at com.android.server.location.gnss.GnssLocationProvider.$r8$lambda$JL2e1UXaMzOyFO9jVFmVGlpGR4o(GnssLocationProvider.java:0)
                                                                                                    	at com.android.server.location.gnss.GnssLocationProvider$$ExternalSyntheticLambda17.run(R8$$SyntheticClass:0)

MHBdev2 avatar Mar 31 '24 13:03 MHBdev2