mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
fix(quic): use hostname-aware trust manager on Android
Android's RootTrustManager throws when an app has Network Security Config domain-specific entries and the 2-arg checkServerTrusted overload is used, crashing Nest room joins on relays covered by such config. Discover the 3-arg checkServerTrusted(chain, authType, hostname) overload via reflection and invoke it with the SNI host; fall back to the standard 2-arg form on plain JVM where that overload doesn't exist.
This commit is contained in:
@@ -22,6 +22,7 @@ package com.vitorpamplona.quic.tls
|
||||
|
||||
import com.vitorpamplona.quic.QuicCodecException
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.net.IDN
|
||||
import java.net.InetAddress
|
||||
import java.security.KeyStore
|
||||
@@ -83,7 +84,22 @@ class JdkCertificateValidator(
|
||||
// RFC 8422 ext, no dedicated TLS 1.3 string
|
||||
else -> "ECDHE_ECDSA"
|
||||
}
|
||||
trustManager.checkServerTrusted(parsed.toTypedArray(), authType)
|
||||
// Android's RootTrustManager rejects the 2-arg overload when the
|
||||
// app has Network Security Config domain-specific entries and
|
||||
// requires the hostname-aware 3-arg variant. That overload is
|
||||
// Android-specific (not on standard X509TrustManager), so we
|
||||
// discover it by reflection and fall back on plain JVM.
|
||||
val chainArray = parsed.toTypedArray()
|
||||
val hostnameAware = hostnameAwareCheckServerTrusted(trustManager)
|
||||
if (hostnameAware != null) {
|
||||
try {
|
||||
hostnameAware.invoke(trustManager, chainArray, authType, expectedHost)
|
||||
} catch (e: InvocationTargetException) {
|
||||
throw e.cause ?: e
|
||||
}
|
||||
} else {
|
||||
trustManager.checkServerTrusted(chainArray, authType)
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
throw QuicCodecException("certificate chain validation failed: ${t.message}", t)
|
||||
}
|
||||
@@ -245,5 +261,17 @@ class JdkCertificateValidator(
|
||||
tmf.init(null as KeyStore?)
|
||||
return tmf.trustManagers.firstNotNullOf { it as? X509TrustManager }
|
||||
}
|
||||
|
||||
private fun hostnameAwareCheckServerTrusted(tm: X509TrustManager): java.lang.reflect.Method? =
|
||||
try {
|
||||
tm.javaClass.getMethod(
|
||||
"checkServerTrusted",
|
||||
Array<X509Certificate>::class.java,
|
||||
String::class.java,
|
||||
String::class.java,
|
||||
)
|
||||
} catch (_: NoSuchMethodException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user