Implement OpenSSL Engine tests for NPN / ALPN.

Motivation:

Currently there are no tests for OpenSSL Engine,
only for JdkSSL engine.

Modifications:

Common methods from `JdkSslEngine` test moved
to `SSLEngineTest`, JdkSslEngine now implements
NPN and ALPN tests.

Result:

OpenSSL Engine is now covered with unit tests.
This commit is contained in:
Alex Petrov 2015-12-26 19:42:00 +01:00 committed by Scott Mitchell
parent 0efb679585
commit ba22b0b944
3 changed files with 151 additions and 117 deletions

View File

@ -18,17 +18,6 @@ package io.netty.handler.ssl;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeNoException;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectorFactory;
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
@ -36,16 +25,12 @@ import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBeh
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.util.NetUtil;
import java.net.InetSocketAddress;
import java.security.cert.CertificateException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import org.junit.Test;
@ -66,7 +51,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
}
ApplicationProtocolConfig apn = failingNegotiator(Protocol.NPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
mySetup(apn);
setupHandlers(apn);
runTest();
} catch (SkipTestException e) {
// NPN availability is dependent on the java version. If NPN is not available because of
@ -88,7 +73,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN,
APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
mySetup(serverApn, clientApn);
setupHandlers(serverApn, clientApn);
runTest(null);
} catch (SkipTestException e) {
// ALPN availability is dependent on the java version. If ALPN is not available because of
@ -110,7 +95,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN,
APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
mySetup(serverApn, clientApn);
setupHandlers(serverApn, clientApn);
assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
assertTrue(clientException instanceof SSLHandshakeException);
} catch (SkipTestException e) {
@ -133,7 +118,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.NPN,
APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
mySetup(serverApn, clientApn);
setupHandlers(serverApn, clientApn);
assertTrue(serverLatch.await(2, TimeUnit.SECONDS));
assertTrue(serverException instanceof SSLHandshakeException);
} catch (SkipTestException e) {
@ -154,7 +139,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
}
ApplicationProtocolConfig apn = failingNegotiator(Protocol.ALPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
mySetup(apn);
setupHandlers(apn);
runTest();
} catch (SkipTestException e) {
// ALPN availability is dependent on the java version. If ALPN is not available because of
@ -176,7 +161,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN,
APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
mySetup(serverApn, clientApn);
setupHandlers(serverApn, clientApn);
runTest(null);
} catch (SkipTestException e) {
// ALPN availability is dependent on the java version. If ALPN is not available because of
@ -198,7 +183,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN,
APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
mySetup(serverApn, clientApn);
setupHandlers(serverApn, clientApn);
assertTrue(serverLatch.await(2, TimeUnit.SECONDS));
assertTrue(serverException instanceof SSLHandshakeException);
} catch (SkipTestException e) {
@ -223,7 +208,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL);
mySetup(serverApn, clientApn);
setupHandlers(serverApn, clientApn);
assertNull(serverException);
runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
} catch (SkipTestException e) {
@ -268,7 +253,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
SslContext clientSslCtx = new JdkSslClientContext(null, InsecureTrustManagerFactory.INSTANCE, null,
IdentityCipherSuiteFilter.INSTANCE, clientApn, 0, 0);
mySetup(serverSslCtx, clientSslCtx);
setupHandlers(serverSslCtx, clientSslCtx);
assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
assertTrue(clientException instanceof SSLHandshakeException);
} catch (SkipTestException e) {
@ -278,96 +263,6 @@ public class JdkSslEngineTest extends SSLEngineTest {
}
}
private void mySetup(ApplicationProtocolConfig apn) throws InterruptedException, SSLException,
CertificateException {
mySetup(apn, apn);
}
private void mySetup(ApplicationProtocolConfig serverApn, ApplicationProtocolConfig clientApn)
throws InterruptedException, SSLException, CertificateException {
SelfSignedCertificate ssc = new SelfSignedCertificate();
mySetup(SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey(), null)
.sslProvider(sslProvider())
.ciphers(null, IdentityCipherSuiteFilter.INSTANCE)
.applicationProtocolConfig(serverApn)
.sessionCacheSize(0)
.sessionTimeout(0)
.build(),
SslContextBuilder.forClient()
.sslProvider(sslProvider())
.applicationProtocolConfig(clientApn)
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.ciphers(null, IdentityCipherSuiteFilter.INSTANCE)
.sessionCacheSize(0)
.sessionTimeout(0)
.build());
}
private void mySetup(SslContext serverCtx, SslContext clientCtx)
throws InterruptedException, SSLException, CertificateException {
serverSslCtx = serverCtx;
clientSslCtx = clientCtx;
serverConnectedChannel = null;
sb = new ServerBootstrap();
cb = new Bootstrap();
sb.group(new NioEventLoopGroup(), new NioEventLoopGroup());
sb.channel(NioServerSocketChannel.class);
sb.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(serverSslCtx.newHandler(ch.alloc()));
p.addLast(new MessageDelegatorChannelHandler(serverReceiver, serverLatch));
p.addLast(new ChannelHandlerAdapter() {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (cause.getCause() instanceof SSLHandshakeException) {
serverException = cause.getCause();
serverLatch.countDown();
} else {
ctx.fireExceptionCaught(cause);
}
}
});
serverConnectedChannel = ch;
}
});
cb.group(new NioEventLoopGroup());
cb.channel(NioSocketChannel.class);
cb.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(clientSslCtx.newHandler(ch.alloc()));
p.addLast(new MessageDelegatorChannelHandler(clientReceiver, clientLatch));
p.addLast(new ChannelHandlerAdapter() {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (cause.getCause() instanceof SSLHandshakeException) {
clientException = cause.getCause();
clientLatch.countDown();
} else {
ctx.fireExceptionCaught(cause);
}
}
});
}
});
serverChannel = sb.bind(new InetSocketAddress(0)).sync().channel();
int port = ((InetSocketAddress) serverChannel.localAddress()).getPort();
ChannelFuture ccf = cb.connect(new InetSocketAddress(NetUtil.LOCALHOST, port));
assertTrue(ccf.awaitUninterruptibly().isSuccess());
clientChannel = ccf.channel();
}
private void runTest() throws Exception {
runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
}

View File

@ -15,9 +15,49 @@
*/
package io.netty.handler.ssl;
import org.junit.Test;
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
import static org.junit.Assert.assertNull;
import static org.junit.Assume.assumeTrue;
public class OpenSslEngineTest extends SSLEngineTest {
private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2";
private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1";
@Test
public void testNpn() throws Exception {
assumeTrue(OpenSsl.isAvailable());
ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.NPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
setupHandlers(apn);
runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
}
@Test
public void testAlpn() throws Exception {
assumeTrue(OpenSsl.isAvailable());
ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.ALPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
setupHandlers(apn);
runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
}
@Test
public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception {
assumeTrue(OpenSsl.isAvailable());
ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL);
setupHandlers(serverApn, clientApn);
assertNull(serverException);
runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
}
@Override
public void testMutualAuthSameCerts() throws Exception {
assumeTrue(OpenSsl.isAvailable());
@ -58,4 +98,12 @@ public class OpenSslEngineTest extends SSLEngineTest {
protected SslProvider sslProvider() {
return SslProvider.OPENSSL;
}
private static ApplicationProtocolConfig acceptingNegotiator(Protocol protocol,
String... supportedProtocols) {
return new ApplicationProtocolConfig(protocol,
SelectorFailureBehavior.NO_ADVERTISE,
SelectedListenerFailureBehavior.ACCEPT,
supportedProtocols);
}
}

View File

@ -22,8 +22,8 @@ import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
@ -49,6 +49,7 @@ import javax.net.ssl.SSLSession;
import java.io.File;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.security.cert.CertificateException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -212,7 +213,7 @@ public abstract class SSLEngineTest {
engine.setNeedClientAuth(true);
p.addLast(new SslHandler(engine));
p.addLast(new MessageDelegatorChannelHandler(serverReceiver, serverLatch));
p.addLast(new ChannelHandlerAdapter() {
p.addLast(new ChannelInboundHandlerAdapter() {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (cause.getCause() instanceof SSLHandshakeException) {
@ -235,7 +236,7 @@ public abstract class SSLEngineTest {
ChannelPipeline p = ch.pipeline();
p.addLast(clientSslCtx.newHandler(ch.alloc()));
p.addLast(new MessageDelegatorChannelHandler(clientReceiver, clientLatch));
p.addLast(new ChannelHandlerAdapter() {
p.addLast(new ChannelInboundHandlerAdapter() {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
@ -380,4 +381,94 @@ public abstract class SSLEngineTest {
}
protected abstract SslProvider sslProvider();
protected void setupHandlers(ApplicationProtocolConfig apn) throws InterruptedException, SSLException,
CertificateException {
setupHandlers(apn, apn);
}
protected void setupHandlers(ApplicationProtocolConfig serverApn, ApplicationProtocolConfig clientApn)
throws InterruptedException, SSLException, CertificateException {
SelfSignedCertificate ssc = new SelfSignedCertificate();
setupHandlers(SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey(), null)
.sslProvider(sslProvider())
.ciphers(null, IdentityCipherSuiteFilter.INSTANCE)
.applicationProtocolConfig(serverApn)
.sessionCacheSize(0)
.sessionTimeout(0)
.build(),
SslContextBuilder.forClient()
.sslProvider(sslProvider())
.applicationProtocolConfig(clientApn)
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.ciphers(null, IdentityCipherSuiteFilter.INSTANCE)
.sessionCacheSize(0)
.sessionTimeout(0)
.build());
}
protected void setupHandlers(SslContext serverCtx, SslContext clientCtx)
throws InterruptedException, SSLException, CertificateException {
serverSslCtx = serverCtx;
clientSslCtx = clientCtx;
serverConnectedChannel = null;
sb = new ServerBootstrap();
cb = new Bootstrap();
sb.group(new NioEventLoopGroup(), new NioEventLoopGroup());
sb.channel(NioServerSocketChannel.class);
sb.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(serverSslCtx.newHandler(ch.alloc()));
p.addLast(new MessageDelegatorChannelHandler(serverReceiver, serverLatch));
p.addLast(new ChannelInboundHandlerAdapter() {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (cause.getCause() instanceof SSLHandshakeException) {
serverException = cause.getCause();
serverLatch.countDown();
} else {
ctx.fireExceptionCaught(cause);
}
}
});
serverConnectedChannel = ch;
}
});
cb.group(new NioEventLoopGroup());
cb.channel(NioSocketChannel.class);
cb.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(clientSslCtx.newHandler(ch.alloc()));
p.addLast(new MessageDelegatorChannelHandler(clientReceiver, clientLatch));
p.addLast(new ChannelInboundHandlerAdapter() {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (cause.getCause() instanceof SSLHandshakeException) {
clientException = cause.getCause();
clientLatch.countDown();
} else {
ctx.fireExceptionCaught(cause);
}
}
});
}
});
serverChannel = sb.bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
ChannelFuture ccf = cb.connect(serverChannel.localAddress());
assertTrue(ccf.syncUninterruptibly().isSuccess());
clientChannel = ccf.channel();
}
}