Skip to content

Commit 91c7466

Browse files
committed
JNI: add pathLen support to WolfSSLCertificate/WolfSSLCertRequest addExtension()
1 parent bbb0153 commit 91c7466

8 files changed

Lines changed: 306 additions & 18 deletions

native/com_wolfssl_WolfSSLCertRequest.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1add_1ext_1via_1
659659
}
660660

661661
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1add_1ext_1via_1set_1object_1boolean
662-
(JNIEnv* jenv, jclass jcl, jlong x509ReqPtr, jint nid, jboolean extValue, jboolean isCritical)
662+
(JNIEnv* jenv, jclass jcl, jlong x509ReqPtr, jint nid, jboolean extValue, jboolean isCritical, jint pathLen)
663663
{
664664
#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_EXTRA)
665665
WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509ReqPtr;
@@ -672,6 +672,17 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1add_1ext_1via_1
672672
return WOLFSSL_FAILURE;
673673
}
674674

675+
/* pathLen >= 0 requires wolfSSL > 5.8.4 which includes fixes so
676+
* wolfSSL_ASN1_OBJECT_dup() copies pathlen and wolfSSL_X509_add_ext()
677+
* correctly sets pathLengthSet for DER encoding. Without these fixes,
678+
* pathLen is silently dropped during cert generation. */
679+
if (pathLen >= 0) {
680+
#if !((LIBWOLFSSL_VERSION_HEX > 0x05008004) || \
681+
defined(WOLFSSL_PR9940_PATCH_APPLIED))
682+
return (jint)NOT_COMPILED_IN;
683+
#endif
684+
}
685+
675686
ext = wolfSSL_X509_EXTENSION_new();
676687
if (ext == NULL) {
677688
ret = WOLFSSL_FAILURE;
@@ -699,6 +710,16 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1add_1ext_1via_1
699710
}
700711
}
701712

713+
if (ret == WOLFSSL_SUCCESS && pathLen >= 0) {
714+
obj->pathlen = wolfSSL_ASN1_INTEGER_new();
715+
if (obj->pathlen == NULL) {
716+
ret = WOLFSSL_FAILURE;
717+
}
718+
else {
719+
obj->pathlen->length = pathLen;
720+
}
721+
}
722+
702723
if (ret == WOLFSSL_SUCCESS) {
703724
ret = wolfSSL_X509_EXTENSION_set_object(ext, obj);
704725
}
@@ -707,7 +728,6 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1add_1ext_1via_1
707728
ret = wolfSSL_X509_add_ext(x509, ext, -1);
708729
}
709730

710-
711731
if (obj != NULL) {
712732
wolfSSL_ASN1_OBJECT_free(obj);
713733
}
@@ -723,6 +743,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1add_1ext_1via_1
723743
(void)nid;
724744
(void)extValue;
725745
(void)isCritical;
746+
(void)pathLen;
726747
return (jint)NOT_COMPILED_IN;
727748
#endif
728749
}

native/com_wolfssl_WolfSSLCertRequest.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

native/com_wolfssl_WolfSSLCertificate.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1add_1ext_1via_1
365365
}
366366

367367
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1add_1ext_1via_1set_1object_1boolean
368-
(JNIEnv* jenv, jclass jcl, jlong x509Ptr, jint nid, jboolean extValue, jboolean isCritical)
368+
(JNIEnv* jenv, jclass jcl, jlong x509Ptr, jint nid, jboolean extValue, jboolean isCritical, jint pathLen)
369369
{
370370
#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_EXTRA)
371371
WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr;
@@ -378,6 +378,17 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1add_1ext_1via_1
378378
return WOLFSSL_FAILURE;
379379
}
380380

381+
/* pathLen >= 0 requires wolfSSL > 5.8.4 which includes fixes so
382+
* wolfSSL_ASN1_OBJECT_dup() copies pathlen and wolfSSL_X509_add_ext()
383+
* correctly sets pathLengthSet for DER encoding. Without these fixes,
384+
* pathLen is silently dropped during cert generation. */
385+
if (pathLen >= 0) {
386+
#if !((LIBWOLFSSL_VERSION_HEX > 0x05008004) || \
387+
defined(WOLFSSL_PR9940_PATCH_APPLIED))
388+
return (jint)NOT_COMPILED_IN;
389+
#endif
390+
}
391+
381392
ext = wolfSSL_X509_EXTENSION_new();
382393
if (ext == NULL) {
383394
ret = WOLFSSL_FAILURE;
@@ -405,6 +416,16 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1add_1ext_1via_1
405416
}
406417
}
407418

419+
if (ret == WOLFSSL_SUCCESS && pathLen >= 0) {
420+
obj->pathlen = wolfSSL_ASN1_INTEGER_new();
421+
if (obj->pathlen == NULL) {
422+
ret = WOLFSSL_FAILURE;
423+
}
424+
else {
425+
obj->pathlen->length = pathLen;
426+
}
427+
}
428+
408429
if (ret == WOLFSSL_SUCCESS) {
409430
ret = wolfSSL_X509_EXTENSION_set_object(ext, obj);
410431
}
@@ -413,7 +434,6 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1add_1ext_1via_1
413434
ret = wolfSSL_X509_add_ext(x509, ext, -1);
414435
}
415436

416-
417437
if (obj != NULL) {
418438
wolfSSL_ASN1_OBJECT_free(obj);
419439
}
@@ -429,6 +449,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1add_1ext_1via_1
429449
(void)nid;
430450
(void)extValue;
431451
(void)isCritical;
452+
(void)pathLen;
432453
return (jint)NOT_COMPILED_IN;
433454
#endif
434455
}

native/com_wolfssl_WolfSSLCertificate.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/java/com/wolfssl/WolfSSLCertRequest.java

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ static native int X509_REQ_set_pubkey_native_open(long x509ReqPtr,
7272
static native int X509_add_ext_via_nconf_nid(long x509Ptr, int nid,
7373
String extValue, boolean isCritical);
7474
static native int X509_add_ext_via_set_object_boolean(long x509Ptr,
75-
int nid, boolean extValue, boolean isCritical);
75+
int nid, boolean extValue, boolean isCritical, int pathLen);
7676

7777
/**
7878
* Create new empty WolfSSLCertRequest object, for use with CSR generation
@@ -506,6 +506,36 @@ public void addExtension(int nid, String value, boolean isCritical)
506506
public void addExtension(int nid, boolean value, boolean isCritical)
507507
throws IllegalStateException, WolfSSLException {
508508

509+
addExtension(nid, value, -1, isCritical);
510+
}
511+
512+
/**
513+
* Add Basic Constraints extension with CA flag and path length constraint
514+
* to a WolfSSLCertRequest.
515+
*
516+
* This method allows setting the Basic Constraints extension with both the
517+
* CA boolean and an optional path length constraint. The path length limits
518+
* the number of intermediate CA certificates that may follow this
519+
* certificate in a valid certification path.
520+
*
521+
* To set Basic Constraints without a path length constraint, use
522+
* {@link #addExtension(int, boolean, boolean)} with
523+
* {@code WolfSSL.NID_basic_constraints} instead.
524+
*
525+
* @param nid NID of extension to add. Must be:
526+
* WolfSSL.NID_basic_constraints
527+
* @param value Boolean value of CA flag (true for CA, false for end entity)
528+
* @param pathLen Maximum number of intermediate CA certificates allowed
529+
* below this CA. Must be >= 0, or -1 to not set a path length
530+
* constraint. Only meaningful when value is true.
531+
* @param isCritical Boolean flag indicating if this extension is critical
532+
*
533+
* @throws IllegalStateException if WolfSSLCertRequest has been freed
534+
* @throws WolfSSLException if invalid arguments or on native JNI error
535+
*/
536+
public void addExtension(int nid, boolean value, int pathLen,
537+
boolean isCritical) throws IllegalStateException, WolfSSLException {
538+
509539
int ret = 0;
510540

511541
confirmObjectIsActive();
@@ -514,20 +544,31 @@ public void addExtension(int nid, boolean value, boolean isCritical)
514544
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
515545
WolfSSLDebug.INFO, this.x509ReqPtr,
516546
() -> "entered addExtension(nid: " + nid + ", value: " + value +
517-
", isCritical: " + isCritical + ")");
547+
", pathLen: " + pathLen + ", isCritical: " + isCritical + ")");
518548
}
519549

520550
if (nid != WolfSSL.NID_basic_constraints) {
521551
throw new WolfSSLException(
522552
"Unsupported X509v3 extension NID: " + nid);
523553
}
524554

555+
if (pathLen < -1) {
556+
throw new WolfSSLException(
557+
"Path length must be >= 0 or -1, got: " + pathLen);
558+
}
559+
525560
synchronized (x509ReqLock) {
526-
ret = X509_add_ext_via_set_object_boolean(
527-
this.x509ReqPtr, nid, value, isCritical);
561+
ret = X509_add_ext_via_set_object_boolean(this.x509ReqPtr, nid,
562+
value, isCritical, pathLen);
528563
}
529564

530-
if (ret != WolfSSL.SSL_SUCCESS) {
565+
if (ret == WolfSSL.NOT_COMPILED_IN) {
566+
throw new WolfSSLException(
567+
"Basic Constraints with pathLen not compiled in, " +
568+
"requires wolfSSL > 5.8.4 or wolfSSL PR 9940 " +
569+
"patch with WOLFSSL_PR9940_PATCH_APPLIED defined");
570+
}
571+
else if (ret != WolfSSL.SSL_SUCCESS) {
531572
throw new WolfSSLException(
532573
"Error setting extension into native WOLFSSL_X509 " +
533574
"(ret: " + ret + ")");

src/java/com/wolfssl/WolfSSLCertificate.java

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ static native int X509_set_pubkey_native_open(long x509Ptr, int keyType,
127127
static native int X509_add_ext_via_nconf_nid(long x509Ptr, int nid,
128128
String extValue, boolean isCritical);
129129
static native int X509_add_ext_via_set_object_boolean(long x509Ptr,
130-
int nid, boolean extValue, boolean isCritical);
130+
int nid, boolean extValue, boolean isCritical, int pathLen);
131131
static native int X509_set_notBefore(long x509Ptr, long timeSecs);
132132
static native int X509_set_notAfter(long x509Ptr, long timeSecs);
133133
static native int X509_set_serialNumber(long x509Ptr, byte[] serialBytes);
@@ -1195,6 +1195,36 @@ public void addExtension(int nid, String value, boolean isCritical)
11951195
public void addExtension(int nid, boolean value, boolean isCritical)
11961196
throws IllegalStateException, WolfSSLException {
11971197

1198+
addExtension(nid, value, -1, isCritical);
1199+
}
1200+
1201+
/**
1202+
* Add Basic Constraints extension with CA flag and path length
1203+
* constraint to a WOLFSSL_X509.
1204+
*
1205+
* This method allows setting the Basic Constraints extension with both the
1206+
* CA boolean and an optional path length constraint. The path length limits
1207+
* the number of intermediate CA certificates that may follow this
1208+
* certificate in a valid certification path.
1209+
*
1210+
* To set Basic Constraints without a path length constraint, use
1211+
* {@link #addExtension(int, boolean, boolean)} with
1212+
* {@code WolfSSL.NID_basic_constraints} instead.
1213+
*
1214+
* @param nid NID of extension to add. Must be:
1215+
* WolfSSL.NID_basic_constraints
1216+
* @param value Boolean value of CA flag (true for CA, false for end entity)
1217+
* @param pathLen Maximum number of intermediate CA certificates allowed
1218+
* below this CA. Must be &gt;= 0, or -1 to not set a path length
1219+
* constraint. Only meaningful when value is true.
1220+
* @param isCritical Boolean flag indicating if this extension is critical
1221+
*
1222+
* @throws IllegalStateException if WolfSSLCertificate has been freed
1223+
* @throws WolfSSLException if invalid arguments or on native JNI error.
1224+
*/
1225+
public void addExtension(int nid, boolean value, int pathLen,
1226+
boolean isCritical) throws IllegalStateException, WolfSSLException {
1227+
11981228
int ret = 0;
11991229

12001230
confirmObjectIsActive();
@@ -1203,20 +1233,33 @@ public void addExtension(int nid, boolean value, boolean isCritical)
12031233
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
12041234
WolfSSLDebug.INFO, this.x509Ptr,
12051235
() -> "entering addExtension(nid: " + nid + ", value: " +
1206-
value + ", isCritical: " + isCritical + ")");
1236+
value + ", pathLen: " + pathLen + ", isCritical: " +
1237+
isCritical + ")");
12071238
}
12081239

12091240
if (nid != WolfSSL.NID_basic_constraints) {
12101241
throw new WolfSSLException(
12111242
"Unsupported X509v3 extension NID: " + nid);
12121243
}
12131244

1245+
if (pathLen < -1) {
1246+
throw new WolfSSLException(
1247+
"Path length must be >= 0 or -1, got: " + pathLen);
1248+
}
1249+
12141250
synchronized (x509Lock) {
1215-
ret = X509_add_ext_via_set_object_boolean(
1216-
this.x509Ptr, nid, value, isCritical);
1251+
ret = X509_add_ext_via_set_object_boolean(this.x509Ptr, nid, value,
1252+
isCritical, pathLen);
12171253
}
12181254

1219-
if (ret != WolfSSL.SSL_SUCCESS) {
1255+
if (ret == WolfSSL.NOT_COMPILED_IN) {
1256+
throw new WolfSSLException(
1257+
"Basic Constraints with pathLen NOT_COMPILED_IN, " +
1258+
"requires wolfSSL > 5.8.4 or wolfSSL PR 9940 " +
1259+
"patch with WOLFSSL_PR9940_PATCH_APPLIED " +
1260+
"defined (ret: " + ret + ")");
1261+
}
1262+
else if (ret != WolfSSL.SSL_SUCCESS) {
12201263
throw new WolfSSLException(
12211264
"Error setting extension into native WOLFSSL_X509 " +
12221265
"(ret: " + ret + ")");

src/test/com/wolfssl/test/WolfSSLCertRequestTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,16 @@ public static void setCertPaths() throws WolfSSLException {
7474
cliEccKeyPem = WolfSSLTestCommon.getPath(cliEccKeyPem);
7575
}
7676

77+
private boolean isNotCompiledIn(WolfSSLException e) {
78+
String msg = e.getMessage();
79+
if (msg == null) {
80+
return false;
81+
}
82+
return msg.contains(
83+
Integer.toString(WolfSSL.NOT_COMPILED_IN)) ||
84+
msg.contains("NOT_COMPILED_IN");
85+
}
86+
7787
/* Internal helper method, generate test SubjectName for cert generation */
7888
private WolfSSLX509Name GenerateTestSubjectName() throws WolfSSLException {
7989

@@ -185,6 +195,42 @@ public void testAddExtension()
185195
req.addExtension(WolfSSL.NID_basic_constraints, true, true);
186196
req.addExtension(WolfSSL.NID_basic_constraints, false, true);
187197

198+
/* Test boolean extension with pathLen */
199+
try {
200+
req.addExtension(WolfSSL.NID_basic_constraints, true, 0, true);
201+
} catch (WolfSSLException e) {
202+
if (!isNotCompiledIn(e)) {
203+
throw e;
204+
}
205+
System.out.println("\t\t\t... skipped");
206+
}
207+
try {
208+
req.addExtension(WolfSSL.NID_basic_constraints, true, 3, true);
209+
} catch (WolfSSLException e) {
210+
if (!isNotCompiledIn(e)) {
211+
throw e;
212+
}
213+
System.out.println("\t\t\t... skipped");
214+
}
215+
216+
/* Invalid pathLen (< -1) should throw WolfSSLException */
217+
try {
218+
req.addExtension(WolfSSL.NID_basic_constraints, true, -2, true);
219+
System.out.println("\t\t\t... failed");
220+
fail("Invalid pathLen did not throw exception");
221+
} catch (WolfSSLException e) {
222+
/* expected */
223+
}
224+
225+
/* Unsupported NID with pathLen should throw exception */
226+
try {
227+
req.addExtension(123456, true, 0, true);
228+
System.out.println("\t\t\t... failed");
229+
fail("Unsupported NID did not throw exception");
230+
} catch (WolfSSLException e) {
231+
/* expected */
232+
}
233+
188234
/* Adding unsupported NID should throw exception */
189235
try {
190236
req.addExtension(123456, true, false);

0 commit comments

Comments
 (0)