Add CRL generation capability

pull/315/head
Paul Adelsbach 2026-01-15 12:53:18 -08:00
parent 416029cd7d
commit 28b435518b
12 changed files with 2574 additions and 5 deletions

View File

@ -350,6 +350,7 @@ add_library(wolfssljni SHARED
${wolfssljni_DIR}/native/com_wolfssl_WolfSSLCertManager.c
${wolfssljni_DIR}/native/com_wolfssl_WolfSSLCertRequest.c
${wolfssljni_DIR}/native/com_wolfssl_WolfSSLCertificate.c
${wolfssljni_DIR}/native/com_wolfssl_WolfSSLCRL.c
${wolfssljni_DIR}/native/com_wolfssl_WolfSSLContext.c
${wolfssljni_DIR}/native/com_wolfssl_WolfSSLSession.c
${wolfssljni_DIR}/native/com_wolfssl_WolfSSLX509Name.c

View File

@ -42,6 +42,7 @@
<ClCompile Include="..\..\native\com_wolfssl_WolfSSLCertificate.c" />
<ClCompile Include="..\..\native\com_wolfssl_WolfSSLCertManager.c" />
<ClCompile Include="..\..\native\com_wolfssl_WolfSSLCertRequest.c" />
<ClCompile Include="..\..\native\com_wolfssl_WolfSSLCRL.c" />
<ClCompile Include="..\..\native\com_wolfssl_WolfSSLContext.c" />
<ClCompile Include="..\..\native\com_wolfssl_WolfSSLSession.c" />
<ClCompile Include="..\..\native\com_wolfssl_WolfSSLX509Name.c" />
@ -57,6 +58,7 @@
<ClInclude Include="..\..\native\com_wolfssl_WolfSSLCertificate.h" />
<ClInclude Include="..\..\native\com_wolfssl_WolfSSLCertManager.h" />
<ClInclude Include="..\..\native\com_wolfssl_WolfSSLCertRequest.h" />
<ClInclude Include="..\..\native\com_wolfssl_WolfSSLCRL.h" />
<ClInclude Include="..\..\native\com_wolfssl_WolfSSLContext.h" />
<ClInclude Include="..\..\native\com_wolfssl_WolfSSLSession.h" />
<ClInclude Include="..\..\native\com_wolfssl_WolfSSLX509Name.h" />

View File

@ -36,6 +36,9 @@
<ClCompile Include="..\..\native\com_wolfssl_WolfSSLCertRequest.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\native\com_wolfssl_WolfSSLCRL.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\native\com_wolfssl_WolfSSLContext.c">
<Filter>Source Files</Filter>
</ClCompile>
@ -80,6 +83,9 @@
<ClInclude Include="..\..\native\com_wolfssl_WolfSSLCertRequest.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\native\com_wolfssl_WolfSSLCRL.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\native\com_wolfssl_WolfSSLContext.h">
<Filter>Header Files</Filter>
</ClInclude>

View File

@ -182,6 +182,7 @@
<class name="com.wolfssl.WolfSSL"/>
<class name="com.wolfssl.WolfSSLCertManager"/>
<class name="com.wolfssl.WolfSSLCertificate"/>
<class name="com.wolfssl.WolfSSLCRL"/>
<class name="com.wolfssl.WolfSSLContext"/>
<class name="com.wolfssl.WolfSSLSession"/>
<class name="com.wolfssl.WolfSSLX509StoreCtx"/>

View File

@ -125,10 +125,12 @@ gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfCryptEccKey.c -o ./native/co
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLCertManager.c -o ./native/com_wolfssl_WolfSSLCertManager.o $javaIncludes
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLCertRequest.c -o ./native/com_wolfssl_WolfSSLCertRequest.o $javaIncludes
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLCertificate.c -o ./native/com_wolfssl_WolfSSLCertificate.o $javaIncludes
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLCRL.c -o ./native/com_wolfssl_WolfSSLCRL.o $javaIncludes
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
if [ $? != 0 ]; then
echo "Error creating native JNI library"
exit 1

View File

@ -0,0 +1,775 @@
/* com_wolfssl_WolfSSLCRL.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <stdio.h>
#include <stdint.h>
#ifdef WOLFSSL_USER_SETTINGS
#include <wolfssl/wolfcrypt/settings.h>
#else
#include <wolfssl/options.h>
#endif
#include <wolfssl/version.h>
#include <wolfssl/ssl.h>
#include <wolfssl/wolfcrypt/asn.h>
#include <wolfssl/openssl/evp.h>
#include <wolfssl/openssl/x509.h>
#include <wolfssl/error-ssl.h>
#include "com_wolfssl_globals.h"
#include "com_wolfssl_WolfSSLCRL.h"
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1new
(JNIEnv* jenv, jclass jcl)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
WOLFSSL_X509_CRL* crl = NULL;
(void)jcl;
if (jenv == NULL) {
return 0;
}
crl = wolfSSL_X509_CRL_new();
if (crl == NULL) {
return 0;
}
return (jlong)(uintptr_t)crl;
#else
(void)jenv;
(void)jcl;
return 0;
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1free
(JNIEnv* jenv, jclass jcl, jlong crlPtr)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
(void)jcl;
if (jenv == NULL || crl == NULL) {
return;
}
wolfSSL_X509_CRL_free(crl);
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1set_1version
(JNIEnv* jenv, jclass jcl, jlong crlPtr, jint version)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
(void)jcl;
if (jenv == NULL || crl == NULL) {
return WOLFSSL_FAILURE;
}
return wolfSSL_X509_CRL_set_version(crl, version);
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
(void)version;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1set_1issuer_1name
(JNIEnv* jenv, jclass jcl, jlong crlPtr, jlong x509NamePtr)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
WOLFSSL_X509_NAME* name = (WOLFSSL_X509_NAME*)(uintptr_t)x509NamePtr;
(void)jcl;
if (jenv == NULL || crl == NULL || name == NULL) {
return WOLFSSL_FAILURE;
}
return wolfSSL_X509_CRL_set_issuer_name(crl, name);
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
(void)x509NamePtr;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1set_1lastUpdate
(JNIEnv* jenv, jclass jcl, jlong crlPtr, jbyteArray time)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
byte* timeBuf = NULL;
int timeSz = 0;
int ret = 0;
WOLFSSL_ASN1_TIME asnTime;
char timeStr[CTC_DATE_SIZE + 1];
int timeLen = 0;
(void)jcl;
if (jenv == NULL || crl == NULL || time == NULL) {
return 0;
}
timeBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, time, NULL);
timeSz = (*jenv)->GetArrayLength(jenv, time);
/* Ensure there is enough room for date string (32 bytes)
plus 4 bytes of length and 4 bytes for type. */
if (timeBuf == NULL || timeSz < (CTC_DATE_SIZE + 8)) {
ret = 0;
}
else {
/* Extract length from bytes 32-35 (assuming native byte order) */
timeLen = *((int*)(timeBuf + CTC_DATE_SIZE));
if (timeLen <= 0 || timeLen > CTC_DATE_SIZE) {
ret = 0;
}
else {
/* Copy time string and null-terminate */
XMEMCPY(timeStr, timeBuf, timeLen);
timeStr[timeLen] = '\0';
/* Create ASN1_TIME object and set string */
if (wolfSSL_ASN1_TIME_set_string(&asnTime, timeStr) == 1) {
ret = wolfSSL_X509_CRL_set_lastUpdate(crl, &asnTime);
}
else {
ret = 0;
}
}
}
(*jenv)->ReleaseByteArrayElements(jenv, time, (jbyte*)timeBuf, JNI_ABORT);
return (jint)ret;
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
(void)time;
return 0;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1set_1nextUpdate
(JNIEnv* jenv, jclass jcl, jlong crlPtr, jbyteArray time)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
byte* timeBuf = NULL;
int timeSz = 0;
int ret = 0;
WOLFSSL_ASN1_TIME asnTime;
char timeStr[CTC_DATE_SIZE + 1];
int timeLen = 0;
(void)jcl;
if (jenv == NULL || crl == NULL || time == NULL) {
return 0;
}
timeBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, time, NULL);
timeSz = (*jenv)->GetArrayLength(jenv, time);
/* Ensure there is enough room for date string (32 bytes)
plus 4 bytes of length and 4 bytes for type. */
if (timeBuf == NULL || timeSz < (CTC_DATE_SIZE + 8)) {
ret = 0;
}
else {
/* Extract length from bytes 32-35 (assuming native byte order) */
timeLen = *((int*)(timeBuf + CTC_DATE_SIZE));
if (timeLen <= 0 || timeLen > CTC_DATE_SIZE) {
ret = 0;
}
else {
/* Copy time string and null-terminate */
XMEMCPY(timeStr, timeBuf, timeLen);
timeStr[timeLen] = '\0';
/* Create ASN1_TIME object and set string */
if (wolfSSL_ASN1_TIME_set_string(&asnTime, timeStr) == 1) {
ret = wolfSSL_X509_CRL_set_nextUpdate(crl, &asnTime);
}
else {
ret = 0;
}
}
}
(*jenv)->ReleaseByteArrayElements(jenv, time, (jbyte*)timeBuf, JNI_ABORT);
return (jint)ret;
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
(void)time;
return 0;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1add_1revoked
(JNIEnv* jenv, jclass jcl, jlong crlPtr, jbyteArray serial,
jbyteArray revDate, jint dateFmt)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
byte* serialBuf = NULL;
byte* dateBuf = NULL;
int serialSz = 0;
int ret = WOLFSSL_SUCCESS;
(void)jcl;
if (jenv == NULL || crl == NULL || serial == NULL) {
return WOLFSSL_FAILURE;
}
serialBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, serial, NULL);
serialSz = (*jenv)->GetArrayLength(jenv, serial);
if (serialBuf == NULL || serialSz == 0) {
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(crl, serialBuf, serialSz,
dateBuf, (unsigned char)dateFmt);
}
if (dateBuf != NULL) {
(*jenv)->ReleaseByteArrayElements(jenv, revDate, (jbyte*)dateBuf,
JNI_ABORT);
}
}
(*jenv)->ReleaseByteArrayElements(jenv, serial, (jbyte*)serialBuf,
JNI_ABORT);
return ret;
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
(void)serial;
(void)revDate;
(void)dateFmt;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1add_1revoked_1cert
(JNIEnv* jenv, jclass jcl, jlong crlPtr, jbyteArray certDer,
jbyteArray revDate, jint dateFmt)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
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;
if (jenv == NULL || crl == NULL || certDer == NULL) {
return WOLFSSL_FAILURE;
}
certBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, certDer, NULL);
certSz = (*jenv)->GetArrayLength(jenv, certDer);
if (certBuf == NULL || certSz == 0) {
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);
}
}
(*jenv)->ReleaseByteArrayElements(jenv, certDer, (jbyte*)certBuf,
JNI_ABORT);
return ret;
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
(void)certDer;
(void)revDate;
(void)dateFmt;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1sign
(JNIEnv* jenv, jclass jcl, jlong crlPtr, jint keyType, jbyteArray keyBytes,
jint format, jstring digestAlg)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
byte* keyBuf = NULL;
int keySz = 0;
byte* derBuf = NULL;
int derSz = 0;
WOLFSSL_EVP_PKEY* priv = NULL;
const WOLFSSL_EVP_MD* md = NULL;
unsigned char* rsaPrivBuf = NULL;
const char* mdName = NULL;
int ret = WOLFSSL_SUCCESS;
(void)jcl;
if (jenv == NULL || crl == NULL || keyBytes == NULL) {
return WOLFSSL_FAILURE;
}
keyBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, keyBytes, NULL);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionClear(jenv);
return WOLFSSL_FAILURE;
}
keySz = (*jenv)->GetArrayLength(jenv, keyBytes);
if (keyBuf == NULL || keySz == 0) {
ret = WOLFSSL_FAILURE;
}
if (ret == WOLFSSL_SUCCESS) {
if (digestAlg != NULL) {
mdName = (*jenv)->GetStringUTFChars(jenv, digestAlg, 0);
if (mdName == NULL) {
ret = WOLFSSL_FAILURE;
}
else {
md = wolfSSL_EVP_get_digestbyname(mdName);
if (md == NULL) {
ret = WOLFSSL_FAILURE;
}
}
}
}
/* convert PEM to DER if needed */
if (ret == WOLFSSL_SUCCESS) {
if ((int)format == WOLFSSL_FILETYPE_ASN1) {
/* already in DER */
derBuf = keyBuf;
derSz = keySz;
}
else {
/* get needed buffer size */
ret = wc_KeyPemToDer(keyBuf, keySz, NULL, 0, NULL);
if (ret <= 0) {
ret = WOLFSSL_FAILURE;
}
else {
derSz = ret;
derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (derBuf == NULL) {
ret = WOLFSSL_FAILURE;
}
else {
XMEMSET(derBuf, 0, derSz);
}
}
/* convert PEM to DER */
if (derBuf != NULL && ret == WOLFSSL_SUCCESS) {
ret = wc_KeyPemToDer(keyBuf, keySz, derBuf, derSz, NULL);
if (ret <= 0 || ret != derSz) {
ret = WOLFSSL_FAILURE;
}
}
}
}
/* convert buffer into WOLFSSL_EVP_PKEY */
if (ret == WOLFSSL_SUCCESS) {
/* Use temp pointer since d2i_PrivateKey() modifies the buffer */
rsaPrivBuf = derBuf;
priv = wolfSSL_d2i_PrivateKey((int)keyType, NULL,
(const unsigned char**)&rsaPrivBuf, derSz);
if (priv == NULL) {
ret = WOLFSSL_FAILURE;
}
}
/* sign WOLFSSL_X509_CRL with WOLFSSL_EVP_PKEY, returns size of signature
* on success or negative on error */
if (ret == WOLFSSL_SUCCESS) {
ret = wolfSSL_X509_CRL_sign(crl, priv, md);
if (ret >= 0) {
ret = WOLFSSL_SUCCESS;
}
}
if (priv != NULL) {
wolfSSL_EVP_PKEY_free(priv);
}
if (derBuf != NULL && derBuf != keyBuf) {
XMEMSET(derBuf, 0, derSz);
XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
derBuf = NULL;
}
if (mdName != NULL) {
(*jenv)->ReleaseStringUTFChars(jenv, digestAlg, mdName);
}
if (keyBuf != NULL) {
(*jenv)->ReleaseByteArrayElements(jenv, keyBytes, (jbyte*)keyBuf,
JNI_ABORT);
}
return ret;
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
(void)keyType;
(void)keyBytes;
(void)format;
(void)digestAlg;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_write_1X509_1CRL
(JNIEnv* jenv, jclass jcl, jlong crlPtr, jstring path, jint format)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
const char* cPath = NULL;
int ret = WOLFSSL_FAILURE;
(void)jcl;
if (jenv == NULL || crl == NULL || path == NULL) {
return WOLFSSL_FAILURE;
}
cPath = (*jenv)->GetStringUTFChars(jenv, path, NULL);
if (cPath == NULL) {
return WOLFSSL_FAILURE;
}
ret = wolfSSL_write_X509_CRL(crl, cPath, format);
(*jenv)->ReleaseStringUTFChars(jenv, path, cPath);
return ret;
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
(void)path;
(void)format;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1version
(JNIEnv* jenv, jclass jcl, jlong crlPtr)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
(void)jcl;
if (jenv == NULL || crl == NULL) {
return 0;
}
return (jint)wolfSSL_X509_CRL_version(crl);
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
return 0;
#endif
}
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1get_1lastUpdate
(JNIEnv* jenv, jclass jcl, jlong crlPtr)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && \
defined(WOLFSSL_CERT_GEN) && !defined(NO_ASN_TIME)
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
WOLFSSL_ASN1_TIME* date = NULL;
char timeStr[CTC_DATE_SIZE];
(void)jcl;
if (jenv == NULL || crl == NULL) {
return NULL;
}
date = wolfSSL_X509_CRL_get_lastUpdate(crl);
if (date != NULL) {
return (*jenv)->NewStringUTF(jenv,
wolfSSL_ASN1_TIME_to_string(date, timeStr, sizeof(timeStr)));
}
return NULL;
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
return NULL;
#endif
}
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1get_1nextUpdate
(JNIEnv* jenv, jclass jcl, jlong crlPtr)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && \
defined(WOLFSSL_CERT_GEN) && !defined(NO_ASN_TIME)
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
WOLFSSL_ASN1_TIME* date = NULL;
char timeStr[CTC_DATE_SIZE];
(void)jcl;
if (jenv == NULL || crl == NULL) {
return NULL;
}
date = wolfSSL_X509_CRL_get_nextUpdate(crl);
if (date != NULL) {
return (*jenv)->NewStringUTF(jenv,
wolfSSL_ASN1_TIME_to_string(date, timeStr, sizeof(timeStr)));
}
return NULL;
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
return NULL;
#endif
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1print
(JNIEnv* jenv, jclass jcl, jlong crlPtr)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
WOLFSSL_BIO* bio;
int sz = 0;
char* mem = NULL;
jbyteArray memArr = NULL;
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
(void)jcl;
if (jenv == NULL || crl == NULL) {
return NULL;
}
bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem());
if (bio == NULL) {
return NULL;
}
if (wolfSSL_X509_CRL_print(bio, crl) != WOLFSSL_SUCCESS) {
wolfSSL_BIO_free(bio);
return NULL;
}
sz = wolfSSL_BIO_get_mem_data(bio, &mem);
if (sz > 0 && mem != NULL) {
memArr = (*jenv)->NewByteArray(jenv, sz);
if (memArr == NULL) {
wolfSSL_BIO_free(bio);
return NULL;
}
(*jenv)->SetByteArrayRegion(jenv, memArr, 0, sz, (jbyte*)mem);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->DeleteLocalRef(jenv, memArr);
wolfSSL_BIO_free(bio);
return NULL;
}
}
wolfSSL_BIO_free(bio);
return memArr;
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
return NULL;
#endif
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1get_1der
(JNIEnv* jenv, jclass jcl, jlong crlPtr)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
unsigned char* der = NULL;
jbyteArray derArr = NULL;
jclass excClass = NULL;
int sz = 0;
(void)jcl;
if (jenv == NULL || crl == NULL) {
return NULL;
}
sz = wolfSSL_i2d_X509_CRL(crl, &der);
if (sz <= 0) {
return NULL;
}
derArr = (*jenv)->NewByteArray(jenv, sz);
if (derArr == NULL) {
(*jenv)->ThrowNew(jenv, jcl,
"Failed to create byte array in native X509_CRL_get_der");
XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
return NULL;
}
excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException");
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
(*jenv)->DeleteLocalRef(jenv, derArr);
XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
return NULL;
}
(*jenv)->SetByteArrayRegion(jenv, derArr, 0, sz, (jbyte*)der);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
(*jenv)->DeleteLocalRef(jenv, derArr);
XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
(*jenv)->ThrowNew(jenv, excClass,
"Failed to set byte region in native X509_CRL_get_der");
return NULL;
}
XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
return derArr;
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
return NULL;
#endif
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1get_1pem
(JNIEnv* jenv, jclass jcl, jlong crlPtr)
{
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN)
WOLFSSL_X509_CRL* crl = (WOLFSSL_X509_CRL*)(uintptr_t)crlPtr;
unsigned char* der = NULL;
unsigned char* pem = NULL;
int sz = 0;
int pemSz = 0;
jbyteArray pemArr = NULL;
jclass excClass = NULL;
(void)jcl;
if (jenv == NULL || crl == NULL) {
return NULL;
}
sz = wolfSSL_i2d_X509_CRL(crl, &der);
if (sz <= 0) {
return NULL;
}
pemSz = wc_DerToPem(der, sz, NULL, 0, CRL_TYPE);
if (pemSz < 0) {
XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
return NULL;
}
pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (pem == NULL) {
XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
return NULL;
}
XMEMSET(pem, 0, pemSz);
pemSz = wc_DerToPem(der, sz, pem, pemSz, CRL_TYPE);
if (pemSz < 0) {
XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return NULL;
}
XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
pemArr = (*jenv)->NewByteArray(jenv, pemSz);
if (pemArr == NULL) {
(*jenv)->ThrowNew(jenv, jcl,
"Failed to create byte array in native X509_CRL_get_pem");
XFREE(pem, 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, pemArr);
XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return NULL;
}
(*jenv)->SetByteArrayRegion(jenv, pemArr, 0, pemSz, (jbyte*)pem);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
(*jenv)->DeleteLocalRef(jenv, pemArr);
XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
(*jenv)->ThrowNew(jenv, excClass,
"Failed to set byte region in native X509_CRL_get_pem");
return NULL;
}
XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return pemArr;
#else
(void)jenv;
(void)jcl;
(void)crlPtr;
return NULL;
#endif
}

View File

@ -0,0 +1,159 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_wolfssl_WolfSSLCRL */
#ifndef _Included_com_wolfssl_WolfSSLCRL
#define _Included_com_wolfssl_WolfSSLCRL
#ifdef __cplusplus
extern "C" {
#endif
#undef com_wolfssl_WolfSSLCRL_serialVersionUID
#define com_wolfssl_WolfSSLCRL_serialVersionUID 1LL
#undef com_wolfssl_WolfSSLCRL_ASN_UTC_TIME
#define com_wolfssl_WolfSSLCRL_ASN_UTC_TIME 23L
#undef com_wolfssl_WolfSSLCRL_ASN_GENERALIZED_TIME
#define com_wolfssl_WolfSSLCRL_ASN_GENERALIZED_TIME 24L
#undef com_wolfssl_WolfSSLCRL_CTC_DATE_SIZE
#define com_wolfssl_WolfSSLCRL_CTC_DATE_SIZE 32L
#undef com_wolfssl_WolfSSLCRL_ASN1_TIME_STRUCT_SIZE
#define com_wolfssl_WolfSSLCRL_ASN1_TIME_STRUCT_SIZE 40L
#undef com_wolfssl_WolfSSLCRL_ASN1_UTC_YEAR_MIN
#define com_wolfssl_WolfSSLCRL_ASN1_UTC_YEAR_MIN 1950L
#undef com_wolfssl_WolfSSLCRL_ASN1_UTC_YEAR_MAX
#define com_wolfssl_WolfSSLCRL_ASN1_UTC_YEAR_MAX 2049L
#undef com_wolfssl_WolfSSLCRL_EVP_PKEY_RSA
#define com_wolfssl_WolfSSLCRL_EVP_PKEY_RSA 16L
#undef com_wolfssl_WolfSSLCRL_EVP_PKEY_EC
#define com_wolfssl_WolfSSLCRL_EVP_PKEY_EC 18L
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_new
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1new
(JNIEnv *, jclass);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_free
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1free
(JNIEnv *, jclass, jlong);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_set_version
* Signature: (JI)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1set_1version
(JNIEnv *, jclass, jlong, jint);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_set_issuer_name
* Signature: (JJ)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1set_1issuer_1name
(JNIEnv *, jclass, jlong, jlong);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_set_lastUpdate
* Signature: (J[B)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1set_1lastUpdate
(JNIEnv *, jclass, jlong, jbyteArray);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_set_nextUpdate
* Signature: (J[B)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1set_1nextUpdate
(JNIEnv *, jclass, jlong, jbyteArray);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_add_revoked
* Signature: (J[B[BI)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1add_1revoked
(JNIEnv *, jclass, jlong, jbyteArray, jbyteArray, jint);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_add_revoked_cert
* Signature: (J[B[BI)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1add_1revoked_1cert
(JNIEnv *, jclass, jlong, jbyteArray, jbyteArray, jint);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_sign
* Signature: (JI[BILjava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1sign
(JNIEnv *, jclass, jlong, jint, jbyteArray, jint, jstring);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: write_X509_CRL
* Signature: (JLjava/lang/String;I)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_write_1X509_1CRL
(JNIEnv *, jclass, jlong, jstring, jint);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_print
* Signature: (J)[B
*/
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1print
(JNIEnv *, jclass, jlong);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_version
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1version
(JNIEnv *, jclass, jlong);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_get_lastUpdate
* Signature: (J)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1get_1lastUpdate
(JNIEnv *, jclass, jlong);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_get_nextUpdate
* Signature: (J)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1get_1nextUpdate
(JNIEnv *, jclass, jlong);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_get_der
* Signature: (J)[B
*/
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1get_1der
(JNIEnv *, jclass, jlong);
/*
* Class: com_wolfssl_WolfSSLCRL
* Method: X509_CRL_get_pem
* Signature: (J)[B
*/
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCRL_X509_1CRL_1get_1pem
(JNIEnv *, jclass, jlong);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1022,7 +1022,7 @@ JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1notBefore
const unsigned char* date = NULL;
#endif
WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr;
char ret[32];
char timeStr[CTC_DATE_SIZE];
(void)jcl;
if (jenv == NULL || x509 == NULL) {
@ -1037,8 +1037,8 @@ JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1notBefore
/* returns string holding date i.e. "Thu Jan 07 08:23:09 MST 2021" */
if (date != NULL) {
return (*jenv)->NewStringUTF(jenv,
wolfSSL_ASN1_TIME_to_string((WOLFSSL_ASN1_TIME*)date, ret,
sizeof(ret)));
wolfSSL_ASN1_TIME_to_string((WOLFSSL_ASN1_TIME*)date, timeStr,
sizeof(timeStr)));
}
return NULL;
}
@ -1052,7 +1052,7 @@ JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1notAfter
const unsigned char* date = NULL;
#endif
WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr;
char ret[32];
char timeStr[CTC_DATE_SIZE];
(void)jcl;
if (jenv == NULL || x509 == NULL) {
@ -1068,7 +1068,7 @@ JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1notAfter
if (date != NULL) {
return (*jenv)->NewStringUTF(jenv,
wolfSSL_ASN1_TIME_to_string((WOLFSSL_ASN1_TIME*)date,
ret, sizeof(ret)));
timeStr, sizeof(timeStr)));
}
return NULL;
}

View File

@ -37,6 +37,7 @@ LOCAL_SRC_FILES := \
native/com_wolfssl_WolfCryptRSA.c \
native/com_wolfssl_WolfSSL.c \
native/com_wolfssl_WolfSSLCertificate.c \
native/com_wolfssl_WolfSSLCRL.c \
native/com_wolfssl_WolfSSLCertManager.c \
native/com_wolfssl_WolfSSLContext.c \
native/com_wolfssl_WolfSSLSession.c \

View File

@ -0,0 +1,682 @@
/* WolfSSLCRL.java
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
package com.wolfssl;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.security.PrivateKey;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.RSAPrivateKey;
/**
* WolfSSLCRL class, wraps native wolfSSL WOLFSSL_X509_CRL functionality.
*/
public class WolfSSLCRL implements Serializable {
private static final long serialVersionUID = 1L;
/** Flag if this class is active or not */
private boolean active = false;
/** Internal pointer for native WOLFSSL_X509_CRL */
private long crlPtr = 0;
/** Does this WolfSSLCRL own the internal WOLFSSL_X509_CRL pointer? */
private boolean weOwnCrlPtr = false;
/** lock around active state */
private transient final Object stateLock = new Object();
/** lock around native WOLFSSL_X509_CRL pointer use */
private transient final Object crlLock = new Object();
/* From wolfssl/wolfcrypt/asn.h and wolfssl/wolfcrypt/asn_public.h */
private static final int ASN_UTC_TIME = 0x17;
private static final int ASN_GENERALIZED_TIME = 0x18;
private static final int CTC_DATE_SIZE = 32;
private static final int ASN1_TIME_STRUCT_SIZE = CTC_DATE_SIZE + 8;
private static final int ASN1_UTC_YEAR_MIN = 1950;
private static final int ASN1_UTC_YEAR_MAX = 2049;
private static final int EVP_PKEY_RSA = 16;
private static final int EVP_PKEY_EC = 18;
/* Native method declarations */
static native long X509_CRL_new();
static native void X509_CRL_free(long crl);
static native int X509_CRL_set_version(long crl, int version);
static native int X509_CRL_set_issuer_name(long crl, long x509NamePtr);
static native int X509_CRL_set_lastUpdate(long crl, byte[] time);
static native int X509_CRL_set_nextUpdate(long crl, byte[] time);
static native int X509_CRL_add_revoked(long crl, byte[] serial,
byte[] revDate, int dateFmt);
static native int X509_CRL_add_revoked_cert(long crl, byte[] certDer,
byte[] revDate, int dateFmt);
static native int X509_CRL_sign(long crl, int keyType, byte[] keyBytes,
int format, String digestAlg);
static native int write_X509_CRL(long crl, String path, int format);
static native byte[] X509_CRL_print(long crl);
static native int X509_CRL_version(long crl);
static native String X509_CRL_get_lastUpdate(long crl);
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);
private static final class Asn1TimeData {
private final byte[] paddedData;
private final int length;
private final int type;
private Asn1TimeData(byte[] paddedData, int length, int type) {
this.paddedData = paddedData;
this.length = length;
this.type = type;
}
}
private static Asn1TimeData buildAsn1TimeData(Date date) {
if (date == null) {
throw new IllegalArgumentException("Date is null");
}
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"),
Locale.US);
cal.setTime(date);
int year = cal.get(Calendar.YEAR);
boolean useUtcTime = (year >= ASN1_UTC_YEAR_MIN &&
year <= ASN1_UTC_YEAR_MAX);
String pattern = useUtcTime ? "yyMMddHHmmss'Z'" :
"yyyyMMddHHmmss'Z'";
int type = useUtcTime ? ASN_UTC_TIME : ASN_GENERALIZED_TIME;
SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
byte[] timeBytes = format.format(date).getBytes(
StandardCharsets.US_ASCII);
if (timeBytes.length > CTC_DATE_SIZE) {
throw new IllegalArgumentException(
"ASN.1 time exceeds max size: " + timeBytes.length);
}
byte[] padded = new byte[CTC_DATE_SIZE];
System.arraycopy(timeBytes, 0, padded, 0, timeBytes.length);
return new Asn1TimeData(padded, timeBytes.length, type);
}
private static byte[] buildAsn1TimeStruct(Date date) {
Asn1TimeData timeData = buildAsn1TimeData(date);
ByteBuffer buffer = ByteBuffer.allocate(ASN1_TIME_STRUCT_SIZE)
.order(ByteOrder.nativeOrder());
buffer.put(timeData.paddedData);
buffer.position(CTC_DATE_SIZE);
buffer.putInt(timeData.length);
buffer.putInt(timeData.type);
return buffer.array();
}
/**
* Create new empty WolfSSLCRL object, for CRL generation.
*
* @throws WolfSSLException if native API call fails.
*/
public WolfSSLCRL() throws WolfSSLException {
crlPtr = X509_CRL_new();
if (crlPtr == 0) {
throw new WolfSSLException("Failed to create WolfSSLCRL");
}
this.weOwnCrlPtr = true;
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, crlPtr,
() -> "creating new WolfSSLCRL");
synchronized (stateLock) {
this.active = true;
}
}
/**
* Create new WolfSSLCRL from DER-encoded byte array.
*
* @param der ASN.1/DER encoded CRL
*
* @throws WolfSSLException if CRL loading is not implemented.
*/
public WolfSSLCRL(byte[] der) throws WolfSSLException {
throw new WolfSSLException("CRL loading from DER not implemented yet");
}
/**
* Create WolfSSLCRL from file in specified format.
*
* @param filePath path to CRL file
* @param format format of CRL, either WolfSSL.SSL_FILETYPE_ASN1 or
* WolfSSL.SSL_FILETYPE_PEM
*
* @throws WolfSSLException if CRL loading is not implemented.
*/
public WolfSSLCRL(String filePath, int format) throws WolfSSLException {
throw new WolfSSLException("CRL loading from file not implemented yet");
}
/**
* Verifies that the current WolfSSLCRL object is active.
*
* @throws IllegalStateException if object has been freed
*/
private void confirmObjectIsActive()
throws IllegalStateException {
synchronized (stateLock) {
if (this.active == false) {
throw new IllegalStateException(
"WolfSSLCRL object has been freed");
}
}
}
/**
* Set CRL version (0 = v1, 1 = v2).
*
* @param version CRL version
*
* @return native wolfSSL return code
* @throws IllegalStateException if WolfSSLCRL has been freed.
*/
public int setVersion(int version) throws IllegalStateException {
confirmObjectIsActive();
synchronized (crlLock) {
return X509_CRL_set_version(this.crlPtr, version);
}
}
/**
* Set CRL issuer name from WolfSSLX509Name.
*
* @param name WolfSSLX509Name to set as issuer
*
* @return native wolfSSL return code
* @throws IllegalStateException if WolfSSLCRL has been freed.
* @throws WolfSSLException if name is null.
*/
public int setIssuerName(WolfSSLX509Name name)
throws IllegalStateException, WolfSSLException {
if (name == null) {
throw new WolfSSLException("Issuer name is null");
}
confirmObjectIsActive();
synchronized (crlLock) {
return X509_CRL_set_issuer_name(this.crlPtr,
name.getNativeX509NamePtr());
}
}
/**
* Set CRL last update date.
*
* @param date Date to set as last update time
*
* @return native wolfSSL return code (WolfSSL.SSL_SUCCESS on success)
*
* @throws IllegalStateException if WolfSSLCRL has been freed.
* @throws IllegalArgumentException if date is null.
*/
public int setLastUpdate(Date date) {
if (date == null) {
throw new IllegalArgumentException("LastUpdate date is null");
}
confirmObjectIsActive();
byte[] asnTime = buildAsn1TimeStruct(date);
synchronized (crlLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.crlPtr,
() -> "entered setLastUpdate(" + date + ")");
int ret = X509_CRL_set_lastUpdate(this.crlPtr, asnTime);
return (ret == 0) ? WolfSSL.SSL_FAILURE : WolfSSL.SSL_SUCCESS;
}
}
/**
* Set CRL next update date.
*
* @param date Date to set as next update time
*
* @return native wolfSSL return code (WolfSSL.SSL_SUCCESS on success)
*
* @throws IllegalStateException if WolfSSLCRL has been freed.
* @throws IllegalArgumentException if date is null.
*/
public int setNextUpdate(Date date) {
if (date == null) {
throw new IllegalArgumentException("NextUpdate date is null");
}
confirmObjectIsActive();
byte[] asnTime = buildAsn1TimeStruct(date);
synchronized (crlLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.crlPtr,
() -> "entered setNextUpdate(" + date + ")");
int ret = X509_CRL_set_nextUpdate(this.crlPtr, asnTime);
return (ret == 0) ? WolfSSL.SSL_FAILURE : WolfSSL.SSL_SUCCESS;
}
}
/**
* Add revoked certificate entry to CRL by serial number.
*
* @param serialNumber Serial number of revoked certificate
* @param revocationDate Date when certificate was revoked, or null
*
* @return native wolfSSL return code
*
* @throws IllegalStateException if WolfSSLCRL has been freed.
* @throws IllegalArgumentException if serialNumber is null or empty.
*/
public int addRevoked(byte[] serialNumber, Date revocationDate) {
if (serialNumber == null || serialNumber.length == 0) {
throw new IllegalArgumentException(
"Serial number is null or empty");
}
confirmObjectIsActive();
byte[] revDateBytes = null;
int dateFmt = 0;
if (revocationDate != null) {
Asn1TimeData timeData = buildAsn1TimeData(revocationDate);
revDateBytes = timeData.paddedData;
dateFmt = timeData.type;
}
synchronized (crlLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.crlPtr,
() -> "entered addRevoked(serial: " + serialNumber.length +
", revocationDate: " + revocationDate + ")");
return X509_CRL_add_revoked(this.crlPtr, serialNumber,
revDateBytes, dateFmt);
}
}
/**
* Add revoked certificate entry to CRL from DER-encoded certificate.
*
* @param certDer DER-encoded certificate to add as revoked
* @param revocationDate Date when certificate was revoked, or null
*
* @return native wolfSSL return code
*
* @throws IllegalStateException if WolfSSLCRL has been freed.
* @throws IllegalArgumentException if certDer is null or empty.
*/
public int addRevokedCert(byte[] certDer, Date revocationDate) {
if (certDer == null || certDer.length == 0) {
throw new IllegalArgumentException(
"Certificate DER is null or empty");
}
confirmObjectIsActive();
byte[] revDateBytes = null;
int dateFmt = 0;
if (revocationDate != null) {
Asn1TimeData timeData = buildAsn1TimeData(revocationDate);
revDateBytes = timeData.paddedData;
dateFmt = timeData.type;
}
synchronized (crlLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.crlPtr,
() -> "entered addRevokedCert(der: " + certDer.length +
", revocationDate: " + revocationDate + ")");
return X509_CRL_add_revoked_cert(this.crlPtr, certDer,
revDateBytes, dateFmt);
}
}
/**
* Add revoked certificate entry to CRL from WolfSSLCertificate object.
*
* @param cert WolfSSLCertificate object to add as revoked
* @param revocationDate Date when certificate was revoked, or null
*
* @return native wolfSSL return code
*
* @throws IllegalStateException if WolfSSLCRL has been freed or if
* certificate DER encoding fails.
* @throws IllegalArgumentException if cert is null.
*/
public int addRevokedCert(WolfSSLCertificate cert, Date revocationDate) {
if (cert == null) {
throw new IllegalArgumentException("Certificate is null");
}
confirmObjectIsActive();
synchronized (crlLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.crlPtr,
() -> "entered addRevokedCert(cert, revocationDate: " +
revocationDate + ")");
}
byte[] certDer = null;
try {
certDer = cert.getDer();
}
catch (WolfSSLJNIException ex) {
throw new IllegalStateException(
"Failed to get certificate DER", ex);
}
if (certDer == null || certDer.length == 0) {
throw new IllegalStateException("Certificate DER is empty");
}
return addRevokedCert(certDer, revocationDate);
}
/**
* Sign CRL with private key from PrivateKey object.
*
* @param key java.security.PrivateKey object containing private key,
* must be of type RSAPrivateKey or ECPrivateKey
* @param digestAlg Message digest algorithm to use for signature
* generation. Options include the following, but native algorithm
* must be compiled into wolfSSL to be available:
* "MD4", "MD5", "SHA1", "SHA224", "SHA256", "SHA384",
* "SHA512", "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512"
*
* @return native wolfSSL return code (WolfSSL.SSL_SUCCESS on success)
*
* @throws IllegalStateException if WolfSSLCRL has been freed.
* @throws IllegalArgumentException if key is null, unsupported key type,
* or key does not support encoding.
*/
public int sign(PrivateKey key, String digestAlg) {
int ret = 0;
int evpKeyType;
byte[] encodedKey = null;
confirmObjectIsActive();
synchronized (crlLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.crlPtr,
() -> "entered sign(" + key + ", digestAlg: " + digestAlg +
")");
}
if (key == null) {
throw new IllegalArgumentException("Key object is null");
}
if (key instanceof RSAPrivateKey) {
evpKeyType = EVP_PKEY_RSA;
}
else if (key instanceof ECPrivateKey) {
evpKeyType = EVP_PKEY_EC;
}
else {
throw new IllegalArgumentException(
"PrivateKey must be of type RSAPrivateKey or ECPrivateKey");
}
/* Get DER encoded key */
encodedKey = key.getEncoded();
if (encodedKey == null) {
throw new IllegalArgumentException(
"PrivateKey does not support encoding");
}
synchronized (crlLock) {
ret = X509_CRL_sign(this.crlPtr, evpKeyType, encodedKey,
WolfSSL.SSL_FILETYPE_ASN1, digestAlg);
}
return ret;
}
/**
* Write CRL to file in specified format.
*
* @param path path to file where CRL should be written
* @param format format of CRL, either WolfSSL.SSL_FILETYPE_ASN1 or
* WolfSSL.SSL_FILETYPE_PEM
*
* @return native wolfSSL return code (WolfSSL.SSL_SUCCESS on success)
*
* @throws IllegalStateException if WolfSSLCRL has been freed.
* @throws IllegalArgumentException if path is null or empty, or format
* is invalid.
*/
public int writeToFile(String path, int format) {
if (path == null || path.length() == 0) {
throw new IllegalArgumentException("Path is null or empty");
}
if (format != WolfSSL.SSL_FILETYPE_ASN1 &&
format != WolfSSL.SSL_FILETYPE_PEM) {
throw new IllegalArgumentException(
"Invalid file format, must be PEM or DER");
}
confirmObjectIsActive();
synchronized (crlLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.crlPtr,
() -> "entered writeToFile(" + path + ", format: " + format +
")");
return write_X509_CRL(this.crlPtr, path, format);
}
}
/**
* Get ASN.1/DER encoding of this CRL.
*
* @return DER encoded array of CRL or null if not available.
*
* @throws IllegalStateException if WolfSSLCRL has been freed.
* @throws WolfSSLJNIException if native JNI error occurs.
*/
public byte[] getDer() throws IllegalStateException, WolfSSLJNIException {
confirmObjectIsActive();
synchronized (crlLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.crlPtr, () -> "entered getDer()");
return X509_CRL_get_der(this.crlPtr);
}
}
/**
* Get PEM encoding of this CRL.
*
* @return PEM encoded array of CRL or null if not available.
*
* @throws IllegalStateException if WolfSSLCRL has been freed.
* @throws WolfSSLJNIException if native JNI error occurs.
*/
public byte[] getPem() throws IllegalStateException, WolfSSLJNIException {
confirmObjectIsActive();
synchronized (crlLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.crlPtr, () -> "entered getPem()");
return X509_CRL_get_pem(this.crlPtr);
}
}
/**
* Get CRL version.
*
* @return version of CRL (0 = v1, 1 = v2)
*
* @throws IllegalStateException if WolfSSLCRL has been freed.
*/
public int getVersion() {
confirmObjectIsActive();
synchronized (crlLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.crlPtr, () -> "entered getVersion()");
return X509_CRL_version(this.crlPtr);
}
}
/**
* Get CRL last update date.
*
* @return last update date as Date object, or null if not available
* or if date parsing fails.
*
* @throws IllegalStateException if WolfSSLCRL has been freed.
*/
public Date getLastUpdate() {
String date;
confirmObjectIsActive();
synchronized (crlLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.crlPtr,
() -> "entered getLastUpdate()");
date = X509_CRL_get_lastUpdate(this.crlPtr);
}
if (date != null) {
SimpleDateFormat format =
new SimpleDateFormat("MMM dd HH:mm:ss yyyy zzz");
try {
return format.parse(date);
} catch (ParseException ex) {
/* error case parsing date */
}
}
return null;
}
/**
* Get CRL next update date.
*
* @return next update date as Date object, or null if not available
* or if date parsing fails.
*
* @throws IllegalStateException if WolfSSLCRL has been freed.
*/
public Date getNextUpdate() {
String date;
confirmObjectIsActive();
synchronized (crlLock) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
WolfSSLDebug.INFO, this.crlPtr,
() -> "entered getNextUpdate()");
date = X509_CRL_get_nextUpdate(this.crlPtr);
}
if (date != null) {
SimpleDateFormat format =
new SimpleDateFormat("MMM dd HH:mm:ss yyyy zzz");
try {
return format.parse(date);
} catch (ParseException ex) {
/* error case parsing date */
}
}
return null;
}
@Override
public String toString() {
byte[] crlText = null;
synchronized (stateLock) {
if (this.active == false) {
return super.toString();
}
synchronized (crlLock) {
crlText = X509_CRL_print(this.crlPtr);
}
if (crlText != null) {
/* let Java do the modified UTF-8 conversion */
return new String(crlText, Charset.forName("UTF-8"));
} else {
System.out.println("toString: crlText == null");
}
}
return super.toString();
}
/**
* Free native CRL resources.
*/
public synchronized void free() {
synchronized (stateLock) {
if (!this.active) {
return;
}
this.active = false;
}
if (this.weOwnCrlPtr) {
synchronized (crlLock) {
X509_CRL_free(this.crlPtr);
this.crlPtr = 0;
this.weOwnCrlPtr = false;
}
}
}
@SuppressWarnings("deprecation")
@Override
protected void finalize() throws Throwable {
this.free();
super.finalize();
}
}

View File

@ -0,0 +1,939 @@
/* WolfSSLCRLTest.java
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
package com.wolfssl.test;
import org.junit.Test;
import org.junit.BeforeClass;
import static org.junit.Assert.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Date;
import java.util.Calendar;
import com.wolfssl.WolfSSL;
import com.wolfssl.WolfSSLX509Name;
import com.wolfssl.WolfSSLCRL;
import com.wolfssl.WolfSSLCertificate;
import com.wolfssl.WolfSSLException;
import com.wolfssl.WolfSSLJNIException;
/**
* @author wolfSSL
*/
public class WolfSSLCRLTest {
public final static int TEST_FAIL = -1;
public final static int TEST_SUCCESS = 0;
public static String caKeyDer = "examples/certs/ca-key.der";
public static String caKeyPem = "examples/certs/ca-key.pem";
public static String caCertPem = "examples/certs/ca-cert.pem";
public static String clientCertPem = "examples/certs/client-cert.pem";
public static String clientKeyDer = "examples/certs/client-key.der";
public static String clientKeyPem = "examples/certs/client-key.pem";
public static String eccCaKeyPem = "examples/certs/ca-ecc-key.pem";
public static String eccClientKeyPem = "examples/certs/ecc-client-key.pem";
@BeforeClass
public static void setCertPaths() throws WolfSSLException {
System.out.println("WolfSSLCRL Class");
try {
WolfSSL.loadLibrary();
} catch (UnsatisfiedLinkError ule) {
fail("failed to load native JNI library");
}
caKeyDer = WolfSSLTestCommon.getPath(caKeyDer);
caKeyPem = WolfSSLTestCommon.getPath(caKeyPem);
caCertPem = WolfSSLTestCommon.getPath(caCertPem);
clientCertPem = WolfSSLTestCommon.getPath(clientCertPem);
clientKeyDer = WolfSSLTestCommon.getPath(clientKeyDer);
clientKeyPem = WolfSSLTestCommon.getPath(clientKeyPem);
eccCaKeyPem = WolfSSLTestCommon.getPath(eccCaKeyPem);
eccClientKeyPem = WolfSSLTestCommon.getPath(eccClientKeyPem);
}
/* Internal helper method, generate test IssuerName for CRL generation */
private WolfSSLX509Name GenerateTestIssuerName() throws WolfSSLException {
WolfSSLX509Name name = new WolfSSLX509Name();
name.setCountryName("US");
name.setStateOrProvinceName("Montana");
name.setLocalityName("Bozeman");
name.setCommonName("wolfSSL Test CA");
name.setEmailAddress("support@wolfssl.com");
name.setOrganizationName("wolfSSL Inc.");
name.setOrganizationalUnitName("Development Test");
return name;
}
@Test
public void testSetVersion()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException {
System.out.print("\tsetVersion()");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Test setting valid versions */
int ret = crl.setVersion(0);
assertTrue("setVersion(0) should succeed", ret >= 0);
ret = crl.setVersion(1);
assertTrue("setVersion(1) should succeed", ret >= 0);
/* Verify version was set */
int version = crl.getVersion();
assertEquals(1, version);
/* Negative versions should still work (native handles validation) */
ret = crl.setVersion(-100);
/* Native may or may not validate, so just check it doesn't crash */
crl.free();
System.out.println("\t\t\t... passed");
}
@Test
public void testSetIssuerName()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException {
System.out.print("\tsetIssuerName()");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Set issuer name */
WolfSSLX509Name issuerName = GenerateTestIssuerName();
assertNotNull(issuerName);
int ret = crl.setIssuerName(issuerName);
assertTrue("setIssuerName should succeed", ret >= 0);
/* Test null issuer name */
try {
crl.setIssuerName(null);
System.out.println("\t\t\t... failed");
fail("null issuer name should throw exception");
} catch (WolfSSLException e) {
/* expected */
}
/* Free native memory */
issuerName.free();
crl.free();
System.out.println("\t\t\t... passed");
}
@Test
public void testSetLastUpdate()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException {
System.out.print("\tsetLastUpdate()");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Set last update date */
Date now = new Date();
int ret = crl.setLastUpdate(now);
assertEquals(WolfSSL.SSL_SUCCESS, ret);
/* Verify date was set */
Date retrieved = crl.getLastUpdate();
assertNotNull(retrieved);
/* Allow some tolerance for date comparison */
long diff = Math.abs(retrieved.getTime() - now.getTime());
assertTrue("Date should be within 1 second", diff < 1000);
/* Test null date */
try {
crl.setLastUpdate(null);
System.out.println("\t\t\t... failed");
fail("null date should throw exception");
} catch (IllegalArgumentException e) {
/* expected */
}
crl.free();
System.out.println("\t\t\t... passed");
}
@Test
public void testSetNextUpdate()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException {
System.out.print("\tsetNextUpdate()");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Set next update date */
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, 30); /* 30 days from now */
Date nextUpdate = cal.getTime();
int ret = crl.setNextUpdate(nextUpdate);
assertEquals(WolfSSL.SSL_SUCCESS, ret);
/* Verify date was set */
Date retrieved = crl.getNextUpdate();
assertNotNull(retrieved);
/* Allow some tolerance for date comparison */
long diff = Math.abs(retrieved.getTime() - nextUpdate.getTime());
assertTrue("Date should be within 1 second", diff < 1000);
/* Test null date */
try {
crl.setNextUpdate(null);
System.out.println("\t\t\t... failed");
fail("null date should throw exception");
} catch (IllegalArgumentException e) {
/* expected */
}
crl.free();
System.out.println("\t\t\t... passed");
}
@Test
public void testAddRevoked()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException {
System.out.print("\taddRevoked()");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Add revoked certificate by serial number */
byte[] serial1 = new byte[] { 0x01, 0x02, 0x03, 0x04 };
Date revDate1 = new Date();
int ret = crl.addRevoked(serial1, revDate1);
assertTrue("addRevoked should succeed", ret >= 0);
/* Add another revoked certificate */
byte[] serial2 = new byte[] { 0x05, 0x06, 0x07, 0x08 };
Date revDate2 = new Date();
ret = crl.addRevoked(serial2, revDate2);
assertTrue("addRevoked should succeed", ret >= 0);
/* Add revoked certificate without revocation date */
byte[] serial3 = new byte[] { 0x09, 0x0A, 0x0B, 0x0C };
ret = crl.addRevoked(serial3, null);
assertTrue("addRevoked should succeed", ret >= 0);
/* Test null serial number */
try {
crl.addRevoked(null, new Date());
System.out.println("\t\t\t... failed");
fail("null serial number should throw exception");
} catch (IllegalArgumentException e) {
/* expected */
}
/* Test empty serial number */
try {
crl.addRevoked(new byte[0], new Date());
System.out.println("\t\t\t... failed");
fail("empty serial number should throw exception");
} catch (IllegalArgumentException e) {
/* expected */
}
crl.free();
System.out.println("\t\t\t... passed");
}
@Test
public void testAddRevokedCert_ByteArray()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException {
System.out.print("\taddRevokedCert(byte[])");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Load certificate from PEM file and convert to DER */
WolfSSLCertificate cert = new WolfSSLCertificate(clientCertPem,
WolfSSL.SSL_FILETYPE_PEM);
assertNotNull(cert);
byte[] certDer = cert.getDer();
assertNotNull(certDer);
assertTrue(certDer.length > 0);
/* Add revoked certificate by DER */
Date revDate = new Date();
int ret = crl.addRevokedCert(certDer, revDate);
assertTrue("addRevokedCert should succeed", ret >= 0);
/* Add revoked certificate without revocation date */
ret = crl.addRevokedCert(certDer, null);
assertTrue("addRevokedCert should succeed", ret >= 0);
/* Test null certificate DER */
try {
crl.addRevokedCert((byte[])null, new Date());
System.out.println("\t\t... failed");
fail("null certificate DER should throw exception");
} catch (IllegalArgumentException e) {
/* expected */
}
/* Test empty certificate DER */
try {
crl.addRevokedCert(new byte[0], new Date());
System.out.println("\t\t... failed");
fail("empty certificate DER should throw exception");
} catch (IllegalArgumentException e) {
/* expected */
}
crl.free();
System.out.println("\t\t... passed");
}
@Test
public void testAddRevokedCert_WolfSSLCertificate()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException {
System.out.print("\taddRevokedCert(WolfSSLCertificate)");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Load certificate */
WolfSSLCertificate cert = new WolfSSLCertificate(clientCertPem,
WolfSSL.SSL_FILETYPE_PEM);
assertNotNull(cert);
/* Add revoked certificate */
Date revDate = new Date();
int ret = crl.addRevokedCert(cert, revDate);
assertTrue("addRevokedCert should succeed", ret >= 0);
/* Add revoked certificate without revocation date */
WolfSSLCertificate cert2 = new WolfSSLCertificate(clientCertPem,
WolfSSL.SSL_FILETYPE_PEM);
ret = crl.addRevokedCert(cert2, null);
assertTrue("addRevokedCert should succeed", ret >= 0);
/* Test null certificate */
try {
crl.addRevokedCert((WolfSSLCertificate)null, new Date());
System.out.println("\t... failed");
fail("null certificate should throw exception");
} catch (IllegalArgumentException e) {
/* expected */
}
/* Free native memory */
cert.free();
cert2.free();
crl.free();
System.out.println("\t... passed");
}
@Test
public void testSign_PrivateKey()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException, NoSuchAlgorithmException {
System.out.print("\tsign(PrivateKey)");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Set issuer name */
WolfSSLX509Name issuerName = GenerateTestIssuerName();
crl.setIssuerName(issuerName);
/* Set dates */
crl.setLastUpdate(new Date());
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, 30);
crl.setNextUpdate(cal.getTime());
/* Add revoked certificate */
byte[] serial = new byte[] { 0x01, 0x02, 0x03, 0x04 };
crl.addRevoked(serial, new Date());
/* Sign with RSA key from file */
byte[] keyBytes = Files.readAllBytes(Paths.get(caKeyDer));
/* Note: sign() method expects PrivateKey object, not byte array */
/* We'll test with generated key pair instead */
/* Generate RSA key pair */
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair keyPair = kpg.generateKeyPair();
PrivateKey privKey = keyPair.getPrivate();
/* Sign CRL */
int ret = crl.sign(privKey, "SHA256");
assertTrue("sign should succeed", ret >= 0);
/* Test null private key */
try {
crl.sign(null, "SHA256");
System.out.println("\t\t... failed");
fail("null private key should throw exception");
} catch (IllegalArgumentException e) {
/* expected */
}
/* Free native memory */
issuerName.free();
crl.free();
System.out.println("\t\t... passed");
}
@Test
public void testWriteToFile()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException, NoSuchAlgorithmException {
System.out.print("\twriteToFile()");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Set issuer name */
WolfSSLX509Name issuerName = GenerateTestIssuerName();
crl.setIssuerName(issuerName);
/* Set dates */
crl.setLastUpdate(new Date());
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, 30);
crl.setNextUpdate(cal.getTime());
/* Add revoked certificate */
byte[] serial = new byte[] { 0x01, 0x02, 0x03, 0x04 };
crl.addRevoked(serial, new Date());
/* Sign CRL */
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair keyPair = kpg.generateKeyPair();
PrivateKey privKey = keyPair.getPrivate();
crl.sign(privKey, "SHA256");
/* Write to DER file */
File tempDer = File.createTempFile("test_crl_", ".der");
int ret = crl.writeToFile(tempDer.getAbsolutePath(),
WolfSSL.SSL_FILETYPE_ASN1);
assertTrue("writeToFile DER should succeed", ret >= 0);
assertTrue(tempDer.exists());
assertTrue(tempDer.length() > 0);
tempDer.delete();
/* Write to PEM file */
File tempPem = File.createTempFile("test_crl_", ".pem");
ret = crl.writeToFile(tempPem.getAbsolutePath(),
WolfSSL.SSL_FILETYPE_PEM);
assertTrue("writeToFile PEM should succeed", ret >= 0);
assertTrue(tempPem.exists());
assertTrue(tempPem.length() > 0);
tempPem.delete();
/* Test null path */
try {
crl.writeToFile(null, WolfSSL.SSL_FILETYPE_PEM);
System.out.println("\t\t\t... failed");
fail("null path should throw exception");
} catch (IllegalArgumentException e) {
/* expected */
}
/* Test empty path */
try {
crl.writeToFile("", WolfSSL.SSL_FILETYPE_PEM);
System.out.println("\t\t\t... failed");
fail("empty path should throw exception");
} catch (IllegalArgumentException e) {
/* expected */
}
/* Test invalid format */
try {
crl.writeToFile("test.der", 12345);
System.out.println("\t\t\t... failed");
fail("invalid format should throw exception");
} catch (IllegalArgumentException e) {
/* expected */
}
/* Free native memory */
issuerName.free();
crl.free();
System.out.println("\t\t\t... passed");
}
@Test
public void testGetDer()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException, NoSuchAlgorithmException {
System.out.print("\tgetDer()");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Set issuer name */
WolfSSLX509Name issuerName = GenerateTestIssuerName();
crl.setIssuerName(issuerName);
/* Set dates */
crl.setLastUpdate(new Date());
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, 30);
crl.setNextUpdate(cal.getTime());
/* Add revoked certificate */
byte[] serial = new byte[] { 0x01, 0x02, 0x03, 0x04 };
crl.addRevoked(serial, new Date());
/* Sign CRL */
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair keyPair = kpg.generateKeyPair();
PrivateKey privKey = keyPair.getPrivate();
crl.sign(privKey, "SHA256");
/* Get DER encoding */
byte[] der = crl.getDer();
assertNotNull(der);
assertTrue(der.length > 0);
/* Free native memory */
issuerName.free();
crl.free();
System.out.println("\t\t\t... passed");
}
@Test
public void testGetPem()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException, NoSuchAlgorithmException {
System.out.print("\tgetPem()");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Set issuer name */
WolfSSLX509Name issuerName = GenerateTestIssuerName();
crl.setIssuerName(issuerName);
/* Set dates */
crl.setLastUpdate(new Date());
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, 30);
crl.setNextUpdate(cal.getTime());
/* Add revoked certificate */
byte[] serial = new byte[] { 0x01, 0x02, 0x03, 0x04 };
crl.addRevoked(serial, new Date());
/* Sign CRL */
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair keyPair = kpg.generateKeyPair();
PrivateKey privKey = keyPair.getPrivate();
crl.sign(privKey, "SHA256");
/* Get PEM encoding */
byte[] pem = crl.getPem();
assertNotNull(pem);
assertTrue(pem.length > 0);
/* PEM should contain BEGIN/END markers */
String pemStr = new String(pem);
assertTrue(pemStr.contains("BEGIN"));
assertTrue(pemStr.contains("CRL"));
/* Free native memory */
issuerName.free();
crl.free();
System.out.println("\t\t\t... passed");
}
@Test
public void testGetVersion()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException {
System.out.print("\tgetVersion()");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t\t... skipped");
return;
}
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);
version = crl.getVersion();
if (version != 1) {
System.out.println("\t\t\t... failed");
fail("Version should be 1 (v2)");
}
crl.free();
System.out.println("\t\t\t... passed");
}
@Test
public void testGenCRL_UsingFiles()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException, NoSuchAlgorithmException {
System.out.print("\tgen CRL using files");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Set version */
crl.setVersion(1);
/* Set issuer name */
WolfSSLX509Name issuerName = GenerateTestIssuerName();
assertNotNull(issuerName);
crl.setIssuerName(issuerName);
/* Set dates */
Date lastUpdate = new Date();
crl.setLastUpdate(lastUpdate);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, 30);
Date nextUpdate = cal.getTime();
crl.setNextUpdate(nextUpdate);
/* Add revoked certificates by serial number */
byte[] serial1 = new byte[] { 0x01, 0x02, 0x03, 0x04 };
Date revDate1 = new Date();
crl.addRevoked(serial1, revDate1);
byte[] serial2 = new byte[] { 0x05, 0x06, 0x07, 0x08 };
Date revDate2 = new Date();
crl.addRevoked(serial2, revDate2);
/* Sign CRL with RSA key */
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair keyPair = kpg.generateKeyPair();
PrivateKey privKey = keyPair.getPrivate();
crl.sign(privKey, "SHA256");
/* Output to DER and PEM */
byte[] derCrl = crl.getDer();
byte[] pemCrl = crl.getPem();
assertNotNull(derCrl);
assertTrue(derCrl.length > 0);
assertNotNull(pemCrl);
assertTrue(pemCrl.length > 0);
/* Verify version */
int version = crl.getVersion();
assertEquals(1, version);
/* Verify dates */
Date retrievedLastUpdate = crl.getLastUpdate();
assertNotNull(retrievedLastUpdate);
Date retrievedNextUpdate = crl.getNextUpdate();
assertNotNull(retrievedNextUpdate);
/* Free native memory */
issuerName.free();
crl.free();
System.out.println("\t\t... passed");
}
@Test
public void testGenCRL_UsingCertificates()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException, NoSuchAlgorithmException {
System.out.print("\tgen CRL using certificates");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Set version */
crl.setVersion(1);
/* Set issuer name */
WolfSSLX509Name issuerName = GenerateTestIssuerName();
assertNotNull(issuerName);
crl.setIssuerName(issuerName);
/* Set dates */
Date lastUpdate = new Date();
crl.setLastUpdate(lastUpdate);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, 30);
Date nextUpdate = cal.getTime();
crl.setNextUpdate(nextUpdate);
/* Add revoked certificates using WolfSSLCertificate objects */
WolfSSLCertificate cert1 = new WolfSSLCertificate(clientCertPem,
WolfSSL.SSL_FILETYPE_PEM);
Date revDate1 = new Date();
crl.addRevokedCert(cert1, revDate1);
/* Sign CRL with RSA key */
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair keyPair = kpg.generateKeyPair();
PrivateKey privKey = keyPair.getPrivate();
crl.sign(privKey, "SHA256");
/* Output to DER and PEM */
byte[] derCrl = crl.getDer();
byte[] pemCrl = crl.getPem();
assertNotNull(derCrl);
assertTrue(derCrl.length > 0);
assertNotNull(pemCrl);
assertTrue(pemCrl.length > 0);
/* Free native memory */
cert1.free();
issuerName.free();
crl.free();
System.out.println("\t... passed");
}
@Test
public void testGenCRL_ECC()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException, NoSuchAlgorithmException {
System.out.print("\tgen CRL with ECC key");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t... skipped");
return;
}
if (!WolfSSL.EccEnabled()) {
System.out.println("\t\t... skipped (ECC not enabled)");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Set version */
crl.setVersion(1);
/* Set issuer name */
WolfSSLX509Name issuerName = GenerateTestIssuerName();
assertNotNull(issuerName);
crl.setIssuerName(issuerName);
/* Set dates */
Date lastUpdate = new Date();
crl.setLastUpdate(lastUpdate);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, 30);
Date nextUpdate = cal.getTime();
crl.setNextUpdate(nextUpdate);
/* Add revoked certificate */
byte[] serial = new byte[] { 0x01, 0x02, 0x03, 0x04 };
Date revDate = new Date();
crl.addRevoked(serial, revDate);
/* Sign CRL with ECC key */
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
kpg.initialize(256);
KeyPair keyPair = kpg.generateKeyPair();
PrivateKey privKey = keyPair.getPrivate();
crl.sign(privKey, "SHA256");
/* Output to DER and PEM */
byte[] derCrl = crl.getDer();
byte[] pemCrl = crl.getPem();
assertNotNull(derCrl);
assertTrue(derCrl.length > 0);
assertNotNull(pemCrl);
assertTrue(pemCrl.length > 0);
/* Free native memory */
issuerName.free();
crl.free();
System.out.println("\t\t... passed");
}
@Test
public void testFree()
throws WolfSSLException, WolfSSLJNIException, IOException,
CertificateException {
System.out.print("\tfree()");
if (WolfSSL.isEnabledCRL() == 0) {
/* CRL not enabled in wolfSSL */
System.out.println("\t\t\t... skipped");
return;
}
WolfSSLCRL crl = new WolfSSLCRL();
assertNotNull(crl);
/* Free should work */
crl.free();
/* Operations after free should throw IllegalStateException */
try {
crl.setVersion(1);
System.out.println("\t\t\t... failed");
fail("setVersion after free should throw exception");
} catch (IllegalStateException e) {
/* expected */
}
try {
crl.getVersion();
System.out.println("\t\t\t... failed");
fail("getVersion after free should throw exception");
} catch (IllegalStateException e) {
/* expected */
}
/* Multiple free() calls should be safe */
crl.free();
System.out.println("\t\t\t... passed");
}
}

View File

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