Add missing API, misc updates

pull/315/head
Paul Adelsbach 2026-01-29 21:36:13 -08:00
parent f53a19b1d7
commit 873ed6c020
8 changed files with 226 additions and 56 deletions

View File

@ -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)"; \

17
java.sh
View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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 \

View File

@ -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;

View File

@ -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();

View File

@ -38,7 +38,7 @@ import com.wolfssl.WolfSSLException;
WolfSSLCertificateTest.class,
WolfSSLCertRequestTest.class,
WolfSSLCertManagerTest.class,
WolfSSLNameConstraintsTest.class
WolfSSLNameConstraintsTest.class,
WolfSSLCRLTest.class
})