[#915] [#923] Expanded scope of the handshake locks in SSLHandler to avoid possible negotiation after the first SSLEngine wrap

This commit is contained in:
Aaron 2013-01-10 09:57:37 -08:00 committed by Norman Maurer
parent 223209864a
commit ca7702f38c

View File

@ -402,76 +402,75 @@ public class SslHandler extends FrameDecoder
* succeeds or fails. * succeeds or fails.
*/ */
public ChannelFuture handshake() { public ChannelFuture handshake() {
if (handshaken && !isEnableRenegotiation()) {
throw new IllegalStateException("renegotiation disabled");
}
final ChannelHandlerContext ctx = this.ctx;
final Channel channel = ctx.getChannel();
ChannelFuture handshakeFuture;
Exception exception = null;
synchronized (handshakeLock) { synchronized (handshakeLock) {
if (handshaken && !isEnableRenegotiation()) {
throw new IllegalStateException("renegotiation disabled");
}
final ChannelHandlerContext ctx = this.ctx;
final Channel channel = ctx.getChannel();
ChannelFuture handshakeFuture;
Exception exception = null;
if (handshaking) { if (handshaking) {
return this.handshakeFuture; return this.handshakeFuture;
} else {
handshaking = true;
try {
engine.beginHandshake();
runDelegatedTasks();
handshakeFuture = this.handshakeFuture = future(channel);
if (handshakeTimeoutInMillis > 0) {
handshakeTimeout = timer.newTimeout(new TimerTask() {
public void run(Timeout timeout) throws Exception {
ChannelFuture future = SslHandler.this.handshakeFuture;
if (future != null && future.isDone()) {
return;
}
setHandshakeFailure(channel, new SSLException("Handshake did not complete within " +
handshakeTimeoutInMillis + "ms"));
}
}, handshakeTimeoutInMillis, TimeUnit.MILLISECONDS);
}
} catch (Exception e) {
handshakeFuture = this.handshakeFuture = failedFuture(channel, e);
exception = e;
}
} }
}
if (exception == null) { // Began handshake successfully. handshaking = true;
try { try {
final ChannelFuture hsFuture = handshakeFuture; engine.beginHandshake();
wrapNonAppData(ctx, channel).addListener(new ChannelFutureListener() { runDelegatedTasks();
public void operationComplete(ChannelFuture future) throws Exception { handshakeFuture = this.handshakeFuture = future(channel);
if (!future.isSuccess()) { if (handshakeTimeoutInMillis > 0) {
Throwable cause = future.getCause(); handshakeTimeout = timer.newTimeout(new TimerTask() {
hsFuture.setFailure(cause); public void run(Timeout timeout) throws Exception {
ChannelFuture future = SslHandler.this.handshakeFuture;
if (future != null && future.isDone()) {
return;
}
fireExceptionCaught(ctx, cause); setHandshakeFailure(channel, new SSLException("Handshake did not complete within " +
if (closeOnSSLException) { handshakeTimeoutInMillis + "ms"));
Channels.close(ctx, future(channel)); }
}, handshakeTimeoutInMillis, TimeUnit.MILLISECONDS);
}
} catch (Exception e) {
handshakeFuture = this.handshakeFuture = failedFuture(channel, e);
exception = e;
}
if (exception == null) { // Began handshake successfully.
try {
final ChannelFuture hsFuture = handshakeFuture;
wrapNonAppData(ctx, channel).addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
Throwable cause = future.getCause();
hsFuture.setFailure(cause);
fireExceptionCaught(ctx, cause);
if (closeOnSSLException) {
Channels.close(ctx, future(channel));
}
} }
} }
} });
}); } catch (SSLException e) {
} catch (SSLException e) { handshakeFuture.setFailure(e);
handshakeFuture.setFailure(e);
fireExceptionCaught(ctx, e); fireExceptionCaught(ctx, e);
if (closeOnSSLException) {
Channels.close(ctx, future(channel));
}
}
} else { // Failed to initiate handshake.
fireExceptionCaught(ctx, exception);
if (closeOnSSLException) { if (closeOnSSLException) {
Channels.close(ctx, future(channel)); Channels.close(ctx, future(channel));
} }
} }
} else { // Failed to initiate handshake. return handshakeFuture;
fireExceptionCaught(ctx, exception);
if (closeOnSSLException) {
Channels.close(ctx, future(channel));
}
} }
return handshakeFuture;
} }
/** /**
@ -1282,19 +1281,19 @@ public class SslHandler extends FrameDecoder
} }
private void handleRenegotiation(HandshakeStatus handshakeStatus) { private void handleRenegotiation(HandshakeStatus handshakeStatus) {
if (handshakeStatus == HandshakeStatus.NOT_HANDSHAKING ||
handshakeStatus == HandshakeStatus.FINISHED) {
// Not handshaking
return;
}
if (!handshaken) {
// Not renegotiation
return;
}
final boolean renegotiate;
synchronized (handshakeLock) { synchronized (handshakeLock) {
if (handshakeStatus == HandshakeStatus.NOT_HANDSHAKING ||
handshakeStatus == HandshakeStatus.FINISHED) {
// Not handshaking
return;
}
if (!handshaken) {
// Not renegotiation
return;
}
final boolean renegotiate;
if (handshaking) { if (handshaking) {
// Renegotiation in progress or failed already. // Renegotiation in progress or failed already.
// i.e. Renegotiation check has been done already below. // i.e. Renegotiation check has been done already below.
@ -1315,20 +1314,20 @@ public class SslHandler extends FrameDecoder
// Prevent reentrance of this method. // Prevent reentrance of this method.
handshaking = true; handshaking = true;
} }
}
if (renegotiate) { if (renegotiate) {
// Renegotiate. // Renegotiate.
handshake(); handshake();
} else { } else {
// Raise an exception. // Raise an exception.
fireExceptionCaught( fireExceptionCaught(
ctx, new SSLException( ctx, new SSLException(
"renegotiation attempted by peer; " + "renegotiation attempted by peer; " +
"closing the connection")); "closing the connection"));
// Close the connection to stop renegotiation. // Close the connection to stop renegotiation.
Channels.close(ctx, succeededFuture(ctx.getChannel())); Channels.close(ctx, succeededFuture(ctx.getChannel()));
}
} }
} }