wildcard certificates only match one label

Daniel Gultsch created

Names may contain the wildcard character * which is considered to match any single domain name component or component fragment. E.g., *.a.com matches foo.a.com but not bar.foo.a.com

Change summary

src/main/java/eu/siacs/conversations/crypto/DomainHostnameVerifier.java | 11 
src/main/java/eu/siacs/conversations/crypto/XmppDomainVerifier.java     | 41 
2 files changed, 16 insertions(+), 36 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/crypto/DomainHostnameVerifier.java πŸ”—

@@ -1,11 +0,0 @@
-package eu.siacs.conversations.crypto;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
-
-public interface DomainHostnameVerifier extends HostnameVerifier {
-
-    boolean verify(String domain, String hostname, SSLSession sslSession) throws SSLPeerUnverifiedException;
-
-}

src/main/java/eu/siacs/conversations/crypto/XmppDomainVerifier.java πŸ”—

@@ -2,22 +2,8 @@ package eu.siacs.conversations.crypto;
 
 import android.util.Log;
 import android.util.Pair;
-
 import com.google.common.base.MoreObjects;
 import com.google.common.collect.ImmutableList;
-
-import org.bouncycastle.asn1.ASN1Object;
-import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.ASN1TaggedObject;
-import org.bouncycastle.asn1.DERIA5String;
-import org.bouncycastle.asn1.DERUTF8String;
-import org.bouncycastle.asn1.DLSequence;
-import org.bouncycastle.asn1.x500.RDN;
-import org.bouncycastle.asn1.x500.X500Name;
-import org.bouncycastle.asn1.x500.style.BCStyle;
-import org.bouncycastle.asn1.x500.style.IETFUtils;
-import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
-
 import java.io.IOException;
 import java.net.IDN;
 import java.security.cert.Certificate;
@@ -28,9 +14,19 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
-
 import javax.net.ssl.SSLPeerUnverifiedException;
 import javax.net.ssl.SSLSession;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.DLSequence;
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.asn1.x500.style.IETFUtils;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
 
 public class XmppDomainVerifier {
 
@@ -82,16 +78,11 @@ public class XmppDomainVerifier {
     public static boolean matchDomain(final String needle, final List<String> haystack) {
         for (final String entry : haystack) {
             if (entry.startsWith("*.")) {
-                int offset = 0;
-                while (offset < needle.length()) {
-                    int i = needle.indexOf('.', offset);
-                    if (i < 0) {
-                        break;
-                    }
-                    if (needle.substring(i).equalsIgnoreCase(entry.substring(1))) {
-                        return true;
-                    }
-                    offset = i + 1;
+                // https://www.rfc-editor.org/rfc/rfc6125#section-6.4.3
+                // wild cards can only be in the left most label and don’t match '.'
+                final int i = needle.indexOf('.');
+                if (i != -1 && needle.substring(i).equalsIgnoreCase(entry.substring(1))) {
+                    return true;
                 }
             } else {
                 if (entry.equalsIgnoreCase(needle)) {