From 5147deca618f079dcdcaa86cd3c159506ce0ce53 Mon Sep 17 00:00:00 2001 From: Thomas Brenner Date: Tue, 28 Jul 2026 16:20:19 +0200 Subject: [PATCH] Support user added CAs in android client The android stores the Certificate Authorities separately which are installed by the user. The Golang ecosystem does not care about them by default, so there was no possibility to use them in self-hosted environment on android clients with user supplied CA. As my understanding to fix that the android code should collect the Certificates Authorities with java API, supply them to go code, and consume it combined with the system provided CAs. By default the system CAs will be used in Golang. * Bump netbird submodule to include updated golang code --- .../java/io/netbird/client/MyApplication.java | 12 ++++++ .../java/io/netbird/client/PlatformUtils.java | 37 ++++++++++++++++++- netbird | 2 +- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/netbird/client/MyApplication.java b/app/src/main/java/io/netbird/client/MyApplication.java index ea2493c1..ab7543c1 100644 --- a/app/src/main/java/io/netbird/client/MyApplication.java +++ b/app/src/main/java/io/netbird/client/MyApplication.java @@ -1,15 +1,27 @@ package io.netbird.client; +import android.util.Log; import android.app.Application; import android.content.SharedPreferences; import androidx.appcompat.app.AppCompatDelegate; +import io.netbird.gomobile.android.Android; + public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); + + try { + byte[] certsPem = PlatformUtils.getSystemAndUserCertificates(); + Android.setAndroidCertificates(certsPem); + Log.d("NetBird-CA", "System and User certificates successfully passed to Go core."); + } catch (Exception e) { + Log.e("NetBird-CA", "Failed to extract or pass Android certificates to Go core", e); + } + // Set Theme at start SharedPreferences prefs = getSharedPreferences("settings", MODE_PRIVATE); int themeMode = prefs.getInt("theme_mode", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM); diff --git a/app/src/main/java/io/netbird/client/PlatformUtils.java b/app/src/main/java/io/netbird/client/PlatformUtils.java index 3e06081e..ae8f9840 100644 --- a/app/src/main/java/io/netbird/client/PlatformUtils.java +++ b/app/src/main/java/io/netbird/client/PlatformUtils.java @@ -4,6 +4,13 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Configuration; +import android.util.Base64; +import java.security.KeyStore; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; public final class PlatformUtils { @@ -27,5 +34,33 @@ public static boolean isChromeOS(Context context) { public static boolean requiresDeviceCodeFlow(Context context) { return isAndroidTV(context) || isChromeOS(context); } -} + public static byte[] getSystemAndUserCertificates() throws Exception { + KeyStore keyStore = KeyStore.getInstance("AndroidCAStore"); + keyStore.load(null, null); + + StringBuilder pemBuilder = new StringBuilder(); + Enumeration aliases = keyStore.aliases(); + + while (aliases.hasMoreElements()) { + String alias = aliases.nextElement(); + if (!alias.startsWith("user:")) { + continue; + } + + X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias); + if (cert != null) { + String base64Cert = Base64.encodeToString(cert.getEncoded(), Base64.NO_WRAP); + + pemBuilder.append("-----BEGIN CERTIFICATE-----\n"); + for (int i = 0; i < base64Cert.length(); i += 64) { + int end = Math.min(i + 64, base64Cert.length()); + pemBuilder.append(base64Cert.substring(i, end)).append("\n"); + } + pemBuilder.append("-----END CERTIFICATE-----\n"); + } + } + + return pemBuilder.toString().getBytes("UTF-8"); + } +} diff --git a/netbird b/netbird index 3aa6c02b..e609786e 160000 --- a/netbird +++ b/netbird @@ -1 +1 @@ -Subproject commit 3aa6c02b932db503e82f9530dddfe95d5ea212c4 +Subproject commit e609786e7efaa368466d67218da10bfd8bb4010e