You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by rg...@apache.org on 2014/09/03 13:39:55 UTC

svn commit: r1622227 [1/2] - in /qpid/trunk/qpid/java/common/src: main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java test/java/org/apache/qpid/transport/network/security/ssl/SSLUtilTest.java

Author: rgodfrey
Date: Wed Sep  3 11:39:54 2014
New Revision: 1622227

URL: http://svn.apache.org/r1622227
Log:
QPID-5968 : [Java Client] Improve SSL hostname verification

Modified:
    qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
    qpid/trunk/qpid/java/common/src/test/java/org/apache/qpid/transport/network/security/ssl/SSLUtilTest.java

Modified: qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java?rev=1622227&r1=1622226&r2=1622227&view=diff
==============================================================================
--- qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java (original)
+++ qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java Wed Sep  3 11:39:54 2014
@@ -20,14 +20,6 @@
  */
 package org.apache.qpid.transport.network.security.ssl;
 
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-import org.apache.qpid.transport.TransportException;
-import org.apache.qpid.transport.util.Logger;
-
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLPeerUnverifiedException;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -36,11 +28,25 @@ import java.security.GeneralSecurityExce
 import java.security.KeyStore;
 import java.security.Principal;
 import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
 import java.security.cert.X509Certificate;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLPeerUnverifiedException;
+
+import org.apache.qpid.transport.TransportException;
+import org.apache.qpid.transport.util.Logger;
 
 public class SSLUtil
 {
     private static final Logger log = Logger.get(SSLUtil.class);
+    private static final Integer DNS_NAME_TYPE = 2;
 
     private SSLUtil()
     {
@@ -50,32 +56,8 @@ public class SSLUtil
     {
         try
         {
-          Certificate cert = engine.getSession().getPeerCertificates()[0];
-          Principal p = ((X509Certificate)cert).getSubjectDN();
-          String dn = p.getName();
-          String hostname = null;
-
-          if (dn.contains("CN="))
-          {
-              hostname = dn.substring(3,
-                      dn.indexOf(",") == -1? dn.length(): dn.indexOf(","));
-          }
-
-          if (log.isDebugEnabled())
-          {
-              log.debug("Hostname expected : " + hostnameExpected);
-              log.debug("Distinguished Name for server certificate : " + dn);
-              log.debug("Host Name obtained from DN : " + hostname);
-          }
-
-          if (hostname != null && !(hostname.equalsIgnoreCase(hostnameExpected) ||
-                  hostname.equalsIgnoreCase(hostnameExpected + ".localdomain")))
-          {
-              throw new TransportException("SSL hostname verification failed." +
-                                           " Expected : " + hostnameExpected +
-                                           " Found in cert : " + hostname);
-          }
-
+            Certificate cert = engine.getSession().getPeerCertificates()[0];
+            verifyHostname(hostnameExpected, (X509Certificate) cert);
         }
         catch(SSLPeerUnverifiedException e)
         {
@@ -87,6 +69,79 @@ public class SSLUtil
         }
     }
 
+    public static void verifyHostname(final String hostnameExpected, final X509Certificate cert)
+    {
+        Principal p = cert.getSubjectDN();
+
+        SortedSet<String> names = new TreeSet<>();
+        String dn = p.getName();
+        try
+        {
+            LdapName ldapName = new LdapName(dn);
+            for (Rdn part : ldapName.getRdns())
+            {
+                if (part.getType().equalsIgnoreCase("CN"))
+                {
+                    names.add(part.getValue().toString());
+                    break;
+                }
+            }
+
+            if(cert.getSubjectAlternativeNames() != null)
+            {
+                for (List<?> entry : cert.getSubjectAlternativeNames())
+                {
+                    if (DNS_NAME_TYPE.equals(entry.get(0)))
+                    {
+                        names.add((String) entry.get(1));
+                    }
+                }
+            }
+
+            if (names.isEmpty())
+            {
+                throw new TransportException("SSL hostname verification failed. Certificate for did not contain CN or DNS subjectAlt");
+            }
+
+            boolean match = false;
+
+            final String hostName = hostnameExpected.trim().toLowerCase();
+            for (String cn : names)
+            {
+
+                boolean doWildcard = cn.startsWith("*.") &&
+                                     cn.lastIndexOf('.') >= 3 &&
+                                     !cn.matches("\\*\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
+
+
+                match = doWildcard
+                        ? hostName.endsWith(cn.substring(1)) && hostName.indexOf(".") == (1 + hostName.length() - cn.length())
+                        : hostName.equals(cn);
+
+                if (match)
+                {
+                    break;
+                }
+
+            }
+            if (!match)
+            {
+                throw new TransportException("SSL hostname verification failed." +
+                                             " Expected : " + hostnameExpected +
+                                             " Found in cert : " + names);
+            }
+
+        }
+        catch (InvalidNameException e)
+        {
+            throw new TransportException("SSL hostname verification failed. Could not parse name " + dn, e);
+        }
+        catch (CertificateParsingException e)
+        {
+            throw new TransportException("SSL hostname verification failed. Could not parse certificate:  " + e.getMessage(), e);
+        }
+    }
+
     public static String getIdFromSubjectDN(String dn)
     {
         String cnStr = null;
@@ -141,7 +196,7 @@ public class SSLUtil
         }
         catch (Exception e)
         {
-            log.info("Exception received while trying to retrive client identity from SSL cert", e);
+            log.info("Exception received while trying to retrieve client identity from SSL cert", e);
         }
         log.debug("Extracted Identity from client certificate : " + id);
         return id;



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org