@@ -3046,6 +3046,128 @@ public void testBufferUnderflowPartialRecord()
30463046 pass ("\t ... passed" );
30473047 }
30483048
3049+ @ Test
3050+ public void testHandshakeUnwrapConsumedNotBufferUnderflow ()
3051+ throws NoSuchProviderException , NoSuchAlgorithmException ,
3052+ KeyManagementException , KeyStoreException ,
3053+ CertificateException , IOException ,
3054+ UnrecoverableKeyException {
3055+
3056+ System .out .print ("\t Test unwrap consumed != BUFFER_UNDERFLOW" );
3057+
3058+ if (!enabledProtocols .contains ("TLSv1.3" )) {
3059+ System .out .println ("\t ... skipped" );
3060+ return ;
3061+ }
3062+
3063+ SSLContext ctx13 = tf .createSSLContext ("TLSv1.3" , engineProvider );
3064+ SSLEngine server = ctx13 .createSSLEngine ();
3065+ SSLEngine client = ctx13 .createSSLEngine ("localhost" , 11111 );
3066+
3067+ server .setUseClientMode (false );
3068+ server .setNeedClientAuth (false );
3069+ client .setUseClientMode (true );
3070+
3071+ server .beginHandshake ();
3072+ client .beginHandshake ();
3073+
3074+ int packetBufSize = client .getSession ().getPacketBufferSize ();
3075+ int appBufSize = client .getSession ().getApplicationBufferSize ();
3076+
3077+ /* Wrap ClientHello */
3078+ ByteBuffer cliToSrv =
3079+ ByteBuffer .allocateDirect (packetBufSize );
3080+ ByteBuffer emptyApp = ByteBuffer .allocate (0 );
3081+ SSLEngineResult result = client .wrap (emptyApp , cliToSrv );
3082+ if (result .getStatus () != SSLEngineResult .Status .OK ) {
3083+ error ("\t ... failed" );
3084+ fail ("client wrap (ClientHello) failed: " +
3085+ result .getStatus ());
3086+ }
3087+ cliToSrv .flip ();
3088+
3089+ /* Server unwraps ClientHello */
3090+ ByteBuffer srvAppBuf =
3091+ ByteBuffer .allocateDirect (appBufSize );
3092+ result = server .unwrap (cliToSrv , srvAppBuf );
3093+ if (result .getStatus () != SSLEngineResult .Status .OK ) {
3094+ error ("\t ... failed" );
3095+ fail ("server unwrap (ClientHello) failed: " +
3096+ result .getStatus ());
3097+ }
3098+
3099+ /* Collect entire TLS 1.3 server first flight (ServerHello,
3100+ * optional Change Cipher Spec, encrypted flight). */
3101+ if (server .getHandshakeStatus () !=
3102+ HandshakeStatus .NEED_WRAP ) {
3103+ error ("\t ... failed" );
3104+ fail ("expected server NEED_WRAP after ClientHello, " +
3105+ "got: " + server .getHandshakeStatus ());
3106+ }
3107+
3108+ ByteBuffer srvFlight =
3109+ ByteBuffer .allocateDirect (packetBufSize * 4 );
3110+ HandshakeStatus hs = server .getHandshakeStatus ();
3111+ while (hs == HandshakeStatus .NEED_WRAP ) {
3112+ ByteBuffer srvNet =
3113+ ByteBuffer .allocateDirect (packetBufSize );
3114+ result = server .wrap (emptyApp , srvNet );
3115+ if (result .getStatus () != SSLEngineResult .Status .OK ) {
3116+ error ("\t ... failed" );
3117+ fail ("server wrap failed: " + result .getStatus ());
3118+ }
3119+ srvNet .flip ();
3120+ if (srvNet .remaining () > srvFlight .remaining ()) {
3121+ error ("\t ... failed" );
3122+ fail ("server flight exceeded srvFlight capacity" );
3123+ }
3124+ srvFlight .put (srvNet );
3125+ hs = server .getHandshakeStatus ();
3126+ }
3127+ srvFlight .flip ();
3128+
3129+ int total = srvFlight .remaining ();
3130+ if (total < 2 ) {
3131+ error ("\t ... failed" );
3132+ fail ("server flight too small to split: " + total );
3133+ }
3134+
3135+ /* Feed the first half of the server flight to
3136+ * client.unwrap(). wolfSSL will consume these bytes through
3137+ * the I/O callback, exhaust the buffer, and return
3138+ * SSL_ERROR_WANT_READ. With the fix, BUFFER_UNDERFLOW must
3139+ * NOT be set because inRemaining > 0 (data was provided). */
3140+ int half = total / 2 ;
3141+ byte [] halfBytes = new byte [half ];
3142+ srvFlight .get (halfBytes );
3143+ ByteBuffer firstHalf = ByteBuffer .wrap (halfBytes );
3144+
3145+ ByteBuffer cliAppBuf =
3146+ ByteBuffer .allocateDirect (appBufSize );
3147+ result = client .unwrap (firstHalf , cliAppBuf );
3148+
3149+ /* BUFFER_UNDERFLOW must not be returned when input was
3150+ * consumed - regression for inRemaining == 0 guard fix */
3151+ if (result .getStatus () ==
3152+ SSLEngineResult .Status .BUFFER_UNDERFLOW ) {
3153+ error ("\t ... failed" );
3154+ fail ("unwrap() with consumed handshake data must not " +
3155+ "return BUFFER_UNDERFLOW (regression: inRemaining" +
3156+ " == 0 guard), bytesConsumed=" +
3157+ result .bytesConsumed ());
3158+ }
3159+
3160+ /* Input was non-empty so at least some bytes must have
3161+ * been consumed */
3162+ if (result .bytesConsumed () == 0 ) {
3163+ error ("\t ... failed" );
3164+ fail ("unwrap() consumed 0 bytes from a non-empty " +
3165+ "handshake buffer" );
3166+ }
3167+
3168+ pass ("\t ... passed" );
3169+ }
3170+
30493171 @ Test
30503172 public void testBufferOverflowSmallOutput ()
30513173 throws NoSuchProviderException , NoSuchAlgorithmException ,
0 commit comments