xmpp-compliance-tester

XMPP Compliance Tester, forked from github.com/iNPUTmice/ComplianceTester
git clone https://git.in0rdr.ch/xmpp-compliance-tester.git
Log | Files | Refs | Pull requests |Archive | README | LICENSE

XmppDomainVerifier.java (5331B)


      1 package eu.siacs.utils;
      2 
      3 import org.bouncycastle.asn1.ASN1Primitive;
      4 import org.bouncycastle.asn1.DERIA5String;
      5 import org.bouncycastle.asn1.DERTaggedObject;
      6 import org.bouncycastle.asn1.DERUTF8String;
      7 import org.bouncycastle.asn1.DLSequence;
      8 import org.bouncycastle.asn1.x500.RDN;
      9 import org.bouncycastle.asn1.x500.X500Name;
     10 import org.bouncycastle.asn1.x500.style.BCStyle;
     11 import org.bouncycastle.asn1.x500.style.IETFUtils;
     12 import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
     13 
     14 import java.io.IOException;
     15 import java.security.cert.Certificate;
     16 import java.security.cert.X509Certificate;
     17 import java.util.ArrayList;
     18 import java.util.Collection;
     19 import java.util.List;
     20 
     21 import javax.net.ssl.HostnameVerifier;
     22 import javax.net.ssl.SSLSession;
     23 
     24 public class XmppDomainVerifier implements HostnameVerifier {
     25 
     26     private static XmppDomainVerifier instance = new XmppDomainVerifier();
     27 
     28     private final static String SRVName = "1.3.6.1.5.5.7.8.7";
     29     private final static  String xmppAddr = "1.3.6.1.5.5.7.8.5";
     30 
     31     @Override
     32     public boolean verify(String domain, SSLSession sslSession) {
     33         try {
     34             Certificate[] chain = sslSession.getPeerCertificates();
     35             if (chain.length == 0 || !(chain[0] instanceof X509Certificate)) {
     36                 return false;
     37             }
     38             X509Certificate certificate = (X509Certificate) chain[0];
     39             Collection<List<?>> alternativeNames = certificate.getSubjectAlternativeNames();
     40             List<String> xmppAddrs = new ArrayList<>();
     41             List<String> srvNames = new ArrayList<>();
     42             List<String> domains = new ArrayList<>();
     43             if (alternativeNames != null) {
     44                 for (List<?> san : alternativeNames) {
     45                     Integer type = (Integer) san.get(0);
     46                     if (type == 0) {
     47                         OtherName otherName = parseOtherName((byte[]) san.get(1));
     48                         if (otherName != null) {
     49                             switch (otherName.oid) {
     50                                 case SRVName:
     51                                     srvNames.add(otherName.value);
     52                                     break;
     53                                 case xmppAddr:
     54                                     xmppAddrs.add(otherName.value);
     55                                     break;
     56                             }
     57                         }
     58                     } else if (type == 2) {
     59                         Object value = san.get(1);
     60                         if (value instanceof String) {
     61                             domains.add((String) value);
     62                         }
     63                     }
     64                 }
     65             }
     66             if (srvNames.size() == 0 && xmppAddrs.size() == 0 && domains.size() == 0) {
     67                 X500Name x500name = new JcaX509CertificateHolder(certificate).getSubject();
     68                 RDN[] rdns = x500name.getRDNs(BCStyle.CN);
     69                 for (int i = 0; i < rdns.length; ++i) {
     70                     domains.add(IETFUtils.valueToString(x500name.getRDNs(BCStyle.CN)[i].getFirst().getValue()));
     71                 }
     72             }
     73             return xmppAddrs.contains(domain) || srvNames.contains("_xmpp-client." + domain) || matchDomain(domain, domains);
     74         } catch (Exception e) {
     75             return false;
     76         }
     77     }
     78 
     79     private static OtherName parseOtherName(byte[] otherName) {
     80         try {
     81             ASN1Primitive asn1Primitive = ASN1Primitive.fromByteArray(otherName);
     82             if (asn1Primitive instanceof DERTaggedObject) {
     83                 ASN1Primitive inner = ((DERTaggedObject) asn1Primitive).getObject();
     84                 if (inner instanceof DLSequence) {
     85                     DLSequence sequence = (DLSequence) inner;
     86                     if (sequence.size() >= 2 && sequence.getObjectAt(1) instanceof DERTaggedObject) {
     87                         String oid = sequence.getObjectAt(0).toString();
     88                         ASN1Primitive value = ((DERTaggedObject) sequence.getObjectAt(1)).getObject();
     89                         if (value instanceof DERUTF8String) {
     90                             return new OtherName(oid, ((DERUTF8String) value).getString());
     91                         } else if (value instanceof DERIA5String) {
     92                             return new OtherName(oid, ((DERIA5String) value).getString());
     93                         }
     94                     }
     95                 }
     96             }
     97             return null;
     98         } catch (IOException e) {
     99             return null;
    100         }
    101     }
    102 
    103     private static boolean matchDomain(String needle, List<String> haystack) {
    104         for (String entry : haystack) {
    105             if (entry.startsWith("*.")) {
    106                 int i = needle.indexOf('.');
    107                 if (i != -1 && needle.substring(i).equals(entry.substring(1))) {
    108                     return true;
    109                 }
    110             } else {
    111                 if (entry.equals(needle)) {
    112                     return true;
    113                 }
    114             }
    115         }
    116         return false;
    117     }
    118 
    119     public static XmppDomainVerifier getInstance() {
    120         return instance;
    121     }
    122 
    123     private static class OtherName {
    124         private final String oid;
    125         private final String value;
    126         private OtherName(String oid, String value) {
    127             this.oid = oid;
    128             this.value = value;
    129         }
    130     }
    131 }