diff --git a/Makefile b/Makefile index 9778d1af..1bb5b43e 100644 --- a/Makefile +++ b/Makefile @@ -164,6 +164,8 @@ dist: exit 1 ; } @mkdir -p "$(NAME)-$(VERSION)" @cp -pr $(DIST_FILES) "$(NAME)-$(VERSION)" + @rm -f "$(NAME)-$(VERSION)"/$(NATIVE_SRC_DIR)/*.o \ + "$(NAME)-$(VERSION)"/$(NATIVE_SRC_DIR)/*.d tar -zcf "$(NAME)-$(VERSION).tar.gz" "$(NAME)-$(VERSION)" @rm -rf "$(NAME)-$(VERSION)" diff --git a/native/com_wolfssl_WolfSSLContext.c b/native/com_wolfssl_WolfSSLContext.c index f06912db..6936e879 100644 --- a/native/com_wolfssl_WolfSSLContext.c +++ b/native/com_wolfssl_WolfSSLContext.c @@ -3223,7 +3223,12 @@ int NativeDecryptVerifyCb(WOLFSSL* ssl, unsigned char* decOut, } return -1; } - *padSz = (unsigned int)tmpVal; + /* Reject negative and too large padSz values */ + if ((tmpVal < 0) || (tmpVal > (jlong)decSz)) { + retval = -1; + } else { + *padSz = (unsigned int)tmpVal; + } } /* delete local refs, detach JNIEnv from thread */ @@ -3533,7 +3538,12 @@ int NativeVerifyDecryptCb(WOLFSSL* ssl, unsigned char* decOut, } return -1; } - *padSz = (unsigned int)tmpVal; + /* Reject negative and too large padSz values */ + if ((tmpVal < 0) || (tmpVal > (jlong)decSz)) { + retval = -1; + } else { + *padSz = (unsigned int)tmpVal; + } } /* delete local refs, detach JNIEnv from thread */ @@ -5537,6 +5547,11 @@ int NativeRsaVerifyCb(WOLFSSL* ssl, unsigned char* sig, unsigned int sigSz, return -1; } + if ((retval > 0) && ((unsigned int)retval > sigSz)) { + /* wolfSSL uses positive return as the output length */ + retval = -1; + } + /* point out* to the beginning of our decrypted buffer */ if (retval > 0) *out = sig; @@ -5833,6 +5848,11 @@ int NativeRsaSignCheckCb(WOLFSSL* ssl, unsigned char* sig, unsigned int sigSz, return -1; } + if ((retval > 0) && ((unsigned int)retval > sigSz)) { + /* wolfSSL uses positive return as the output length */ + retval = -1; + } + /* point out* to the beginning of decrypted buffer */ if (retval > 0) { *out = sig; @@ -6070,6 +6090,11 @@ int NativeRsaPssSignCheckCb(WOLFSSL* ssl, unsigned char* sig, return -1; } + if ((retval > 0) && ((unsigned int)retval > sigSz)) { + /* wolfSSL uses positive return as the output length */ + retval = -1; + } + /* point out* to the beginning of decrypted buffer */ if (retval > 0) { *out = sig; @@ -6648,6 +6673,11 @@ int NativeRsaDecCb(WOLFSSL* ssl, unsigned char* in, unsigned int inSz, retval = -1; } + if ((retval > 0) && ((unsigned int)retval > inSz)) { + /* wolfSSL uses positive return as the output length */ + retval = -1; + } + /* point out* to the beginning of our decrypted buffer */ if (retval > 0) *out = in; diff --git a/native/com_wolfssl_WolfSSLSession.c b/native/com_wolfssl_WolfSSLSession.c index edea56d2..8d1525c7 100644 --- a/native/com_wolfssl_WolfSSLSession.c +++ b/native/com_wolfssl_WolfSSLSession.c @@ -7066,7 +7066,7 @@ int NativeSSLIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx) return WOLFSSL_CBIO_ERR_GENERAL; } - /* call Java send callback, ignore ctx since Java handles it */ + /* call Java receive callback, ignore ctx since Java handles it */ retval = (*jenv)->CallIntMethod(jenv, (jobject)(*g_cachedSSLObj), g_sslIORecvMethodId, (jobject)(*g_cachedSSLObj), inData, (jint)sz); diff --git a/src/java/com/wolfssl/WolfSSLByteBufferIORecvCallback.java b/src/java/com/wolfssl/WolfSSLByteBufferIORecvCallback.java index a9ae1d65..dfb9c0bf 100644 --- a/src/java/com/wolfssl/WolfSSLByteBufferIORecvCallback.java +++ b/src/java/com/wolfssl/WolfSSLByteBufferIORecvCallback.java @@ -50,6 +50,10 @@ public interface WolfSSLByteBufferIORecvCallback { * be read from the transport layer. The callback should read data and * place the data into the buffer provided. The number of bytes read should * be returned. The callback should return an error code on error. + *

+ * The buf ByteBuffer wraps native memory that is only valid + * until this method returns. Do not use it, or any duplicate or + * slice of it, after returning. * * @param ssl the current SSL session object from which the callback was * initiated. diff --git a/src/java/com/wolfssl/WolfSSLByteBufferIOSendCallback.java b/src/java/com/wolfssl/WolfSSLByteBufferIOSendCallback.java index bb7b071b..0a8dcb79 100644 --- a/src/java/com/wolfssl/WolfSSLByteBufferIOSendCallback.java +++ b/src/java/com/wolfssl/WolfSSLByteBufferIOSendCallback.java @@ -51,6 +51,10 @@ public interface WolfSSLByteBufferIOSendCallback { * The callback should send data from the provided ByteBuffer (buf) across * the transport layer. The number of bytes sent should be returned, or * a negative error code on error. + *

+ * The buf ByteBuffer wraps native memory that is only valid + * until this method returns. Do not use it, or any duplicate or + * slice of it, after returning. * * @param ssl the current SSL session object from which the callback was * initiated. diff --git a/src/java/com/wolfssl/WolfSSLDecryptVerifyCallback.java b/src/java/com/wolfssl/WolfSSLDecryptVerifyCallback.java index 1c4ef87f..81374fd9 100644 --- a/src/java/com/wolfssl/WolfSSLDecryptVerifyCallback.java +++ b/src/java/com/wolfssl/WolfSSLDecryptVerifyCallback.java @@ -42,6 +42,10 @@ public interface WolfSSLDecryptVerifyCallback { * Atomic record layer decrypt/verify callback method. * This method acts as the decrypt/verify callback to be used with * the wolfSSL atomic record layer processing. + *

+ * ByteBuffer arguments wrap native memory that is only valid until + * this method returns. Do not use them, or any duplicate or slice of + * them, after returning. * * @param ssl the current SSL session object from which the * callback was initiated. diff --git a/src/java/com/wolfssl/WolfSSLEccSharedSecretCallback.java b/src/java/com/wolfssl/WolfSSLEccSharedSecretCallback.java index 2a825c7c..8a3111a8 100644 --- a/src/java/com/wolfssl/WolfSSLEccSharedSecretCallback.java +++ b/src/java/com/wolfssl/WolfSSLEccSharedSecretCallback.java @@ -40,6 +40,10 @@ public interface WolfSSLEccSharedSecretCallback { /** * ECC shared secret callback method. * This method acts as ECC shared secret callback. + *

+ * The out buffer, and pubKeyDer on the client side, wrap + * native memory that is only valid until this method returns. Do not + * use them, or any duplicate or slice of them, after returning. * * @param ssl the current SSL session object from which the * callback was initiated. diff --git a/src/java/com/wolfssl/WolfSSLEccSignCallback.java b/src/java/com/wolfssl/WolfSSLEccSignCallback.java index cdc8b1b7..3ca77f90 100644 --- a/src/java/com/wolfssl/WolfSSLEccSignCallback.java +++ b/src/java/com/wolfssl/WolfSSLEccSignCallback.java @@ -40,6 +40,10 @@ public interface WolfSSLEccSignCallback { /** * ECC signing callback method. * This method acts as ECC signing callback. + *

+ * ByteBuffer arguments wrap native memory that is only valid until + * this method returns. Do not use them, or any duplicate or slice of + * them, after returning. * * @param ssl the current SSL session object from which the * callback was initiated. diff --git a/src/java/com/wolfssl/WolfSSLEccVerifyCallback.java b/src/java/com/wolfssl/WolfSSLEccVerifyCallback.java index 270e85b9..75f10491 100644 --- a/src/java/com/wolfssl/WolfSSLEccVerifyCallback.java +++ b/src/java/com/wolfssl/WolfSSLEccVerifyCallback.java @@ -40,6 +40,10 @@ public interface WolfSSLEccVerifyCallback { /** * ECC verification callback method. * This method acts as ECC verification callback. + *

+ * ByteBuffer arguments wrap native memory that is only valid until + * this method returns. Do not use them, or any duplicate or slice of + * them, after returning. * * @param ssl the current SSL session object from which the * callback was initiated. diff --git a/src/java/com/wolfssl/WolfSSLMacEncryptCallback.java b/src/java/com/wolfssl/WolfSSLMacEncryptCallback.java index 59abcc1e..a3411fd6 100644 --- a/src/java/com/wolfssl/WolfSSLMacEncryptCallback.java +++ b/src/java/com/wolfssl/WolfSSLMacEncryptCallback.java @@ -42,6 +42,10 @@ public interface WolfSSLMacEncryptCallback { * Atomic record layer MAC Encrypt callback method. * This method acts as the Atomic User Record Processing Mac/Encrypt * callback to be used with the wolfSSL atomic record layer processing. + *

+ * ByteBuffer arguments wrap native memory that is only valid until + * this method returns. Do not use them, or any duplicate or slice of + * them, after returning. * * @param ssl the current SSL session object from which the * callback was initiated. diff --git a/src/java/com/wolfssl/WolfSSLRsaDecCallback.java b/src/java/com/wolfssl/WolfSSLRsaDecCallback.java index 4eb222f3..1eae1d64 100644 --- a/src/java/com/wolfssl/WolfSSLRsaDecCallback.java +++ b/src/java/com/wolfssl/WolfSSLRsaDecCallback.java @@ -40,6 +40,10 @@ public interface WolfSSLRsaDecCallback { /** * RSA private decrypt callback method. * This method acts as RSA private decrypt callback. + *

+ * ByteBuffer arguments wrap native memory that is only valid until + * this method returns. Do not use them, or any duplicate or slice of + * them, after returning. * * @param ssl the current SSL session object from which the * callback was initiated. diff --git a/src/java/com/wolfssl/WolfSSLRsaEncCallback.java b/src/java/com/wolfssl/WolfSSLRsaEncCallback.java index 83a7e673..cd55d281 100644 --- a/src/java/com/wolfssl/WolfSSLRsaEncCallback.java +++ b/src/java/com/wolfssl/WolfSSLRsaEncCallback.java @@ -40,6 +40,10 @@ public interface WolfSSLRsaEncCallback { /** * RSA public encrypt callback method. * This method acts as RSA public enrypt callback. + *

+ * ByteBuffer arguments wrap native memory that is only valid until + * this method returns. Do not use them, or any duplicate or slice of + * them, after returning. * * @param ssl the current SSL session object from which the * callback was initiated. diff --git a/src/java/com/wolfssl/WolfSSLRsaPssSignCallback.java b/src/java/com/wolfssl/WolfSSLRsaPssSignCallback.java index fe672f7c..0f15af2a 100644 --- a/src/java/com/wolfssl/WolfSSLRsaPssSignCallback.java +++ b/src/java/com/wolfssl/WolfSSLRsaPssSignCallback.java @@ -40,6 +40,10 @@ public interface WolfSSLRsaPssSignCallback { /** * RSA-PSS signing callback method. * This method acts as RSA-PSS signing callback. + *

+ * ByteBuffer arguments wrap native memory that is only valid until + * this method returns. Do not use them, or any duplicate or slice of + * them, after returning. * * @param ssl the current SSL session object from which the callback was * initiated. diff --git a/src/java/com/wolfssl/WolfSSLRsaPssVerifyCallback.java b/src/java/com/wolfssl/WolfSSLRsaPssVerifyCallback.java index a1142988..2631a016 100644 --- a/src/java/com/wolfssl/WolfSSLRsaPssVerifyCallback.java +++ b/src/java/com/wolfssl/WolfSSLRsaPssVerifyCallback.java @@ -40,6 +40,10 @@ public interface WolfSSLRsaPssVerifyCallback { /** * RSA-PSS verification callback method. * This method acts as RSA-PSS verification callback. + *

+ * ByteBuffer arguments wrap native memory that is only valid until + * this method returns. Do not use them, or any duplicate or slice of + * them, after returning. * * @param ssl the current SSL session object from which the callback * was initiated. diff --git a/src/java/com/wolfssl/WolfSSLRsaSignCallback.java b/src/java/com/wolfssl/WolfSSLRsaSignCallback.java index 0c452049..90eb342c 100644 --- a/src/java/com/wolfssl/WolfSSLRsaSignCallback.java +++ b/src/java/com/wolfssl/WolfSSLRsaSignCallback.java @@ -40,6 +40,10 @@ public interface WolfSSLRsaSignCallback { /** * RSA signing callback method. * This method acts as RSA signing callback. + *

+ * ByteBuffer arguments wrap native memory that is only valid until + * this method returns. Do not use them, or any duplicate or slice of + * them, after returning. * * @param ssl the current SSL session object from which the * callback was initiated. diff --git a/src/java/com/wolfssl/WolfSSLRsaVerifyCallback.java b/src/java/com/wolfssl/WolfSSLRsaVerifyCallback.java index 9ab84793..6dce5290 100644 --- a/src/java/com/wolfssl/WolfSSLRsaVerifyCallback.java +++ b/src/java/com/wolfssl/WolfSSLRsaVerifyCallback.java @@ -40,6 +40,10 @@ public interface WolfSSLRsaVerifyCallback { /** * RSA verification callback method. * This method acts as RSA verification callback. + *

+ * ByteBuffer arguments wrap native memory that is only valid until + * this method returns. Do not use them, or any duplicate or slice of + * them, after returning. * * @param ssl the current SSL session object from which the * callback was initiated. diff --git a/src/java/com/wolfssl/WolfSSLVerifyDecryptCallback.java b/src/java/com/wolfssl/WolfSSLVerifyDecryptCallback.java index da983346..06920f16 100644 --- a/src/java/com/wolfssl/WolfSSLVerifyDecryptCallback.java +++ b/src/java/com/wolfssl/WolfSSLVerifyDecryptCallback.java @@ -43,6 +43,10 @@ public interface WolfSSLVerifyDecryptCallback { * Atomic record layer verify/decrypt callback method. * This method acts as the verify/decrypt callback to be used with * the wolfSSL atomic record layer processing. + *

+ * ByteBuffer arguments wrap native memory that is only valid until + * this method returns. Do not use them, or any duplicate or slice of + * them, after returning. * * @param ssl the current SSL session object from which the * callback was initiated. diff --git a/src/test/com/wolfssl/test/WolfSSLContextTest.java b/src/test/com/wolfssl/test/WolfSSLContextTest.java index 62e27370..16c0fc37 100644 --- a/src/test/com/wolfssl/test/WolfSSLContextTest.java +++ b/src/test/com/wolfssl/test/WolfSSLContextTest.java @@ -37,7 +37,10 @@ import java.net.Socket; import java.net.ServerSocket; import java.nio.ByteBuffer; +import javax.crypto.Cipher; import javax.crypto.KeyAgreement; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -69,6 +72,8 @@ import com.wolfssl.WolfSSLRsaPssVerifyCallback; import com.wolfssl.WolfSSLRsaEncCallback; import com.wolfssl.WolfSSLRsaDecCallback; +import com.wolfssl.WolfSSLDecryptVerifyCallback; +import com.wolfssl.WolfSSLVerifyDecryptCallback; import com.wolfssl.WolfCryptRSA; import com.wolfssl.WolfCryptECC; import com.wolfssl.WolfCryptEccKey; @@ -1476,9 +1481,10 @@ public void test_WolfSSLContext_rsaCbHandshake() { } } - /* Accept or connect until the handshake finishes, returns final ret */ - private static int pkCbHandshakeLoop(WolfSSLSession ses, boolean client) - throws Exception { + /* Accept or connect until the handshake finishes, returns + * { final ret, error code } */ + private static int[] pkCbHandshakeLoop(WolfSSLSession ses, + boolean client) throws Exception { int ret; int err; @@ -1488,23 +1494,24 @@ private static int pkCbHandshakeLoop(WolfSSLSession ses, boolean client) } while (ret != WolfSSL.SSL_SUCCESS && (err == WolfSSL.SSL_ERROR_WANT_READ || err == WolfSSL.SSL_ERROR_WANT_WRITE)); - return ret; + return new int[] { ret, err }; } - /* Run one localhost handshake, returns { accept() ret, connect() ret } */ + /* Run one localhost handshake, returns { accept() ret, connect() ret, + * server error, client error } */ private int[] runPkCbHandshake(final WolfSSLContext srvCtx, WolfSSLContext cliCtx) throws Exception { ServerSocket srvSocket = null; ExecutorService es = null; - int cliRet; + int[] cliRet; try { srvSocket = new ServerSocket(0); srvSocket.setSoTimeout(10000); final ServerSocket fSrvSock = srvSocket; es = Executors.newSingleThreadExecutor(); - Future srv = es.submit(() -> { + Future srv = es.submit(() -> { try (Socket sock = fSrvSock.accept()) { sock.setSoTimeout(10000); WolfSSLSession ses = new WolfSSLSession(srvCtx); @@ -1534,7 +1541,8 @@ private int[] runPkCbHandshake(final WolfSSLContext srvCtx, ses.freeSSL(); } } - return new int[] { srv.get(10, TimeUnit.SECONDS), cliRet }; + int[] srvRet = srv.get(10, TimeUnit.SECONDS); + return new int[] { srvRet[0], cliRet[0], srvRet[1], cliRet[1] }; } finally { if (es != null) { es.shutdownNow(); @@ -1739,6 +1747,253 @@ public int rsaDecCallback(WolfSSLSession ssl, } } + /* RSA verify callback returning a length larger than the signature + * buffer must be rejected in JNI. wolfSSL keeps only the low 16 bits of + * the length, so 65536 plus the real length would otherwise pass */ + @Test + public void test_WolfSSLContext_rsaVerifyCbOversizedReturn() + throws Exception { + + Assume.assumeTrue(WolfSSL.RsaEnabled() && WolfSSL.FileSystemEnabled()); + + final boolean[] called = new boolean[1]; + final int[] verifyRet = { -1 }; + WolfSSLContext srvCtx = null; + WolfSSLContext cliCtx = null; + + try { + srvCtx = createCtx(svrCert, svrKey, caCert, + WolfSSL.TLSv1_2_ServerMethod()); + cliCtx = createCtx(cliCert, cliKey, caCert, + WolfSSL.TLSv1_2_ClientMethod()); + if (WolfSSL.RsaPssEnabled()) { + /* Server must sign PKCS#1 v1.5 to reach this callback */ + Assume.assumeTrue("set1SigAlgsList() not compiled in", + srvCtx.set1SigAlgsList("RSA+SHA256") == + WolfSSL.SSL_SUCCESS); + } + try { + cliCtx.setRsaVerifyCb(new WolfSSLRsaVerifyCallback() { + public int rsaVerifyCallback(WolfSSLSession ssl, + ByteBuffer sig, long sigSz, ByteBuffer out, + long outSz, ByteBuffer keyDer, long keySz, + Object ctx) { + called[0] = true; + verifyRet[0] = new WolfCryptRSA().doVerify(sig, + sigSz, out, outSz, keyDer, keySz); + if (verifyRet[0] <= 0) { + return verifyRet[0]; + } + return (1 << 16) + verifyRet[0]; + } + }); + } catch (WolfSSLJNIException e) { + assumePkCallbacks(e); + } + + /* Skip cert check so only ServerKeyExchange calls verify cb */ + cliCtx.setVerify(WolfSSL.SSL_VERIFY_NONE, null); + int[] ret = runPkCbHandshake(srvCtx, cliCtx); + + assertTrue("RSA verify cb not called", called[0]); + assertTrue("RSA verify failed: " + verifyRet[0], verifyRet[0] > 0); + assertTrue("client connect() should fail", + ret[1] != WolfSSL.SSL_SUCCESS); + assertEquals("oversized return reached wolfSSL", + WolfSSL.SSL_FATAL_ERROR, ret[3]); + } finally { + if (cliCtx != null) { + cliCtx.free(); + } + if (srvCtx != null) { + srvCtx.free(); + } + } + } + + /* RSA sign check callbacks returning a length larger than the signature + * buffer must be rejected in JNI, not as a signature fault in wolfSSL */ + @Test + public void test_WolfSSLContext_rsaSignCheckCbOversizedReturn() + throws Exception { + + Assume.assumeTrue(WolfSSL.RsaEnabled() && WolfSSL.FileSystemEnabled()); + + for (final boolean pss : new boolean[] { false, true }) { + if (pss && !WolfSSL.RsaPssEnabled()) { + continue; + } + final boolean[] called = new boolean[1]; + WolfSSLContext srvCtx = null; + WolfSSLContext cliCtx = null; + + try { + srvCtx = createCtx(svrCert, svrKey, caCert, + WolfSSL.TLSv1_2_ServerMethod()); + cliCtx = createCtx(cliCert, cliKey, caCert, + WolfSSL.TLSv1_2_ClientMethod()); + if (!pss && WolfSSL.RsaPssEnabled() && + srvCtx.set1SigAlgsList("RSA+SHA256") != + WolfSSL.SSL_SUCCESS) { + /* cannot force PKCS#1 v1.5, the PSS pass still runs */ + continue; + } + try { + if (pss) { + srvCtx.setRsaPssSignCheckCb( + new WolfSSLRsaPssVerifyCallback() { + public int rsaPssVerifyCallback( + WolfSSLSession ssl, ByteBuffer sig, + long sigSz, ByteBuffer out, long outSz, + int hash, int mgf, ByteBuffer keyDer, + long keySz, Object ctx) { + called[0] = true; + return (int)sigSz + 1; + } + }); + } + else { + srvCtx.setRsaSignCheckCb( + new WolfSSLRsaVerifyCallback() { + public int rsaVerifyCallback(WolfSSLSession ssl, + ByteBuffer sig, long sigSz, ByteBuffer out, + long outSz, ByteBuffer keyDer, long keySz, + Object ctx) { + called[0] = true; + return (int)sigSz + 1; + } + }); + } + } catch (WolfSSLJNIException e) { + assumePkCallbacks(e); + } + + int[] ret = runPkCbHandshake(srvCtx, cliCtx); + + assertTrue("sign check cb not called, pss=" + pss, called[0]); + assertTrue("server accept() should fail, pss=" + pss, + ret[0] != WolfSSL.SSL_SUCCESS); + assertEquals("oversized return reached wolfSSL, pss=" + pss, + WolfSSL.SSL_FATAL_ERROR, ret[2]); + } finally { + if (cliCtx != null) { + cliCtx.free(); + } + if (srvCtx != null) { + srvCtx.free(); + } + } + } + } + + /* Atomic decrypt callbacks setting a padding size outside the record + * must be rejected in JNI. The jlong is narrowed to unsigned int, so + * 2^32 plus the real size would otherwise pass */ + @Test + public void test_WolfSSLContext_decryptVerifyCbOversizedPadSz() + throws Exception { + + Assume.assumeTrue(WolfSSL.RsaEnabled() && WolfSSL.FileSystemEnabled()); + Assume.assumeTrue("ATOMIC_USER not compiled in", + WolfSSL.isEnabledAtomicUser() == 1); + + /* 0: real padding, 1: 2^32 plus real padding, 2: negative */ + for (final int mode : new int[] { 0, 1, 2 }) { + final boolean[] called = new boolean[2]; + WolfSSLContext srvCtx = null; + WolfSSLContext cliCtx = null; + + try { + srvCtx = createCtx(svrCert, svrKey, caCert, + WolfSSL.TLSv1_2_ServerMethod()); + cliCtx = createCtx(cliCert, cliKey, caCert, + WolfSSL.TLSv1_2_ClientMethod()); + /* The callbacks below only decrypt AES-CBC */ + Assume.assumeTrue("no AES-CBC cipher suite", + cliCtx.setCipherList("ECDHE-RSA-AES128-SHA256:" + + "ECDHE-RSA-AES256-SHA384") == WolfSSL.SSL_SUCCESS); + + /* With encrypt-then-MAC negotiated wolfSSL calls + * verify/decrypt and leaves the MAC out of decSz, + * otherwise it calls decrypt/verify */ + cliCtx.setDecryptVerifyCb(new WolfSSLDecryptVerifyCallback() { + public int decryptVerifyCallback(WolfSSLSession ssl, + ByteBuffer decOut, byte[] decIn, long decSz, + int content, int verify, long[] padSz, Object ctx) { + called[0] = true; + return cbcDecryptForTest(ssl, decOut, decIn, decSz, + true, mode, padSz); + } + }); + cliCtx.setVerifyDecryptCb(new WolfSSLVerifyDecryptCallback() { + public int verifyDecryptCallback(WolfSSLSession ssl, + ByteBuffer decOut, byte[] decIn, long decSz, + int content, int macVerify, long[] padSz, + Object ctx) { + called[1] = true; + return cbcDecryptForTest(ssl, decOut, decIn, decSz, + false, mode, padSz); + } + }); + + int[] ret = runPkCbHandshake(srvCtx, cliCtx); + + assertTrue("atomic decrypt cb not called, mode=" + mode, + called[0] || called[1]); + if (mode == 0) { + assertEquals("client connect() failed, mode=0", + WolfSSL.SSL_SUCCESS, ret[1]); + } else { + assertTrue("client connect() should fail, mode=" + mode, + ret[1] != WolfSSL.SSL_SUCCESS); + assertEquals("bad padSz reached wolfSSL, mode=" + mode, + WolfSSL.SSL_FATAL_ERROR, ret[3]); + } + } finally { + if (cliCtx != null) { + cliCtx.free(); + } + if (srvCtx != null) { + srvCtx.free(); + } + } + } + } + + /* Decrypt one AES-CBC record without checking the MAC. decIn starts with + * the explicit IV, which wolfSSL discards after the callback. padSz gets + * the real padding size adjusted for mode */ + private static int cbcDecryptForTest(WolfSSLSession ssl, + ByteBuffer decOut, byte[] decIn, long decSz, boolean withMac, + int mode, long[] padSz) { + + try { + int blockSz = ssl.getCipherBlockSize(); + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, + new SecretKeySpec(ssl.getServerWriteKey(), "AES"), + new IvParameterSpec(decIn, 0, blockSz)); + byte[] plain = cipher.doFinal(decIn, blockSz, + (int)decSz - blockSz); + decOut.position(blockSz); + decOut.put(plain); + + long pad = (plain[plain.length - 1] & 0xFF) + 1; + if (withMac) { + pad += ssl.getHmacSize(); + } + if (mode == 1) { + pad += (1L << 32); + } else if (mode == 2) { + pad = -1; + } + padSz[0] = pad; + return 0; + } catch (Exception e) { + return -1; + } + } + /* ECC sign callback reporting a signature longer than the out buffer * must fail before wolfSSL sends it to the peer */ @Test