/* com_wolfssl_WolfSSLNameConstraints.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 3 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 #include #ifdef WOLFSSL_USER_SETTINGS #include #else #include #endif #include #include #include #include "com_wolfssl_globals.h" #include "com_wolfssl_WolfSSLNameConstraints.h" /* Maximum reasonable string length to prevent excessive allocation (64KB) */ #define NC_MAX_STRING_LEN 65536 /* Name Constraints API was added after wolfSSL 5.8.4 in PR 9705. Version * check must be greater than 5.8.4 or patch from PR 9705 must be applied * and WOLFSSL_PR9705_PATCH_APPLIED defined when compiling this JNI wrapper. */ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLNameConstraints_wolfSSL_1NAME_1CONSTRAINTS_1free (JNIEnv* jenv, jclass jcl, jlong ncPtr) { #if defined(OPENSSL_EXTRA) && !defined(IGNORE_NAME_CONSTRAINTS) && \ ((LIBWOLFSSL_VERSION_HEX > 0x05008004) || \ defined(WOLFSSL_PR9705_PATCH_APPLIED)) (void)jenv; (void)jcl; if (ncPtr != 0) { wolfSSL_NAME_CONSTRAINTS_free( (WOLFSSL_NAME_CONSTRAINTS*)(uintptr_t)ncPtr); } #else (void)jenv; (void)jcl; (void)ncPtr; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLNameConstraints_wolfSSL_1NAME_1CONSTRAINTS_1permittedNum (JNIEnv* jenv, jclass jcl, jlong ncPtr) { #if defined(OPENSSL_EXTRA) && !defined(IGNORE_NAME_CONSTRAINTS) && \ ((LIBWOLFSSL_VERSION_HEX > 0x05008004) || \ defined(WOLFSSL_PR9705_PATCH_APPLIED)) WOLFSSL_NAME_CONSTRAINTS* nc = (WOLFSSL_NAME_CONSTRAINTS*)(uintptr_t)ncPtr; (void)jenv; (void)jcl; if (nc == NULL || nc->permittedSubtrees == NULL) { return 0; } return (jint)wolfSSL_sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); #else (void)jenv; (void)jcl; (void)ncPtr; return 0; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLNameConstraints_wolfSSL_1NAME_1CONSTRAINTS_1excludedNum (JNIEnv* jenv, jclass jcl, jlong ncPtr) { #if defined(OPENSSL_EXTRA) && !defined(IGNORE_NAME_CONSTRAINTS) && \ ((LIBWOLFSSL_VERSION_HEX > 0x05008004) || \ defined(WOLFSSL_PR9705_PATCH_APPLIED)) WOLFSSL_NAME_CONSTRAINTS* nc = (WOLFSSL_NAME_CONSTRAINTS*)(uintptr_t)ncPtr; (void)jenv; (void)jcl; if (nc == NULL || nc->excludedSubtrees == NULL) { return 0; } return (jint)wolfSSL_sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); #else (void)jenv; (void)jcl; (void)ncPtr; return 0; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLNameConstraints_wolfSSL_1GENERAL_1SUBTREE_1getBaseType (JNIEnv* jenv, jclass jcl, jlong ncPtr, jboolean permitted, jint idx) { #if defined(OPENSSL_EXTRA) && !defined(IGNORE_NAME_CONSTRAINTS) && \ ((LIBWOLFSSL_VERSION_HEX > 0x05008004) || \ defined(WOLFSSL_PR9705_PATCH_APPLIED)) WOLFSSL_NAME_CONSTRAINTS* nc = (WOLFSSL_NAME_CONSTRAINTS*)(uintptr_t)ncPtr; WOLFSSL_STACK* sk; WOLFSSL_GENERAL_SUBTREE* subtree; int skNum; (void)jenv; (void)jcl; if (nc == NULL) { return -1; } sk = permitted ? nc->permittedSubtrees : nc->excludedSubtrees; if (sk == NULL) { return -1; } /* Bounds check for idx to prevent out-of-bounds access */ skNum = wolfSSL_sk_GENERAL_SUBTREE_num(sk); if (idx < 0 || idx >= skNum) { return -1; } subtree = wolfSSL_sk_GENERAL_SUBTREE_value(sk, (int)idx); if (subtree == NULL || subtree->base == NULL) { return -1; } return (jint)subtree->base->type; #else (void)jenv; (void)jcl; (void)ncPtr; (void)permitted; (void)idx; return -1; #endif } JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLNameConstraints_wolfSSL_1GENERAL_1SUBTREE_1getBaseValue (JNIEnv* jenv, jclass jcl, jlong ncPtr, jboolean permitted, jint idx) { #if defined(OPENSSL_EXTRA) && !defined(IGNORE_NAME_CONSTRAINTS) && \ ((LIBWOLFSSL_VERSION_HEX > 0x05008004) || \ defined(WOLFSSL_PR9705_PATCH_APPLIED)) WOLFSSL_NAME_CONSTRAINTS* nc = (WOLFSSL_NAME_CONSTRAINTS*)(uintptr_t)ncPtr; WOLFSSL_STACK* sk; WOLFSSL_GENERAL_SUBTREE* subtree; WOLFSSL_GENERAL_NAME* gn; const unsigned char* str = NULL; int strLen = 0; int skNum; char* buf = NULL; jstring result = NULL; (void)jcl; if (nc == NULL || jenv == NULL) { return NULL; } sk = permitted ? nc->permittedSubtrees : nc->excludedSubtrees; if (sk == NULL) { return NULL; } /* Bounds check for idx to prevent out-of-bounds access */ skNum = wolfSSL_sk_GENERAL_SUBTREE_num(sk); if (idx < 0 || idx >= skNum) { return NULL; } subtree = wolfSSL_sk_GENERAL_SUBTREE_value(sk, (int)idx); if (subtree == NULL || subtree->base == NULL) { return NULL; } gn = subtree->base; switch (gn->type) { case WOLFSSL_GEN_DNS: case WOLFSSL_GEN_EMAIL: case WOLFSSL_GEN_URI: if (gn->d.ia5 != NULL) { str = wolfSSL_ASN1_STRING_get0_data(gn->d.ia5); strLen = wolfSSL_ASN1_STRING_length(gn->d.ia5); } break; case WOLFSSL_GEN_DIRNAME: if (gn->d.directoryName != NULL) { /* Convert X509_NAME to one-line string */ buf = wolfSSL_X509_NAME_oneline(gn->d.directoryName, NULL, 0); if (buf != NULL) { result = (*jenv)->NewStringUTF(jenv, buf); XFREE(buf, NULL, DYNAMIC_TYPE_OPENSSL); return result; } } return NULL; case WOLFSSL_GEN_IPADD: /* For IP addresses, return address/mask notation. * IPv4 (8 bytes): "192.168.1.0/255.255.255.0" * IPv6 (32 bytes): "fe80:0000:...:0001/ffff:ffff:...:0000" */ if (gn->d.ip != NULL) { int i; int ipLen = wolfSSL_ASN1_STRING_length(gn->d.ip); const unsigned char* ipData = wolfSSL_ASN1_STRING_get0_data(gn->d.ip); if (ipData != NULL && ipLen > 0 && ipLen <= 32) { if (ipLen == 8) { /* IPv4: 4 bytes IP + 4 bytes mask */ /* Max: "255.255.255.255/255.255.255.255" = 31 chars */ buf = (char*)XMALLOC(40, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (buf != NULL) { XSNPRINTF(buf, 40, "%d.%d.%d.%d/%d.%d.%d.%d", ipData[0], ipData[1], ipData[2], ipData[3], ipData[4], ipData[5], ipData[6], ipData[7]); result = (*jenv)->NewStringUTF(jenv, buf); XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return result; } } else if (ipLen == 32) { /* IPv6: 16 bytes IP + 16 bytes mask * Format: "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/ * yyyy:yyyy:yyyy:yyyy:yyyy:yyyy:yyyy:yyyy" * 8 groups * 4 chars + 7 colons = 39 chars per addr * 39 + 1 (slash) + 39 = 79 chars + null = 80 */ buf = (char*)XMALLOC(80, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (buf != NULL) { int pos = 0; /* Format address (first 16 bytes) */ for (i = 0; i < 16; i += 2) { if (i > 0) { buf[pos++] = ':'; } XSNPRINTF(buf + pos, 5, "%02x%02x", ipData[i], ipData[i + 1]); pos += 4; } buf[pos++] = '/'; /* Format mask (next 16 bytes) */ for (i = 16; i < 32; i += 2) { if (i > 16) { buf[pos++] = ':'; } XSNPRINTF(buf + pos, 5, "%02x%02x", ipData[i], ipData[i + 1]); pos += 4; } buf[pos] = '\0'; result = (*jenv)->NewStringUTF(jenv, buf); XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return result; } } else { /* Other lengths: return colon-separated hex bytes */ int bufLen = ipLen * 3; buf = (char*)XMALLOC(bufLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (buf != NULL) { int pos = 0; for (i = 0; i < ipLen; i++) { if (i > 0) { buf[pos++] = ':'; } XSNPRINTF(buf + pos, 3, "%02X", ipData[i]); pos += 2; } buf[pos] = '\0'; result = (*jenv)->NewStringUTF(jenv, buf); XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return result; } } } } return NULL; default: return NULL; } /* Validate strLen to prevent excessive allocation */ if (str != NULL && strLen > 0 && strLen <= NC_MAX_STRING_LEN) { /* Create null-terminated copy for JNI NewStringUTF */ buf = (char*)XMALLOC(strLen + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (buf != NULL) { XMEMCPY(buf, str, strLen); buf[strLen] = '\0'; result = (*jenv)->NewStringUTF(jenv, buf); XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); } } return result; #else (void)jenv; (void)jcl; (void)ncPtr; (void)permitted; (void)idx; return NULL; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLNameConstraints_wolfSSL_1NAME_1CONSTRAINTS_1check_1name (JNIEnv* jenv, jclass jcl, jlong ncPtr, jint type, jstring name) { #if defined(OPENSSL_EXTRA) && !defined(IGNORE_NAME_CONSTRAINTS) && \ ((LIBWOLFSSL_VERSION_HEX > 0x05008004) || \ defined(WOLFSSL_PR9705_PATCH_APPLIED)) WOLFSSL_NAME_CONSTRAINTS* nc = (WOLFSSL_NAME_CONSTRAINTS*)(uintptr_t)ncPtr; const char* nameStr = NULL; int nameLen = 0; int ret = 0; (void)jcl; if (nc == NULL || jenv == NULL || name == NULL) { return 0; } /* Get the name string from Java */ nameStr = (*jenv)->GetStringUTFChars(jenv, name, NULL); if (nameStr == NULL) { return 0; } nameLen = (int)(*jenv)->GetStringUTFLength(jenv, name); /* Call native wolfSSL function */ ret = wolfSSL_NAME_CONSTRAINTS_check_name(nc, (int)type, nameStr, nameLen); /* Release the string */ (*jenv)->ReleaseStringUTFChars(jenv, name, nameStr); return (jint)ret; #else (void)jenv; (void)jcl; (void)ncPtr; (void)type; (void)name; return 0; #endif }