Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Certificate injection failure in Android 14 #114

Open
MHBdev2 opened this issue Mar 31, 2024 · 2 comments
Open

Certificate injection failure in Android 14 #114

MHBdev2 opened this issue Mar 31, 2024 · 2 comments

Comments

@MHBdev2
Copy link

MHBdev2 commented Mar 31, 2024

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
Copy link
Author

MHBdev2 commented Mar 31, 2024

More precisely
Even if you use your application (http toolkit), and use full monitoring mode by injecting certificates into the system,
When trying to connect to the network via wifi, a crash similar to the above occurs

 !@*** FATAL EXCEPTION IN SYSTEM PROCESS: Thread-48
                                                                                                    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.OkUrlFactories.open(OkUrlFactories.java:39)
                                                                                                    	at com.android.okhttp.internalandroidapi.HttpURLConnectionFactory.internalOpenConnection(HttpURLConnectionFactory.java:154)
                                                                                                    	at com.android.okhttp.internalandroidapi.HttpURLConnectionFactory.openConnection(HttpURLConnectionFactory.java:123)
                                                                                                    	at libcore.net.http.HttpURLConnectionFactory.openConnection(HttpURLConnectionFactory.java:101)
                                                                                                    	at android.net.Network.openConnection(Network.java:372)
                                                                                                    	at android.net.Network.openConnection(Network.java:332)
                                                                                                    	at com.samsung.android.server.wifi.routerinfo.WifiRouterInfoCollector.runHttpGet(WifiRouterInfoCollector.java:143)
                                                                                                    	at com.samsung.android.server.wifi.routerinfo.WifiRouterInfoCollector.checkRouterInfoFromHttp(WifiRouterInfoCollector.java:50)
                                                                                                    	at com.samsung.android.server.wifi.routerinfo.WifiRouterInfoCollector.-$$Nest$mcheckRouterInfoFromHttp(WifiRouterInfoCollector.java:1)
                                                                                                    	at com.samsung.android.server.wifi.routerinfo.WifiRouterInfoCollector$ConnectedState.lambda$processMessage$0(WifiRouterInfoCollector.java:13)
                                                                                                    	at com.samsung.android.server.wifi.routerinfo.WifiRouterInfoCollector$ConnectedState.$r8$lambda$MVjnii19NWrcUKHWZqtUZ7NOc2o(WifiRouterInfoCollector.java:1)
    

@pimterry
Copy link
Member

pimterry commented Apr 1, 2024

The failing code is here: https://android.googlesource.com/platform/external/okhttp/+/refs/heads/main/okhttp/src/main/java/com/squareup/okhttp/OkHttpClient.java#635

It's not clear why, but it seems like on your device this results in a setup where TLS becomes completely unavailable - and so any attempt to use it fails.

That error isn't really the problem. The issue here is why TLS has become unavailable. I suspect for some reason, the changes here are effectively hiding all certificates (or the directory entirely) from the TLS loading on your device, so TLS initialization fails completely.

This definitely isn't the normal behaviour of those hooks on an Android device, so there must be something unique to your setup.

Can you reboot the device, and then run (via ADB, as root):

  • ls -Zl /apex/com.android.conscrypt/cacerts
  • ls -Zl /system/etc/security/cacerts/

then run HTTP Toolkit's ADB setup, and then run the same commands again?

You should see one new certificate appear (in both locations) but otherwise no changes - everything else should look exactly the same before & after, and the new certificate should exactly match all the other certs here.

If that doesn't come up with any clues, you're going to need to do some in-depth debugging. It would be useful to know the full details of the GeneralSecurityException that must be being thrown in the code linked above, and which that code just ignores (rethrowing an AssertionError with no more details instead). To find that, you might be able to attach a debugger to something somehow (not sure) or build a demo app that calls the same code but exposes the actual exception directly.

It would also be useful to have a really detailed understanding of your device setup, to be able to reproduce this or match it to other issues/solutions. Can you please share:

  • The exact device model
  • The OS you're using
  • Exactly how it's been rooted (full steps so this can be reproduced on a test device) and all other root-related tools/modules/etc you've used, including their specific versions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants