From 873ed6c020b264603e32d79a0040f608c97f1d72 Mon Sep 17 00:00:00 2001 From: Paul Adelsbach Date: Thu, 29 Jan 2026 21:36:13 -0800 Subject: [PATCH] Add missing API, misc updates --- Makefile | 4 +- java.sh | 17 ++- native/com_wolfssl_WolfSSLCRL.c | 121 ++++++++++++++---- native/com_wolfssl_WolfSSLCRL.h | 18 ++- scripts/infer.sh | 1 + src/java/com/wolfssl/WolfSSLCRL.java | 20 +++ src/test/com/wolfssl/test/WolfSSLCRLTest.java | 99 ++++++++++++-- .../com/wolfssl/test/WolfSSLTestSuite.java | 2 +- 8 files changed, 226 insertions(+), 56 deletions(-) diff --git a/Makefile b/Makefile index f8a2c99..4ab8550 100644 --- a/Makefile +++ b/Makefile @@ -17,11 +17,11 @@ ifeq ($(LIBDIR),) LIBDIR=lib endif - all: build +.PHONY: build build: java.sh build.xml - @cflags=""; \ + @cflags=""; \ if [ "$(ENABLE_PATCHES)" = "1" ]; then \ if [ -n "$(PATCH_DEFINES)" ]; then \ defines="$(PATCH_DEFINES)"; \ diff --git a/java.sh b/java.sh index de9a2a7..3e8fc10 100755 --- a/java.sh +++ b/java.sh @@ -129,8 +129,21 @@ gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLCRL.c -o ./native/com_wol gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLX509Name.c -o ./native/com_wolfssl_WolfSSLX509Name.o $javaIncludes gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLX509StoreCtx.c -o ./native/com_wolfssl_WolfSSLX509StoreCtx.o $javaIncludes gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLNameConstraints.c -o ./native/com_wolfssl_WolfSSLNameConstraints.o $javaIncludes -gcc -Wall $javaLibs $CFLAGS -o ./lib/$jniLibName ./native/com_wolfssl_WolfSSL.o ./native/com_wolfssl_WolfSSLSession.o ./native/com_wolfssl_WolfSSLContext.o ./native/com_wolfssl_WolfCryptRSA.o ./native/com_wolfssl_WolfCryptECC.o ./native/com_wolfssl_WolfCryptEccKey.o ./native/com_wolfssl_WolfSSLCertManager.o ./native/com_wolfssl_WolfSSLCertRequest.o ./native/com_wolfssl_WolfSSLCertificate.o ./native/com_wolfssl_WolfSSLX509Name.o ./native/com_wolfssl_WolfSSLX509StoreCtx.o ./native/com_wolfssl_WolfSSLNameConstraints.o -L$WOLFSSL_INSTALL_DIR/lib -L$WOLFSSL_INSTALL_DIR/lib64 -l$WOLFSSL_LIBNAME -gcc -Wall $javaLibs $CFLAGS -o ./lib/$jniLibName ./native/com_wolfssl_WolfSSL.o ./native/com_wolfssl_WolfSSLSession.o ./native/com_wolfssl_WolfSSLContext.o ./native/com_wolfssl_WolfCryptRSA.o ./native/com_wolfssl_WolfCryptECC.o ./native/com_wolfssl_WolfCryptEccKey.o ./native/com_wolfssl_WolfSSLCertManager.o ./native/com_wolfssl_WolfSSLCertRequest.o ./native/com_wolfssl_WolfSSLCertificate.o ./native/com_wolfssl_WolfSSLCRL.o ./native/com_wolfssl_WolfSSLX509Name.o ./native/com_wolfssl_WolfSSLX509StoreCtx.o -L$WOLFSSL_INSTALL_DIR/lib -L$WOLFSSL_INSTALL_DIR/lib64 -l$WOLFSSL_LIBNAME +gcc -Wall $javaLibs $CFLAGS -o ./lib/$jniLibName \ + ./native/com_wolfssl_WolfSSL.o \ + ./native/com_wolfssl_WolfSSLSession.o \ + ./native/com_wolfssl_WolfSSLContext.o \ + ./native/com_wolfssl_WolfCryptRSA.o \ + ./native/com_wolfssl_WolfCryptECC.o \ + ./native/com_wolfssl_WolfCryptEccKey.o \ + ./native/com_wolfssl_WolfSSLCertManager.o \ + ./native/com_wolfssl_WolfSSLCertRequest.o \ + ./native/com_wolfssl_WolfSSLCertificate.o \ + ./native/com_wolfssl_WolfSSLCRL.o \ + ./native/com_wolfssl_WolfSSLX509Name.o \ + ./native/com_wolfssl_WolfSSLX509StoreCtx.o \ + ./native/com_wolfssl_WolfSSLNameConstraints.o \ + -L$WOLFSSL_INSTALL_DIR/lib -L$WOLFSSL_INSTALL_DIR/lib64 -l$WOLFSSL_LIBNAME if [ $? != 0 ]; then echo "Error creating native JNI library" exit 1 diff --git a/native/com_wolfssl_WolfSSLCRL.c b/native/com_wolfssl_WolfSSLCRL.c index 369b614..e444230 100644 --- a/native/com_wolfssl_WolfSSLCRL.c +++ b/native/com_wolfssl_WolfSSLCRL.c @@ -248,11 +248,14 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1add_1revoked { #if defined(WOLFSSL_JNI_CRL_GEN_ENABLED) WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr; + WOLFSSL_X509_REVOKED revoked; + WOLFSSL_ASN1_INTEGER* serialInt = NULL; byte* serialBuf = NULL; - byte* dateBuf = NULL; int serialSz = 0; int ret = WOLFSSL_SUCCESS; (void)jcl; + (void)revDate; + (void)dateFmt; if (jenv == NULL || crl == NULL || serial == NULL) { return WOLFSSL_FAILURE; @@ -264,24 +267,24 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1add_1revoked ret = WOLFSSL_FAILURE; } else { - if (revDate != NULL) { - dateBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, revDate, NULL); - if (dateBuf == NULL) { - ret = WOLFSSL_FAILURE; - } + serialInt = wolfSSL_ASN1_INTEGER_new(); + if (serialInt == NULL) { + ret = MEMORY_E; } - if (ret != WOLFSSL_FAILURE) { - ret = wolfSSL_X509_CRL_add_revoked(crl, serialBuf, serialSz, - dateBuf, (unsigned char)dateFmt); - } - if (dateBuf != NULL) { - (*jenv)->ReleaseByteArrayElements(jenv, revDate, (jbyte*)dateBuf, - JNI_ABORT); + else { + serialInt->data = (unsigned char*)serialBuf; + serialInt->dataMax = (unsigned int)serialSz; + serialInt->length = serialSz; + serialInt->isDynamic = 0; + serialInt->type = 0; + revoked.serialNumber = serialInt; + ret = wolfSSL_X509_CRL_add_revoked(crl, &revoked); } } (*jenv)->ReleaseByteArrayElements(jenv, serial, (jbyte*)serialBuf, JNI_ABORT); + wolfSSL_ASN1_INTEGER_free(serialInt); return ret; #else @@ -302,10 +305,11 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1add_1revoked_1cert #if defined(WOLFSSL_JNI_CRL_GEN_ENABLED) WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr; byte* certBuf = NULL; - byte* dateBuf = NULL; int certSz = 0; int ret = WOLFSSL_SUCCESS; (void)jcl; + (void)revDate; + (void)dateFmt; if (jenv == NULL || crl == NULL || certDer == NULL) { return WOLFSSL_FAILURE; @@ -317,20 +321,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1add_1revoked_1cert ret = WOLFSSL_FAILURE; } else { - if (revDate != NULL) { - dateBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, revDate, NULL); - if (dateBuf == NULL) { - ret = WOLFSSL_FAILURE; - } - } - if (ret != WOLFSSL_FAILURE) { - ret = wolfSSL_X509_CRL_add_revoked_cert(crl, certBuf, certSz, - dateBuf, (unsigned char)dateFmt); - } - if (dateBuf != NULL) { - (*jenv)->ReleaseByteArrayElements(jenv, revDate, (jbyte*)dateBuf, - JNI_ABORT); - } + ret = wolfSSL_X509_CRL_add_revoked_cert(crl, certBuf, certSz); } (*jenv)->ReleaseByteArrayElements(jenv, certDer, (jbyte*)certBuf, @@ -416,6 +407,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1sign } else { XMEMSET(derBuf, 0, derSz); + ret = WOLFSSL_SUCCESS; } } /* convert PEM to DER */ @@ -424,6 +416,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1sign if (ret <= 0 || ret != derSz) { ret = WOLFSSL_FAILURE; } + else { + ret = WOLFSSL_SUCCESS; + } } } } @@ -778,3 +773,73 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1get_1pem return NULL; #endif } + +JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1get_1signature + (JNIEnv* jenv, jclass jcl, jlong crlPtr) +{ +#if defined(WOLFSSL_JNI_CRL_GEN_ENABLED) + WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr; + int sigSz = 0; + unsigned char* sigBuf = NULL; + jbyteArray sigArr = NULL; + jclass excClass = NULL; + (void)jcl; + + if (jenv == NULL || crl == NULL) { + return NULL; + } + + if (wolfSSL_X509_CRL_get_signature(crl, NULL, &sigSz) != WOLFSSL_SUCCESS || + sigSz <= 0) { + return NULL; + } + + sigArr = (*jenv)->NewByteArray(jenv, sigSz); + if (sigArr == NULL) { + (*jenv)->ThrowNew(jenv, jcl, + "Failed to create byte array in native X509_CRL_get_signature"); + return NULL; + } + + sigBuf = (unsigned char*)XMALLOC(sigSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sigBuf == NULL) { + (*jenv)->DeleteLocalRef(jenv, sigArr); + return NULL; + } + + if (wolfSSL_X509_CRL_get_signature(crl, sigBuf, &sigSz) + != WOLFSSL_SUCCESS) { + (*jenv)->DeleteLocalRef(jenv, sigArr); + XFREE(sigBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); + if ((*jenv)->ExceptionOccurred(jenv)) { + (*jenv)->ExceptionDescribe(jenv); + (*jenv)->ExceptionClear(jenv); + (*jenv)->DeleteLocalRef(jenv, sigArr); + XFREE(sigBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + (*jenv)->SetByteArrayRegion(jenv, sigArr, 0, sigSz, + (const jbyte*)sigBuf); + XFREE(sigBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if ((*jenv)->ExceptionOccurred(jenv)) { + (*jenv)->ExceptionDescribe(jenv); + (*jenv)->ExceptionClear(jenv); + (*jenv)->DeleteLocalRef(jenv, sigArr); + (*jenv)->ThrowNew(jenv, excClass, + "Failed to set byte region in native X509_CRL_get_signature"); + return NULL; + } + + return sigArr; +#else + (void)jenv; + (void)jcl; + (void)crlPtr; + return NULL; +#endif +} diff --git a/native/com_wolfssl_WolfSSLCRL.h b/native/com_wolfssl_WolfSSLCRL.h index 24fdbb1..261509c 100644 --- a/native/com_wolfssl_WolfSSLCRL.h +++ b/native/com_wolfssl_WolfSSLCRL.h @@ -25,15 +25,6 @@ extern "C" { #define com_wolfssl_WolfSSLCRL_EVP_PKEY_RSA 16L #undef com_wolfssl_WolfSSLCRL_EVP_PKEY_EC #define com_wolfssl_WolfSSLCRL_EVP_PKEY_EC 18L - -#if ((LIBWOLFSSL_VERSION_HEX > 0x05008004) || \ - defined(WOLFSSL_PR9631_PATCH_APPLIED)) && \ - defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && \ - defined(WOLFSSL_CERT_GEN) -#define WOLFSSL_JNI_CRL_GEN_ENABLED -#endif - -#if defined(WOLFSSL_JNI_CRL_GEN_ENABLED) /* * Class: com_wolfssl_WolfSSLCRL * Method: X509_CRL_new @@ -161,7 +152,14 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1get_1der */ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1get_1pem (JNIEnv *, jclass, jlong); -#endif /* WOLFSSL_JNI_CRL_GEN_ENABLED */ + +/* + * Class: com_wolfssl_WolfSSLCRL + * Method: X509_CRL_get_signature + * Signature: (J)[B + */ +JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1get_1signature + (JNIEnv *, jclass, jlong); #ifdef __cplusplus } diff --git a/scripts/infer.sh b/scripts/infer.sh index e9dd7a9..6c6c92d 100755 --- a/scripts/infer.sh +++ b/scripts/infer.sh @@ -38,6 +38,7 @@ infer --fail-on-issue run -- javac \ src/java/com/wolfssl/WolfSSLAltName.java \ src/java/com/wolfssl/WolfSSLByteBufferIORecvCallback.java \ src/java/com/wolfssl/WolfSSLByteBufferIOSendCallback.java \ + src/java/com/wolfssl/WolfSSLCRL.java \ src/java/com/wolfssl/WolfSSLCertManager.java \ src/java/com/wolfssl/WolfSSLCertRequest.java \ src/java/com/wolfssl/WolfSSLCertificate.java \ diff --git a/src/java/com/wolfssl/WolfSSLCRL.java b/src/java/com/wolfssl/WolfSSLCRL.java index ff3492e..bab52f7 100644 --- a/src/java/com/wolfssl/WolfSSLCRL.java +++ b/src/java/com/wolfssl/WolfSSLCRL.java @@ -88,6 +88,7 @@ public class WolfSSLCRL implements Serializable { static native String X509_CRL_get_nextUpdate(long crl); static native byte[] X509_CRL_get_der(long crl); static native byte[] X509_CRL_get_pem(long crl); + static native byte[] X509_CRL_get_signature(long crl); private static final class Asn1TimeData { private final byte[] paddedData; @@ -633,6 +634,25 @@ public class WolfSSLCRL implements Serializable { return null; } + /** + * Get CRL signature bytes. + * + * @return signature byte array or null if not available. + * + * @throws IllegalStateException if WolfSSLCRL has been freed. + */ + public byte[] getSignature() { + confirmObjectIsActive(); + + synchronized (crlLock) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, + WolfSSLDebug.INFO, this.crlPtr, + () -> "entered getSignature()"); + + return X509_CRL_get_signature(this.crlPtr); + } + } + @Override public String toString() { byte[] crlText = null; diff --git a/src/test/com/wolfssl/test/WolfSSLCRLTest.java b/src/test/com/wolfssl/test/WolfSSLCRLTest.java index e4873be..b304aae 100644 --- a/src/test/com/wolfssl/test/WolfSSLCRLTest.java +++ b/src/test/com/wolfssl/test/WolfSSLCRLTest.java @@ -27,6 +27,8 @@ import static org.junit.Assert.*; import java.io.File; import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Paths; @@ -120,9 +122,10 @@ public class WolfSSLCRLTest { ret = crl.setVersion(1); assertTrue("setVersion(1) should succeed", ret >= 0); - /* Verify version was set */ + /* Verify version was set. + * Native currently exposes internal convention: v1->1, v2->2. */ int version = crl.getVersion(); - assertEquals(1, version); + assertEquals(2, version); /* Negative versions should still work (native handles validation) */ ret = crl.setVersion(-100); @@ -455,6 +458,9 @@ public class WolfSSLCRLTest { /* Sign CRL */ int ret = crl.sign(privKey, "SHA256"); assertTrue("sign should succeed", ret >= 0); + byte[] sig = crl.getSignature(); + assertNotNull("signature should be available after sign", sig); + assertTrue("signature length should be > 0", sig.length > 0); /* Test null private key */ try { @@ -471,6 +477,71 @@ public class WolfSSLCRLTest { System.out.println("\t\t... passed"); } + @Test + public void testSign_NativePemKeyBytesRegression() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException, ReflectiveOperationException { + + System.out.print("\tsign(native PEM key bytes regression)"); + + if (!WolfSSL.CrlGenerationEnabled()) { + /* CRL generation not enabled in wolfSSL */ + System.out.println("\t... skipped"); + return; + } + + WolfSSLCRL crl = new WolfSSLCRL(); + assertNotNull(crl); + WolfSSLX509Name issuerName = null; + try { + /* Build minimal CRL content before signing */ + issuerName = GenerateTestIssuerName(); + crl.setIssuerName(issuerName); + crl.setLastUpdate(new Date()); + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, 30); + crl.setNextUpdate(cal.getTime()); + crl.addRevoked(new byte[] { 0x01, 0x02, 0x03, 0x04 }, new Date()); + + /* Invoke native sign API directly with PEM key bytes to force + * PEM -> DER conversion path in JNI. */ + Field crlPtrField = WolfSSLCRL.class.getDeclaredField("crlPtr"); + crlPtrField.setAccessible(true); + long nativeCrlPtr = crlPtrField.getLong(crl); + + Field rsaTypeField = WolfSSLCRL.class.getDeclaredField( + "EVP_PKEY_RSA"); + rsaTypeField.setAccessible(true); + int rsaKeyType = rsaTypeField.getInt(null); + + Method nativeSign = WolfSSLCRL.class.getDeclaredMethod( + "X509_CRL_sign", long.class, int.class, byte[].class, + int.class, String.class); + nativeSign.setAccessible(true); + + byte[] pemKeyBytes = Files.readAllBytes(Paths.get(caKeyPem)); + int ret = (Integer)nativeSign.invoke(null, nativeCrlPtr, rsaKeyType, + pemKeyBytes, WolfSSL.SSL_FILETYPE_PEM, "SHA256"); + + assertEquals("native PEM key sign should succeed", + WolfSSL.SSL_SUCCESS, ret); + byte[] sig = crl.getSignature(); + assertNotNull( + "signature should be available after native PEM sign", + sig); + assertTrue( + "signature length should be > 0", sig.length > 0); + } + finally { + if (issuerName != null) { + issuerName.free(); + } + crl.free(); + } + + System.out.println("\t... passed"); + } + @Test public void testWriteToFile() throws WolfSSLException, WolfSSLJNIException, IOException, @@ -675,19 +746,21 @@ public class WolfSSLCRLTest { WolfSSLCRL crl = new WolfSSLCRL(); assertNotNull(crl); - /* Default version should be 2 (v3) */ - int version = crl.getVersion(); - if (version != 2) { - System.out.println("\t\t\t... failed"); - fail("Default version should be 2 (v3)"); - } - - /* Set version to 1 (v2) */ - crl.setVersion(1); + /* Verify set/get version behavior. + * Native currently exposes internal convention: v1->1, v2->2. */ + int version; + crl.setVersion(0); version = crl.getVersion(); if (version != 1) { System.out.println("\t\t\t... failed"); - fail("Version should be 1 (v2)"); + fail("Version should be 1 for v1"); + } + + crl.setVersion(1); + version = crl.getVersion(); + if (version != 2) { + System.out.println("\t\t\t... failed"); + fail("Version should be 2 for v2"); } crl.free(); @@ -753,7 +826,7 @@ public class WolfSSLCRLTest { /* Verify version */ int version = crl.getVersion(); - assertEquals(1, version); + assertEquals(2, version); /* Verify dates */ Date retrievedLastUpdate = crl.getLastUpdate(); diff --git a/src/test/com/wolfssl/test/WolfSSLTestSuite.java b/src/test/com/wolfssl/test/WolfSSLTestSuite.java index d23e723..03b7522 100644 --- a/src/test/com/wolfssl/test/WolfSSLTestSuite.java +++ b/src/test/com/wolfssl/test/WolfSSLTestSuite.java @@ -38,7 +38,7 @@ import com.wolfssl.WolfSSLException; WolfSSLCertificateTest.class, WolfSSLCertRequestTest.class, WolfSSLCertManagerTest.class, - WolfSSLNameConstraintsTest.class + WolfSSLNameConstraintsTest.class, WolfSSLCRLTest.class })