@@ -821,17 +821,14 @@ private void wrapAndFlush(ChannelHandlerContext ctx) throws SSLException {
821
821
// This method will not call setHandshakeFailure(...) !
822
822
private void wrap (ChannelHandlerContext ctx , boolean inUnwrap ) throws SSLException {
823
823
ByteBuf out = null ;
824
- ChannelPromise promise = null ;
825
824
ByteBufAllocator alloc = ctx .alloc ();
826
- boolean needUnwrap = false ;
827
- ByteBuf buf = null ;
828
825
try {
829
826
final int wrapDataSize = this .wrapDataSize ;
830
827
// Only continue to loop if the handler was not removed in the meantime.
831
828
// See https://github.com/netty/netty/issues/5860
832
829
outer : while (!ctx .isRemoved ()) {
833
- promise = ctx .newPromise ();
834
- buf = wrapDataSize > 0 ?
830
+ ChannelPromise promise = ctx .newPromise ();
831
+ ByteBuf buf = wrapDataSize > 0 ?
835
832
pendingUnencryptedWrites .remove (alloc , wrapDataSize , promise ) :
836
833
pendingUnencryptedWrites .removeFirst (promise );
837
834
if (buf == null ) {
@@ -844,9 +841,31 @@ private void wrap(ChannelHandlerContext ctx, boolean inUnwrap) throws SSLExcepti
844
841
845
842
SSLEngineResult result = wrap (alloc , engine , buf , out );
846
843
847
- if (result .getStatus () == Status .CLOSED ) {
844
+ if (buf .isReadable ()) {
845
+ pendingUnencryptedWrites .addFirst (buf , promise );
846
+ // When we add the buffer/promise pair back we need to be sure we don't complete the promise
847
+ // later. We only complete the promise if the buffer is completely consumed.
848
+ promise = null ;
849
+ } else {
848
850
buf .release ();
849
- buf = null ;
851
+ }
852
+
853
+ // We need to write any data before we invoke any methods which may trigger re-entry, otherwise
854
+ // writes may occur out of order and TLS sequencing may be off (e.g. SSLV3_ALERT_BAD_RECORD_MAC).
855
+ if (out .isReadable ()) {
856
+ final ByteBuf b = out ;
857
+ out = null ;
858
+ if (promise != null ) {
859
+ ctx .write (b , promise );
860
+ } else {
861
+ ctx .write (b );
862
+ }
863
+ } else if (promise != null ) {
864
+ ctx .write (Unpooled .EMPTY_BUFFER , promise );
865
+ }
866
+ // else out is not readable we can re-use it and so save an extra allocation
867
+
868
+ if (result .getStatus () == Status .CLOSED ) {
850
869
// Make a best effort to preserve any exception that way previously encountered from the handshake
851
870
// or the transport, else fallback to a general error.
852
871
Throwable exception = handshakePromise .cause ();
@@ -856,23 +875,9 @@ private void wrap(ChannelHandlerContext ctx, boolean inUnwrap) throws SSLExcepti
856
875
exception = new SslClosedEngineException ("SSLEngine closed already" );
857
876
}
858
877
}
859
- promise .tryFailure (exception );
860
- promise = null ;
861
- // SSLEngine has been closed already.
862
- // Any further write attempts should be denied.
863
878
pendingUnencryptedWrites .releaseAndFailAll (ctx , exception );
864
879
return ;
865
880
} else {
866
- if (buf .isReadable ()) {
867
- pendingUnencryptedWrites .addFirst (buf , promise );
868
- // When we add the buffer/promise pair back we need to be sure we don't complete the promise
869
- // later in finishWrap. We only complete the promise if the buffer is completely consumed.
870
- promise = null ;
871
- } else {
872
- buf .release ();
873
- }
874
- buf = null ;
875
-
876
881
switch (result .getHandshakeStatus ()) {
877
882
case NEED_TASK :
878
883
if (!runDelegatedTasks (inUnwrap )) {
@@ -883,27 +888,11 @@ private void wrap(ChannelHandlerContext ctx, boolean inUnwrap) throws SSLExcepti
883
888
break ;
884
889
case FINISHED :
885
890
setHandshakeSuccess ();
886
- // deliberate fall-through
891
+ break ;
887
892
case NOT_HANDSHAKING :
888
893
setHandshakeSuccessIfStillHandshaking ();
889
- // deliberate fall-through
890
- case NEED_WRAP : {
891
- ChannelPromise p = promise ;
892
-
893
- // Null out the promise so it is not reused in the finally block in the cause of
894
- // finishWrap(...) throwing.
895
- promise = null ;
896
- final ByteBuf b ;
897
-
898
- if (out .isReadable ()) {
899
- // There is something in the out buffer. Ensure we null it out so it is not re-used.
900
- b = out ;
901
- out = null ;
902
- } else {
903
- // If out is not readable we can re-use it and so save an extra allocation
904
- b = null ;
905
- }
906
- finishWrap (ctx , b , p , inUnwrap , false );
894
+ break ;
895
+ case NEED_WRAP :
907
896
// If we are expected to wrap again and we produced some data we need to ensure there
908
897
// is something in the queue to process as otherwise we will not try again before there
909
898
// was more added. Failing to do so may fail to produce an alert that can be
@@ -912,9 +901,10 @@ private void wrap(ChannelHandlerContext ctx, boolean inUnwrap) throws SSLExcepti
912
901
pendingUnencryptedWrites .add (Unpooled .EMPTY_BUFFER );
913
902
}
914
903
break ;
915
- }
916
904
case NEED_UNWRAP :
917
- needUnwrap = true ;
905
+ // The underlying engine is starving so we need to feed it with more data.
906
+ // See https://github.com/netty/netty/pull/5039
907
+ readIfNeeded (ctx );
918
908
return ;
919
909
default :
920
910
throw new IllegalStateException (
@@ -923,37 +913,12 @@ private void wrap(ChannelHandlerContext ctx, boolean inUnwrap) throws SSLExcepti
923
913
}
924
914
}
925
915
} finally {
926
- // Ownership of buffer was not transferred, release it.
927
- if (buf != null ) {
928
- buf .release ();
916
+ if (out != null ) {
917
+ out .release ();
918
+ }
919
+ if (inUnwrap ) {
920
+ needsFlush = true ;
929
921
}
930
- finishWrap (ctx , out , promise , inUnwrap , needUnwrap );
931
- }
932
- }
933
-
934
- private void finishWrap (ChannelHandlerContext ctx , ByteBuf out , ChannelPromise promise , boolean inUnwrap ,
935
- boolean needUnwrap ) {
936
- if (out == null ) {
937
- out = Unpooled .EMPTY_BUFFER ;
938
- } else if (!out .isReadable ()) {
939
- out .release ();
940
- out = Unpooled .EMPTY_BUFFER ;
941
- }
942
-
943
- if (promise != null ) {
944
- ctx .write (out , promise );
945
- } else {
946
- ctx .write (out );
947
- }
948
-
949
- if (inUnwrap ) {
950
- needsFlush = true ;
951
- }
952
-
953
- if (needUnwrap ) {
954
- // The underlying engine is starving so we need to feed it with more data.
955
- // See https://github.com/netty/netty/pull/5039
956
- readIfNeeded (ctx );
957
922
}
958
923
}
959
924
@@ -977,7 +942,6 @@ private boolean wrapNonAppData(final ChannelHandlerContext ctx, boolean inUnwrap
977
942
out = allocateOutNetBuf (ctx , 2048 , 1 );
978
943
}
979
944
SSLEngineResult result = wrap (alloc , engine , Unpooled .EMPTY_BUFFER , out );
980
- HandshakeStatus status = result .getHandshakeStatus ();
981
945
if (result .bytesProduced () > 0 ) {
982
946
ctx .write (out ).addListener (new ChannelFutureListener () {
983
947
@ Override
@@ -989,21 +953,22 @@ public void operationComplete(ChannelFuture future) {
989
953
}
990
954
});
991
955
if (inUnwrap ) {
992
- // We may be here because we read data and discovered the remote peer initiated a renegotiation
993
- // and this write is to complete the new handshake. The user may have previously done a
994
- // writeAndFlush which wasn't able to wrap data due to needing the pending handshake, so we
995
- // attempt to wrap application data here if any is pending.
996
- if (status == HandshakeStatus .FINISHED && !pendingUnencryptedWrites .isEmpty ()) {
997
- wrap (ctx , true );
998
- }
999
956
needsFlush = true ;
1000
957
}
1001
958
out = null ;
1002
959
}
1003
960
961
+ HandshakeStatus status = result .getHandshakeStatus ();
1004
962
switch (status ) {
1005
963
case FINISHED :
1006
964
setHandshakeSuccess ();
965
+ // We may be here because we read data and discovered the remote peer initiated a renegotiation
966
+ // and this write is to complete the new handshake. The user may have previously done a
967
+ // writeAndFlush which wasn't able to wrap data due to needing the pending handshake, so we
968
+ // attempt to wrap application data here if any is pending.
969
+ if (inUnwrap && !pendingUnencryptedWrites .isEmpty ()) {
970
+ wrap (ctx , true );
971
+ }
1007
972
return false ;
1008
973
case NEED_TASK :
1009
974
if (!runDelegatedTasks (inUnwrap )) {
@@ -1095,11 +1060,9 @@ private SSLEngineResult wrap(ByteBufAllocator alloc, SSLEngine engine, ByteBuf i
1095
1060
in .skipBytes (result .bytesConsumed ());
1096
1061
out .writerIndex (out .writerIndex () + result .bytesProduced ());
1097
1062
1098
- switch (result .getStatus ()) {
1099
- case BUFFER_OVERFLOW :
1063
+ if (result .getStatus () == Status .BUFFER_OVERFLOW ) {
1100
1064
out .ensureWritable (engine .getSession ().getPacketBufferSize ());
1101
- break ;
1102
- default :
1065
+ } else {
1103
1066
return result ;
1104
1067
}
1105
1068
}
0 commit comments