@@ -3253,4 +3253,231 @@ public void testBufferOverflowSmallOutput()
32533253
32543254 pass ("\t \t ... passed" );
32553255 }
3256+
3257+ @ Test
3258+ public void testCloseOutboundBeforeHandshake ()
3259+ throws NoSuchProviderException , NoSuchAlgorithmException ,
3260+ KeyManagementException , KeyStoreException ,
3261+ CertificateException , IOException ,
3262+ UnrecoverableKeyException {
3263+
3264+ /* Regression: closeOutbound() before handshake started must
3265+ * also close inbound, otherwise isInboundDone() never returns
3266+ * true and callers loop forever. */
3267+ System .out .print ("\t closeOutbound() pre-handshake" );
3268+
3269+ this .ctx = tf .createSSLContext ("TLS" , engineProvider );
3270+ SSLEngine engine = this .ctx .createSSLEngine ();
3271+ engine .setUseClientMode (true );
3272+
3273+ /* Do not call beginHandshake() — needInit stays true. */
3274+ engine .closeOutbound ();
3275+
3276+ if (!engine .isOutboundDone ()) {
3277+ error ("\t \t ... failed" );
3278+ fail ("isOutboundDone() should be true after closeOutbound()" );
3279+ }
3280+
3281+ if (!engine .isInboundDone ()) {
3282+ error ("\t \t ... failed" );
3283+ fail ("isInboundDone() should be true after closeOutbound() " +
3284+ "before handshake (was leaving inBound open)" );
3285+ }
3286+
3287+ pass ("\t \t ... passed" );
3288+ }
3289+
3290+ @ Test
3291+ public void testWrapWithBufferArrayOffset ()
3292+ throws NoSuchProviderException , NoSuchAlgorithmException ,
3293+ KeyManagementException , KeyStoreException ,
3294+ CertificateException , IOException ,
3295+ UnrecoverableKeyException {
3296+
3297+ /* Regression for wrap(ByteBuffer[], ofst, len, out) and
3298+ * SendAppData() when ofst > 0. Previously triggered AIOOBE
3299+ * because pos[]/limit[] were sized [len] but indexed by i
3300+ * starting at ofst, and the null-check loop iterated
3301+ * i < len instead of i < ofst + len. */
3302+ System .out .print ("\t wrap() with ofst > 0" );
3303+
3304+ this .ctx = tf .createSSLContext ("TLS" , engineProvider );
3305+ SSLEngine server = this .ctx .createSSLEngine ();
3306+ SSLEngine client = this .ctx .createSSLEngine ("wolfSSL test" , 11111 );
3307+
3308+ server .setUseClientMode (false );
3309+ server .setNeedClientAuth (false );
3310+ client .setUseClientMode (true );
3311+
3312+ server .beginHandshake ();
3313+ client .beginHandshake ();
3314+
3315+ int ret = tf .testConnection (server , client , null , null ,
3316+ "wrap ofst test" );
3317+ if (ret != 0 ) {
3318+ error ("\t \t ... failed" );
3319+ fail ("failed to create connection" );
3320+ }
3321+
3322+ /* Build a 2-element ByteBuffer[] and wrap with ofst=1, len=1
3323+ * so the null check, pos/limit recording, and gather loops
3324+ * all index past the [len] boundary. The buffer at index 0
3325+ * intentionally contains data that must NOT be sent. */
3326+ byte [] decoy = "DECOY-MUST-NOT-BE-SENT" .getBytes ();
3327+ byte [] payload = "real-payload-bytes" .getBytes ();
3328+
3329+ ByteBuffer [] inBufs = new ByteBuffer [2 ];
3330+ inBufs [0 ] = ByteBuffer .wrap (decoy );
3331+ inBufs [1 ] = ByteBuffer .wrap (payload );
3332+
3333+ ByteBuffer netOut = ByteBuffer .allocateDirect (
3334+ client .getSession ().getPacketBufferSize ());
3335+
3336+ SSLEngineResult result = client .wrap (inBufs , 1 , 1 , netOut );
3337+ if (result .getStatus () != SSLEngineResult .Status .OK ) {
3338+ error ("\t \t ... failed" );
3339+ fail ("wrap with ofst=1 failed: " + result .getStatus ());
3340+ }
3341+
3342+ /* Decoy must be untouched, payload fully consumed. */
3343+ if (inBufs [0 ].position () != 0 ) {
3344+ error ("\t \t ... failed" );
3345+ fail ("decoy buffer at index 0 was advanced: pos=" +
3346+ inBufs [0 ].position ());
3347+ }
3348+ if (inBufs [1 ].position () != payload .length ) {
3349+ error ("\t \t ... failed" );
3350+ fail ("payload buffer not fully consumed: pos=" +
3351+ inBufs [1 ].position ());
3352+ }
3353+
3354+ /* Decrypt on server side and verify content is the payload. */
3355+ netOut .flip ();
3356+ ByteBuffer plain = ByteBuffer .allocate (
3357+ server .getSession ().getApplicationBufferSize ());
3358+ result = server .unwrap (netOut , plain );
3359+ if (result .getStatus () != SSLEngineResult .Status .OK ) {
3360+ error ("\t \t ... failed" );
3361+ fail ("server unwrap failed: " + result .getStatus ());
3362+ }
3363+
3364+ plain .flip ();
3365+ byte [] received = new byte [plain .remaining ()];
3366+ plain .get (received );
3367+ if (!java .util .Arrays .equals (received , payload )) {
3368+ error ("\t \t ... failed" );
3369+ fail ("received data does not match payload" );
3370+ }
3371+
3372+ pass ("\t \t ... passed" );
3373+ }
3374+
3375+ @ Test
3376+ public void testUnwrapWithBufferArrayOffset ()
3377+ throws NoSuchProviderException , NoSuchAlgorithmException ,
3378+ KeyManagementException , KeyStoreException ,
3379+ CertificateException , IOException ,
3380+ UnrecoverableKeyException {
3381+
3382+ /* Regression for unwrap(in, ByteBuffer[], ofst, length) with
3383+ * ofst > 0. Previously the null/readOnly-check loop iterated
3384+ * i < length instead of i < ofst + length, skipping the
3385+ * actually-targeted output buffers. */
3386+ System .out .print ("\t unwrap() with ofst > 0" );
3387+
3388+ this .ctx = tf .createSSLContext ("TLS" , engineProvider );
3389+ SSLEngine server = this .ctx .createSSLEngine ();
3390+ SSLEngine client = this .ctx .createSSLEngine ("wolfSSL test" , 11111 );
3391+
3392+ server .setUseClientMode (false );
3393+ server .setNeedClientAuth (false );
3394+ client .setUseClientMode (true );
3395+
3396+ server .beginHandshake ();
3397+ client .beginHandshake ();
3398+
3399+ int ret = tf .testConnection (server , client , null , null ,
3400+ "unwrap ofst test" );
3401+ if (ret != 0 ) {
3402+ error ("\t \t ... failed" );
3403+ fail ("failed to create connection" );
3404+ }
3405+
3406+ byte [] payload = "unwrap-target-bytes" .getBytes ();
3407+
3408+ /* Client wraps payload, server will unwrap into ByteBuffer[]
3409+ * at ofst=1. */
3410+ ByteBuffer appBuf = ByteBuffer .wrap (payload );
3411+ ByteBuffer netBuf = ByteBuffer .allocateDirect (
3412+ client .getSession ().getPacketBufferSize ());
3413+
3414+ SSLEngineResult result = client .wrap (appBuf , netBuf );
3415+ if (result .getStatus () != SSLEngineResult .Status .OK ) {
3416+ error ("\t \t ... failed" );
3417+ fail ("client wrap failed: " + result .getStatus ());
3418+ }
3419+ netBuf .flip ();
3420+
3421+ /* Build 2-element output array, ofst=1 so index 0 must stay
3422+ * untouched and decrypted bytes land at index 1. */
3423+ int appBufSize = server .getSession ().getApplicationBufferSize ();
3424+ ByteBuffer [] outBufs = new ByteBuffer [2 ];
3425+ outBufs [0 ] = ByteBuffer .allocate (appBufSize );
3426+ outBufs [1 ] = ByteBuffer .allocate (appBufSize );
3427+
3428+ result = server .unwrap (netBuf , outBufs , 1 , 1 );
3429+ if (result .getStatus () != SSLEngineResult .Status .OK ) {
3430+ error ("\t \t ... failed" );
3431+ fail ("server unwrap with ofst=1 failed: " + result .getStatus ());
3432+ }
3433+
3434+ if (outBufs [0 ].position () != 0 ) {
3435+ error ("\t \t ... failed" );
3436+ fail ("output buffer at index 0 was written: pos=" +
3437+ outBufs [0 ].position ());
3438+ }
3439+
3440+ outBufs [1 ].flip ();
3441+ byte [] received = new byte [outBufs [1 ].remaining ()];
3442+ outBufs [1 ].get (received );
3443+ if (!java .util .Arrays .equals (received , payload )) {
3444+ error ("\t \t ... failed" );
3445+ fail ("received data does not match payload" );
3446+ }
3447+
3448+ pass ("\t \t ... passed" );
3449+ }
3450+
3451+ @ Test
3452+ public void testWrapRejectsNullAtOffset () throws Exception {
3453+ System .out .print ("\t wrap() rejects null at ofst+len-1" );
3454+ this .ctx = tf .createSSLContext ("TLS" , engineProvider );
3455+ SSLEngine c = this .ctx .createSSLEngine ("wolfSSL test" , 11111 );
3456+ c .setUseClientMode (true );
3457+ ByteBuffer [] in = {ByteBuffer .wrap ("x" .getBytes ()), null };
3458+ ByteBuffer out = ByteBuffer .allocateDirect (
3459+ c .getSession ().getPacketBufferSize ());
3460+ try {
3461+ c .wrap (in , 1 , 1 , out );
3462+ fail ("expected SSLException for null at ofst=1" );
3463+ } catch (SSLException e ) { /* expected */ }
3464+ pass ("\t ... passed" );
3465+ }
3466+
3467+ @ Test
3468+ public void testUnwrapRejectsReadOnlyAtOffset () throws Exception {
3469+ System .out .print ("\t unwrap() rejects readOnly at ofst+length-1" );
3470+ this .ctx = tf .createSSLContext ("TLS" , engineProvider );
3471+ SSLEngine s = this .ctx .createSSLEngine ();
3472+ s .setUseClientMode (false );
3473+ ByteBuffer in = ByteBuffer .allocateDirect (
3474+ s .getSession ().getPacketBufferSize ());
3475+ ByteBuffer [] out = {ByteBuffer .allocate (64 ),
3476+ ByteBuffer .allocate (64 ).asReadOnlyBuffer ()};
3477+ try {
3478+ s .unwrap (in , out , 1 , 1 );
3479+ fail ("expected ReadOnlyBufferException at ofst=1" );
3480+ } catch (java .nio .ReadOnlyBufferException e ) { /* expected */ }
3481+ pass ("\t ... passed" );
3482+ }
32563483}
0 commit comments