Skip to content
Snippets Groups Projects
Verified Commit 66967d9e authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Implement TLSv1.3 support

parent 60ace405
No related branches found
No related tags found
No related merge requests found
Pipeline #562 passed
...@@ -101,6 +101,7 @@ class CoreInfoFragment : ServiceBoundFragment() { ...@@ -101,6 +101,7 @@ class CoreInfoFragment : ServiceBoundFragment() {
private val movementMethod = BetterLinkMovementMethod.newInstance() private val movementMethod = BetterLinkMovementMethod.newInstance()
private val cipherSuiteRegex = Regex("TLS_(.*)_WITH_(.*)") private val cipherSuiteRegex = Regex("TLS_(.*)_WITH_(.*)")
private val cipherSuiteRegex13 = Regex("TLS_()(.*)")
init { init {
movementMethod.setOnLinkLongClickListener(LinkLongClickMenuHelper()) movementMethod.setOnLinkLongClickListener(LinkLongClickMenuHelper())
...@@ -188,19 +189,30 @@ class CoreInfoFragment : ServiceBoundFragment() { ...@@ -188,19 +189,30 @@ class CoreInfoFragment : ServiceBoundFragment() {
secureDetails.visibility = View.GONE secureDetails.visibility = View.GONE
} }
val protocol = it.orNull()?.protocol
val cipherSuiteRegex =
if (it.orNull()?.protocol == "TLSv1.3") cipherSuiteRegex13
else cipherSuiteRegex
val (keyExchangeMechanism, cipherSuite) = it.orNull()?.cipherSuite?.let { cipherSuite -> val (keyExchangeMechanism, cipherSuite) = it.orNull()?.cipherSuite?.let { cipherSuite ->
cipherSuiteRegex.matchEntire(cipherSuite)?.destructured cipherSuiteRegex.matchEntire(cipherSuite)?.destructured
}?.let { (keyExchangeMechanism, cipherSuite) -> }?.let { (keyExchangeMechanism, cipherSuite) ->
Pair(keyExchangeMechanism, cipherSuite) Pair(keyExchangeMechanism, cipherSuite)
} ?: Pair(null, null) } ?: Pair(null, null)
val protocol = it.orNull()?.protocol
if (cipherSuite != null && keyExchangeMechanism != null && protocol != null) { if (cipherSuite != null && keyExchangeMechanism != null && protocol != null) {
secureConnectionProtocol.text = context?.getString(R.string.label_core_connection_protocol, // TLSv1.3 has no key exchange mechanism in the ciphersuite
protocol) if (keyExchangeMechanism.isEmpty()) {
secureConnectionCiphersuite.text = context?.getString(R.string.label_core_connection_ciphersuite_13,
cipherSuite)
} else {
secureConnectionCiphersuite.text = context?.getString(R.string.label_core_connection_ciphersuite, secureConnectionCiphersuite.text = context?.getString(R.string.label_core_connection_ciphersuite,
cipherSuite, cipherSuite,
keyExchangeMechanism) keyExchangeMechanism)
}
secureConnectionProtocol.text = context?.getString(R.string.label_core_connection_protocol,
protocol)
secureConnectionProtocol.visibility = View.VISIBLE secureConnectionProtocol.visibility = View.VISIBLE
secureConnectionCiphersuite.visibility = View.VISIBLE secureConnectionCiphersuite.visibility = View.VISIBLE
} else { } else {
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
<string name="label_core_connection_verified_by">Verbindung verifiziert von %1$s</string> <string name="label_core_connection_verified_by">Verbindung verifiziert von %1$s</string>
<string name="label_core_connection_protocol">Die Verbindung verwendet %1$s</string> <string name="label_core_connection_protocol">Die Verbindung verwendet %1$s</string>
<string name="label_core_connection_ciphersuite">Die Verbindung ist mit %1$s verschlüsselt und authentifiziert und verwendet %2$s als Mechanismus für den Schlüsselaustausch</string> <string name="label_core_connection_ciphersuite">Die Verbindung ist mit %1$s verschlüsselt und authentifiziert und verwendet %2$s als Mechanismus für den Schlüsselaustausch</string>
<string name="label_core_connection_ciphersuite_13">Die Verbindung ist mit %1$s verschlüsselt und authentifiziert</string>
<string name="label_core_connection_verified_by_unknown">Unbekannt</string> <string name="label_core_connection_verified_by_unknown">Unbekannt</string>
<string name="label_core_connection_insecure">Unsichere Verbindung</string> <string name="label_core_connection_insecure">Unsichere Verbindung</string>
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
<string name="label_core_connection_verified_by">Connessione verificata da %1$s</string> <string name="label_core_connection_verified_by">Connessione verificata da %1$s</string>
<string name="label_core_connection_protocol">La connessione utilizza %1$s</string> <string name="label_core_connection_protocol">La connessione utilizza %1$s</string>
<string name="label_core_connection_ciphersuite">La connessione è crittografata ed autenticata con %1$s ed utilizza %2$s come meccanismo di scambio delle chiavi</string> <string name="label_core_connection_ciphersuite">La connessione è crittografata ed autenticata con %1$s ed utilizza %2$s come meccanismo di scambio delle chiavi</string>
<string name="label_core_connection_ciphersuite_13">La connessione è crittografata ed autenticata con %1$s</string>
<string name="label_core_connection_verified_by_unknown">Sconosciuto</string> <string name="label_core_connection_verified_by_unknown">Sconosciuto</string>
<string name="label_core_connection_insecure">Connessione insicura</string> <string name="label_core_connection_insecure">Connessione insicura</string>
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
<string name="label_core_connection_verified_by">Ryšys patvirtintas %1$s</string> <string name="label_core_connection_verified_by">Ryšys patvirtintas %1$s</string>
<string name="label_core_connection_protocol">Šis ryšys naudoja %1$s</string> <string name="label_core_connection_protocol">Šis ryšys naudoja %1$s</string>
<string name="label_core_connection_ciphersuite">Šis ryšys yra užkoduotas ir autentifikuotas naudojant %1$s, ir naudoja %2$s raktų apsikeitimui</string> <string name="label_core_connection_ciphersuite">Šis ryšys yra užkoduotas ir autentifikuotas naudojant %1$s, ir naudoja %2$s raktų apsikeitimui</string>
<string name="label_core_connection_ciphersuite_13">Šis ryšys yra užkoduotas ir autentifikuotas naudojant %1$s</string>
<string name="label_core_connection_verified_by_unknown">Nežinoma</string> <string name="label_core_connection_verified_by_unknown">Nežinoma</string>
<string name="label_core_connection_insecure">Nesaugus ryšys</string> <string name="label_core_connection_insecure">Nesaugus ryšys</string>
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
<string name="label_core_connection_verified_by">Ligação verificada por %1$s</string> <string name="label_core_connection_verified_by">Ligação verificada por %1$s</string>
<string name="label_core_connection_protocol">A ligação utiliza %1$s</string> <string name="label_core_connection_protocol">A ligação utiliza %1$s</string>
<string name="label_core_connection_ciphersuite">A ligação é encriptada e autenticada utilizando %1$s e usa %2$s como mecanismo de troca de chaves</string> <string name="label_core_connection_ciphersuite">A ligação é encriptada e autenticada utilizando %1$s e usa %2$s como mecanismo de troca de chaves</string>
<string name="label_core_connection_ciphersuite_13">A ligação é encriptada e autenticada utilizando %1$s</string>
<string name="label_core_connection_verified_by_unknown">Desconhecido</string> <string name="label_core_connection_verified_by_unknown">Desconhecido</string>
<string name="label_core_connection_insecure">Ligação insegura</string> <string name="label_core_connection_insecure">Ligação insegura</string>
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
<string name="label_core_connection_verified_by">Connection verified by %1$s</string> <string name="label_core_connection_verified_by">Connection verified by %1$s</string>
<string name="label_core_connection_protocol">The connection uses %1$s</string> <string name="label_core_connection_protocol">The connection uses %1$s</string>
<string name="label_core_connection_ciphersuite">The connection is encrypted and authenticated using %1$s and uses %2$s as the key exchange mechanism</string> <string name="label_core_connection_ciphersuite">The connection is encrypted and authenticated using %1$s and uses %2$s as the key exchange mechanism</string>
<string name="label_core_connection_ciphersuite_13">The connection is encrypted and authenticated using %1$s</string>
<string name="label_core_connection_verified_by_unknown">Unknown</string> <string name="label_core_connection_verified_by_unknown">Unknown</string>
<string name="label_core_connection_insecure">Insecure Connection</string> <string name="label_core_connection_insecure">Insecure Connection</string>
......
...@@ -22,6 +22,8 @@ package de.kuschku.libquassel.util.nio ...@@ -22,6 +22,8 @@ package de.kuschku.libquassel.util.nio
import de.kuschku.libquassel.connection.HostnameVerifier import de.kuschku.libquassel.connection.HostnameVerifier
import de.kuschku.libquassel.connection.SocketAddress import de.kuschku.libquassel.connection.SocketAddress
import de.kuschku.libquassel.util.compatibility.CompatibilityUtils import de.kuschku.libquassel.util.compatibility.CompatibilityUtils
import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel
import de.kuschku.libquassel.util.compatibility.StreamChannelFactory import de.kuschku.libquassel.util.compatibility.StreamChannelFactory
import java.io.* import java.io.*
import java.net.Socket import java.net.Socket
...@@ -32,6 +34,7 @@ import java.nio.channels.InterruptibleChannel ...@@ -32,6 +34,7 @@ import java.nio.channels.InterruptibleChannel
import java.nio.channels.ReadableByteChannel import java.nio.channels.ReadableByteChannel
import java.nio.channels.WritableByteChannel import java.nio.channels.WritableByteChannel
import java.security.GeneralSecurityException import java.security.GeneralSecurityException
import java.security.NoSuchAlgorithmException
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import java.util.zip.InflaterInputStream import java.util.zip.InflaterInputStream
import javax.net.ssl.SSLContext import javax.net.ssl.SSLContext
...@@ -60,6 +63,8 @@ class WrappedChannel private constructor( ...@@ -60,6 +63,8 @@ class WrappedChannel private constructor(
} }
companion object { companion object {
const val DEFAULT_TLS_VERSION = "TLSv1.2"
fun ofSocket(s: Socket, closeListeners: List<Closeable> = emptyList()): WrappedChannel { fun ofSocket(s: Socket, closeListeners: List<Closeable> = emptyList()): WrappedChannel {
return WrappedChannel( return WrappedChannel(
s, s,
...@@ -68,6 +73,12 @@ class WrappedChannel private constructor( ...@@ -68,6 +73,12 @@ class WrappedChannel private constructor(
closeListeners = closeListeners + s.getInputStream() + s.getOutputStream() closeListeners = closeListeners + s.getInputStream() + s.getOutputStream()
) )
} }
fun selectBestTlsVersion(availableVersions: Array<String>): String? {
return availableVersions.filter {
it.startsWith("TLSv") && it >= "TLSv1.2"
}.sorted().lastOrNull()
}
} }
fun withCompression(): WrappedChannel { fun withCompression(): WrappedChannel {
...@@ -82,7 +93,16 @@ class WrappedChannel private constructor( ...@@ -82,7 +93,16 @@ class WrappedChannel private constructor(
@Throws(GeneralSecurityException::class, IOException::class) @Throws(GeneralSecurityException::class, IOException::class)
fun withSSL(certificateManager: X509TrustManager, hostnameVerifier: HostnameVerifier, fun withSSL(certificateManager: X509TrustManager, hostnameVerifier: HostnameVerifier,
address: SocketAddress): WrappedChannel { address: SocketAddress): WrappedChannel {
val context = SSLContext.getInstance("TLSv1.2") val tlsVersion = try {
selectBestTlsVersion(SSLContext.getDefault().defaultSSLParameters.protocols)
} catch (e: NoSuchAlgorithmException) {
null
}
log(LogLevel.DEBUG,
"WrappedChannel",
"TLS Version chosen is: $tlsVersion, with fallback $DEFAULT_TLS_VERSION")
val context = SSLContext.getInstance(tlsVersion ?: DEFAULT_TLS_VERSION)
val managers = arrayOf(certificateManager) val managers = arrayOf(certificateManager)
context.init(null, managers, null) context.init(null, managers, null)
val factory = context.socketFactory val factory = context.socketFactory
......
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2020 Janne Mareike Koschinski
* Copyright (c) 2020 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel.util.nio
import de.kuschku.libquassel.util.nio.WrappedChannel.Companion.selectBestTlsVersion
import org.junit.Assert.assertEquals
import org.junit.Test
class WrappedChannelTest {
@Test
fun doesNotSelectOutdatedTlsVersions() {
assertEquals(null, selectBestTlsVersion(arrayOf(
"SSLv3", "TLSv1", "TLSv1.0", "TLSv1.1"
)))
}
@Test
fun rejectsNonTlsProtocols() {
assertEquals(null, selectBestTlsVersion(arrayOf(
"SSLv3", "UberSecurityProtocol5"
)))
}
@Test
fun selectsLatestTlsVersion() {
assertEquals("TLSv1.2", selectBestTlsVersion(arrayOf(
"SSLv3", "TLSv1", "TLSv1.0", "TLSv1.1", "TLSv1.2", "UberSecurityProtocol5"
)))
assertEquals("TLSv1.3", selectBestTlsVersion(arrayOf(
"SSLv3", "TLSv1", "TLSv1.0", "TLSv1.1", "TLSv1.2", "TLSv1.3", "UberSecurityProtocol5"
)))
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment