diff options
Diffstat (limited to 'qpid/java/common/src/main')
| -rw-r--r-- | qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java | 125 |
1 files changed, 90 insertions, 35 deletions
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java index 7553e3dad8..487b0c485b 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java @@ -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.GeneralSecurityException; 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; |
