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:
Trustin Lee 2012-06-08 01:22:35 +09:00
parent 4a23c2a6eb
commit 50fafdc3d3
10 changed files with 290 additions and 760 deletions

View File

@ -17,7 +17,6 @@ package io.netty.example.securechat;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.handler.ssl.SslHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -30,16 +29,6 @@ public class SecureChatClientHandler extends ChannelInboundMessageHandlerAdapter
private static final Logger logger = Logger.getLogger(
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
public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
System.err.println(msg);

View File

@ -16,8 +16,6 @@
package io.netty.example.securechat;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.group.ChannelGroup;
@ -40,13 +38,18 @@ public class SecureChatServerHandler extends ChannelInboundMessageHandlerAdapter
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// Get the SslHandler in the current pipeline.
// We added it in SecureChatPipelineFactory.
final SslHandler sslHandler = ctx.pipeline().get(SslHandler.class);
// Once session is secured, send a greeting.
ctx.write(
"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.
ChannelFuture handshakeFuture = sslHandler.handshake();
handshakeFuture.addListener(new Greeter(sslHandler));
// Register the channel to the global channel list
// so the channel received the messages from others.
channels.add(ctx.channel());
}
@Override
@ -74,33 +77,4 @@ public class SecureChatServerHandler extends ChannelInboundMessageHandlerAdapter
"Unexpected exception from downstream.", cause);
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();
}
}
}
}

View File

@ -39,11 +39,6 @@
<artifactId>netty-transport</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-codec</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>

File diff suppressed because it is too large Load Diff

View File

@ -92,15 +92,7 @@ public class SocketSslEchoTest extends AbstractSocketTest {
Channel sc = sb.bind().sync().channel();
Channel cc = cb.connect().sync().channel();
ChannelFuture hf = cc.pipeline().get(SslHandler.class).handshake();
hf.awaitUninterruptibly();
if (!hf.isSuccess()) {
logger.error("Handshake failed", hf.cause());
sh.channel.close().awaitUninterruptibly();
ch.channel.close().awaitUninterruptibly();
sc.close().awaitUninterruptibly();
}
assertTrue(hf.isSuccess());
hf.sync();
for (int i = 0; i < data.length;) {
int length = Math.min(random.nextInt(1024 * 64), data.length - i);

View File

@ -25,6 +25,8 @@ import java.net.SocketAddress;
abstract class AbstractOioChannel extends AbstractChannel {
static final int SO_TIMEOUT = 1000;
protected AbstractOioChannel(Channel parent, Integer id) {
super(parent, id);
}

View File

@ -58,7 +58,21 @@ class OioChildEventLoop extends SingleThreadEventLoop {
// Waken up by interruptThread()
}
} 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();
// Handle deregistration

View File

@ -69,7 +69,7 @@ public class OioDatagramChannel extends AbstractOioMessageChannel
boolean success = false;
try {
socket.setSoTimeout(1000);
socket.setSoTimeout(SO_TIMEOUT);
socket.setBroadcast(false);
success = true;
} catch (SocketException e) {

View File

@ -66,7 +66,7 @@ public class OioServerSocketChannel extends AbstractOioMessageChannel
boolean success = false;
try {
socket.setSoTimeout(1000);
socket.setSoTimeout(SO_TIMEOUT);
success = true;
} catch (IOException e) {
throw new ChannelException(

View File

@ -62,7 +62,7 @@ public class OioSocketChannel extends AbstractOioStreamChannel
is = socket.getInputStream();
os = socket.getOutputStream();
}
socket.setSoTimeout(1000);
socket.setSoTimeout(SO_TIMEOUT);
success = true;
} catch (Exception e) {
throw new ChannelException("failed to initialize a socket", e);