If exists, use TLS CA File (if it exists) also when loading account configuration

This commit is contained in:
Juha Heinanen
2025-10-17 08:47:52 +03:00
parent 82f0a669e0
commit 3b7f45844a
2 changed files with 50 additions and 2 deletions
@@ -73,6 +73,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserFactory import org.xmlpull.v1.XmlPullParserFactory
import java.io.File
import java.io.StringReader import java.io.StringReader
import java.net.URL import java.net.URL
import java.util.Locale import java.util.Locale
@@ -1538,8 +1539,12 @@ private fun initAccountFromConfig(acc: Account, onConfigLoaded: () -> Unit) {
val scope = CoroutineScope(Job() + Dispatchers.Main) val scope = CoroutineScope(Job() + Dispatchers.Main)
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
val url = "https://${Utils.uriHostPart(acc.aor)}/baresip/account_config.xml" val url = "https://${Utils.uriHostPart(acc.aor)}/baresip/account_config.xml"
val caFile = File(BaresipService.filesPath + "/ca_certs.crt")
val config = try { val config = try {
URL(url).readText() if (caFile.exists())
Utils.readUrlWithCustomCas(URL(url), caFile)
else
URL(url).readText()
} catch (e: java.lang.Exception) { } catch (e: java.lang.Exception) {
Log.d(TAG, "Failed to get account configuration from network: ${e.message}") Log.d(TAG, "Failed to get account configuration from network: ${e.message}")
null null
@@ -45,7 +45,10 @@ import java.lang.reflect.Method
import java.net.InetAddress import java.net.InetAddress
import java.net.NetworkInterface import java.net.NetworkInterface
import java.net.SocketException import java.net.SocketException
import java.net.URL
import java.security.KeyStore
import java.security.SecureRandom import java.security.SecureRandom
import java.security.cert.CertificateFactory
import java.text.DateFormat import java.text.DateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Enumeration import java.util.Enumeration
@@ -61,6 +64,9 @@ import javax.crypto.SecretKeyFactory
import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.PBEKeySpec import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec import javax.crypto.spec.SecretKeySpec
import javax.net.ssl.HttpsURLConnection
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManagerFactory
import kotlin.text.replaceFirstChar import kotlin.text.replaceFirstChar
object Utils { object Utils {
@@ -961,7 +967,6 @@ object Utils {
} }
fun aecAgcCheck() { fun aecAgcCheck() {
val sessionId = Api.AAudio_open_stream() val sessionId = Api.AAudio_open_stream()
if (sessionId == -1) { if (sessionId == -1) {
Log.e(TAG, "Failed to open AAudio stream") Log.e(TAG, "Failed to open AAudio stream")
@@ -995,7 +1000,45 @@ object Utils {
Log.i(TAG, "Hardware AGC is NOT available") Log.i(TAG, "Hardware AGC is NOT available")
Api.AAudio_close_stream() Api.AAudio_close_stream()
}
fun readUrlWithCustomCas(url: URL, caFile: File): String? {
if (!caFile.exists()) {
Log.d("Utils", "Custom CA file not found at ${caFile.path}")
return null
}
// 1. Create a CertificateFactory and load the user's certificate
val certificateFactory = CertificateFactory.getInstance("X.509")
val certificateInputStream = caFile.inputStream()
val userCertificate = certificateFactory.generateCertificate(certificateInputStream)
certificateInputStream.close()
// 2. Create a KeyStore containing our trusted CAs
val keyStoreType = KeyStore.getDefaultType()
val keyStore = KeyStore.getInstance(keyStoreType)
keyStore.load(null, null)
keyStore.setCertificateEntry("user_ca", userCertificate)
// 3. Create a TrustManager that trusts the CAs in our KeyStore
val tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm()
val tmf = TrustManagerFactory.getInstance(tmfAlgorithm)
tmf.init(keyStore)
// 4. Create an SSLContext that uses our TrustManager
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, tmf.trustManagers, null)
// 5. Tell HttpsURLConnection to use our custom SSLContext
val urlConnection = url.openConnection() as HttpsURLConnection
urlConnection.sslSocketFactory = sslContext.socketFactory
// 6. Proceed with the connection
return try {
urlConnection.inputStream.bufferedReader().use { it.readText() }
} finally {
urlConnection.disconnect()
}
} }
/*fun listFilesInDirectory(directoryPath: String): List<File> { /*fun listFilesInDirectory(directoryPath: String): List<File> {