@@ -2926,6 +2926,128 @@ public void testBufferUnderflowPartialRecord()
29262926 pass ("\t ... passed" );
29272927 }
29282928
2929+ @ Test
2930+ public void testHandshakeUnwrapConsumedNotBufferUnderflow ()
2931+ throws NoSuchProviderException , NoSuchAlgorithmException ,
2932+ KeyManagementException , KeyStoreException ,
2933+ CertificateException , IOException ,
2934+ UnrecoverableKeyException {
2935+
2936+ System .out .print ("\t Test unwrap consumed != BUFFER_UNDERFLOW" );
2937+
2938+ if (!enabledProtocols .contains ("TLSv1.3" )) {
2939+ System .out .println ("\t ... skipped" );
2940+ return ;
2941+ }
2942+
2943+ SSLContext ctx13 = tf .createSSLContext ("TLSv1.3" , engineProvider );
2944+ SSLEngine server = ctx13 .createSSLEngine ();
2945+ SSLEngine client = ctx13 .createSSLEngine ("localhost" , 11111 );
2946+
2947+ server .setUseClientMode (false );
2948+ server .setNeedClientAuth (false );
2949+ client .setUseClientMode (true );
2950+
2951+ server .beginHandshake ();
2952+ client .beginHandshake ();
2953+
2954+ int packetBufSize = client .getSession ().getPacketBufferSize ();
2955+ int appBufSize = client .getSession ().getApplicationBufferSize ();
2956+
2957+ /* Wrap ClientHello */
2958+ ByteBuffer cliToSrv =
2959+ ByteBuffer .allocateDirect (packetBufSize );
2960+ ByteBuffer emptyApp = ByteBuffer .allocate (0 );
2961+ SSLEngineResult result = client .wrap (emptyApp , cliToSrv );
2962+ if (result .getStatus () != SSLEngineResult .Status .OK ) {
2963+ error ("\t ... failed" );
2964+ fail ("client wrap (ClientHello) failed: " +
2965+ result .getStatus ());
2966+ }
2967+ cliToSrv .flip ();
2968+
2969+ /* Server unwraps ClientHello */
2970+ ByteBuffer srvAppBuf =
2971+ ByteBuffer .allocateDirect (appBufSize );
2972+ result = server .unwrap (cliToSrv , srvAppBuf );
2973+ if (result .getStatus () != SSLEngineResult .Status .OK ) {
2974+ error ("\t ... failed" );
2975+ fail ("server unwrap (ClientHello) failed: " +
2976+ result .getStatus ());
2977+ }
2978+
2979+ /* Collect entire TLS 1.3 server first flight (ServerHello,
2980+ * optional Change Cipher Spec, encrypted flight). */
2981+ if (server .getHandshakeStatus () !=
2982+ HandshakeStatus .NEED_WRAP ) {
2983+ error ("\t ... failed" );
2984+ fail ("expected server NEED_WRAP after ClientHello, " +
2985+ "got: " + server .getHandshakeStatus ());
2986+ }
2987+
2988+ ByteBuffer srvFlight =
2989+ ByteBuffer .allocateDirect (packetBufSize * 4 );
2990+ HandshakeStatus hs = server .getHandshakeStatus ();
2991+ while (hs == HandshakeStatus .NEED_WRAP ) {
2992+ ByteBuffer srvNet =
2993+ ByteBuffer .allocateDirect (packetBufSize );
2994+ result = server .wrap (emptyApp , srvNet );
2995+ if (result .getStatus () != SSLEngineResult .Status .OK ) {
2996+ error ("\t ... failed" );
2997+ fail ("server wrap failed: " + result .getStatus ());
2998+ }
2999+ srvNet .flip ();
3000+ if (srvNet .remaining () > srvFlight .remaining ()) {
3001+ error ("\t ... failed" );
3002+ fail ("server flight exceeded srvFlight capacity" );
3003+ }
3004+ srvFlight .put (srvNet );
3005+ hs = server .getHandshakeStatus ();
3006+ }
3007+ srvFlight .flip ();
3008+
3009+ int total = srvFlight .remaining ();
3010+ if (total < 2 ) {
3011+ error ("\t ... failed" );
3012+ fail ("server flight too small to split: " + total );
3013+ }
3014+
3015+ /* Feed the first half of the server flight to
3016+ * client.unwrap(). wolfSSL will consume these bytes through
3017+ * the I/O callback, exhaust the buffer, and return
3018+ * SSL_ERROR_WANT_READ. With the fix, BUFFER_UNDERFLOW must
3019+ * NOT be set because inRemaining > 0 (data was provided). */
3020+ int half = total / 2 ;
3021+ byte [] halfBytes = new byte [half ];
3022+ srvFlight .get (halfBytes );
3023+ ByteBuffer firstHalf = ByteBuffer .wrap (halfBytes );
3024+
3025+ ByteBuffer cliAppBuf =
3026+ ByteBuffer .allocateDirect (appBufSize );
3027+ result = client .unwrap (firstHalf , cliAppBuf );
3028+
3029+ /* BUFFER_UNDERFLOW must not be returned when input was
3030+ * consumed - regression for inRemaining == 0 guard fix */
3031+ if (result .getStatus () ==
3032+ SSLEngineResult .Status .BUFFER_UNDERFLOW ) {
3033+ error ("\t ... failed" );
3034+ fail ("unwrap() with consumed handshake data must not " +
3035+ "return BUFFER_UNDERFLOW (regression: inRemaining" +
3036+ " == 0 guard), bytesConsumed=" +
3037+ result .bytesConsumed ());
3038+ }
3039+
3040+ /* Input was non-empty so at least some bytes must have
3041+ * been consumed */
3042+ if (result .bytesConsumed () == 0 ) {
3043+ error ("\t ... failed" );
3044+ fail ("unwrap() consumed 0 bytes from a non-empty " +
3045+ "handshake buffer" );
3046+ }
3047+
3048+ pass ("\t ... passed" );
3049+ }
3050+
29293051 @ Test
29303052 public void testBufferOverflowSmallOutput ()
29313053 throws NoSuchProviderException , NoSuchAlgorithmException ,
0 commit comments