Rewrite SslHandler / Reduce the chance of OIO-OIO dead lock
- SslHandler always begins handshake unless startTls is true - Removed issueHandshake property - If a user wants to start handshake later, he/she has to add SslHandler later. - Removed enableRenegotiation property - JDK upgrade fixes the security vulnerability - no need to complicate our code - Some property name changes - getSSLEngineInboundCloseFuture() -> sslCloseFuture() - Updated securechat example - Added timeout for handshake and close_notify for better security - However, it's currently hard-coded. Will make it a property later.
This commit is contained in:
parent
4a23c2a6eb
commit
50fafdc3d3
@ -17,7 +17,6 @@ package io.netty.example.securechat;
|
|||||||
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
|
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
|
||||||
import io.netty.handler.ssl.SslHandler;
|
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@ -30,16 +29,6 @@ public class SecureChatClientHandler extends ChannelInboundMessageHandlerAdapter
|
|||||||
private static final Logger logger = Logger.getLogger(
|
private static final Logger logger = Logger.getLogger(
|
||||||
SecureChatClientHandler.class.getName());
|
SecureChatClientHandler.class.getName());
|
||||||
|
|
||||||
@Override
|
|
||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
|
||||||
// Get the SslHandler from the pipeline
|
|
||||||
// which were added in SecureChatPipelineFactory.
|
|
||||||
SslHandler sslHandler = ctx.pipeline().get(SslHandler.class);
|
|
||||||
|
|
||||||
// Begin handshake.
|
|
||||||
sslHandler.handshake();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
|
public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
|
||||||
System.err.println(msg);
|
System.err.println(msg);
|
||||||
|
@ -16,8 +16,6 @@
|
|||||||
package io.netty.example.securechat;
|
package io.netty.example.securechat;
|
||||||
|
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelFuture;
|
|
||||||
import io.netty.channel.ChannelFutureListener;
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
|
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
|
||||||
import io.netty.channel.group.ChannelGroup;
|
import io.netty.channel.group.ChannelGroup;
|
||||||
@ -40,13 +38,18 @@ public class SecureChatServerHandler extends ChannelInboundMessageHandlerAdapter
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||||
// Get the SslHandler in the current pipeline.
|
// Once session is secured, send a greeting.
|
||||||
// We added it in SecureChatPipelineFactory.
|
ctx.write(
|
||||||
final SslHandler sslHandler = ctx.pipeline().get(SslHandler.class);
|
"Welcome to " + InetAddress.getLocalHost().getHostName() +
|
||||||
|
" secure chat service!\n");
|
||||||
|
ctx.write(
|
||||||
|
"Your session is protected by " +
|
||||||
|
ctx.pipeline().get(SslHandler.class).getEngine().getSession().getCipherSuite() +
|
||||||
|
" cipher suite.\n");
|
||||||
|
|
||||||
// Get notified when SSL handshake is done.
|
// Register the channel to the global channel list
|
||||||
ChannelFuture handshakeFuture = sslHandler.handshake();
|
// so the channel received the messages from others.
|
||||||
handshakeFuture.addListener(new Greeter(sslHandler));
|
channels.add(ctx.channel());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -74,33 +77,4 @@ public class SecureChatServerHandler extends ChannelInboundMessageHandlerAdapter
|
|||||||
"Unexpected exception from downstream.", cause);
|
"Unexpected exception from downstream.", cause);
|
||||||
ctx.close();
|
ctx.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class Greeter implements ChannelFutureListener {
|
|
||||||
|
|
||||||
private final SslHandler sslHandler;
|
|
||||||
|
|
||||||
Greeter(SslHandler sslHandler) {
|
|
||||||
this.sslHandler = sslHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void operationComplete(ChannelFuture future) throws Exception {
|
|
||||||
if (future.isSuccess()) {
|
|
||||||
// Once session is secured, send a greeting.
|
|
||||||
future.channel().write(
|
|
||||||
"Welcome to " + InetAddress.getLocalHost().getHostName() +
|
|
||||||
" secure chat service!\n");
|
|
||||||
future.channel().write(
|
|
||||||
"Your session is protected by " +
|
|
||||||
sslHandler.getEngine().getSession().getCipherSuite() +
|
|
||||||
" cipher suite.\n");
|
|
||||||
|
|
||||||
// Register the channel to the global channel list
|
|
||||||
// so the channel received the messages from others.
|
|
||||||
channels.add(future.channel());
|
|
||||||
} else {
|
|
||||||
future.channel().close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -39,11 +39,6 @@
|
|||||||
<artifactId>netty-transport</artifactId>
|
<artifactId>netty-transport</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>${project.groupId}</groupId>
|
|
||||||
<artifactId>netty-codec</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -92,15 +92,7 @@ public class SocketSslEchoTest extends AbstractSocketTest {
|
|||||||
Channel sc = sb.bind().sync().channel();
|
Channel sc = sb.bind().sync().channel();
|
||||||
Channel cc = cb.connect().sync().channel();
|
Channel cc = cb.connect().sync().channel();
|
||||||
ChannelFuture hf = cc.pipeline().get(SslHandler.class).handshake();
|
ChannelFuture hf = cc.pipeline().get(SslHandler.class).handshake();
|
||||||
hf.awaitUninterruptibly();
|
hf.sync();
|
||||||
if (!hf.isSuccess()) {
|
|
||||||
logger.error("Handshake failed", hf.cause());
|
|
||||||
sh.channel.close().awaitUninterruptibly();
|
|
||||||
ch.channel.close().awaitUninterruptibly();
|
|
||||||
sc.close().awaitUninterruptibly();
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue(hf.isSuccess());
|
|
||||||
|
|
||||||
for (int i = 0; i < data.length;) {
|
for (int i = 0; i < data.length;) {
|
||||||
int length = Math.min(random.nextInt(1024 * 64), data.length - i);
|
int length = Math.min(random.nextInt(1024 * 64), data.length - i);
|
||||||
|
@ -25,6 +25,8 @@ import java.net.SocketAddress;
|
|||||||
|
|
||||||
abstract class AbstractOioChannel extends AbstractChannel {
|
abstract class AbstractOioChannel extends AbstractChannel {
|
||||||
|
|
||||||
|
static final int SO_TIMEOUT = 1000;
|
||||||
|
|
||||||
protected AbstractOioChannel(Channel parent, Integer id) {
|
protected AbstractOioChannel(Channel parent, Integer id) {
|
||||||
super(parent, id);
|
super(parent, id);
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,21 @@ class OioChildEventLoop extends SingleThreadEventLoop {
|
|||||||
// Waken up by interruptThread()
|
// Waken up by interruptThread()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
runAllTasks();
|
long startTime = System.nanoTime();
|
||||||
|
for (;;) {
|
||||||
|
final Runnable task = pollTask();
|
||||||
|
if (task == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
task.run();
|
||||||
|
|
||||||
|
// Ensure running tasks doesn't take too much time.
|
||||||
|
if (System.nanoTime() - startTime > AbstractOioChannel.SO_TIMEOUT * 1000000L) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ch.unsafe().read();
|
ch.unsafe().read();
|
||||||
|
|
||||||
// Handle deregistration
|
// Handle deregistration
|
||||||
|
@ -69,7 +69,7 @@ public class OioDatagramChannel extends AbstractOioMessageChannel
|
|||||||
|
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
try {
|
try {
|
||||||
socket.setSoTimeout(1000);
|
socket.setSoTimeout(SO_TIMEOUT);
|
||||||
socket.setBroadcast(false);
|
socket.setBroadcast(false);
|
||||||
success = true;
|
success = true;
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
|
@ -66,7 +66,7 @@ public class OioServerSocketChannel extends AbstractOioMessageChannel
|
|||||||
|
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
try {
|
try {
|
||||||
socket.setSoTimeout(1000);
|
socket.setSoTimeout(SO_TIMEOUT);
|
||||||
success = true;
|
success = true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ChannelException(
|
throw new ChannelException(
|
||||||
|
@ -62,7 +62,7 @@ public class OioSocketChannel extends AbstractOioStreamChannel
|
|||||||
is = socket.getInputStream();
|
is = socket.getInputStream();
|
||||||
os = socket.getOutputStream();
|
os = socket.getOutputStream();
|
||||||
}
|
}
|
||||||
socket.setSoTimeout(1000);
|
socket.setSoTimeout(SO_TIMEOUT);
|
||||||
success = true;
|
success = true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ChannelException("failed to initialize a socket", e);
|
throw new ChannelException("failed to initialize a socket", e);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user