diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java index d7e1770efb..3f175b33fd 100644 --- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java @@ -646,17 +646,45 @@ public class SslHandler return false; } - @Override - public void inboundBufferUpdated(final ChannelHandlerContext ctx) throws Exception { - final ByteBuf in = ctx.inboundByteBuffer(); + /** + * Returns true if the given {@link ByteBuf} is encrypted. Be aware that this method + * will not increase the readerIndex of the given {@link ByteBuf}. + * + * @param buffer + * The {@link ByteBuf} to read from. Be aware that it must have at least 5 bytes to read, + * otherwise it will throw an {@link IllegalArgumentException}. + * @return encrypted + * true if the {@link ByteBuf} is encrypted, false otherwise. + * @throws IllegalArgumentException + * Is thrown if the given {@link ByteBuf} has not at least 5 bytes to read. + */ + public static boolean isEncrypted(ByteBuf buffer) { + return getEncryptedPacketLength(buffer) != -1; + } - if (in.readableBytes() < 5) { - return; + /** + * Return how much bytes can be read out of the encrypted data. Be aware that this method will not increase + * the readerIndex of the given {@link ByteBuf}. + * + * @param buffer + * The {@link ByteBuf} to read from. Be aware that it must have at least 5 bytes to read, + * otherwise it will throw an {@link IllegalArgumentException}. + * @return length + * The length of the encrypted packet that is included in the buffer. This will + * return -1 if the given {@link ByteBuf} is not encrypted at all. + * @throws IllegalArgumentException + * Is thrown if the given {@link ByteBuf} has not at least 5 bytes to read. + */ + private static int getEncryptedPacketLength(ByteBuf buffer) { + if (buffer.readableBytes() < 5) { + throw new IllegalArgumentException("buffer must have at least 5 readable bytes"); } + int packetLength = 0; + // SSLv3 or TLS - Check ContentType boolean tls; - switch (in.getUnsignedByte(in.readerIndex())) { + switch (buffer.getUnsignedByte(buffer.readerIndex())) { case 20: // change_cipher_spec case 21: // alert case 22: // handshake @@ -668,13 +696,12 @@ public class SslHandler tls = false; } - int packetLength = -1; if (tls) { // SSLv3 or TLS - Check ProtocolVersion - int majorVersion = in.getUnsignedByte(in.readerIndex() + 1); + int majorVersion = buffer.getUnsignedByte(buffer.readerIndex() + 1); if (majorVersion == 3) { // SSLv3 or TLS - packetLength = (getShort(in, in.readerIndex() + 3) & 0xFFFF) + 5; + packetLength = (getShort(buffer, buffer.readerIndex() + 3) & 0xFFFF) + 5; if (packetLength <= 5) { // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data) tls = false; @@ -688,16 +715,16 @@ public class SslHandler if (!tls) { // SSLv2 or bad data - Check the version boolean sslv2 = true; - int headerLength = (in.getUnsignedByte( - in.readerIndex()) & 0x80) != 0 ? 2 : 3; - int majorVersion = in.getUnsignedByte( - in.readerIndex() + headerLength + 1); + int headerLength = (buffer.getUnsignedByte( + buffer.readerIndex()) & 0x80) != 0 ? 2 : 3; + int majorVersion = buffer.getUnsignedByte( + buffer.readerIndex() + headerLength + 1); if (majorVersion == 2 || majorVersion == 3) { // SSLv2 if (headerLength == 2) { - packetLength = (getShort(in, in.readerIndex()) & 0x7FFF) + 2; + packetLength = (getShort(buffer, buffer.readerIndex()) & 0x7FFF) + 2; } else { - packetLength = (getShort(in, in.readerIndex()) & 0x3FFF) + 3; + packetLength = (getShort(buffer, buffer.readerIndex()) & 0x3FFF) + 3; } if (packetLength <= headerLength) { sslv2 = false; @@ -707,15 +734,31 @@ public class SslHandler } if (!sslv2) { - // Bad data - discard the buffer and raise an exception. - NotSslRecordException e = new NotSslRecordException( - "not an SSL/TLS record: " + ByteBufUtil.hexDump(in)); - in.skipBytes(in.readableBytes()); - ctx.fireExceptionCaught(e); - setHandshakeFailure(e); - return; + return -1; } } + return packetLength; + } + + @Override + public void inboundBufferUpdated(final ChannelHandlerContext ctx) throws Exception { + final ByteBuf in = ctx.inboundByteBuffer(); + + if (in.readableBytes() < 5) { + return; + } + + int packetLength = getEncryptedPacketLength(in); + + if (packetLength == -1) { + // Bad data - discard the buffer and raise an exception. + NotSslRecordException e = new NotSslRecordException( + "not an SSL/TLS record: " + ByteBufUtil.hexDump(in)); + in.skipBytes(in.readableBytes()); + ctx.fireExceptionCaught(e); + setHandshakeFailure(e); + return; + } assert packetLength > 0;