Merge pull request #394 from cconlon/fenrirAug10

Fix native return code handling in cert cache save, I/O recv callback, and sign wrappers
pull/398/head
Ruby Martin 2026-08-13 17:14:38 -05:00 committed by GitHub
commit 2a84779fbb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 348 additions and 37 deletions

View File

@ -451,11 +451,12 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1sign
}
}
/* sign WOLFSSL_X509_CRL with WOLFSSL_EVP_PKEY, returns size of signature
* on success or negative on error */
/* sign WOLFSSL_X509_CRL with WOLFSSL_EVP_PKEY, wolfSSL_X509_CRL_sign()
* returns WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE (0) or negative
* code on error */
if (ret == WOLFSSL_SUCCESS) {
ret = wolfSSL_X509_CRL_sign(crl, priv, md);
if (ret >= 0) {
if (ret > 0) {
ret = WOLFSSL_SUCCESS;
}
}

View File

@ -327,13 +327,16 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1sign
}
}
/* sign WOLFSSL_X509 with WOLFSSL_EVP_PKEY, returns size of signature
* on success or negative on error */
/* sign X509 REQ with WOLFSSL_EVP_PKEY, wolfSSL_X509_REQ_sign() returns
* WOLFSSL_SUCCESS on success or WOLFSSL_FAILURE (0) on error */
if (ret == WOLFSSL_SUCCESS) {
ret = wolfSSL_X509_REQ_sign(x509, priv, md);
if (ret >= 0) {
if (ret > 0) {
ret = WOLFSSL_SUCCESS;
}
else {
ret = WOLFSSL_FAILURE;
}
}
if (priv != NULL) {

View File

@ -975,13 +975,16 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1sign
ret = wolfSSL_X509_set_version(x509, 2L);
}
/* sign WOLFSSL_X509 with WOLFSSL_EVP_PKEY, returns size of signature
* on success or negative on error */
/* sign WOLFSSL_X509 with WOLFSSL_EVP_PKEY, wolfSSL_X509_sign() returns
* signature size on success or WOLFSSL_FAILURE (0) on error */
if (ret == WOLFSSL_SUCCESS) {
ret = wolfSSL_X509_sign(x509, priv, md);
if (ret >= 0) {
if (ret > 0) {
ret = WOLFSSL_SUCCESS;
}
else {
ret = WOLFSSL_FAILURE;
}
}
if (priv != NULL) {

View File

@ -935,13 +935,13 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_memsaveCertCache
{
#ifdef PERSIST_CERT_CACHE
int ret;
int usedTmp;
int usedTmp = 0;
unsigned char* memBuf = NULL;
WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr;
jclass excClass = NULL;
(void)jcl;
if (jenv == NULL || ctx == NULL || mem == NULL || sz <= 0) {
if (jenv == NULL || ctx == NULL || mem == NULL || used == NULL || sz <= 0) {
return (jint)BAD_FUNC_ARG;
}
@ -961,23 +961,16 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_memsaveCertCache
ret = wolfSSL_CTX_memsave_cert_cache(ctx, memBuf, (int)sz, &usedTmp);
/* set used value for return */
(*jenv)->SetIntArrayRegion(jenv, used, 0, 1, &usedTmp);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
/* only publish used and mem on success, usedTmp is not set on error */
if (ret == WOLFSSL_SUCCESS) {
/* fail if native reported size is outside memBuf bounds */
if ((usedTmp < 0) || (usedTmp > (int)sz)) {
XFREE(memBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return (jint)SSL_FAILURE;
}
XFREE(memBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
(*jenv)->ThrowNew(jenv, excClass,
"Failed to set array region in native memsaveCertCache");
return (jint)SSL_FAILURE;
}
/* set jbyteArray for return */
if (usedTmp >= 0) {
(*jenv)->SetByteArrayRegion(jenv, mem, 0, usedTmp, (jbyte*)memBuf);
/* set used value for return */
(*jenv)->SetIntArrayRegion(jenv, used, 0, 1, &usedTmp);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
@ -985,10 +978,26 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_memsaveCertCache
XFREE(memBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
(*jenv)->ThrowNew(jenv, excClass,
"Failed to set byte region in native memsaveCertCache");
"Failed to set array region in native memsaveCertCache");
return (jint)SSL_FAILURE;
}
/* set jbyteArray for return */
if (usedTmp > 0) {
(*jenv)->SetByteArrayRegion(jenv, mem, 0, usedTmp, (jbyte*)memBuf);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
XFREE(memBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
(*jenv)->ThrowNew(jenv, excClass,
"Failed to set byte region in native memsaveCertCache");
return (jint)SSL_FAILURE;
}
}
}
XFREE(memBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@ -1318,6 +1327,7 @@ int NativeIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
jobject ctxRef; /* WolfSSLContext object */
jclass innerCtxClass; /* WolfSSLContext class */
jmethodID recvCbMethodId; /* internalIORecvCallback ID */
jbyteArray inData;
if (!g_vm || !ssl || !buf || !ctx) {
@ -1429,10 +1439,17 @@ int NativeIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
return WOLFSSL_CBIO_ERR_GENERAL;
}
/* make sure cached recv callback method ID is not null */
if (!g_sslIORecvMethodId) {
/* call internal I/O recv callback */
recvCbMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass,
"internalIORecvCallback", "(Lcom/wolfssl/WolfSSLSession;[BI)I");
if (!recvCbMethodId) {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
(*jenv)->ThrowNew(jenv, excClass,
"Cached recv callback method ID is null in NativeIORecvCb");
"Error getting internalIORecvCallback method from JNI");
(*jenv)->DeleteLocalRef(jenv, ctxRef);
if (needsDetach)
(*g_vm)->DetachCurrentThread(g_vm);
return WOLFSSL_CBIO_ERR_GENERAL;
@ -1449,11 +1466,9 @@ int NativeIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
return WOLFSSL_CBIO_ERR_GENERAL;
}
/* call Java send callback, ignore native ctx since Java
* handles it */
retval = (*jenv)->CallIntMethod(jenv, ctxRef, g_sslIORecvMethodId,
(jobject)(*g_cachedSSLObj),
inData, (jint)sz);
/* call Java recv callback, ignore native ctx since Java handles it */
retval = (*jenv)->CallIntMethod(jenv, ctxRef, recvCbMethodId,
(jobject)(*g_cachedSSLObj), inData, (jint)sz);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);

View File

@ -466,7 +466,7 @@ public class WolfSSLCRLTest {
/* Sign CRL */
int ret = crl.sign(privKey, "SHA256");
assertTrue("sign should succeed", ret >= 0);
assertEquals("sign should succeed", WolfSSL.SSL_SUCCESS, ret);
byte[] sig = crl.getSignature();
assertNotNull("signature should be available after sign", sig);
assertTrue("signature length should be > 0", sig.length > 0);
@ -484,6 +484,27 @@ public class WolfSSLCRLTest {
crl.free();
}
@Test
public void testSignEmptyCrlFails()
throws WolfSSLException, WolfSSLJNIException,
NoSuchAlgorithmException {
Assume.assumeTrue(WolfSSL.CrlGenerationEnabled());
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair keyPair = kpg.generateKeyPair();
int ret = crl.sign(keyPair.getPrivate(), "SHA256");
assertEquals("sign of empty CRL should fail",
WolfSSL.BAD_FUNC_ARG, ret);
crl.free();
}
@Test
public void testSign_NativePemKeyBytesRegression()
throws WolfSSLException, WolfSSLJNIException, IOException,

View File

@ -618,6 +618,35 @@ public class WolfSSLCertRequestTest {
req.free();
}
@Test
public void testSignRequestFailureThrows()
throws WolfSSLException, WolfSSLJNIException, IOException {
Assume.assumeTrue(WolfSSL.certReqEnabled());
WolfSSLCertRequest req = new WolfSSLCertRequest();
assertNotNull(req);
WolfSSLX509Name subjectName = GenerateTestSubjectName();
assertNotNull(subjectName);
try {
req.setSubjectName(subjectName);
/* no public key set, native signing fails */
try {
req.signRequest(cliKeyDer, WolfSSL.RSAk,
WolfSSL.SSL_FILETYPE_ASN1, "SHA256");
fail("signRequest() should throw when native signing fails");
} catch (WolfSSLException expected) {
/* expected */
}
} finally {
subjectName.free();
req.free();
}
}
@Test
public void testGenCSR_UsingBuffers()
throws WolfSSLException, WolfSSLJNIException, IOException,

View File

@ -797,6 +797,43 @@ public class WolfSSLCertificateTest {
}
}
@Test
public void testCertSignFailureThrows()
throws WolfSSLException, WolfSSLJNIException, IOException {
WolfSSLCertificate x509 = null;
WolfSSLX509Name name = null;
if (WolfSSL.FileSystemEnabled() == false) {
return;
}
x509 = new WolfSSLCertificate();
name = new WolfSSLX509Name();
try {
Instant now = Instant.now();
x509.setNotBefore(Date.from(now));
x509.setNotAfter(Date.from(now.plus(Duration.ofDays(365))));
x509.setSerialNumber(BigInteger.valueOf(1123));
name.setCommonName("sign failure test");
x509.setSubjectName(name);
/* no public key set, native signing fails */
try {
x509.signCert(cliKeyDer, WolfSSL.RSAk,
WolfSSL.SSL_FILETYPE_ASN1, "SHA256");
fail("signCert() should throw when native signing fails");
} catch (WolfSSLException expected) {
/* expected */
}
} finally {
name.free();
x509.free();
}
}
/* Generate a self-signed cert with the given CN and an optional single
* SubjectAltName entry, return its DER encoding. */
private byte[] genIpTestCertDer(String cn, String sanValue, int sanType)

View File

@ -46,6 +46,8 @@ import java.util.concurrent.TimeUnit;
import com.wolfssl.WolfSSL;
import com.wolfssl.WolfSSLContext;
import com.wolfssl.WolfSSLException;
import com.wolfssl.WolfSSLIORecvCallback;
import com.wolfssl.WolfSSLIOSendCallback;
import com.wolfssl.WolfSSLJNIException;
import com.wolfssl.WolfSSLVerifyCallback;
import com.wolfssl.WolfSSLMissingCRLCallback;
@ -249,6 +251,206 @@ public class WolfSSLContextTest {
}
}
@Test
public void test_WolfSSLContext_memsaveCertCache()
throws WolfSSLException, WolfSSLJNIException {
int ret;
int sz;
int[] used = new int[1];
byte[] mem = null;
WolfSSLContext ctx2 = null;
if (WolfSSL.FileSystemEnabled() == false) {
return;
}
ret = ctx.loadVerifyLocations(caCert, null);
assertEquals(WolfSSL.SSL_SUCCESS, ret);
sz = ctx.getCertCacheMemsize();
if (sz == WolfSSL.NOT_COMPILED_IN) {
/* skip when PERSIST_CERT_CACHE is not compiled in */
return;
}
assertTrue(sz > 0);
/* undersized buffer returns BUFFER_E and leaves used untouched */
used[0] = -1;
ret = ctx.memsaveCertCache(new byte[1], 1, used);
assertEquals(WolfSSL.BUFFER_E, ret);
assertEquals(-1, used[0]);
/* null used array is rejected */
ret = ctx.memsaveCertCache(new byte[sz], sz, null);
assertEquals(WolfSSL.BAD_FUNC_ARG, ret);
/* correctly sized buffer saves cert cache */
mem = new byte[sz];
used[0] = 0;
ret = ctx.memsaveCertCache(mem, sz, used);
assertEquals(WolfSSL.SSL_SUCCESS, ret);
assertTrue(used[0] > 0 && used[0] <= sz);
/* saved cache restores into a new context */
ctx2 = new WolfSSLContext(WolfSSL.SSLv23_ServerMethod());
try {
ret = ctx2.memrestoreCertCache(mem, used[0]);
assertEquals(WolfSSL.SSL_SUCCESS, ret);
} finally {
ctx2.free();
}
}
/* in-memory byte queue connecting context level I/O callbacks */
class TestIOQueue {
private byte[] data = new byte[0];
synchronized void add(byte[] buf, int sz) {
byte[] tmp = new byte[data.length + sz];
System.arraycopy(data, 0, tmp, 0, data.length);
System.arraycopy(buf, 0, tmp, data.length, sz);
data = tmp;
}
synchronized int take(byte[] buf, int sz) {
byte[] tmp = null;
int n = Math.min(sz, data.length);
if (n == 0) {
return 0;
}
System.arraycopy(data, 0, buf, 0, n);
tmp = new byte[data.length - n];
System.arraycopy(data, n, tmp, 0, tmp.length);
data = tmp;
return n;
}
}
class TestCtxIOCallback implements WolfSSLIORecvCallback,
WolfSSLIOSendCallback {
private final TestIOQueue in;
private final TestIOQueue out;
TestCtxIOCallback(TestIOQueue in, TestIOQueue out) {
this.in = in;
this.out = out;
}
public int receiveCallback(WolfSSLSession ssl, byte[] buf, int sz,
Object ctx) {
int n = in.take(buf, sz);
if (n == 0) {
return WolfSSL.WOLFSSL_CBIO_ERR_WANT_READ;
}
return n;
}
public int sendCallback(WolfSSLSession ssl, byte[] buf, int sz,
Object ctx) {
out.add(buf, sz);
return sz;
}
}
@Test
public void test_WolfSSLContext_ioRecvSendCallbacks() throws Exception {
int cliRet = WolfSSL.SSL_FAILURE;
int srvRet = WolfSSL.SSL_FAILURE;
int cliErr = 0;
int srvErr = 0;
int i;
WolfSSLContext srvCtx = null;
WolfSSLContext cliCtx = null;
WolfSSLSession server = null;
WolfSSLSession client = null;
TestIOQueue cliToSrv = new TestIOQueue();
TestIOQueue srvToCli = new TestIOQueue();
TestCtxIOCallback srvCb = new TestCtxIOCallback(cliToSrv, srvToCli);
TestCtxIOCallback cliCb = new TestCtxIOCallback(srvToCli, cliToSrv);
if (WolfSSL.FileSystemEnabled() == false) {
return;
}
try {
srvCtx = new WolfSSLContext(WolfSSL.SSLv23_ServerMethod());
cliCtx = new WolfSSLContext(WolfSSL.SSLv23_ClientMethod());
assertEquals(WolfSSL.SSL_SUCCESS, srvCtx.useCertificateFile(
svrCert, WolfSSL.SSL_FILETYPE_PEM));
assertEquals(WolfSSL.SSL_SUCCESS, srvCtx.usePrivateKeyFile(
svrKey, WolfSSL.SSL_FILETYPE_PEM));
assertEquals(WolfSSL.SSL_SUCCESS,
cliCtx.loadVerifyLocations(caCert, null));
/* register context level I/O callbacks before creating sessions
* so new sessions inherit them */
srvCtx.setIORecv(srvCb);
srvCtx.setIOSend(srvCb);
cliCtx.setIORecv(cliCb);
cliCtx.setIOSend(cliCb);
server = new WolfSSLSession(srvCtx);
client = new WolfSSLSession(cliCtx);
/* single threaded handshake, alternate client and server until
* both complete */
for (i = 0; i < 100; i++) {
if (cliRet != WolfSSL.SSL_SUCCESS) {
cliRet = client.connect();
cliErr = client.getError(cliRet);
if (cliRet != WolfSSL.SSL_SUCCESS &&
cliErr != WolfSSL.SSL_ERROR_WANT_READ &&
cliErr != WolfSSL.SSL_ERROR_WANT_WRITE) {
break;
}
}
if (srvRet != WolfSSL.SSL_SUCCESS) {
srvRet = server.accept();
srvErr = server.getError(srvRet);
if (srvRet != WolfSSL.SSL_SUCCESS &&
srvErr != WolfSSL.SSL_ERROR_WANT_READ &&
srvErr != WolfSSL.SSL_ERROR_WANT_WRITE) {
break;
}
}
if (cliRet == WolfSSL.SSL_SUCCESS &&
srvRet == WolfSSL.SSL_SUCCESS) {
break;
}
}
assertEquals("client connect over context I/O callbacks, " +
"error: " + cliErr, WolfSSL.SSL_SUCCESS, cliRet);
assertEquals("server accept over context I/O callbacks, " +
"error: " + srvErr, WolfSSL.SSL_SUCCESS, srvRet);
/* exchange application data through the callbacks */
byte[] msg = "hello callbacks".getBytes();
byte[] rcvd = new byte[msg.length];
assertEquals(msg.length, client.write(msg, msg.length));
assertEquals(msg.length, server.read(rcvd, rcvd.length));
assertArrayEquals(msg, rcvd);
} finally {
if (server != null) {
server.freeSSL();
}
if (client != null) {
client.freeSSL();
}
if (srvCtx != null) {
srvCtx.free();
}
if (cliCtx != null) {
cliCtx.free();
}
}
}
class TestPskClientCb implements WolfSSLPskClientCallback
{
public long pskClientCallback(WolfSSLSession ssl, String hint,