diff --git a/app/src/main/java/de/kuschku/quasseldroid/ssl/BrowserCompatibleHostnameVerifier.kt b/app/src/main/java/de/kuschku/quasseldroid/ssl/BrowserCompatibleHostnameVerifier.kt
index cbb6affbfbd3763256ac5a25cce0d08dc648a6f6..022a97f8ceee001bcf9b46cd31bfa416d014997e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ssl/BrowserCompatibleHostnameVerifier.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ssl/BrowserCompatibleHostnameVerifier.kt
@@ -15,9 +15,30 @@ class BrowserCompatibleHostnameVerifier : HostnameVerifier {
   }
 
   private fun matches(name: String, host: String): Boolean {
-    val normalizedName = IDN.toASCII(name).trimEnd('.')
-    val normalizedHost = IDN.toASCII(host).trimEnd('.')
-    return normalizedName.equals(normalizedHost, ignoreCase = true)
+    // First we normalize both by removing trailing dots (absolute DNS names), splitting into DNS
+    // labels, and punycoding all unicode parts.
+    val normalizedName = name.trimEnd('.').split('.').map(IDN::toASCII)
+    val normalizedHost = host.trimEnd('.').split('.').map(IDN::toASCII)
+
+    // Only if both have the same number of DNS labels they can match
+    if (normalizedHost.size != normalizedName.size) return false
+
+    // Hosts with size of zero are invalid
+    if (normalizedHost.isEmpty()) return false
+
+    val both = normalizedName.zip(normalizedHost)
+
+    // The first label has to either match exactly, or be *
+    if (!both.take(1).all { (target, actual) ->
+        target.equals(actual, ignoreCase = true) || target == "*"
+      }) return false
+
+    // All other labels have to match exactly.
+    if (!both.drop(1).all { (target, actual) ->
+        target.equals(actual, ignoreCase = true)
+      }) return false
+
+    return true
   }
 
   private fun hostnames(certificate: X509Certificate): Sequence<String> =