/* conf.c * * Copyright (C) 2006-2022 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 */ #ifdef HAVE_CONFIG_H #include #endif #include #if !defined(WOLFSSL_CONF_INCLUDED) #ifndef WOLFSSL_IGNORE_FILE_WARN #warning conf.c does not need to be compiled separately from ssl.c #endif #else /******************************************************************************* * START OF TXT_DB API ******************************************************************************/ #if defined(OPENSSL_ALL) && !defined(NO_BIO) /** * This function reads a tab delimetered CSV input and returns * a populated WOLFSSL_TXT_DB structure. * @param in Tab delimetered CSV input * @param num Number of fields in each row. * @return */ WOLFSSL_TXT_DB *wolfSSL_TXT_DB_read(WOLFSSL_BIO *in, int num) { WOLFSSL_TXT_DB *ret = NULL; char *buf = NULL; char *bufEnd = NULL; char *idx = NULL; char* lineEnd = NULL; int bufSz; int failed = 1; /* Space in front of str reserved for field pointers + \0 */ int fieldsSz = (num + 1) * sizeof(char *); WOLFSSL_ENTER("wolfSSL_TXT_DB_read"); if (!in || num <= 0 || num > WOLFSSL_TXT_DB_MAX_FIELDS) { WOLFSSL_MSG("Bad parameter or too many fields"); return NULL; } if (!(ret = (WOLFSSL_TXT_DB*)XMALLOC(sizeof(WOLFSSL_TXT_DB), NULL, DYNAMIC_TYPE_OPENSSL))) { WOLFSSL_MSG("malloc error"); goto error; } XMEMSET (ret, 0, sizeof(WOLFSSL_TXT_DB)); ret->num_fields = num; if (!(ret->data = wolfSSL_sk_WOLFSSL_STRING_new())) { WOLFSSL_MSG("wolfSSL_sk_WOLFSSL_STRING_new error"); goto error; } bufSz = wolfSSL_BIO_get_len(in); if (bufSz <= 0 || !(buf = (char*)XMALLOC(bufSz+1, NULL, DYNAMIC_TYPE_TMP_BUFFER))) { WOLFSSL_MSG("malloc error or no data in BIO"); goto error; } if (wolfSSL_BIO_read(in, buf, bufSz) != bufSz) { WOLFSSL_MSG("malloc error or no data in BIO"); goto error; } buf[bufSz] = '\0'; idx = buf; for (bufEnd = buf + bufSz; idx < bufEnd; idx = lineEnd + 1) { char* strBuf = NULL; char** fieldPtr = NULL; int fieldPtrIdx = 0; char* fieldCheckIdx = NULL; lineEnd = XSTRNSTR(idx, "\n", (unsigned int)(bufEnd - idx)); if (!lineEnd) lineEnd = bufEnd; if (idx == lineEnd) /* empty line */ continue; if (*idx == '#') continue; *lineEnd = '\0'; strBuf = (char*)XMALLOC(fieldsSz + lineEnd - idx + 1, NULL, DYNAMIC_TYPE_OPENSSL); if (!strBuf) { WOLFSSL_MSG("malloc error"); goto error; } XMEMCPY(strBuf + fieldsSz, idx, lineEnd - idx + 1); /* + 1 for NULL */ XMEMSET(strBuf, 0, fieldsSz); /* Check for appropriate number of fields */ fieldPtr = (char**)strBuf; fieldCheckIdx = strBuf + fieldsSz; fieldPtr[fieldPtrIdx++] = fieldCheckIdx; while (*fieldCheckIdx != '\0') { /* Handle escaped tabs */ if (*fieldCheckIdx == '\t' && fieldCheckIdx[-1] != '\\') { fieldPtr[fieldPtrIdx++] = fieldCheckIdx + 1; *fieldCheckIdx = '\0'; if (fieldPtrIdx > num) { WOLFSSL_MSG("too many fields"); XFREE(strBuf, NULL, DYNAMIC_TYPE_OPENSSL); goto error; } } fieldCheckIdx++; } if (fieldPtrIdx != num) { WOLFSSL_MSG("wrong number of fields"); XFREE(strBuf, NULL, DYNAMIC_TYPE_OPENSSL); goto error; } if (wolfSSL_sk_push(ret->data, strBuf) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_sk_push error"); XFREE(strBuf, NULL, DYNAMIC_TYPE_OPENSSL); goto error; } } failed = 0; error: if (failed && ret) { XFREE(ret, NULL, DYNAMIC_TYPE_OPENSSL); ret = NULL; } if (buf) { XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); } return ret; } long wolfSSL_TXT_DB_write(WOLFSSL_BIO *out, WOLFSSL_TXT_DB *db) { const WOLF_STACK_OF(WOLFSSL_STRING)* data; long totalLen = 0; char buf[512]; /* Should be more than enough for a single row */ char* bufEnd = buf + sizeof(buf); int sz; int i; WOLFSSL_ENTER("wolfSSL_TXT_DB_write"); if (!out || !db || !db->num_fields) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } data = db->data; while (data) { char** fields = (char**)data->data.string; char* idx = buf; if (!fields) { WOLFSSL_MSG("Missing row"); return WOLFSSL_FAILURE; } for (i = 0; i < db->num_fields; i++) { const char* fieldValue = fields[i]; if (!fieldValue) { fieldValue = ""; } /* Copy over field escaping tabs */ while (*fieldValue != '\0') { if (idx+1 < bufEnd) { if (*fieldValue == '\t') *idx++ = '\\'; *idx++ = *fieldValue++; } else { WOLFSSL_MSG("Data row is too big"); return WOLFSSL_FAILURE; } } if (idx < bufEnd) { *idx++ = '\t'; } else { WOLFSSL_MSG("Data row is too big"); return WOLFSSL_FAILURE; } } idx[-1] = '\n'; sz = (int)(idx - buf); if (wolfSSL_BIO_write(out, buf, sz) != sz) { WOLFSSL_MSG("wolfSSL_BIO_write error"); return WOLFSSL_FAILURE; } totalLen += sz; data = data->next; } return totalLen; } int wolfSSL_TXT_DB_insert(WOLFSSL_TXT_DB *db, WOLFSSL_STRING *row) { WOLFSSL_ENTER("wolfSSL_TXT_DB_insert"); if (!db || !row || !db->data) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } if (wolfSSL_sk_push(db->data, row) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_sk_push error"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } void wolfSSL_TXT_DB_free(WOLFSSL_TXT_DB *db) { WOLFSSL_ENTER("wolfSSL_TXT_DB_free"); if (db) { if (db->data) { wolfSSL_sk_pop_free(db->data, NULL); } XFREE(db, NULL, DYNAMIC_TYPE_OPENSSL); } } int wolfSSL_TXT_DB_create_index(WOLFSSL_TXT_DB *db, int field, void* qual, wolf_sk_hash_cb hash, wolf_sk_compare_cb cmp) { WOLFSSL_ENTER("wolfSSL_TXT_DB_create_index"); (void)qual; if (!db || !hash || !cmp || field >= db->num_fields || field < 0) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } db->hash_fn[field] = hash; db->comp[field] = cmp; return WOLFSSL_SUCCESS; } WOLFSSL_STRING *wolfSSL_TXT_DB_get_by_index(WOLFSSL_TXT_DB *db, int idx, WOLFSSL_STRING *value) { WOLFSSL_ENTER("wolfSSL_TXT_DB_get_by_index"); if (!db || !db->data || idx < 0 || idx >= db->num_fields) { WOLFSSL_MSG("Bad parameter"); return NULL; } if (!db->hash_fn[idx] || !db->comp[idx]) { WOLFSSL_MSG("Missing hash or cmp functions"); return NULL; } /* If first data struct has correct hash and cmp function then * assume others do too */ if (db->data->hash_fn != db->hash_fn[idx] || db->data->comp != db->comp[idx]) { /* Set the hash and comp functions */ WOLF_STACK_OF(WOLFSSL_STRING)* data = db->data; while (data) { if (data->comp != db->comp[idx] || data->hash_fn != db->hash_fn[idx]) { data->comp = db->comp[idx]; data->hash_fn = db->hash_fn[idx]; data->hash = 0; } data= data->next; } } return (WOLFSSL_STRING*) wolfSSL_lh_retrieve(db->data, value); } #endif /* OPENSSL_ALL && !NO_BIO */ /******************************************************************************* * END OF TXT_DB API ******************************************************************************/ /******************************************************************************* * START OF CONF API ******************************************************************************/ #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ || defined(HAVE_STUNNEL) #ifndef NO_WOLFSSL_STUB void wolfSSL_OPENSSL_config(char *config_name) { (void)config_name; WOLFSSL_STUB("OPENSSL_config"); } #endif /* !NO_WOLFSSL_STUB */ #endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY || HAVE_STUNNEL*/ #if !defined(NO_CERTS) && defined(OPENSSL_EXTRA) && defined(OPENSSL_ALL) /** * This is the same hashing algo for WOLFSSL_CONF_VALUE as OpenSSL */ static unsigned long wolfSSL_CONF_VALUE_hash(const WOLFSSL_CONF_VALUE *val) { if (val) return (wolfSSL_LH_strhash(val->section) << 2) ^ wolfSSL_LH_strhash(val->name); else return 0; } static int wolfssl_conf_value_cmp(const WOLFSSL_CONF_VALUE *a, const WOLFSSL_CONF_VALUE *b) { int cmp_val; if (!a || !b) { return WOLFSSL_FATAL_ERROR; } if (a->section != b->section) { if ((cmp_val = XSTRCMP(a->section, b->section)) != 0) { return cmp_val; } } if (a->name && b->name) { return XSTRCMP(a->name, b->name); } else if (a->name == b->name) { return 0; } else { return a->name ? 1 : -1; } } /* Use SHA for hashing as OpenSSL uses a hash algorithm that is * "not as good as MD5, but still good" so using SHA should be more * than good enough for this application. The produced hashes don't * need to line up between OpenSSL and wolfSSL. The hashes are for * internal indexing only */ unsigned long wolfSSL_LH_strhash(const char *str) { unsigned long ret = 0; #ifndef NO_SHA wc_Sha sha; int strLen; byte digest[WC_SHA_DIGEST_SIZE]; #endif WOLFSSL_ENTER("wolfSSL_LH_strhash"); if (!str) return 0; #ifndef NO_SHA strLen = (int)XSTRLEN(str); if (wc_InitSha_ex(&sha, NULL, 0) != 0) { WOLFSSL_MSG("SHA1 Init failed"); return 0; } ret = wc_ShaUpdate(&sha, (const byte *)str, (word32)strLen); if (ret != 0) { WOLFSSL_MSG("SHA1 Update failed"); } else { ret = wc_ShaFinal(&sha, digest); if (ret != 0) { WOLFSSL_MSG("SHA1 Final failed"); } } wc_ShaFree(&sha); if (ret != 0) return 0; /* Take first 4 bytes in small endian as unsigned long */ ret = (unsigned int)digest[0]; ret |= ((unsigned int)digest[1] << 8 ); ret |= ((unsigned int)digest[2] << 16); ret |= ((unsigned int)digest[3] << 24); #else WOLFSSL_MSG("No SHA available for wolfSSL_LH_strhash"); #endif return ret; } WOLFSSL_CONF_VALUE *wolfSSL_lh_WOLFSSL_CONF_VALUE_retrieve( WOLF_LHASH_OF(WOLFSSL_CONF_VALUE) *sk, WOLFSSL_CONF_VALUE *data) { WOLFSSL_ENTER("wolfSSL_lh_WOLFSSL_CONF_VALUE_retrieve"); if (!sk || !data) { WOLFSSL_MSG("Bad parameter"); return NULL; } return (WOLFSSL_CONF_VALUE*)wolfSSL_lh_retrieve(sk, data); } int wolfSSL_CONF_modules_load(const WOLFSSL_CONF *cnf, const char *appname, unsigned long flags) { WOLFSSL_ENTER("wolfSSL_CONF_modules_load"); WOLFSSL_MSG("All wolfSSL modules are already compiled in. " "wolfSSL_CONF_modules_load doesn't load anything new."); (void)cnf; (void)appname; (void)flags; return WOLFSSL_SUCCESS; } WOLFSSL_CONF_VALUE *wolfSSL_CONF_VALUE_new(void) { WOLFSSL_CONF_VALUE* ret; WOLFSSL_ENTER("wolfSSL_CONF_new"); ret = (WOLFSSL_CONF_VALUE*)XMALLOC(sizeof(WOLFSSL_CONF_VALUE), NULL, DYNAMIC_TYPE_OPENSSL); if (ret) XMEMSET(ret, 0, sizeof(WOLFSSL_CONF_VALUE)); return ret; } int wolfSSL_CONF_add_string(WOLFSSL_CONF *conf, WOLFSSL_CONF_VALUE *section, WOLFSSL_CONF_VALUE *value) { WOLF_STACK_OF(WOLFSSL_CONF_VALUE) *sk = NULL; if (!conf || !section || !value) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } sk = (WOLF_STACK_OF(WOLFSSL_CONF_VALUE) *)section->value; value->section = section->section; if (wolfSSL_sk_CONF_VALUE_push(sk, value) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_sk_CONF_VALUE_push error"); return WOLFSSL_FAILURE; } if (wolfSSL_sk_CONF_VALUE_push(conf->data, value) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_sk_CONF_VALUE_push error"); return WOLFSSL_FAILURE; } return WOLFSSL_SUCCESS; } WOLFSSL_CONF_VALUE *wolfSSL_CONF_new_section(WOLFSSL_CONF *conf, const char *section) { WOLFSSL_CONF_VALUE* ret = NULL; WOLF_STACK_OF(WOLFSSL_CONF_VALUE) *sk = NULL; int slen; WOLFSSL_ENTER("wolfSSL_CONF_new_section"); if (!conf || !section) { WOLFSSL_MSG("Bad parameter"); return NULL; } slen = (int)XSTRLEN(section); if (!(ret = wolfSSL_CONF_VALUE_new())) { WOLFSSL_MSG("wolfSSL_CONF_new error"); goto error; } if (!(ret->section = (char*)XMALLOC(slen+1, NULL, DYNAMIC_TYPE_OPENSSL))) { WOLFSSL_MSG("section malloc error"); goto error; } XMEMCPY(ret->section, section, slen+1); if (!(sk = wolfSSL_sk_CONF_VALUE_new(NULL))) { WOLFSSL_MSG("wolfSSL_sk_CONF_VALUE_new error"); goto error; } ret->value = (char*)sk; if (wolfSSL_sk_CONF_VALUE_push(conf->data, ret) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_sk_CONF_VALUE_push error"); goto error; } return ret; error: if (ret) { /* NULL so that wolfSSL_X509V3_conf_free doesn't attempt to free it */ ret->value = NULL; wolfSSL_X509V3_conf_free(ret); } if (sk) { wolfSSL_sk_CONF_VALUE_free(sk); } return NULL; } WOLFSSL_CONF_VALUE *wolfSSL_CONF_get_section(WOLFSSL_CONF *conf, const char *section) { WOLF_STACK_OF(WOLFSSL_CONF_VALUE) *sk = NULL; WOLFSSL_ENTER("wolfSSL_CONF_get_section"); if (!conf || !section) { WOLFSSL_MSG("Bad parameter"); return NULL; } sk = conf->data; while (sk) { WOLFSSL_CONF_VALUE* val = sk->data.conf; if (val) { if (!val->name && XSTRCMP(section, val->section) == 0) { return val; } } sk = sk->next; } return NULL; } WOLFSSL_CONF *wolfSSL_NCONF_new(void *meth) { WOLFSSL_CONF* ret; WOLFSSL_ENTER("wolfSSL_NCONF_new"); if (meth) { WOLFSSL_MSG("wolfSSL does not support CONF_METHOD"); } ret = (WOLFSSL_CONF*)XMALLOC(sizeof(WOLFSSL_CONF), NULL, DYNAMIC_TYPE_OPENSSL); if (ret) { XMEMSET(ret, 0, sizeof(WOLFSSL_CONF)); ret->data = wolfSSL_sk_CONF_VALUE_new(NULL); if (!ret->data) { wolfSSL_NCONF_free(ret); return NULL; } } return ret; } char *wolfSSL_NCONF_get_string(const WOLFSSL_CONF *conf, const char *group, const char *name) { WOLFSSL_CONF_VALUE find_val; WOLFSSL_CONF_VALUE *val; WOLFSSL_ENTER("wolfSSL_NCONF_get_string"); if (!conf) { #ifdef HAVE_SECURE_GETENV return secure_getenv(name); #else WOLFSSL_MSG("Missing secure_getenv"); return NULL; #endif } find_val.name = (char *)name; if (group) { find_val.section = (char *)group; val = wolfSSL_lh_WOLFSSL_CONF_VALUE_retrieve(conf->data, &find_val); if (val) return val->value; if (XSTRCMP(group, "ENV") == 0) { #ifdef HAVE_SECURE_GETENV return secure_getenv(name); #else WOLFSSL_MSG("Missing secure_getenv"); return NULL; #endif } } find_val.section = (char *)"default"; val = wolfSSL_lh_WOLFSSL_CONF_VALUE_retrieve(conf->data, &find_val); if (val) return val->value; else return NULL; } int wolfSSL_NCONF_get_number(const CONF *conf, const char *group, const char *name, long *result) { char *str; WOLFSSL_ENTER("wolfSSL_NCONF_get_number"); if (!conf || !name || !result) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } if (!(str = wolfSSL_NCONF_get_string(conf, group, name))) { WOLFSSL_MSG("wolfSSL_NCONF_get_string error"); return WOLFSSL_FAILURE; } *result = atol(str); return WOLFSSL_SUCCESS; } /** * The WOLFSSL_CONF->value member is treated as a * WOLFSSL_STACK_OF(WOLFSSL_CONF_VALUE) which becomes * the return value. * @param conf * @param section * @return WOLFSSL_STACK_OF(WOLFSSL_CONF_VALUE) */ WOLFSSL_STACK *wolfSSL_NCONF_get_section( const WOLFSSL_CONF *conf, const char *section) { WOLFSSL_CONF_VALUE *val; WOLFSSL_CONF_VALUE find_val; WOLFSSL_ENTER("wolfSSL_NCONF_get_section"); if (!conf || !section) { WOLFSSL_MSG("Bad parameter"); return NULL; } find_val.name = NULL; find_val.section = (char*)section; val = wolfSSL_lh_WOLFSSL_CONF_VALUE_retrieve(conf->data, &find_val); if (val) return (WOLFSSL_STACK*)val->value; else return NULL; } #if !defined(NO_BIO) static WOLFSSL_CONF_VALUE *wolfSSL_CONF_VALUE_new_values(char* section, char* name, char* value) { WOLFSSL_CONF_VALUE* ret; int len; WOLFSSL_ENTER("wolfSSL_CONF_VALUE_new_values"); if (!(ret = wolfSSL_CONF_VALUE_new())) { WOLFSSL_MSG("wolfSSL_CONF_VALUE_new error"); return NULL; } if (section) { len = (int)XSTRLEN(section); ret->section = (char*)XMALLOC(len+1, NULL, DYNAMIC_TYPE_OPENSSL); if (!ret->section) { WOLFSSL_MSG("malloc error"); wolfSSL_X509V3_conf_free(ret); return NULL; } XMEMCPY(ret->section, section, len+1); } if (name) { len = (int)XSTRLEN(name); ret->name = (char*)XMALLOC(len+1, NULL, DYNAMIC_TYPE_OPENSSL); if (!ret->name) { WOLFSSL_MSG("malloc error"); wolfSSL_X509V3_conf_free(ret); return NULL; } XMEMCPY(ret->name, name, len+1); } if (value) { len = (int)XSTRLEN(value); ret->value = (char*)XMALLOC(len+1, NULL, DYNAMIC_TYPE_OPENSSL); if (!ret->value) { WOLFSSL_MSG("malloc error"); wolfSSL_X509V3_conf_free(ret); return NULL; } XMEMCPY(ret->value, value, len+1); } return ret; } static char* expandValue(WOLFSSL_CONF *conf, const char* section, char *str) { int strLen = (int)XSTRLEN(str); char* ret = NULL; /* Check to see if there is anything to expand */ if (XSTRNSTR(str, "$", strLen)) { int idx = 0; char* strIdx = str; ret = (char*)XMALLOC(strLen + 1, NULL, DYNAMIC_TYPE_OPENSSL); if (!ret) { WOLFSSL_MSG("malloc error"); return str; } while (*strIdx) { if (*strIdx == '$') { /* Expand variable */ char* startIdx = ++strIdx; char* endIdx; const char* s = section; const char* value; char prevValue; if (*startIdx == '{') { /* First read the section. * format: ${section_name::var_name} */ s = ++startIdx; while (*strIdx && *strIdx != ':') strIdx++; if (!*strIdx || s == strIdx || strIdx[1] != ':') { WOLFSSL_MSG("invalid section name in " "variable expansion"); goto expand_cleanup; } *strIdx = '\0'; strIdx += 2; startIdx = strIdx; } while (*strIdx && (XISALNUM(*strIdx) || *strIdx == '_')) strIdx++; endIdx = strIdx; if (startIdx == endIdx) { WOLFSSL_MSG("invalid variable name in config"); goto expand_cleanup; } if (s != section) { /* We are expecting a trailing '}' */ if (*strIdx != '}') { WOLFSSL_MSG("Missing '}' in variable"); goto expand_cleanup; } strIdx++; } /* Save char value at the end of the name so that we can place * a null char there. */ prevValue = *endIdx; *endIdx = '\0'; value = wolfSSL_NCONF_get_string(conf, s, startIdx); *endIdx = prevValue; /* Skip copy if no value or zero-length value */ if (value && *value) { int valueLen = (int)XSTRLEN(value); char* newRet; /* This will allocate slightly more memory than necessary * but better be safe */ strLen += valueLen; newRet = (char*)XREALLOC(ret, strLen + 1, NULL, DYNAMIC_TYPE_OPENSSL); if (!newRet) { WOLFSSL_MSG("realloc error"); goto expand_cleanup; } ret = newRet; XMEMCPY(ret + idx, value, valueLen); idx += valueLen; } } else { ret[idx++] = *strIdx++; } } ret[idx] = '\0'; } return ret ? ret : str; expand_cleanup: if (ret) XFREE(ret, NULL, DYNAMIC_TYPE_OPENSSL); return NULL; } #define SKIP_WHITESPACE(idx, max_idx) \ while ((idx) < (max_idx) && (*(idx) == ' ' || *(idx) == '\t')) \ {(idx)++;} int wolfSSL_NCONF_load(WOLFSSL_CONF *conf, const char *file, long *eline) { int ret = WOLFSSL_FAILURE; WOLFSSL_BIO *in = NULL; char* buf = NULL; char* idx = NULL; char* bufEnd = NULL; CONF_VALUE* section = NULL; long line = 0; int bufLen = 0; if (!conf || !file) { WOLFSSL_MSG("Bad parameter"); return WOLFSSL_FAILURE; } /* Open file */ if (!(in = wolfSSL_BIO_new_file(file, "rb"))) { WOLFSSL_MSG("wolfSSL_BIO_new_file error"); return WOLFSSL_FAILURE; } /* Read file */ bufLen = wolfSSL_BIO_get_len(in); if (bufLen <= 0) { WOLFSSL_MSG("wolfSSL_BIO_get_len error"); goto cleanup; } if (!(buf = (char*)XMALLOC(bufLen + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER))) { WOLFSSL_MSG("malloc error"); goto cleanup; } if (wolfSSL_BIO_read(in, buf, bufLen) != bufLen) { WOLFSSL_MSG("wolfSSL_BIO_read error"); goto cleanup; } if (!(section = wolfSSL_CONF_new_section(conf, "default"))) { WOLFSSL_MSG("wolfSSL_CONF_new_section error"); goto cleanup; } /* LETS START READING SOME CONFIGS */ idx = buf; bufEnd = buf + bufLen; while (idx < bufEnd) { char* lineEnd = XSTRNSTR(idx, "\n", (unsigned int)(bufEnd - idx)); char* maxIdx; if (!lineEnd) lineEnd = bufEnd; /* Last line in file */ maxIdx = XSTRNSTR(idx, "#", (unsigned int)(lineEnd - idx)); if (!maxIdx) maxIdx = lineEnd; line++; SKIP_WHITESPACE(idx, maxIdx); if (idx == maxIdx) { /* Empty line */ idx = lineEnd + 1; continue; } if (*idx == '[') { /* New section. Spaces not allowed in section name. */ char* sectionName; int sectionNameLen; if (idx < maxIdx) idx++; else { WOLFSSL_MSG("Invalid section definition."); goto cleanup; } SKIP_WHITESPACE(idx, maxIdx); sectionName = idx; /* Find end of section name */ while (idx < maxIdx && *idx != ' ' && *idx != ']') idx++; sectionNameLen = (int)(idx - sectionName); SKIP_WHITESPACE(idx, maxIdx); if (*idx != ']') { WOLFSSL_MSG("Section definition error. " "Closing brace not found."); goto cleanup; } sectionName[sectionNameLen] = '\0'; if (!(section = wolfSSL_CONF_get_section(conf, sectionName))) { section = wolfSSL_CONF_new_section(conf, sectionName); if (!section) goto cleanup; } } else { char* name; int nameLen; char* value; char* exValue; /* expanded value */ int valueLen; WOLFSSL_CONF_VALUE* newVal = NULL; SKIP_WHITESPACE(idx, maxIdx); name = idx; /* Find end of name */ while (idx < maxIdx && *idx != ' ' && *idx != '=') idx++; nameLen = (int)(idx - name); SKIP_WHITESPACE(idx, maxIdx); if (*idx != '=') { WOLFSSL_MSG("Missing equals sign"); goto cleanup; } idx++; SKIP_WHITESPACE(idx, maxIdx); value = idx; /* Find end of value */ idx = maxIdx-1; while (idx >= value && (*idx == ' ' || *idx == '\t' || *idx == '\r')) idx--; valueLen = (int)(idx - value + 1); /* Sanity checks */ if (nameLen <= 0 || valueLen <= 0) { WOLFSSL_MSG("Sanity checks failed"); goto cleanup; } name[nameLen] = '\0'; value[valueLen] = '\0'; if (!(exValue = expandValue(conf, section->section, value))) { WOLFSSL_MSG("Variable expansion failed"); goto cleanup; } if (!(newVal = wolfSSL_CONF_VALUE_new_values(NULL, name, exValue))) { WOLFSSL_MSG("wolfSSL_CONF_VALUE_new_values error"); if (exValue != value) XFREE(exValue, NULL, DYNAMIC_TYPE_OPENSSL); goto cleanup; } if (exValue != value) XFREE(exValue, NULL, DYNAMIC_TYPE_OPENSSL); if (wolfSSL_CONF_add_string(conf, section, newVal) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("wolfSSL_CONF_add_string error"); goto cleanup; } } idx = lineEnd + 1; } ret = WOLFSSL_SUCCESS; cleanup: if (in) wolfSSL_BIO_free(in); if (buf) XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (eline) *eline = line; return ret; } #endif /* !NO_BIO */ void wolfSSL_NCONF_free(WOLFSSL_CONF *conf) { WOLFSSL_ENTER("wolfSSL_NCONF_free"); if (conf) { wolfSSL_sk_CONF_VALUE_free(conf->data); XFREE(conf, NULL, DYNAMIC_TYPE_OPENSSL); } } void wolfSSL_X509V3_conf_free(WOLFSSL_CONF_VALUE *val) { WOLF_STACK_OF(WOLFSSL_CONF_VALUE) *sk = NULL; if (val) { if (val->name) { /* Not a section. Don't free section as it is a shared pointer. */ XFREE(val->name, NULL, DYNAMIC_TYPE_OPENSSL); if (val->value) XFREE(val->value, NULL, DYNAMIC_TYPE_OPENSSL); } else { /* Section so val->value is a stack */ if (val->section) XFREE(val->section, NULL, DYNAMIC_TYPE_OPENSSL); /* Only free the stack structures. The contained conf values * will be freed in wolfSSL_NCONF_free */ sk = (WOLF_STACK_OF(WOLFSSL_CONF_VALUE)*)val->value; while (sk) { WOLF_STACK_OF(WOLFSSL_CONF_VALUE) *tmp = sk->next; XFREE(sk, NULL, DYNAMIC_TYPE_OPENSSL); sk = tmp; } } XFREE(val, NULL, DYNAMIC_TYPE_OPENSSL); } } WOLFSSL_STACK *wolfSSL_sk_CONF_VALUE_new(wolf_sk_compare_cb compFunc) { WOLFSSL_STACK* ret; WOLFSSL_ENTER("wolfSSL_sk_CONF_VALUE_new"); ret = wolfSSL_sk_new_node(NULL); if (!ret) return NULL; ret->comp = compFunc ? compFunc : (wolf_sk_compare_cb)wolfssl_conf_value_cmp; ret->hash_fn = (wolf_sk_hash_cb)wolfSSL_CONF_VALUE_hash; ret->type = STACK_TYPE_CONF_VALUE; return ret; } /* Free the structure for WOLFSSL_CONF_VALUE stack * * sk stack to free nodes in */ void wolfSSL_sk_CONF_VALUE_free(WOLF_STACK_OF(WOLFSSL_CONF_VALUE)* sk) { WOLFSSL_STACK* tmp; WOLFSSL_ENTER("wolfSSL_sk_CONF_VALUE_free"); if (sk == NULL) return; /* parse through stack freeing each node */ while (sk) { tmp = sk->next; wolfSSL_X509V3_conf_free(sk->data.conf); XFREE(sk, NULL, DYNAMIC_TYPE_OPENSSL); sk = tmp; } } int wolfSSL_sk_CONF_VALUE_num(const WOLFSSL_STACK *sk) { WOLFSSL_ENTER("wolfSSL_sk_CONF_VALUE_num"); if (sk) return wolfSSL_sk_num(sk); return 0; } WOLFSSL_CONF_VALUE *wolfSSL_sk_CONF_VALUE_value(const WOLFSSL_STACK *sk, int i) { WOLFSSL_ENTER("wolfSSL_sk_CONF_VALUE_value"); if (sk) return (WOLFSSL_CONF_VALUE*)wolfSSL_sk_value(sk, i); return NULL; } /* return 1 on success 0 on fail */ int wolfSSL_sk_CONF_VALUE_push(WOLF_STACK_OF(WOLFSSL_CONF_VALUE)* sk, WOLFSSL_CONF_VALUE* val) { WOLFSSL_ENTER("wolfSSL_sk_CONF_VALUE_push"); if (sk == NULL || val == NULL) { return WOLFSSL_FAILURE; } return wolfSSL_sk_push(sk, val); } #endif /* !NO_CERTS && OPENSSL_EXTRA && OPENSSL_ALL */ #ifdef OPENSSL_EXTRA #ifndef NO_WOLFSSL_STUB /* Returns default file name and path of config file. However a wolfssl.cnf file is not currently supported */ char* wolfSSL_CONF_get1_default_config_file(void) { WOLFSSL_ENTER("wolfSSL_CONF_get1_default_config_file"); WOLFSSL_STUB("CONF_get1_default_config_file"); return NULL; } #endif /** * Allocate WOLFSSL_CONF_CTX instance * @return pointer to WOLFSSL_CONF_CTX structure on success and NULL on fail */ WOLFSSL_CONF_CTX* wolfSSL_CONF_CTX_new(void) { WOLFSSL_CONF_CTX* cctx; WOLFSSL_ENTER("wolfSSL_CONF_CTX_new"); cctx = (WOLFSSL_CONF_CTX*)XMALLOC(sizeof(WOLFSSL_CONF_CTX), NULL, DYNAMIC_TYPE_OPENSSL); if (!cctx) { WOLFSSL_MSG("malloc error"); return NULL; } XMEMSET(cctx, 0, sizeof(WOLFSSL_CONF_CTX)); return cctx; } /** * Release WOLFSSL_CONF_CTX instance * @param cctx a pointer to WOLFSSL_CONF_CTX structure to be freed */ void wolfSSL_CONF_CTX_free(WOLFSSL_CONF_CTX* cctx) { WOLFSSL_ENTER("wolfSSL_CONF_CTX_free"); if (cctx) { XFREE(cctx, NULL, DYNAMIC_TYPE_OPENSSL); } WOLFSSL_LEAVE("wolfSSL_CONF_CTX_free", 1); } /** * Set WOLFSSL_CTX instance to WOLFSSL_CONF_CTX * @param cctx a pointer to WOLFSSL_CONF_CTX structure to set a WOLFSSL_CTX * pointer to its ctx * @param ctx a pointer to WOLFSSL_CTX structure to be set */ void wolfSSL_CONF_CTX_set_ssl_ctx(WOLFSSL_CONF_CTX* cctx, WOLFSSL_CTX *ctx) { WOLFSSL_ENTER("wolfSSL_CONF_CTX_set_ssl_ctx"); /* sanity check */ if (cctx == NULL) { WOLFSSL_MSG("cctx is null"); return; } cctx->ctx = ctx; WOLFSSL_LEAVE("wolfSSL_CONF_CTX_set_ssl_ctx", 1); } /** * set flag value into WOLFSSL_CONF_CTX * @param cctx a pointer to WOLFSSL_CONF_CTX structure to be set * @param flags falg value to be OR'd * @return OR'd flag value, otherwise 0 */ unsigned int wolfSSL_CONF_CTX_set_flags(WOLFSSL_CONF_CTX* cctx, unsigned int flags) { /* sanity check */ if (cctx == NULL) return 0; cctx->flags |= flags; return cctx->flags; } /** * finish configuration command operation * @param cctx a pointer to WOLFSSL_CONF_CTX structure to be set * @return WOLFSSL_SUCCESS on success */ int wolfSSL_CONF_CTX_finish(WOLFSSL_CONF_CTX* cctx) { (void)cctx; return WOLFSSL_SUCCESS; } /* * The following definitions and static functions are used for * wolfSSL_CONF_cmd() to handle command. * * Definitions below are a part of conf_cmds_tbl[] contents. * WOLFSSL_CONF_FILE_CMDx represents command name in configuration file * WOLFSSL_CONF_CMDL_CMDx represents command name on command line * * The static functions after the definition section process * those FILE or CMDL which are defined in the conf_cmds_tbl. * * To add a new command handling: * 1. Add new #define to a section of WOLFSSL_CONF_FILE_CMD* and * WOLFSSL_CONF_CMDL_CMD* * 2. Add new static function after #define section, before * "typedef struct conf_cmd_tbl {" line * 3. Add new entry to conf_cmds_tbl[] by following other command entries */ #define WOLFSSL_CONF_FILE_CMD1 "Curves" #define WOLFSSL_CONF_FILE_CMD2 "Certificate" #define WOLFSSL_CONF_FILE_CMD3 "PrivateKey" #define WOLFSSL_CONF_FILE_CMD4 "Protocol" #define WOLFSSL_CONF_FILE_CMD5 "Options" #define WOLFSSL_CONF_FILE_CMD6 "ServerInfoFile" #define WOLFSSL_CONF_FILE_CMD7 "SignatureAlgorithms" #define WOLFSSL_CONF_FILE_CMD8 "ClientSignatureAlgorithms" #define WOLFSSL_CONF_FILE_CMD9 "CipherString" #define WOLFSSL_CONF_CMDL_CMD1 "curves" #define WOLFSSL_CONF_CMDL_CMD2 "cert" #define WOLFSSL_CONF_CMDL_CMD3 "key" #define WOLFSSL_CONF_CMDL_CMD4 NULL #define WOLFSSL_CONF_CMDL_CMD5 NULL #define WOLFSSL_CONF_CMDL_CMD6 NULL #define WOLFSSL_CONF_CMDL_CMD7 "sigalgs" #define WOLFSSL_CONF_CMDL_CMD8 "client_sigalgs" #define WOLFSSL_CONF_CMDL_CMD9 "cipher" #if !defined(NO_DH) && !defined(NO_BIO) #define WOLFSSL_CONF_FILE_CMD10 "DHParameters" #define WOLFSSL_CONF_CMDL_CMD10 "dhparam" #endif #ifdef HAVE_ECC #define WOLFSSL_CONF_FILE_CMD11 "ECDHParameters" #define WOLFSSL_CONF_CMDL_CMD11 "named_curves" #endif /** * process Cipher String command * @param cctx a pointer to WOLFSSL_CONF_CTX structure * @param value arguments for cmd * @return WOLFSSL_SUCCESS on success, * otherwise WOLFSSL_FAILURE or * -3 if value is null or * negative value on other failure */ static int cmdfunc_cipherstring(WOLFSSL_CONF_CTX* cctx, const char* value) { int ret = -3; WOLFSSL_ENTER("cmdfunc_cipherstring"); /* sanity check */ if (cctx == NULL) return WOLFSSL_FAILURE; if (value == NULL) { WOLFSSL_MSG("bad arguments"); return ret; } if (cctx->ctx) { ret = wolfSSL_CTX_set_cipher_list(cctx->ctx, value); } if (((cctx->ctx && ret == WOLFSSL_SUCCESS) || (!cctx->ctx && ret == -3)) && cctx->ssl) { ret = wolfSSL_set_cipher_list(cctx->ssl, value); } WOLFSSL_LEAVE("cmdfunc_cipherstring", ret); return ret; } /** * process curves command * @param cctx a pointer to WOLFSSL_CONF_CTX structure * @param value arguments for cmd * @return WOLFSSL_SUCCESS on success, * otherwise WOLFSSL_FAILURE or * -3 if value is null or * negative value on other failure */ #if defined(HAVE_ECC) static int cmdfunc_curves(WOLFSSL_CONF_CTX* cctx, const char* value) { int ret = -3; WOLFSSL_ENTER("cmdfunc_curves"); /* sanity check */ if (cctx == NULL) return WOLFSSL_FAILURE; if (value == NULL) { WOLFSSL_MSG("bad arguments"); return ret; } if (cctx->ctx) { ret = wolfSSL_CTX_set1_curves_list(cctx->ctx, value); } if (((cctx->ctx && ret == WOLFSSL_SUCCESS) || (!cctx->ctx && ret == -3)) && cctx->ssl) { ret = wolfSSL_set1_curves_list(cctx->ssl, value); } WOLFSSL_LEAVE("cmdfunc_curves", ret); return ret; } #endif #ifndef NO_FILESYSTEM /** * process cert command * @param cctx a pointer to WOLFSSL_CONF_CTX structure * @param value arguments for cmd * @return WOLFSSL_SUCCESS on success, * otherwise WOLFSSL_FAILURE or * -3 if value is null or * negative value on other failure */ static int cmdfunc_cert(WOLFSSL_CONF_CTX* cctx, const char* value) { int ret = -3; WOLFSSL_ENTER("cmdfunc_cert"); /* sanity check */ if (cctx == NULL) return WOLFSSL_FAILURE; if (value == NULL) { WOLFSSL_MSG("bad arguments"); return ret; } if (!(cctx->flags & WOLFSSL_CONF_FLAG_CERTIFICATE)) { WOLFSSL_MSG("certificate flag is not set"); return -2; } if (cctx->ctx) { ret = wolfSSL_CTX_use_certificate_chain_file(cctx->ctx, value); } if (((cctx->ctx && ret == WOLFSSL_SUCCESS) || (!cctx->ctx && ret == -3)) && cctx->ssl) { ret = wolfSSL_use_certificate_file(cctx->ssl, value, WOLFSSL_FILETYPE_PEM); } WOLFSSL_LEAVE("cmdfunc_cert", ret); return ret; } /** * process key command * @param cctx a pointer to WOLFSSL_CONF_CTX structure * @param value arguments for cmd * @return WOLFSSL_SUCCESS on success, * otherwise WOLFSSL_FAILURE or * -3 if value is null or * negative value on other failure */ static int cmdfunc_key(WOLFSSL_CONF_CTX* cctx, const char* value) { int ret = -3; WOLFSSL_ENTER("cmdfunc_key"); /* sanity check */ if (cctx == NULL) return WOLFSSL_FAILURE; if (value == NULL) { WOLFSSL_MSG("bad arguments"); return ret; } if (!(cctx->flags & WOLFSSL_CONF_FLAG_CERTIFICATE)) { WOLFSSL_MSG("certificate flag is not set"); return -2; } if (cctx->ctx) { ret = wolfSSL_CTX_use_PrivateKey_file(cctx->ctx, value, WOLFSSL_FILETYPE_PEM); } if (((cctx->ctx && ret == WOLFSSL_SUCCESS) || (!cctx->ctx && ret == -3)) && cctx->ssl) { ret = wolfSSL_use_PrivateKey_file(cctx->ssl, value, WOLFSSL_FILETYPE_PEM); } WOLFSSL_LEAVE("cmdfunc_key", ret); return ret; } #endif /* NO_FILESYSTEM */ /** * process DH parameter command * @param cctx a pointer to WOLFSSL_CONF_CTX structure * @param value arguments for cmd * @return WOLFSSL_SUCCESS on success, * otherwise WOLFSSL_FAILURE or * -3 if value is null or * negative value on other failure */ #if !defined(NO_DH) && !defined(NO_BIO) static int cmdfunc_dhparam(WOLFSSL_CONF_CTX* cctx, const char* value) { int ret = -3; WOLFSSL_DH* dh = NULL; WOLFSSL_BIO* bio = NULL; WOLFSSL_MSG("cmdfunc_dhparam"); /* sanity check */ if (cctx == NULL) return WOLFSSL_FAILURE; if (value == NULL) { WOLFSSL_MSG("bad arguments"); return ret; } if (cctx->ctx || cctx->ssl) { bio = wolfSSL_BIO_new_file(value, "rb"); if (!bio) { WOLFSSL_MSG("bio new file failed"); return WOLFSSL_FAILURE; } dh = wolfSSL_PEM_read_bio_DHparams(bio, NULL, NULL, NULL); if (!dh) { wolfSSL_BIO_free(bio); WOLFSSL_MSG("PEM read bio failed"); return WOLFSSL_FAILURE; } } else { return 1; } if (cctx->ctx) { ret = (int)wolfSSL_CTX_set_tmp_dh(cctx->ctx, dh); } if (((cctx->ctx && ret == WOLFSSL_SUCCESS) || (!cctx->ctx && ret == -3)) && cctx->ssl) { ret = (int)wolfSSL_CTX_set_tmp_dh(cctx->ssl->ctx, dh); } if (dh) wolfSSL_DH_free(dh); if (bio) wolfSSL_BIO_free(bio); WOLFSSL_LEAVE("cmdfunc_dhparam", ret); return ret; } #endif /* !NO_DH && !NO_BIO */ /** * command table */ typedef struct conf_cmd_tbl { const char* file_cmd; const char* cmdline_cmd; word32 data_type; int (*cmdfunc)(WOLFSSL_CONF_CTX* cctx, const char* value); }conf_cmd_tbl; static const conf_cmd_tbl conf_cmds_tbl[] = { #if defined(HAVE_ECC) /* cmd Curves */ {WOLFSSL_CONF_FILE_CMD1, WOLFSSL_CONF_CMDL_CMD1, WOLFSSL_CONF_TYPE_STRING, cmdfunc_curves}, #endif #if !defined(NO_FILESYSTEM) /* cmd Certificate */ {WOLFSSL_CONF_FILE_CMD2, WOLFSSL_CONF_CMDL_CMD2, WOLFSSL_CONF_TYPE_FILE, cmdfunc_cert}, /* cmd PrivateKey */ {WOLFSSL_CONF_FILE_CMD3, WOLFSSL_CONF_CMDL_CMD3, WOLFSSL_CONF_TYPE_FILE, cmdfunc_key}, #endif /* cmd Protocol */ {WOLFSSL_CONF_FILE_CMD4, WOLFSSL_CONF_CMDL_CMD4, WOLFSSL_CONF_TYPE_STRING, NULL}, /* cmd Options */ {WOLFSSL_CONF_FILE_CMD5, WOLFSSL_CONF_CMDL_CMD5, WOLFSSL_CONF_TYPE_STRING, NULL}, /* cmd ServerInfoFile */ {WOLFSSL_CONF_FILE_CMD6, WOLFSSL_CONF_CMDL_CMD6, WOLFSSL_CONF_TYPE_FILE, NULL}, /* cmd SignatureAlgorithms */ {WOLFSSL_CONF_FILE_CMD7, WOLFSSL_CONF_CMDL_CMD7, WOLFSSL_CONF_TYPE_STRING, NULL}, /* cmd ClientSignatureAlgorithms */ {WOLFSSL_CONF_FILE_CMD8, WOLFSSL_CONF_CMDL_CMD8, WOLFSSL_CONF_TYPE_STRING, NULL}, /* cmd CipherString */ {WOLFSSL_CONF_FILE_CMD9, WOLFSSL_CONF_CMDL_CMD9, WOLFSSL_CONF_TYPE_STRING, cmdfunc_cipherstring}, #if !defined(NO_DH) && !defined(NO_BIO) /* cmd DHParameters */ {WOLFSSL_CONF_FILE_CMD10, WOLFSSL_CONF_CMDL_CMD10, WOLFSSL_CONF_TYPE_FILE, cmdfunc_dhparam}, #endif #ifdef HAVE_ECC /* cmd ECHDParameters */ {WOLFSSL_CONF_FILE_CMD11, WOLFSSL_CONF_CMDL_CMD11, WOLFSSL_CONF_TYPE_STRING, NULL}, #endif }; /* size of command table */ static const size_t size_of_cmd_tbls = sizeof(conf_cmds_tbl) / sizeof(conf_cmd_tbl); static const conf_cmd_tbl* wolfssl_conf_find_cmd(WOLFSSL_CONF_CTX* cctx, const char* cmd) { size_t i = 0; size_t cmdlen = 0; if (cctx->flags & WOLFSSL_CONF_FLAG_CMDLINE) { cmdlen = XSTRLEN(cmd); if (cmdlen < 2) { WOLFSSL_MSG("bad cmdline command"); return NULL; } /* skip "-" prefix */ ++cmd; } for (i = 0; i < size_of_cmd_tbls; i++) { /* check if the cmd is valid */ if (cctx->flags & WOLFSSL_CONF_FLAG_CMDLINE) { if (conf_cmds_tbl[i].cmdline_cmd != NULL && XSTRCMP(cmd, conf_cmds_tbl[i].cmdline_cmd) == 0) { return &conf_cmds_tbl[i]; } } if (cctx->flags & WOLFSSL_CONF_FLAG_FILE) { if (conf_cmds_tbl[i].file_cmd != NULL && XSTRCMP(cmd, conf_cmds_tbl[i].file_cmd) == 0) { return &conf_cmds_tbl[i]; } } } return NULL; } /** * send configuration command * @param cctx a pointer to WOLFSSL_CONF_CTX structure * @param cmd configuration command * @param value arguments for cmd * @return 1 when cmd is recognised, but value is not used * 2 both cmd and value are used * otherwise WOLFSSL_FAILURE * -2 if cmd is not recognised * -3 if value is NULL, but cmd is recognized */ int wolfSSL_CONF_cmd(WOLFSSL_CONF_CTX* cctx, const char* cmd, const char* value) { int ret = WOLFSSL_FAILURE; const conf_cmd_tbl* confcmd = NULL; WOLFSSL_ENTER("wolfSSL_CONF_cmd"); /* sanity check */ if (cctx == NULL || cmd == NULL) { WOLFSSL_MSG("bad arguments"); return ret; } confcmd = wolfssl_conf_find_cmd(cctx, cmd); if (confcmd == NULL) return -2; if (confcmd->cmdfunc == NULL) { WOLFSSL_MSG("cmd not yet implemented"); return -2; } ret = confcmd->cmdfunc(cctx, value); /* return code compliant with OpenSSL */ if (ret < -3) ret = 0; WOLFSSL_LEAVE("wolfSSL_CONF_cmd", ret); return ret; } /** * * @param cctx a pointer to WOLFSSL_CONF_CTX structure * @param cmd configuration command * @return The SSL_CONF_TYPE_* type or SSL_CONF_TYPE_UNKNOWN if an * unvalid command */ int wolfSSL_CONF_cmd_value_type(WOLFSSL_CONF_CTX *cctx, const char *cmd) { const conf_cmd_tbl* confcmd = NULL; WOLFSSL_ENTER("wolfSSL_CONF_cmd_value_type"); confcmd = wolfssl_conf_find_cmd(cctx, cmd); if (confcmd == NULL) return SSL_CONF_TYPE_UNKNOWN; return (int)confcmd->data_type; } #endif /* OPENSSL_EXTRA */ /******************************************************************************* * END OF CONF API ******************************************************************************/ #endif /* WOLFSSL_CONF_INCLUDED */