Merged branch 'jetty-9.4.x' into 'jetty-10.0.x'.
This commit is contained in:
commit
6d44b13945
|
@ -33,11 +33,10 @@ import org.eclipse.jetty.io.EndPoint;
|
|||
import org.eclipse.jetty.io.NegotiatingClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.ssl.ALPNProcessor.Client;
|
||||
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
|
||||
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFactory implements SslHandshakeListener
|
||||
public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFactory
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ALPNClientConnectionFactory.class);
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
|
@ -325,7 +326,6 @@ public class HttpClientTLSTest
|
|||
@Test
|
||||
public void testHandshakeSucceededWithSessionResumption() throws Exception
|
||||
{
|
||||
|
||||
SslContextFactory serverTLSFactory = createSslContextFactory();
|
||||
startServer(serverTLSFactory, new EmptyServerHandler());
|
||||
|
||||
|
@ -405,7 +405,6 @@ public class HttpClientTLSTest
|
|||
@Test
|
||||
public void testClientRawCloseDoesNotInvalidateSession() throws Exception
|
||||
{
|
||||
|
||||
SslContextFactory serverTLSFactory = createSslContextFactory();
|
||||
startServer(serverTLSFactory, new EmptyServerHandler());
|
||||
|
||||
|
@ -527,4 +526,30 @@ public class HttpClientTLSTest
|
|||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostNameVerificationFailure() throws Exception
|
||||
{
|
||||
SslContextFactory serverTLSFactory = createSslContextFactory();
|
||||
startServer(serverTLSFactory, new EmptyServerHandler());
|
||||
|
||||
SslContextFactory clientTLSFactory = createSslContextFactory();
|
||||
// Make sure the host name is not verified at the TLS level.
|
||||
clientTLSFactory.setEndpointIdentificationAlgorithm(null);
|
||||
// Add host name verification after the TLS handshake.
|
||||
clientTLSFactory.setHostnameVerifier((host, session) -> false);
|
||||
startClient(clientTLSFactory);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(HttpScheme.HTTPS.asString())
|
||||
.send(result ->
|
||||
{
|
||||
Throwable failure = result.getFailure();
|
||||
if (failure instanceof SSLPeerUnverifiedException)
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,10 @@ import java.util.Map;
|
|||
import java.util.Objects;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
|
@ -98,6 +101,7 @@ public class SslClientConnectionFactory implements ClientConnectionFactory
|
|||
EndPoint appEndPoint = sslConnection.getDecryptedEndPoint();
|
||||
appEndPoint.setConnection(connectionFactory.newConnection(appEndPoint, context));
|
||||
|
||||
sslConnection.addHandshakeListener(new HTTPSHandshakeListener(context));
|
||||
customize(sslConnection, context);
|
||||
|
||||
return sslConnection;
|
||||
|
@ -123,4 +127,37 @@ public class SslClientConnectionFactory implements ClientConnectionFactory
|
|||
}
|
||||
return ClientConnectionFactory.super.customize(connection, context);
|
||||
}
|
||||
|
||||
private class HTTPSHandshakeListener implements SslHandshakeListener
|
||||
{
|
||||
private final Map<String, Object> context;
|
||||
|
||||
private HTTPSHandshakeListener(Map<String, Object> context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handshakeSucceeded(Event event) throws SSLException
|
||||
{
|
||||
HostnameVerifier verifier = sslContextFactory.getHostnameVerifier();
|
||||
if (verifier != null)
|
||||
{
|
||||
String host = (String)context.get(SSL_PEER_HOST_CONTEXT_KEY);
|
||||
try
|
||||
{
|
||||
if (!verifier.verify(host, event.getSSLEngine().getSession()))
|
||||
throw new SSLPeerUnverifiedException("Host name verification failed for host: " + host);
|
||||
}
|
||||
catch (SSLException x)
|
||||
{
|
||||
throw x;
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
throw (SSLException)new SSLPeerUnverifiedException("Host name verification failed for host: " + host).initCause(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -759,7 +759,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
}
|
||||
}
|
||||
|
||||
private void handshakeSucceeded()
|
||||
private void handshakeSucceeded() throws SSLException
|
||||
{
|
||||
if (_handshake.compareAndSet(Handshake.INITIAL, Handshake.SUCCEEDED))
|
||||
{
|
||||
|
@ -1182,7 +1182,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
}
|
||||
}
|
||||
|
||||
private void notifyHandshakeSucceeded(SSLEngine sslEngine)
|
||||
private void notifyHandshakeSucceeded(SSLEngine sslEngine) throws SSLException
|
||||
{
|
||||
SslHandshakeListener.Event event = null;
|
||||
for (SslHandshakeListener listener : handshakeListeners)
|
||||
|
@ -1193,6 +1193,10 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
|||
{
|
||||
listener.handshakeSucceeded(event);
|
||||
}
|
||||
catch (SSLException x)
|
||||
{
|
||||
throw x;
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.info("Exception while notifying listener " + listener, x);
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.EventListener;
|
|||
import java.util.EventObject;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
/**
|
||||
* <p>Implementations of this interface are notified of TLS handshake events.</p>
|
||||
|
@ -36,7 +37,7 @@ public interface SslHandshakeListener extends EventListener
|
|||
*
|
||||
* @param event the event object carrying information about the TLS handshake event
|
||||
*/
|
||||
default void handshakeSucceeded(Event event)
|
||||
default void handshakeSucceeded(Event event) throws SSLException
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.net.ssl.CertPathTrustManagerParameters;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SNIHostName;
|
||||
|
@ -194,6 +195,7 @@ public class SslContextFactory extends AbstractLifeCycle implements Dumpable
|
|||
private int _renegotiationLimit = 5;
|
||||
private Factory _factory;
|
||||
private PKIXCertPathChecker _pkixCertPathChecker;
|
||||
private HostnameVerifier _hostnameVerifier;
|
||||
|
||||
/**
|
||||
* Construct an instance of SslContextFactory
|
||||
|
@ -1565,6 +1567,31 @@ public class SslContextFactory extends AbstractLifeCycle implements Dumpable
|
|||
_sslSessionTimeout = sslSessionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the HostnameVerifier used by a client to verify host names in the server certificate
|
||||
*/
|
||||
public HostnameVerifier getHostnameVerifier()
|
||||
{
|
||||
return _hostnameVerifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets a {@code HostnameVerifier} used by a client to verify host names in the server certificate.</p>
|
||||
* <p>The {@code HostnameVerifier} works in conjunction with {@link #setEndpointIdentificationAlgorithm(String)}.</p>
|
||||
* <p>When {@code endpointIdentificationAlgorithm=="HTTPS"} (the default) the JDK TLS implementation
|
||||
* checks that the host name indication set by the client matches the host names in the server certificate.
|
||||
* If this check passes successfully, the {@code HostnameVerifier} is invoked and the application
|
||||
* can perform additional checks and allow/deny the connection to the server.</p>
|
||||
* <p>When {@code endpointIdentificationAlgorithm==null} the JDK TLS implementation will not check
|
||||
* the host names, and any check is therefore performed only by the {@code HostnameVerifier.}</p>
|
||||
*
|
||||
* @param hostnameVerifier the HostnameVerifier used by a client to verify host names in the server certificate
|
||||
*/
|
||||
public void setHostnameVerifier(HostnameVerifier hostnameVerifier)
|
||||
{
|
||||
_hostnameVerifier = hostnameVerifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the password object for the given realm.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue