470351 Fixed SNI matching of wildcard certificates
This commit is contained in:
parent
e1827f659e
commit
df6b935b94
|
@ -488,4 +488,14 @@ public class IOTest
|
|||
for (int i=0;i<buffers.length;i++)
|
||||
assertEquals(0,buffers[i].remaining());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomain()
|
||||
{
|
||||
assertTrue(IO.isInDomain("foo.com","foo.com"));
|
||||
assertTrue(IO.isInDomain("www.foo.com","foo.com"));
|
||||
assertFalse(IO.isInDomain("foo.com","bar.com"));
|
||||
assertFalse(IO.isInDomain("www.foo.com","bar.com"));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.eclipse.jetty.http.BadMessageException;
|
|||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -107,8 +108,13 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
|||
String sniName = (String)sslSession.getValue("org.eclipse.jetty.util.ssl.sniname");
|
||||
if (sniName!=null && !sniName.equalsIgnoreCase(request.getServerName()))
|
||||
{
|
||||
LOG.warn("Host does not match SNI Name: {}!={}",sniName,request.getServerName());
|
||||
throw new BadMessageException(400,"Host does not match SNI");
|
||||
String wild=(String)sslSession.getValue("org.eclipse.jetty.util.ssl.sniwild");
|
||||
String name=request.getServerName();
|
||||
if (wild==null || !IO.isInDomain(name,wild))
|
||||
{
|
||||
LOG.warn("Host does not match SNI Name: {}/{}!={}",sniName,wild,request.getServerName());
|
||||
throw new BadMessageException(400,"Host does not match SNI");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,8 @@ import org.eclipse.jetty.server.SslConnectionFactory;
|
|||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.ConcurrentArrayQueue;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.ssl.SniX509ExtendedKeyManager;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
|
@ -146,6 +148,22 @@ public class SniSslConnectionFactoryTest
|
|||
Assert.assertThat(response,Matchers.containsString("host=www.san.com"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWildSNIConnect() throws Exception
|
||||
{
|
||||
String response;
|
||||
|
||||
response= getResponse("domain.com","www.domain.com","*.domain.com");
|
||||
Assert.assertThat(response,Matchers.containsString("host=www.domain.com"));
|
||||
|
||||
response= getResponse("domain.com","domain.com","*.domain.com");
|
||||
Assert.assertThat(response,Matchers.containsString("host=domain.com"));
|
||||
|
||||
response= getResponse("www.domain.com","www.domain.com","*.domain.com");
|
||||
Assert.assertThat(response,Matchers.containsString("host=www.domain.com"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadSNIConnect() throws Exception
|
||||
|
|
|
@ -463,7 +463,21 @@ public class IO
|
|||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param name A host name like www.foo.com
|
||||
* @param domain A domain name like foo.com
|
||||
* @return True if the host name is in the domain name
|
||||
*/
|
||||
public static boolean isInDomain(String name, String domain)
|
||||
{
|
||||
if (!name.endsWith(domain))
|
||||
return false;
|
||||
if (name.length()==domain.length())
|
||||
return true;
|
||||
return name.charAt(name.length()-domain.length()-1)=='.';
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
|
|
@ -44,6 +44,7 @@ public class SniX509ExtendedKeyManager extends X509ExtendedKeyManager
|
|||
{
|
||||
static final Logger LOG = Log.getLogger(SniX509ExtendedKeyManager.class);
|
||||
public final static String SNI_NAME = "org.eclipse.jetty.util.ssl.sniname";
|
||||
public final static String SNI_WILD = "org.eclipse.jetty.util.ssl.sniwild";
|
||||
public final static String NO_MATCHERS="No Matchers";
|
||||
private final X509ExtendedKeyManager _delegate;
|
||||
|
||||
|
@ -81,6 +82,7 @@ public class SniX509ExtendedKeyManager extends X509ExtendedKeyManager
|
|||
// Look for an SNI alias
|
||||
String alias=null;
|
||||
String host=null;
|
||||
String wild=null;
|
||||
if (matchers!=null)
|
||||
{
|
||||
for (SNIMatcher m : matchers)
|
||||
|
@ -90,6 +92,7 @@ public class SniX509ExtendedKeyManager extends X509ExtendedKeyManager
|
|||
SslContextFactory.AliasSNIMatcher matcher = (SslContextFactory.AliasSNIMatcher)m;
|
||||
alias=matcher.getAlias();
|
||||
host=matcher.getServerName();
|
||||
wild=matcher.getWildDomain();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +109,8 @@ public class SniX509ExtendedKeyManager extends X509ExtendedKeyManager
|
|||
if (a.equals(alias))
|
||||
{
|
||||
session.putValue(SNI_NAME,host);
|
||||
if (wild!=null)
|
||||
session.putValue(SNI_WILD,wild);
|
||||
return alias;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -428,7 +428,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
_certWilds.clear();
|
||||
for (String name : _certAliases.keySet())
|
||||
if (name.startsWith("*."))
|
||||
_certWilds.put(name.substring(1),_certAliases.get(name));
|
||||
_certWilds.put(name.substring(2),_certAliases.get(name));
|
||||
|
||||
LOG.info("x509={} wild={} alias={} for {}",_certAliases,_certWilds,_certAlias,this);
|
||||
|
||||
|
@ -1728,6 +1728,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
class AliasSNIMatcher extends SNIMatcher
|
||||
{
|
||||
private String _alias;
|
||||
private String _wild;
|
||||
private SNIHostName _name;
|
||||
|
||||
protected AliasSNIMatcher()
|
||||
|
@ -1760,18 +1761,23 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
// Try wild card matches
|
||||
String domain = _name.getAsciiName();
|
||||
int dot=domain.indexOf('.');
|
||||
if (dot>=0)
|
||||
_alias = _certWilds.get(domain);
|
||||
if (_alias==null)
|
||||
{
|
||||
domain=domain.substring(dot);
|
||||
_alias = _certWilds.get(domain);
|
||||
if (_alias!=null)
|
||||
int dot=domain.indexOf('.');
|
||||
if (dot>=0)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("wild match {}->{}",_name.getAsciiName(),_alias);
|
||||
return true;
|
||||
domain=domain.substring(dot+1);
|
||||
_alias = _certWilds.get(domain);
|
||||
}
|
||||
}
|
||||
if (_alias!=null)
|
||||
{
|
||||
_wild=domain;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("wild match {}->{}",_name.getAsciiName(),_alias);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("No match for {}",_name.getAsciiName());
|
||||
|
@ -1785,6 +1791,11 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
return _alias;
|
||||
}
|
||||
|
||||
public String getWildDomain()
|
||||
{
|
||||
return _wild;
|
||||
}
|
||||
|
||||
public String getServerName()
|
||||
{
|
||||
return _name==null?null:_name.getAsciiName();
|
||||
|
|
Loading…
Reference in New Issue