diff options
Diffstat (limited to 'runtime/net_ossl.c')
-rw-r--r-- | runtime/net_ossl.c | 1217 |
1 files changed, 1217 insertions, 0 deletions
diff --git a/runtime/net_ossl.c b/runtime/net_ossl.c new file mode 100644 index 0000000..60e3fa2 --- /dev/null +++ b/runtime/net_ossl.c @@ -0,0 +1,1217 @@ +/* net.c + * Implementation of network-related stuff. + * + * File begun on 2023-08-29 by Alorbach (extracted from net.c) + * + * Copyright 2023 Andre Lorbach and Adiscon GmbH. + * + * This file is part of rsyslog. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * -or- + * see COPYING.ASL20 in the source distribution + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <strings.h> + +#include <errno.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <pthread.h> + +#include "rsyslog.h" +#include "syslogd-types.h" +#include "module-template.h" +#include "parse.h" +#include "srUtils.h" +#include "obj.h" +#include "errmsg.h" +#include "net.h" +#include "net_ossl.h" +#include "nsd_ptcp.h" +#include "rsconf.h" + +/* static data */ +DEFobjStaticHelpers +DEFobjCurrIf(glbl) +DEFobjCurrIf(net) +DEFobjCurrIf(nsd_ptcp) + +/*--------------------------------------MT OpenSSL helpers ------------------------------------------*/ +static MUTEX_TYPE *mutex_buf = NULL; +static sbool openssl_initialized = 0; // Avoid multiple initialization / deinitialization + +void locking_function(int mode, int n, + __attribute__((unused)) const char * file, __attribute__((unused)) int line) +{ + if (mode & CRYPTO_LOCK) + MUTEX_LOCK(mutex_buf[n]); + else + MUTEX_UNLOCK(mutex_buf[n]); +} + +unsigned long id_function(void) +{ + return ((unsigned long)THREAD_ID); +} + + +struct CRYPTO_dynlock_value * dyn_create_function( + __attribute__((unused)) const char *file, __attribute__((unused)) int line) +{ + struct CRYPTO_dynlock_value *value; + value = (struct CRYPTO_dynlock_value *)malloc(sizeof(struct CRYPTO_dynlock_value)); + if (!value) + return NULL; + + MUTEX_SETUP(value->mutex); + return value; +} + +void dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l, + __attribute__((unused)) const char *file, __attribute__((unused)) int line) +{ + if (mode & CRYPTO_LOCK) + MUTEX_LOCK(l->mutex); + else + MUTEX_UNLOCK(l->mutex); +} + +void dyn_destroy_function(struct CRYPTO_dynlock_value *l, + __attribute__((unused)) const char *file, __attribute__((unused)) int line) +{ + MUTEX_CLEANUP(l->mutex); + free(l); +} + +/* set up support functions for openssl multi-threading. This must + * be done at library initialisation. If the function fails, + * processing can not continue normally. On failure, 0 is + * returned, on success 1. + */ +int opensslh_THREAD_setup(void) +{ + int i; + if (openssl_initialized == 1) { + DBGPRINTF("openssl: multithread setup already initialized\n"); + return 1; + } + + mutex_buf = (MUTEX_TYPE *)malloc(CRYPTO_num_locks( ) * sizeof(MUTEX_TYPE)); + if (mutex_buf == NULL) + return 0; + for (i = 0; i < CRYPTO_num_locks( ); i++) + MUTEX_SETUP(mutex_buf[i]); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + CRYPTO_set_id_callback(id_function); +#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ + CRYPTO_set_locking_callback(locking_function); + /* The following three CRYPTO_... functions are the OpenSSL functions + for registering the callbacks we implemented above */ + CRYPTO_set_dynlock_create_callback(dyn_create_function); + CRYPTO_set_dynlock_lock_callback(dyn_lock_function); + CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function); + + DBGPRINTF("openssl: multithread setup finished\n"); + openssl_initialized = 1; + return 1; +} + +/* shut down openssl - do this only when you are totally done + * with openssl. + */ +int opensslh_THREAD_cleanup(void) +{ + int i; + if (openssl_initialized == 0) { + DBGPRINTF("openssl: multithread cleanup already done\n"); + return 1; + } + if (!mutex_buf) + return 0; + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + CRYPTO_set_id_callback(NULL); +#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ + CRYPTO_set_locking_callback(NULL); + CRYPTO_set_dynlock_create_callback(NULL); + CRYPTO_set_dynlock_lock_callback(NULL); + CRYPTO_set_dynlock_destroy_callback(NULL); + + for (i = 0; i < CRYPTO_num_locks( ); i++) + MUTEX_CLEANUP(mutex_buf[i]); + + free(mutex_buf); + mutex_buf = NULL; + + DBGPRINTF("openssl: multithread cleanup finished\n"); + openssl_initialized = 0; + return 1; +} +/*-------------------------------------- MT OpenSSL helpers -----------------------------------------*/ + + +/*--------------------------------------OpenSSL helpers ------------------------------------------*/ + +/* globally initialize OpenSSL + */ +void +osslGlblInit(void) +{ + DBGPRINTF("openssl: entering osslGlblInit\n"); + + if((opensslh_THREAD_setup() == 0) || +#if OPENSSL_VERSION_NUMBER < 0x10100000L + /* Setup OpenSSL library < 1.1.0 */ + !SSL_library_init() +#else + /* Setup OpenSSL library >= 1.1.0 with system default settings */ + OPENSSL_init_ssl(0, NULL) == 0 +#endif + ) { + LogError(0, RS_RET_NO_ERRCODE, "Error: OpenSSL initialization failed!"); + } + + /* Load readable error strings */ + SSL_load_error_strings(); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) + /* + * ERR_load_*(), ERR_func_error_string(), ERR_get_error_line(), ERR_get_error_line_data(), ERR_get_state() + * OpenSSL now loads error strings automatically so these functions are not needed. + * SEE FOR MORE: + * https://www.openssl.org/docs/manmaster/man7/migration_guide.html + * + */ +#else + /* Load error strings into mem*/ + ERR_load_BIO_strings(); + ERR_load_crypto_strings(); +#endif +} + +/* globally de-initialize OpenSSL */ +void +osslGlblExit(void) +{ + DBGPRINTF("openssl: entering osslGlblExit\n"); + ENGINE_cleanup(); + ERR_free_strings(); + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); +} + + +/* initialize openssl context; called on + * - listener creation + * - outbound connection creation + * Once created, the ctx object is used by-subobjects (accepted inbound connections) + */ +static rsRetVal +net_ossl_osslCtxInit(net_ossl_t *pThis, const SSL_METHOD *method) +{ + DEFiRet; + int bHaveCA; + int bHaveCRL; + int bHaveCert; + int bHaveKey; + int bHaveExtraCAFiles; + const char *caFile, *crlFile, *certFile, *keyFile; + char *extraCaFiles, *extraCaFile; + /* Setup certificates */ + caFile = (char*) ((pThis->pszCAFile == NULL) ? glbl.GetDfltNetstrmDrvrCAF(runConf) : pThis->pszCAFile); + if(caFile == NULL) { + LogMsg(0, RS_RET_CA_CERT_MISSING, LOG_WARNING, + "Warning: CA certificate is not set"); + bHaveCA = 0; + } else { + dbgprintf("osslCtxInit: OSSL CA file: '%s'\n", caFile); + bHaveCA = 1; + } + crlFile = (char*) ((pThis->pszCRLFile == NULL) ? glbl.GetDfltNetstrmDrvrCRLF(runConf) : pThis->pszCRLFile); + if(crlFile == NULL) { + bHaveCRL = 0; + } else { + dbgprintf("osslCtxInit: OSSL CRL file: '%s'\n", crlFile); + bHaveCRL = 1; + } + certFile = (char*) ((pThis->pszCertFile == NULL) ? + glbl.GetDfltNetstrmDrvrCertFile(runConf) : pThis->pszCertFile); + if(certFile == NULL) { + LogMsg(0, RS_RET_CERT_MISSING, LOG_WARNING, + "Warning: Certificate file is not set"); + bHaveCert = 0; + } else { + dbgprintf("osslCtxInit: OSSL CERT file: '%s'\n", certFile); + bHaveCert = 1; + } + keyFile = (char*) ((pThis->pszKeyFile == NULL) ? glbl.GetDfltNetstrmDrvrKeyFile(runConf) : pThis->pszKeyFile); + if(keyFile == NULL) { + LogMsg(0, RS_RET_CERTKEY_MISSING, LOG_WARNING, + "Warning: Key file is not set"); + bHaveKey = 0; + } else { + dbgprintf("osslCtxInit: OSSL KEY file: '%s'\n", keyFile); + bHaveKey = 1; + } + extraCaFiles = (char*) ((pThis->pszExtraCAFiles == NULL) ? glbl.GetNetstrmDrvrCAExtraFiles(runConf) : + pThis->pszExtraCAFiles); + if(extraCaFiles == NULL) { + bHaveExtraCAFiles = 0; + } else { + dbgprintf("osslCtxInit: OSSL EXTRA CA files: '%s'\n", extraCaFiles); + bHaveExtraCAFiles = 1; + } + + /* Create main CTX Object based on method parameter */ + pThis->ctx = SSL_CTX_new(method); + + if(bHaveExtraCAFiles == 1) { + while((extraCaFile = strsep(&extraCaFiles, ","))) { + if(SSL_CTX_load_verify_locations(pThis->ctx, extraCaFile, NULL) != 1) { + LogError(0, RS_RET_TLS_CERT_ERR, "Error: Extra Certificate file could not be accessed. " + "Check at least: 1) file path is correct, 2) file exist, " + "3) permissions are correct, 4) file content is correct. " + "OpenSSL error info may follow in next messages"); + net_ossl_lastOpenSSLErrorMsg(NULL, 0, NULL, LOG_ERR, "osslCtxInit", + "SSL_CTX_load_verify_locations"); + ABORT_FINALIZE(RS_RET_TLS_CERT_ERR); + } + } + } + if(bHaveCA == 1 && SSL_CTX_load_verify_locations(pThis->ctx, caFile, NULL) != 1) { + LogError(0, RS_RET_TLS_CERT_ERR, "Error: CA certificate could not be accessed. " + "Check at least: 1) file path is correct, 2) file exist, " + "3) permissions are correct, 4) file content is correct. " + "OpenSSL error info may follow in next messages"); + net_ossl_lastOpenSSLErrorMsg(NULL, 0, NULL, LOG_ERR, "osslCtxInit", "SSL_CTX_load_verify_locations"); + ABORT_FINALIZE(RS_RET_TLS_CERT_ERR); + } + if(bHaveCRL == 1) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) + // Get X509_STORE reference + X509_STORE *store = SSL_CTX_get_cert_store(pThis->ctx); + if (!X509_STORE_load_file(store, crlFile)) { + LogError(0, RS_RET_CRL_INVALID, "Error: CRL could not be accessed. " + "Check at least: 1) file path is correct, 2) file exist, " + "3) permissions are correct, 4) file content is correct. " + "OpenSSL error info may follow in next messages"); + net_ossl_lastOpenSSLErrorMsg(NULL, 0, NULL, LOG_ERR, "osslCtxInit", "X509_STORE_load_file"); + ABORT_FINALIZE(RS_RET_CRL_INVALID); + } + X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK); +#else +# if OPENSSL_VERSION_NUMBER >= 0x10002000L + // Get X509_STORE reference + X509_STORE *store = SSL_CTX_get_cert_store(pThis->ctx); + // Load the CRL PEM file + FILE *fp = fopen(crlFile, "r"); + if(fp == NULL) { + LogError(0, RS_RET_CRL_MISSING, "Error: CRL could not be accessed. " + "Check at least: 1) file path is correct, 2) file exist, " + "3) permissions are correct, 4) file content is correct. " + "OpenSSL error info may follow in next messages"); + net_ossl_lastOpenSSLErrorMsg(NULL, 0, NULL, LOG_ERR, "osslCtxInit", "fopen"); + ABORT_FINALIZE(RS_RET_CRL_MISSING); + } + X509_CRL *crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL); + fclose(fp); + if(crl == NULL) { + LogError(0, RS_RET_CRL_INVALID, "Error: Unable to read CRL." + "OpenSSL error info may follow in next messages"); + net_ossl_lastOpenSSLErrorMsg(NULL, 0, NULL, LOG_ERR, "osslCtxInit", "PEM_read_X509_CRL"); + ABORT_FINALIZE(RS_RET_CRL_INVALID); + } + // Add the CRL to the X509_STORE + if(!X509_STORE_add_crl(store, crl)) { + LogError(0, RS_RET_CRL_INVALID, "Error: Unable to add CRL to store." + "OpenSSL error info may follow in next messages"); + net_ossl_lastOpenSSLErrorMsg(NULL, 0, NULL, LOG_ERR, "osslCtxInit", "X509_STORE_add_crl"); + X509_CRL_free(crl); + ABORT_FINALIZE(RS_RET_CRL_INVALID); + } + // Set the X509_STORE to the SSL_CTX + // SSL_CTX_set_cert_store(pThis->ctx, store); + // Enable CRL checking + X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); + X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); + SSL_CTX_set1_param(pThis->ctx, param); + X509_VERIFY_PARAM_free(param); +# else + LogError(0, RS_RET_SYS_ERR, "Warning: TLS library does not support X509_STORE_load_file" + "(requires OpenSSL 3.x or higher). Cannot use Certificate revocation list (CRL) '%s'.", + crlFile); +# endif +#endif + } + if(bHaveCert == 1 && SSL_CTX_use_certificate_chain_file(pThis->ctx, certFile) != 1) { + LogError(0, RS_RET_TLS_CERT_ERR, "Error: Certificate file could not be accessed. " + "Check at least: 1) file path is correct, 2) file exist, " + "3) permissions are correct, 4) file content is correct. " + "OpenSSL error info may follow in next messages"); + net_ossl_lastOpenSSLErrorMsg(NULL, 0, NULL, LOG_ERR, "osslCtxInit", + "SSL_CTX_use_certificate_chain_file"); + ABORT_FINALIZE(RS_RET_TLS_CERT_ERR); + } + if(bHaveKey == 1 && SSL_CTX_use_PrivateKey_file(pThis->ctx, keyFile, SSL_FILETYPE_PEM) != 1) { + LogError(0, RS_RET_TLS_KEY_ERR , "Error: Key could not be accessed. " + "Check at least: 1) file path is correct, 2) file exist, " + "3) permissions are correct, 4) file content is correct. " + "OpenSSL error info may follow in next messages"); + net_ossl_lastOpenSSLErrorMsg(NULL, 0, NULL, LOG_ERR, "osslCtxInit", "SSL_CTX_use_PrivateKey_file"); + ABORT_FINALIZE(RS_RET_TLS_KEY_ERR); + } + + /* Set CTX Options */ + SSL_CTX_set_options(pThis->ctx, SSL_OP_NO_SSLv2); /* Disable insecure SSLv2 Protocol */ + SSL_CTX_set_options(pThis->ctx, SSL_OP_NO_SSLv3); /* Disable insecure SSLv3 Protocol */ + SSL_CTX_sess_set_cache_size(pThis->ctx,1024); /* TODO: make configurable? */ + + /* Set default VERIFY Options for OpenSSL CTX - and CALLBACK */ + if (pThis->authMode == OSSL_AUTH_CERTANON) { + dbgprintf("osslCtxInit: SSL_VERIFY_NONE\n"); + net_ossl_set_ctx_verify_callback(pThis->ctx, SSL_VERIFY_NONE); + } else { + dbgprintf("osslCtxInit: SSL_VERIFY_PEER\n"); + net_ossl_set_ctx_verify_callback(pThis->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT); + } + + SSL_CTX_set_timeout(pThis->ctx, 30); /* Default Session Timeout, TODO: Make configureable */ + SSL_CTX_set_mode(pThis->ctx, SSL_MODE_AUTO_RETRY); + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +# if OPENSSL_VERSION_NUMBER <= 0x101010FFL + /* Enable Support for automatic EC temporary key parameter selection. */ + SSL_CTX_set_ecdh_auto(pThis->ctx, 1); +# else + /* + * SSL_CTX_set_ecdh_auto and SSL_CTX_set_tmp_ecdh are depreceated in higher + * OpenSSL Versions, so we no more need them - see for more: + * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_ecdh_auto.html + */ +# endif +#else + dbgprintf("osslCtxInit: openssl to old, cannot use SSL_CTX_set_ecdh_auto." + "Using SSL_CTX_set_tmp_ecdh with NID_X9_62_prime256v1/() instead.\n"); + SSL_CTX_set_tmp_ecdh(pThis->ctx, EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); +#endif +finalize_it: + RETiRet; +} + +/* Helper function to print usefull OpenSSL errors + */ +void net_ossl_lastOpenSSLErrorMsg + (uchar *fromHost, int ret, SSL *ssl, int severity, const char* pszCallSource, const char* pszOsslApi) +{ + unsigned long un_error = 0; + int iSSLErr = 0; + if (ssl == NULL) { + /* Output Error Info*/ + DBGPRINTF("lastOpenSSLErrorMsg: Error in '%s' with ret=%d\n", pszCallSource, ret); + } else { + /* if object is set, get error code */ + iSSLErr = SSL_get_error(ssl, ret); + /* Output Debug as well */ + DBGPRINTF("lastOpenSSLErrorMsg: %s Error in '%s': '%s(%d)' with ret=%d, errno=%d(%s), sslapi='%s'\n", + (iSSLErr == SSL_ERROR_SSL ? "SSL_ERROR_SSL" : + (iSSLErr == SSL_ERROR_SYSCALL ? "SSL_ERROR_SYSCALL" : "SSL_ERROR_UNKNOWN")), + pszCallSource, ERR_error_string(iSSLErr, NULL), + iSSLErr, + ret, + errno, + strerror(errno), + pszOsslApi); + + /* Output error message */ + LogMsg(0, RS_RET_NO_ERRCODE, severity, + "%s Error in '%s': '%s(%d)' with ret=%d, errno=%d(%s), sslapi='%s'\n", + (iSSLErr == SSL_ERROR_SSL ? "SSL_ERROR_SSL" : + (iSSLErr == SSL_ERROR_SYSCALL ? "SSL_ERROR_SYSCALL" : "SSL_ERROR_UNKNOWN")), + pszCallSource, ERR_error_string(iSSLErr, NULL), + iSSLErr, + ret, + errno, + strerror(errno), + pszOsslApi); + } + + /* Loop through ERR_get_error */ + while ((un_error = ERR_get_error()) > 0){ + LogMsg(0, RS_RET_NO_ERRCODE, severity, + "net_ossl:remote '%s' OpenSSL Error Stack: %s", fromHost, ERR_error_string(un_error, NULL) ); + } +} + +/* initialize tls config commands in openssl context + */ +rsRetVal net_ossl_apply_tlscgfcmd(net_ossl_t *pThis, uchar *tlscfgcmd) +{ + DEFiRet; + char *pCurrentPos; + char *pNextPos; + char *pszCmd; + char *pszValue; + int iConfErr; + + if (tlscfgcmd == NULL) { + FINALIZE; + } + + dbgprintf("net_ossl_apply_tlscgfcmd: Apply tlscfgcmd: '%s'\n", tlscfgcmd); + + /* Set working pointer */ + pCurrentPos = (char*) tlscfgcmd; + if (pCurrentPos != NULL && strlen(pCurrentPos) > 0) { + // Create CTX Config Helper + SSL_CONF_CTX *cctx; + cctx = SSL_CONF_CTX_new(); + if (pThis->sslState == osslServer) { + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); + } else { + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT); + } + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SHOW_ERRORS); + SSL_CONF_CTX_set_ssl_ctx(cctx, pThis->ctx); + + do + { + pNextPos = index(pCurrentPos, '='); + if (pNextPos != NULL) { + while ( *pCurrentPos != '\0' && + (*pCurrentPos == ' ' || *pCurrentPos == '\t') ) + pCurrentPos++; + pszCmd = strndup(pCurrentPos, pNextPos-pCurrentPos); + pCurrentPos = pNextPos+1; + pNextPos = index(pCurrentPos, '\n'); + pNextPos = (pNextPos == NULL ? index(pCurrentPos, ';') : pNextPos); + pszValue = (pNextPos == NULL ? + strdup(pCurrentPos) : + strndup(pCurrentPos, pNextPos - pCurrentPos)); + pCurrentPos = (pNextPos == NULL ? NULL : pNextPos+1); + + /* Add SSL Conf Command */ + iConfErr = SSL_CONF_cmd(cctx, pszCmd, pszValue); + if (iConfErr > 0) { + dbgprintf("net_ossl_apply_tlscgfcmd: Successfully added Command " + "'%s':'%s'\n", + pszCmd, pszValue); + } + else { + LogError(0, RS_RET_SYS_ERR, "Failed to added Command: %s:'%s' " + "in net_ossl_apply_tlscgfcmd with error '%d'", + pszCmd, pszValue, iConfErr); + } + + free(pszCmd); + free(pszValue); + } else { + /* Abort further parsing */ + pCurrentPos = NULL; + } + } + while (pCurrentPos != NULL); + + /* Finalize SSL Conf */ + iConfErr = SSL_CONF_CTX_finish(cctx); + if (!iConfErr) { + LogError(0, RS_RET_SYS_ERR, "Error: setting openssl command parameters: %s" + "OpenSSL error info may follow in next messages", + tlscfgcmd); + net_ossl_lastOpenSSLErrorMsg(NULL, 0, NULL, LOG_ERR, + "net_ossl_apply_tlscgfcmd", "SSL_CONF_CTX_finish"); + } + SSL_CONF_CTX_free(cctx); + } + +finalize_it: + RETiRet; +} + + +/* Convert a fingerprint to printable data. The conversion is carried out + * according IETF I-D syslog-transport-tls-12. The fingerprint string is + * returned in a new cstr object. It is the caller's responsibility to + * destruct that object. + * rgerhards, 2008-05-08 + */ +static rsRetVal +net_ossl_genfingerprintstr(uchar *pFingerprint, size_t sizeFingerprint, cstr_t **ppStr, const char* prefix) +{ + cstr_t *pStr = NULL; + uchar buf[4]; + size_t i; + DEFiRet; + + CHKiRet(rsCStrConstruct(&pStr)); + CHKiRet(rsCStrAppendStrWithLen(pStr, (uchar*) prefix, strlen(prefix))); + for(i = 0 ; i < sizeFingerprint ; ++i) { + snprintf((char*)buf, sizeof(buf), ":%2.2X", pFingerprint[i]); + CHKiRet(rsCStrAppendStrWithLen(pStr, buf, 3)); + } + cstrFinalize(pStr); + + *ppStr = pStr; + +finalize_it: + if(iRet != RS_RET_OK) { + if(pStr != NULL) + rsCStrDestruct(&pStr); + } + RETiRet; +} + + + +/* Perform a match on ONE peer name obtained from the certificate. This name + * is checked against the set of configured credentials. *pbFoundPositiveMatch is + * set to 1 if the ID matches. *pbFoundPositiveMatch must have been initialized + * to 0 by the caller (this is a performance enhancement as we expect to be + * called multiple times). + * TODO: implemet wildcards? + * rgerhards, 2008-05-26 + */ +static rsRetVal +net_ossl_chkonepeername(net_ossl_t *pThis, X509 *certpeer, uchar *pszPeerID, int *pbFoundPositiveMatch) +{ + permittedPeers_t *pPeer; +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + int osslRet; +#endif + char *x509name = NULL; + DEFiRet; + + if (certpeer == NULL) { + ABORT_FINALIZE(RS_RET_TLS_NO_CERT); + } + + ISOBJ_TYPE_assert(pThis, net_ossl); + assert(pszPeerID != NULL); + assert(pbFoundPositiveMatch != NULL); + + /* Obtain Namex509 name from subject */ + x509name = X509_NAME_oneline(RSYSLOG_X509_NAME_oneline(certpeer), NULL, 0); + + if(pThis->pPermPeers) { /* do we have configured peer IDs? */ + pPeer = pThis->pPermPeers; + while(pPeer != NULL) { + CHKiRet(net.PermittedPeerWildcardMatch(pPeer, pszPeerID, pbFoundPositiveMatch)); + if(*pbFoundPositiveMatch) + break; + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + /* if we did not succeed so far, try ossl X509_check_host + * ( Includes check against SubjectAlternativeName ) + */ + osslRet = X509_check_host( certpeer, (const char*)pPeer->pszID, + strlen((const char*)pPeer->pszID), 0, NULL); + if ( osslRet == 1 ) { + /* Found Peer cert in allowed Peerslist */ + dbgprintf("net_ossl_chkonepeername: Client ('%s') is allowed (X509_check_host)\n", + x509name); + *pbFoundPositiveMatch = 1; + break; + } else if ( osslRet < 0 ) { + net_ossl_lastOpenSSLErrorMsg(NULL, osslRet, NULL, LOG_ERR, + "net_ossl_chkonepeername", "X509_check_host"); + ABORT_FINALIZE(RS_RET_NO_ERRCODE); + } +#endif + /* Check next peer */ + pPeer = pPeer->pNext; + } + } else { + LogMsg(0, RS_RET_TLS_NO_CERT, LOG_WARNING, + "net_ossl_chkonepeername: Peername check could not be done: " + "no peernames configured."); + } +finalize_it: + if (x509name != NULL){ + OPENSSL_free(x509name); + } + + RETiRet; +} + + +/* Check the peer's ID in fingerprint auth mode. + * rgerhards, 2008-05-22 + */ +rsRetVal +net_ossl_peerfingerprint(net_ossl_t *pThis, X509* certpeer, uchar *fromHostIP) +{ + DEFiRet; + unsigned int n; + uchar fingerprint[20 /*EVP_MAX_MD_SIZE**/]; + uchar fingerprintSha256[32 /*EVP_MAX_MD_SIZE**/]; + size_t size; + size_t sizeSha256; + cstr_t *pstrFingerprint = NULL; + cstr_t *pstrFingerprintSha256 = NULL; + int bFoundPositiveMatch; + permittedPeers_t *pPeer; + const EVP_MD *fdig = EVP_sha1(); + const EVP_MD *fdigSha256 = EVP_sha256(); + + ISOBJ_TYPE_assert(pThis, net_ossl); + + if (certpeer == NULL) { + ABORT_FINALIZE(RS_RET_TLS_NO_CERT); + } + + /* obtain the SHA1 fingerprint */ + size = sizeof(fingerprint); + if (!X509_digest(certpeer,fdig,fingerprint,&n)) { + dbgprintf("net_ossl_peerfingerprint: error X509cert is not valid!\n"); + ABORT_FINALIZE(RS_RET_INVALID_FINGERPRINT); + } + sizeSha256 = sizeof(fingerprintSha256); + if (!X509_digest(certpeer,fdigSha256,fingerprintSha256,&n)) { + dbgprintf("net_ossl_peerfingerprint: error X509cert is not valid!\n"); + ABORT_FINALIZE(RS_RET_INVALID_FINGERPRINT); + } + CHKiRet(net_ossl_genfingerprintstr(fingerprint, size, &pstrFingerprint, "SHA1")); + dbgprintf("net_ossl_peerfingerprint: peer's certificate SHA1 fingerprint: %s\n", + cstrGetSzStrNoNULL(pstrFingerprint)); + CHKiRet(net_ossl_genfingerprintstr(fingerprintSha256, sizeSha256, &pstrFingerprintSha256, "SHA256")); + dbgprintf("net_ossl_peerfingerprint: peer's certificate SHA256 fingerprint: %s\n", + cstrGetSzStrNoNULL(pstrFingerprintSha256)); + + /* now search through the permitted peers to see if we can find a permitted one */ + bFoundPositiveMatch = 0; + pPeer = pThis->pPermPeers; + while(pPeer != NULL && !bFoundPositiveMatch) { + if(!rsCStrSzStrCmp(pstrFingerprint, pPeer->pszID, strlen((char*) pPeer->pszID))) { + dbgprintf("net_ossl_peerfingerprint: peer's certificate SHA1 MATCH found: %s\n", + pPeer->pszID); + bFoundPositiveMatch = 1; + } else if(!rsCStrSzStrCmp(pstrFingerprintSha256, pPeer->pszID, strlen((char*) pPeer->pszID))) { + dbgprintf("net_ossl_peerfingerprint: peer's certificate SHA256 MATCH found: %s\n", + pPeer->pszID); + bFoundPositiveMatch = 1; + } else { + dbgprintf("net_ossl_peerfingerprint: NOMATCH peer certificate: %s\n", pPeer->pszID); + pPeer = pPeer->pNext; + } + } + + if(!bFoundPositiveMatch) { + dbgprintf("net_ossl_peerfingerprint: invalid peer fingerprint, not permitted to talk to it\n"); + if(pThis->bReportAuthErr == 1) { + errno = 0; + LogMsg(0, RS_RET_INVALID_FINGERPRINT, LOG_WARNING, + "nsd_ossl:TLS session terminated with remote syslog server '%s': " + "Fingerprint check failed, not permitted to talk to %s", + fromHostIP, cstrGetSzStrNoNULL(pstrFingerprint)); + pThis->bReportAuthErr = 0; + } + ABORT_FINALIZE(RS_RET_INVALID_FINGERPRINT); + } + +finalize_it: + if(pstrFingerprint != NULL) + cstrDestruct(&pstrFingerprint); + RETiRet; +} + + +/* Check the peer's ID in name auth mode. + */ +rsRetVal +net_ossl_chkpeername(net_ossl_t *pThis, X509* certpeer, uchar *fromHostIP) +{ + DEFiRet; + uchar lnBuf[256]; + int bFoundPositiveMatch; + cstr_t *pStr = NULL; + char *x509name = NULL; + + ISOBJ_TYPE_assert(pThis, net_ossl); + + bFoundPositiveMatch = 0; + CHKiRet(rsCStrConstruct(&pStr)); + + /* Obtain Namex509 name from subject */ + x509name = X509_NAME_oneline(RSYSLOG_X509_NAME_oneline(certpeer), NULL, 0); + + dbgprintf("net_ossl_chkpeername: checking - peername '%s' on server '%s'\n", x509name, fromHostIP); + snprintf((char*)lnBuf, sizeof(lnBuf), "name: %s; ", x509name); + CHKiRet(rsCStrAppendStr(pStr, lnBuf)); + CHKiRet(net_ossl_chkonepeername(pThis, certpeer, (uchar*)x509name, &bFoundPositiveMatch)); + + if(!bFoundPositiveMatch) { + dbgprintf("net_ossl_chkpeername: invalid peername, not permitted to talk to it\n"); + if(pThis->bReportAuthErr == 1) { + cstrFinalize(pStr); + errno = 0; + LogMsg(0, RS_RET_INVALID_FINGERPRINT, LOG_WARNING, + "nsd_ossl:TLS session terminated with remote syslog server: " + "peer name not authorized, not permitted to talk to %s", + cstrGetSzStrNoNULL(pStr)); + pThis->bReportAuthErr = 0; + } + ABORT_FINALIZE(RS_RET_INVALID_FINGERPRINT); + } else { + dbgprintf("net_ossl_chkpeername: permitted to talk!\n"); + } + +finalize_it: + if (x509name != NULL){ + OPENSSL_free(x509name); + } + + if(pStr != NULL) + rsCStrDestruct(&pStr); + RETiRet; +} + + +/* check the ID of the remote peer - used for both fingerprint and + * name authentication. + */ +X509* +net_ossl_getpeercert(net_ossl_t *pThis, SSL *ssl, uchar *fromHostIP) +{ + X509* certpeer; + + ISOBJ_TYPE_assert(pThis, net_ossl); + + /* Get peer certificate from SSL */ + certpeer = SSL_get_peer_certificate(ssl); + if ( certpeer == NULL ) { + if(pThis->bReportAuthErr == 1 && 1) { + errno = 0; + pThis->bReportAuthErr = 0; + LogMsg(0, RS_RET_TLS_NO_CERT, LOG_WARNING, + "nsd_ossl:TLS session terminated with remote syslog server '%s': " + "Peer check failed, peer did not provide a certificate.", fromHostIP); + } + } + return certpeer; +} + + +/* Verify the validity of the remote peer's certificate. + */ +rsRetVal +net_ossl_chkpeercertvalidity(net_ossl_t __attribute__((unused)) *pThis, SSL *ssl, uchar *fromHostIP) +{ + DEFiRet; + int iVerErr = X509_V_OK; + + ISOBJ_TYPE_assert(pThis, net_ossl); + PermitExpiredCerts* pPermitExpiredCerts = (PermitExpiredCerts*) SSL_get_ex_data(ssl, 1); + + iVerErr = SSL_get_verify_result(ssl); + if (iVerErr != X509_V_OK) { + if (iVerErr == X509_V_ERR_CERT_HAS_EXPIRED) { + if (pPermitExpiredCerts != NULL && *pPermitExpiredCerts == OSSL_EXPIRED_DENY) { + LogMsg(0, RS_RET_CERT_EXPIRED, LOG_INFO, + "net_ossl:TLS session terminated with remote syslog server '%s': " + "not permitted to talk to peer, certificate invalid: " + "Certificate expired: %s", + fromHostIP, X509_verify_cert_error_string(iVerErr)); + ABORT_FINALIZE(RS_RET_CERT_EXPIRED); + } else if (pPermitExpiredCerts != NULL && *pPermitExpiredCerts == OSSL_EXPIRED_WARN) { + LogMsg(0, RS_RET_NO_ERRCODE, LOG_WARNING, + "net_ossl:CertValidity check - warning talking to peer '%s': " + "certificate expired: %s", + fromHostIP, X509_verify_cert_error_string(iVerErr)); + } else { + dbgprintf("net_ossl_chkpeercertvalidity: talking to peer '%s': " + "certificate expired: %s\n", + fromHostIP, X509_verify_cert_error_string(iVerErr)); + }/* Else do nothing */ + } else if (iVerErr == X509_V_ERR_CERT_REVOKED) { + LogMsg(0, RS_RET_CERT_REVOKED, LOG_INFO, + "net_ossl:TLS session terminated with remote syslog server '%s': " + "not permitted to talk to peer, certificate invalid: " + "certificate revoked '%s'", + fromHostIP, X509_verify_cert_error_string(iVerErr)); + ABORT_FINALIZE(RS_RET_CERT_EXPIRED); + } else { + LogMsg(0, RS_RET_CERT_INVALID, LOG_INFO, + "net_ossl:TLS session terminated with remote syslog server '%s': " + "not permitted to talk to peer, certificate validation failed: %s", + fromHostIP, X509_verify_cert_error_string(iVerErr)); + ABORT_FINALIZE(RS_RET_CERT_INVALID); + } + } else { + dbgprintf("net_ossl_chkpeercertvalidity: client certificate validation success: %s\n", + X509_verify_cert_error_string(iVerErr)); + } + +finalize_it: + RETiRet; +} + +/* Verify Callback for X509 Certificate validation. Force visibility as this function is not called anywhere but +* only used as callback! +*/ +int +net_ossl_verify_callback(int status, X509_STORE_CTX *store) +{ + char szdbgdata1[256]; + char szdbgdata2[256]; + + dbgprintf("verify_callback: status %d\n", status); + + if(status == 0) { + /* Retrieve all needed pointers */ + X509 *cert = X509_STORE_CTX_get_current_cert(store); + int depth = X509_STORE_CTX_get_error_depth(store); + int err = X509_STORE_CTX_get_error(store); + SSL* ssl = X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx()); + int iVerifyMode = SSL_get_verify_mode(ssl); + nsd_t *pNsdTcp = (nsd_t*) SSL_get_ex_data(ssl, 0); + PermitExpiredCerts* pPermitExpiredCerts = (PermitExpiredCerts*) SSL_get_ex_data(ssl, 1); + + dbgprintf("verify_callback: Certificate validation failed, Mode (%d)!\n", iVerifyMode); + + X509_NAME_oneline(X509_get_issuer_name(cert), szdbgdata1, sizeof(szdbgdata1)); + X509_NAME_oneline(RSYSLOG_X509_NAME_oneline(cert), szdbgdata2, sizeof(szdbgdata2)); + + uchar *fromHost = NULL; + if (pNsdTcp != NULL) { + nsd_ptcp.GetRemoteHName(pNsdTcp, &fromHost); + } + + if (iVerifyMode != SSL_VERIFY_NONE) { + /* Handle expired Certificates **/ + if (err == X509_V_OK || err == X509_V_ERR_CERT_HAS_EXPIRED) { + if (pPermitExpiredCerts != NULL && *pPermitExpiredCerts == OSSL_EXPIRED_PERMIT) { + dbgprintf("verify_callback: EXPIRED cert but PERMITTED at depth: %d \n\t" + "issuer = %s\n\t" + "subject = %s\n\t" + "err %d:%s\n", depth, szdbgdata1, szdbgdata2, + err, X509_verify_cert_error_string(err)); + + /* Set Status to OK*/ + status = 1; + } + else if (pPermitExpiredCerts != NULL && *pPermitExpiredCerts == OSSL_EXPIRED_WARN) { + LogMsg(0, RS_RET_CERT_EXPIRED, LOG_WARNING, + "Certificate EXPIRED warning at depth: %d \n\t" + "issuer = %s\n\t" + "subject = %s\n\t" + "err %d:%s peer '%s'", + depth, szdbgdata1, szdbgdata2, + err, X509_verify_cert_error_string(err), fromHost); + + /* Set Status to OK*/ + status = 1; + } + else /* also default - if (pPermitExpiredCerts == OSSL_EXPIRED_DENY)*/ { + LogMsg(0, RS_RET_CERT_EXPIRED, LOG_ERR, + "Certificate EXPIRED at depth: %d \n\t" + "issuer = %s\n\t" + "subject = %s\n\t" + "err %d:%s\n\t" + "not permitted to talk to peer '%s', certificate invalid: " + "certificate expired", + depth, szdbgdata1, szdbgdata2, + err, X509_verify_cert_error_string(err), fromHost); + } + } else if (err == X509_V_ERR_CERT_REVOKED) { + LogMsg(0, RS_RET_CERT_REVOKED, LOG_ERR, + "Certificate REVOKED at depth: %d \n\t" + "issuer = %s\n\t" + "subject = %s\n\t" + "err %d:%s\n\t" + "not permitted to talk to peer '%s', certificate invalid: " + "certificate revoked", + depth, szdbgdata1, szdbgdata2, + err, X509_verify_cert_error_string(err), fromHost); + } else { + /* all other error codes cause failure */ + LogMsg(0, RS_RET_NO_ERRCODE, LOG_ERR, + "Certificate error at depth: %d \n\t" + "issuer = %s\n\t" + "subject = %s\n\t" + "err %d:%s - peer '%s'", + depth, szdbgdata1, szdbgdata2, + err, X509_verify_cert_error_string(err), fromHost); + } + } else { + /* do not verify certs in ANON mode, just log into debug */ + dbgprintf("verify_callback: Certificate validation DISABLED but Error at depth: %d \n\t" + "issuer = %s\n\t" + "subject = %s\n\t" + "err %d:%s\n", depth, szdbgdata1, szdbgdata2, + err, X509_verify_cert_error_string(err)); + + /* Set Status to OK*/ + status = 1; + } + free(fromHost); + } + + return status; +} + + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) +static long +RSYSLOG_BIO_debug_callback_ex(BIO *bio, int cmd, const char __attribute__((unused)) *argp, + size_t __attribute__((unused)) len, int argi, long __attribute__((unused)) argl, + int ret, size_t __attribute__((unused)) *processed) +#else +static long +RSYSLOG_BIO_debug_callback(BIO *bio, int cmd, const char __attribute__((unused)) *argp, + int argi, long __attribute__((unused)) argl, long ret) +#endif +{ + long ret2 = ret; + long r = 1; + if (BIO_CB_RETURN & cmd) + r = ret; + dbgprintf("openssl debugmsg: BIO[%p]: ", (void *)bio); + switch (cmd) { + case BIO_CB_FREE: + dbgprintf("Free - %s\n", RSYSLOG_BIO_method_name(bio)); + break; +/* Disabled due API changes for OpenSSL 1.1.0+ */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + case BIO_CB_READ: + if (bio->method->type & BIO_TYPE_DESCRIPTOR) + dbgprintf("read(%d,%lu) - %s fd=%d\n", + RSYSLOG_BIO_number_read(bio), (unsigned long)argi, + RSYSLOG_BIO_method_name(bio), RSYSLOG_BIO_number_read(bio)); + else + dbgprintf("read(%d,%lu) - %s\n", RSYSLOG_BIO_number_read(bio), + (unsigned long)argi, RSYSLOG_BIO_method_name(bio)); + break; + case BIO_CB_WRITE: + if (bio->method->type & BIO_TYPE_DESCRIPTOR) + dbgprintf("write(%d,%lu) - %s fd=%d\n", + RSYSLOG_BIO_number_written(bio), (unsigned long)argi, + RSYSLOG_BIO_method_name(bio), RSYSLOG_BIO_number_written(bio)); + else + dbgprintf("write(%d,%lu) - %s\n", + RSYSLOG_BIO_number_written(bio), + (unsigned long)argi, + RSYSLOG_BIO_method_name(bio)); + break; +#else + case BIO_CB_READ: + dbgprintf("read %s\n", RSYSLOG_BIO_method_name(bio)); + break; + case BIO_CB_WRITE: + dbgprintf("write %s\n", RSYSLOG_BIO_method_name(bio)); + break; +#endif + case BIO_CB_PUTS: + dbgprintf("puts() - %s\n", RSYSLOG_BIO_method_name(bio)); + break; + case BIO_CB_GETS: + dbgprintf("gets(%lu) - %s\n", (unsigned long)argi, + RSYSLOG_BIO_method_name(bio)); + break; + case BIO_CB_CTRL: + dbgprintf("ctrl(%lu) - %s\n", (unsigned long)argi, + RSYSLOG_BIO_method_name(bio)); + break; + case BIO_CB_RETURN | BIO_CB_READ: + dbgprintf("read return %ld\n", ret2); + break; + case BIO_CB_RETURN | BIO_CB_WRITE: + dbgprintf("write return %ld\n", ret2); + break; + case BIO_CB_RETURN | BIO_CB_GETS: + dbgprintf("gets return %ld\n", ret2); + break; + case BIO_CB_RETURN | BIO_CB_PUTS: + dbgprintf("puts return %ld\n", ret2); + break; + case BIO_CB_RETURN | BIO_CB_CTRL: + dbgprintf("ctrl return %ld\n", ret2); + break; + default: + dbgprintf("bio callback - unknown type (%d)\n", cmd); + break; + } + + return (r); +} + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +// Requires at least OpenSSL v1.1.1 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +static int +net_ossl_generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len) +{ + unsigned char result[EVP_MAX_MD_SIZE]; + unsigned int resultlength; + unsigned char *sslHello; + unsigned int length; + + sslHello = (unsigned char *) "rsyslog"; + length = strlen((char *)sslHello); + + // Generate the cookie using SHA256 hash + if (!EVP_Digest(sslHello, length, result, &resultlength, EVP_sha256(), NULL)) { + return 0; + } + + memcpy(cookie, result, resultlength); + *cookie_len = resultlength; + dbgprintf("net_ossl_generate_cookie: generate cookie SUCCESS\n"); + + return 1; +} +#pragma GCC diagnostic pop + +static int +net_ossl_verify_cookie(SSL *ssl, const unsigned char *cookie, unsigned int cookie_len) +{ + unsigned char cookie_gen[EVP_MAX_MD_SIZE]; + unsigned int cookie_gen_len; + + // Generate a cookie using the same method as in net_ossl_generate_cookie + if (!net_ossl_generate_cookie(ssl, cookie_gen, &cookie_gen_len)) { + dbgprintf("net_ossl_verify_cookie: generate cookie FAILED\n"); + return 0; + } + + // Check if the generated cookie matches the cookie received + if (cookie_len == cookie_gen_len && memcmp(cookie, cookie_gen, cookie_len) == 0) { + dbgprintf("net_ossl_verify_cookie: compare cookie SUCCESS\n"); + return 1; + } + + dbgprintf("net_ossl_verify_cookie: compare cookie FAILED\n"); + return 0; +} + +static rsRetVal +net_ossl_ctx_init_cookie(net_ossl_t *pThis) +{ + DEFiRet; + // Set our cookie generation and verification callbacks + SSL_CTX_set_options(pThis->ctx, SSL_OP_COOKIE_EXCHANGE); + SSL_CTX_set_cookie_generate_cb(pThis->ctx, net_ossl_generate_cookie); + SSL_CTX_set_cookie_verify_cb(pThis->ctx, net_ossl_verify_cookie); + RETiRet; +} +#endif // OPENSSL_VERSION_NUMBER >= 0x10100000L + +/* ------------------------------ end OpenSSL helpers ------------------------------------------*/ + +/* ------------------------------ OpenSSL Callback set helpers ---------------------------------*/ +void +net_ossl_set_ssl_verify_callback(SSL *pSsl, int flags) +{ + /* Enable certificate valid checking */ + SSL_set_verify(pSsl, flags, net_ossl_verify_callback); +} + +void +net_ossl_set_ctx_verify_callback(SSL_CTX *pCtx, int flags) +{ + /* Enable certificate valid checking */ + SSL_CTX_set_verify(pCtx, flags, net_ossl_verify_callback); +} + +void +net_ossl_set_bio_callback(BIO *conn) +{ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) + BIO_set_callback_ex(conn, RSYSLOG_BIO_debug_callback_ex); +#else + BIO_set_callback(conn, RSYSLOG_BIO_debug_callback); +#endif // OPENSSL_VERSION_NUMBER >= 0x10100000L +} +/* ------------------------------ End OpenSSL Callback set helpers -----------------------------*/ + + +/* Standard-Constructor */ +BEGINobjConstruct(net_ossl) /* be sure to specify the object type also in END macro! */ + DBGPRINTF("net_ossl_construct: [%p]\n", pThis); + pThis->bReportAuthErr = 1; +ENDobjConstruct(net_ossl) + +/* destructor for the net_ossl object */ +BEGINobjDestruct(net_ossl) /* be sure to specify the object type also in END and CODESTART macros! */ +CODESTARTobjDestruct(net_ossl) + DBGPRINTF("net_ossl_destruct: [%p]\n", pThis); + /* Free SSL obj also if we do not have a session - or are NOT in TLS mode! */ + if (pThis->ssl != NULL) { + DBGPRINTF("net_ossl_destruct: [%p] FREE pThis->ssl \n", pThis); + SSL_free(pThis->ssl); + pThis->ssl = NULL; + } + if(pThis->ctx != NULL && !pThis->ctx_is_copy) { + SSL_CTX_free(pThis->ctx); + } + free((void*) pThis->pszCAFile); + free((void*) pThis->pszCRLFile); + free((void*) pThis->pszKeyFile); + free((void*) pThis->pszCertFile); + free((void*) pThis->pszExtraCAFiles); +ENDobjDestruct(net_ossl) + +/* queryInterface function */ +BEGINobjQueryInterface(net_ossl) +CODESTARTobjQueryInterface(net_ossl) + DBGPRINTF("netosslQueryInterface\n"); + if(pIf->ifVersion != net_osslCURR_IF_VERSION) {/* check for current version, increment on each change */ + ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); + } + pIf->Construct = (rsRetVal(*)(net_ossl_t**)) net_osslConstruct; + pIf->Destruct = (rsRetVal(*)(net_ossl_t**)) net_osslDestruct; + pIf->osslCtxInit = net_ossl_osslCtxInit; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + pIf->osslCtxInitCookie = net_ossl_ctx_init_cookie; +#endif +finalize_it: +ENDobjQueryInterface(net_ossl) + + +/* exit our class + */ +BEGINObjClassExit(net_ossl, OBJ_IS_CORE_MODULE) /* CHANGE class also in END MACRO! */ +CODESTARTObjClassExit(net_ossl) + DBGPRINTF("netosslClassExit\n"); + /* release objects we no longer need */ + objRelease(nsd_ptcp, LM_NSD_PTCP_FILENAME); + objRelease(net, LM_NET_FILENAME); + objRelease(glbl, CORE_COMPONENT); + /* shut down OpenSSL */ + osslGlblExit(); +ENDObjClassExit(net_ossl) + + +/* Initialize the net_ossl class. Must be called as the very first method + * before anything else is called inside this class. + */ +BEGINObjClassInit(net_ossl, 1, OBJ_IS_CORE_MODULE) /* class, version */ + DBGPRINTF("net_osslClassInit\n"); + // request objects we use + CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(net, LM_NET_FILENAME)); + CHKiRet(objUse(nsd_ptcp, LM_NSD_PTCP_FILENAME)); + // Do global TLS init stuff + osslGlblInit(); +ENDObjClassInit(net_ossl) + +/* --------------- here now comes the plumbing that makes as a library module --------------- */ + +/* vi:set ai: + */ |