Blob Blame History Raw
diff -up rsyslog-8.24.0/plugins/imtcp/imtcp.c.v36tls rsyslog-8.24.0/plugins/imtcp/imtcp.c
--- rsyslog-8.24.0/plugins/imtcp/imtcp.c.v36tls	2019-08-19 17:37:07.872166694 +0100
+++ rsyslog-8.24.0/plugins/imtcp/imtcp.c	2019-08-19 17:37:07.876166693 +0100
@@ -100,6 +100,7 @@ static struct configSettings_s {
 	int bDisableLFDelim;
 	int bUseFlowControl;
 	int bPreserveCase;
+	uchar *gnutlsPriorityString;
 	uchar *pszStrmDrvrAuthMode;
 	uchar *pszInputName;
 	uchar *pszBindRuleset;
@@ -136,6 +137,7 @@ struct modConfData_s {
 	int iKeepAliveProbes;
 	int iKeepAliveTime;
 	sbool bEmitMsgOnClose; /* emit an informational message on close by remote peer */
+	uchar *gnutlsPriorityString;
 	uchar *pszStrmDrvrName; /* stream driver to use */
 	uchar *pszStrmDrvrAuthMode; /* authentication mode to use */
 	struct cnfarray *permittedPeers;
@@ -164,7 +166,8 @@ static struct cnfparamdescr modpdescr[]
 	{ "keepalive.probes", eCmdHdlrPositiveInt, 0 },
 	{ "keepalive.time", eCmdHdlrPositiveInt, 0 },
 	{ "keepalive.interval", eCmdHdlrPositiveInt, 0 },
-	{ "preservecase", eCmdHdlrBinary, 0 }
+	{ "preservecase", eCmdHdlrBinary, 0 },
+	{ "gnutlsprioritystring", eCmdHdlrString, 0 }
 };
 static struct cnfparamblk modpblk =
 	{ CNFPARAMBLK_VERSION,
@@ -354,6 +357,7 @@ addListner(modConfData_t *modConf, insta
 		CHKiRet(tcpsrv.SetKeepAliveIntvl(pOurTcpsrv, modConf->iKeepAliveIntvl));
 		CHKiRet(tcpsrv.SetKeepAliveProbes(pOurTcpsrv, modConf->iKeepAliveProbes));
 		CHKiRet(tcpsrv.SetKeepAliveTime(pOurTcpsrv, modConf->iKeepAliveTime));
+		CHKiRet(tcpsrv.SetGnutlsPriorityString(pOurTcpsrv, modConf->gnutlsPriorityString));
 		CHKiRet(tcpsrv.SetSessMax(pOurTcpsrv, modConf->iTCPSessMax));
 		CHKiRet(tcpsrv.SetLstnMax(pOurTcpsrv, modConf->iTCPLstnMax));
 		CHKiRet(tcpsrv.SetDrvrMode(pOurTcpsrv, modConf->iStrmDrvrMode));
@@ -463,6 +467,7 @@ CODESTARTbeginCnfLoad
 	loadModConf->bEmitMsgOnClose = 0;
 	loadModConf->iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER;
 	loadModConf->bDisableLFDelim = 0;
+	loadModConf->gnutlsPriorityString = NULL;
 	loadModConf->pszStrmDrvrName = NULL;
 	loadModConf->pszStrmDrvrAuthMode = NULL;
 	loadModConf->permittedPeers = NULL;
@@ -517,6 +522,8 @@ CODESTARTsetModCnf
 			loadModConf->iKeepAliveTime = (int) pvals[i].val.d.n;
 		} else if(!strcmp(modpblk.descr[i].name, "keepalive.interval")) {
 			loadModConf->iKeepAliveIntvl = (int) pvals[i].val.d.n;
+		} else if(!strcmp(modpblk.descr[i].name, "gnutlsprioritystring")) {
+			loadModConf->gnutlsPriorityString = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
 		} else if(!strcmp(modpblk.descr[i].name, "streamdriver.mode")) {
 			loadModConf->iStrmDrvrMode = (int) pvals[i].val.d.n;
 		} else if(!strcmp(modpblk.descr[i].name, "streamdriver.authmode")) {
diff -up rsyslog-8.24.0/runtime/netstrm.c.v36tls rsyslog-8.24.0/runtime/netstrm.c
--- rsyslog-8.24.0/runtime/netstrm.c.v36tls	2017-01-10 09:00:04.000000000 +0000
+++ rsyslog-8.24.0/runtime/netstrm.c	2019-08-19 17:37:07.876166693 +0100
@@ -280,6 +280,16 @@ SetKeepAliveIntvl(netstrm_t *pThis, int
 	RETiRet;
 }
 
+/* gnutls priority string */
+static rsRetVal
+SetGnutlsPriorityString(netstrm_t *pThis, uchar *gnutlsPriorityString)
+{
+	DEFiRet;
+	ISOBJ_TYPE_assert(pThis, netstrm);
+	iRet = pThis->Drvr.SetGnutlsPriorityString(pThis->pDrvrData, gnutlsPriorityString);
+	RETiRet;
+}
+
 /* check connection - slim wrapper for NSD driver function */
 static rsRetVal
 CheckConnection(netstrm_t *pThis)
@@ -387,6 +397,7 @@ CODESTARTobjQueryInterface(netstrm)
 	pIf->SetKeepAliveProbes = SetKeepAliveProbes;
 	pIf->SetKeepAliveTime = SetKeepAliveTime;
 	pIf->SetKeepAliveIntvl = SetKeepAliveIntvl;
+	pIf->SetGnutlsPriorityString = SetGnutlsPriorityString;
 finalize_it:
 ENDobjQueryInterface(netstrm)
 
diff -up rsyslog-8.24.0/runtime/netstrm.h.v36tls rsyslog-8.24.0/runtime/netstrm.h
--- rsyslog-8.24.0/runtime/netstrm.h.v36tls	2017-01-10 09:00:04.000000000 +0000
+++ rsyslog-8.24.0/runtime/netstrm.h	2019-08-19 17:37:07.876166693 +0100
@@ -75,14 +75,16 @@ BEGINinterface(netstrm) /* name must als
 	rsRetVal (*SetKeepAliveProbes)(netstrm_t *pThis, int keepAliveProbes);
 	rsRetVal (*SetKeepAliveTime)(netstrm_t *pThis, int keepAliveTime);
 	rsRetVal (*SetKeepAliveIntvl)(netstrm_t *pThis, int keepAliveIntvl);
+	rsRetVal (*SetGnutlsPriorityString)(netstrm_t *pThis, uchar *priorityString);
 ENDinterface(netstrm)
-#define netstrmCURR_IF_VERSION 8 /* increment whenever you change the interface structure! */
+#define netstrmCURR_IF_VERSION 9 /* increment whenever you change the interface structure! */
 /* interface version 3 added GetRemAddr()
  * interface version 4 added EnableKeepAlive() -- rgerhards, 2009-06-02
  * interface version 5 changed return of CheckConnection from void to rsRetVal -- alorbach, 2012-09-06
  * interface version 6 changed signature of GetRemoteIP() -- rgerhards, 2013-01-21
  * interface version 7 added KeepAlive parameter set functions
  * interface version 8 changed signature of Connect() -- dsa, 2016-11-14
+ * interface version 9 added SetGnutlsPriorityString -- PascalWithopf, 2017-08-08
  * */
 
 /* prototypes */
diff -up rsyslog-8.24.0/runtime/netstrms.c.v36tls rsyslog-8.24.0/runtime/netstrms.c
--- rsyslog-8.24.0/runtime/netstrms.c.v36tls	2016-12-03 17:41:03.000000000 +0000
+++ rsyslog-8.24.0/runtime/netstrms.c	2019-08-19 17:37:07.876166693 +0100
@@ -113,6 +113,10 @@ CODESTARTobjDestruct(netstrms)
 		free(pThis->pBaseDrvrName);
 		pThis->pBaseDrvrName = NULL;
 	}
+	if(pThis->gnutlsPriorityString != NULL) {
+		free(pThis->gnutlsPriorityString);
+		pThis->gnutlsPriorityString = NULL;
+	}
 ENDobjDestruct(netstrms)
 
 
@@ -196,6 +200,31 @@ GetDrvrAuthMode(netstrms_t *pThis)
 }
 
 
+/* Set the priorityString for GnuTLS
+ * PascalWithopf 2017-08-16
+ */
+static rsRetVal
+SetDrvrGnutlsPriorityString(netstrms_t *pThis, uchar *iVal)
+{
+	DEFiRet;
+	ISOBJ_TYPE_assert(pThis, netstrms);
+	CHKmalloc(pThis->gnutlsPriorityString = (uchar*)strdup((char*)iVal));
+finalize_it:
+	RETiRet;
+}
+
+
+/* return the priorityString for GnuTLS
+ * PascalWithopf, 2017-08-16
+ */
+static uchar*
+GetDrvrGnutlsPriorityString(netstrms_t *pThis)
+{
+	ISOBJ_TYPE_assert(pThis, netstrms);
+	return pThis->gnutlsPriorityString;
+}
+
+
 /* set the driver mode -- rgerhards, 2008-04-30 */
 static rsRetVal
 SetDrvrMode(netstrms_t *pThis, int iMode)
@@ -272,6 +301,8 @@ CODESTARTobjQueryInterface(netstrms)
 	pIf->GetDrvrMode = GetDrvrMode;
 	pIf->SetDrvrAuthMode = SetDrvrAuthMode;
 	pIf->GetDrvrAuthMode = GetDrvrAuthMode;
+	pIf->SetDrvrGnutlsPriorityString = SetDrvrGnutlsPriorityString;
+	pIf->GetDrvrGnutlsPriorityString = GetDrvrGnutlsPriorityString;
 	pIf->SetDrvrPermPeers = SetDrvrPermPeers;
 	pIf->GetDrvrPermPeers = GetDrvrPermPeers;
 finalize_it:
diff -up rsyslog-8.24.0/runtime/netstrms.h.v36tls rsyslog-8.24.0/runtime/netstrms.h
--- rsyslog-8.24.0/runtime/netstrms.h.v36tls	2016-12-03 17:41:03.000000000 +0000
+++ rsyslog-8.24.0/runtime/netstrms.h	2019-08-19 17:37:07.876166693 +0100
@@ -33,6 +33,7 @@ struct netstrms_s {
 	uchar *pDrvrName;	/**< full base driver name (set when driver is loaded) */
 	int iDrvrMode;		/**< current default driver mode */
 	uchar *pszDrvrAuthMode;	/**< current driver authentication mode */
+	uchar *gnutlsPriorityString; /**< priorityString for connection */
 	permittedPeers_t *pPermPeers;/**< current driver's permitted peers */
 
 	nsd_if_t Drvr;		/**< our stream driver */
@@ -52,6 +53,8 @@ BEGINinterface(netstrms) /* name must al
 	int      (*GetDrvrMode)(netstrms_t *pThis);
 	uchar*   (*GetDrvrAuthMode)(netstrms_t *pThis);
 	permittedPeers_t* (*GetDrvrPermPeers)(netstrms_t *pThis);
+	rsRetVal (*SetDrvrGnutlsPriorityString)(netstrms_t *pThis, uchar*);
+	uchar*   (*GetDrvrGnutlsPriorityString)(netstrms_t *pThis);
 ENDinterface(netstrms)
 #define netstrmsCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
 
diff -up rsyslog-8.24.0/runtime/nsd_gtls.c.v36tls rsyslog-8.24.0/runtime/nsd_gtls.c
--- rsyslog-8.24.0/runtime/nsd_gtls.c.v36tls	2017-01-10 09:00:04.000000000 +0000
+++ rsyslog-8.24.0/runtime/nsd_gtls.c	2019-08-19 17:39:30.576158227 +0100
@@ -73,8 +73,20 @@ DEFobjCurrIf(nsd_ptcp)
 
 static int bGlblSrvrInitDone = 0;	/**< 0 - server global init not yet done, 1 - already done */
 
-static pthread_mutex_t mutGtlsStrerror; /**< a mutex protecting the potentially non-reentrant gtlStrerror() function */
+static pthread_mutex_t mutGtlsStrerror;
+/*< a mutex protecting the potentially non-reentrant gtlStrerror() function */
 
+/* a macro to abort if GnuTLS error is not acceptable. We split this off from
+ * CHKgnutls() to avoid some Coverity report in cases where we know GnuTLS
+ * failed. Note: gnuRet must already be set accordingly!
+ */
+#define ABORTgnutls { \
+		uchar *pErr = gtlsStrerror(gnuRet); \
+		LogError(0, RS_RET_GNUTLS_ERR, "unexpected GnuTLS error %d in %s:%d: %s\n", \
+	gnuRet, __FILE__, __LINE__, pErr); \
+		free(pErr); \
+		ABORT_FINALIZE(RS_RET_GNUTLS_ERR); \
+}
 /* a macro to check GnuTLS calls against unexpected errors */
 #define CHKgnutls(x) { \
 	gnuRet = (x); \
@@ -82,10 +94,7 @@ static pthread_mutex_t mutGtlsStrerror;
 		errmsg.LogError(0, RS_RET_GNUTLS_ERR, "error reading file - a common cause is that the file  does not exist"); \
 		ABORT_FINALIZE(RS_RET_GNUTLS_ERR); \
 	} else if(gnuRet != 0) { \
-		uchar *pErr = gtlsStrerror(gnuRet); \
-		errmsg.LogError(0, RS_RET_GNUTLS_ERR, "unexpected GnuTLS error %d in %s:%d: %s\n", gnuRet, __FILE__, __LINE__, pErr); \
-		free(pErr); \
-		ABORT_FINALIZE(RS_RET_GNUTLS_ERR); \
+		ABORTgnutls; \
 	} \
 }
 
@@ -192,9 +201,13 @@ gtlsLoadOurCertKey(nsd_gtls_t *pThis)
 
 	/* try load certificate */
 	CHKiRet(readFile(certFile, &data));
-	CHKgnutls(gnutls_x509_crt_init(&pThis->ourCert));
	pThis->bOurCertIsInit = 1;
-	CHKgnutls(gnutls_x509_crt_import(pThis->ourCert, &data, GNUTLS_X509_FMT_PEM));
+	pThis->nOurCerts = sizeof(pThis->pOurCerts) / sizeof(gnutls_x509_crt_t);
+	gnuRet = gnutls_x509_crt_list_import(pThis->pOurCerts, &pThis->nOurCerts,
+		&data, GNUTLS_X509_FMT_PEM,  GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
+	if(gnuRet < 0) {
+		ABORTgnutls;
+	}
 	free(data.data);
 	data.data = NULL;
 
@@ -210,7 +222,9 @@ finalize_it:
 		if(data.data != NULL)
 			free(data.data);
 		if(pThis->bOurCertIsInit) {
-			gnutls_x509_crt_deinit(pThis->ourCert);
+			for(unsigned i=0; i<pThis->nOurCerts; ++i) {
+				gnutls_x509_crt_deinit(pThis->pOurCerts[i]);
+			}
 			pThis->bOurCertIsInit = 0;
 		}
 		if(pThis->bOurKeyIsInit) {
@@ -255,8 +269,8 @@ gtlsClientCertCallback(gnutls_session_t
 #else
 	st->type = GNUTLS_CRT_X509;
 #endif
-	st->ncerts = 1;
-	st->cert.x509 = &pThis->ourCert;
+	st->ncerts = pThis->nOurCerts;
+	st->cert.x509 = pThis->pOurCerts;
 	st->key.x509 = pThis->ourKey;
 	st->deinit_all = 0;
 
@@ -532,8 +546,8 @@ gtlsRecordRecv(nsd_gtls_t *pThis)
 		dbgprintf("GnuTLS receive requires a retry (this most probably is OK and no error condition)\n");
 		ABORT_FINALIZE(RS_RET_RETRY);
 	} else {
-		int gnuRet; /* TODO: build a specific function for GnuTLS error reporting */
-		CHKgnutls(lenRcvd); /* this will abort the function */
+		int gnuRet = lenRcvd;
+		ABORTgnutls;
 	}
 
 finalize_it:
@@ -646,7 +660,7 @@ gtlsInitSession(nsd_gtls_t *pThis)
 	pThis->bIsInitiator = 0;
 
 	/* avoid calling all the priority functions, since the defaults are adequate. */
-	CHKgnutls(gnutls_set_default_priority(session));
+
 	CHKgnutls(gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred));
 
 	/* request client certificate if any.  */
@@ -1204,7 +1218,9 @@ CODESTARTobjDestruct(nsd_gtls)
 	}
 
 	if(pThis->bOurCertIsInit)
-		gnutls_x509_crt_deinit(pThis->ourCert);
+                for(unsigned i=0; i<pThis->nOurCerts; ++i) {
+			gnutls_x509_crt_deinit(pThis->pOurCerts[i]);
+                }
 	if(pThis->bOurKeyIsInit)
 		gnutls_x509_privkey_deinit(pThis->ourKey);
 	if(pThis->bHaveSess)
@@ -1299,6 +1315,21 @@ finalize_it:
 }
 
 
+/* gnutls priority string
+ * PascalWithopf 2017-08-16
+ */
+static rsRetVal
+SetGnutlsPriorityString(nsd_t *pNsd, uchar *gnutlsPriorityString)
+{
+	DEFiRet;
+	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
+
+	ISOBJ_TYPE_assert((pThis), nsd_gtls);
+	pThis->gnutlsPriorityString = gnutlsPriorityString;
+	RETiRet;
+}
+
+
 /* Provide access to the underlying OS socket. This is primarily
  * useful for other drivers (like nsd_gtls) who utilize ourselfs
  * for some of their functionality. -- rgerhards, 2008-04-18
@@ -1476,6 +1507,7 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew
 	int gnuRet;
 	nsd_gtls_t *pNew = NULL;
 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
+	const char *error_position;
 
 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
 	CHKiRet(nsd_gtlsConstruct(&pNew)); // TODO: prevent construct/destruct!
@@ -1493,6 +1525,19 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew
 	gtlsSetTransportPtr(pNew, ((nsd_ptcp_t*) (pNew->pTcp))->sock);
 	pNew->authMode = pThis->authMode;
 	pNew->pPermPeers = pThis->pPermPeers;
+	pNew->gnutlsPriorityString = pThis->gnutlsPriorityString;
+	/* here is the priorityString set */
+	if(pNew->gnutlsPriorityString != NULL) {
+		if(gnutls_priority_set_direct(pNew->sess,
+					(const char*) pNew->gnutlsPriorityString,
+					&error_position)==GNUTLS_E_INVALID_REQUEST) {
+			LogError(0, RS_RET_GNUTLS_ERR, "Syntax Error in"
+					" Priority String: \"%s\"\n", error_position);
+		}
+	} else {
+		/* Use default priorities */
+		CHKgnutls(gnutls_set_default_priority(pNew->sess));
+	}
 
 	/* we now do the handshake. This is a bit complicated, because we are 
 	 * on non-blocking sockets. Usually, the handshake will not complete
@@ -1673,6 +1718,31 @@ EnableKeepAlive(nsd_t *pNsd)
 	return nsd_ptcp.EnableKeepAlive(pThis->pTcp);
 }
 
+/*
+ * SNI should not be used if the hostname is a bare IP address
+ */
+static int
+SetServerNameIfPresent(nsd_gtls_t *pThis, uchar *host) {
+	struct sockaddr_in sa;
+	struct sockaddr_in6 sa6;
+
+	int inet_pton_ret = inet_pton(AF_INET, CHAR_CONVERT(host), &(sa.sin_addr));
+
+	if (inet_pton_ret == 0) { // host wasn't a bare IPv4 address: try IPv6
+		inet_pton_ret = inet_pton(AF_INET6, CHAR_CONVERT(host), &(sa6.sin6_addr));
+	}
+
+	switch(inet_pton_ret) {
+		case 1: // host is a valid IP address: don't use SNI
+			return 0;
+		case 0: // host isn't a valid IP address: assume it's a domain name, use SNI
+			return gnutls_server_name_set(pThis->sess, GNUTLS_NAME_DNS, host, ustrlen(host));
+		default: // unexpected error
+			return -1;
+	}
+
+}
+
 /* open a connection to a remote host (server). With GnuTLS, we always
  * open a plain tcp socket and then, if in TLS mode, do a handshake on it.
  * rgerhards, 2008-03-19
@@ -1685,6 +1755,7 @@ Connect(nsd_t *pNsd, int family, uchar *
 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
 	int sock;
 	int gnuRet;
+	const char *error_position;
 #	ifdef HAVE_GNUTLS_CERTIFICATE_TYPE_SET_PRIORITY
 	static const int cert_type_priority[2] = { GNUTLS_CRT_X509, 0 };
 #	endif
@@ -1704,6 +1775,8 @@ Connect(nsd_t *pNsd, int family, uchar *
 	pThis->bHaveSess = 1;
 	pThis->bIsInitiator = 1;
 
+	CHKgnutls(SetServerNameIfPresent(pThis, host));
+
 	/* in the client case, we need to set a callback that ensures our certificate
 	 * will be presented to the server even if it is not signed by one of the server's
 	 * trusted roots. This is necessary to support fingerprint authentication.
@@ -1721,8 +1794,19 @@ Connect(nsd_t *pNsd, int family, uchar *
 		FINALIZE; /* we have an error case! */
 	}
 
-	/* Use default priorities */
-	CHKgnutls(gnutls_set_default_priority(pThis->sess));
+	/*priority string setzen*/
+	if(pThis->gnutlsPriorityString != NULL) {
+		if(gnutls_priority_set_direct(pThis->sess,
+					(const char*) pThis->gnutlsPriorityString,
+					&error_position)==GNUTLS_E_INVALID_REQUEST) {
+			LogError(0, RS_RET_GNUTLS_ERR, "Syntax Error in"
+					" Priority String: \"%s\"\n", error_position);
+		}
+	} else {
+		/* Use default priorities */
+		CHKgnutls(gnutls_set_default_priority(pThis->sess));
+	}
+
 #	ifdef HAVE_GNUTLS_CERTIFICATE_TYPE_SET_PRIORITY
 	/* The gnutls_certificate_type_set_priority function is deprecated
 	 * and not available in recent GnuTLS versions. However, there is no
@@ -1806,6 +1890,7 @@ CODESTARTobjQueryInterface(nsd_gtls)
 	pIf->SetKeepAliveIntvl = SetKeepAliveIntvl;
 	pIf->SetKeepAliveProbes = SetKeepAliveProbes;
 	pIf->SetKeepAliveTime = SetKeepAliveTime;
+	pIf->SetGnutlsPriorityString = SetGnutlsPriorityString;
 finalize_it:
 ENDobjQueryInterface(nsd_gtls)
 
diff -up rsyslog-8.24.0/runtime/nsd_gtls.h.v36tls rsyslog-8.24.0/runtime/nsd_gtls.h
--- rsyslog-8.24.0/runtime/nsd_gtls.h.v36tls	2016-12-03 17:41:03.000000000 +0000
+++ rsyslog-8.24.0/runtime/nsd_gtls.h	2019-08-19 17:37:07.878166693 +0100
@@ -25,6 +25,7 @@
 #include "nsd.h"
 
 #define NSD_GTLS_MAX_RCVBUF 8 * 1024 /* max size of buffer for message reception */
+#define NSD_GTLS_MAX_CERT 10 /* max number of certs in our chain */
 
 typedef enum {
 	gtlsRtry_None = 0,	/**< no call needs to be retried */
@@ -56,7 +57,10 @@ struct nsd_gtls_s {
 				 * set to 1 and changed to 0 after the first report. It is changed back to 1 after
 				 * one successful authentication. */
 	permittedPeers_t *pPermPeers; /* permitted peers */
-	gnutls_x509_crt_t ourCert;	/**< our certificate, if in client mode (unused in server mode) */
+	uchar *gnutlsPriorityString;	/* gnutls priority string */
+	gnutls_x509_crt_t pOurCerts[NSD_GTLS_MAX_CERT];	/**< our certificate, if in client mode
+							(unused in server mode) */
+	unsigned int nOurCerts;  /* number of certificates in our chain */
 	gnutls_x509_privkey_t ourKey;	/**< our private key, if in client mode (unused in server mode) */
 	short	bOurCertIsInit;	/**< 1 if our certificate is initialized and must be deinit on destruction */
 	short	bOurKeyIsInit;	/**< 1 if our private key is initialized and must be deinit on destruction */
diff -up rsyslog-8.24.0/runtime/nsd.h.v36tls rsyslog-8.24.0/runtime/nsd.h
--- rsyslog-8.24.0/runtime/nsd.h.v36tls	2017-01-10 09:00:04.000000000 +0000
+++ rsyslog-8.24.0/runtime/nsd.h	2019-08-19 17:37:07.878166693 +0100
@@ -83,14 +83,17 @@ BEGINinterface(nsd) /* name must also be
 	rsRetVal (*SetKeepAliveIntvl)(nsd_t *pThis, int keepAliveIntvl);
 	rsRetVal (*SetKeepAliveProbes)(nsd_t *pThis, int keepAliveProbes);
 	rsRetVal (*SetKeepAliveTime)(nsd_t *pThis, int keepAliveTime);
+	/* v10 */
+	rsRetVal (*SetGnutlsPriorityString)(nsd_t *pThis, uchar *gnutlsPriorityString);
 ENDinterface(nsd)
-#define nsdCURR_IF_VERSION 9 /* increment whenever you change the interface structure! */
+#define nsdCURR_IF_VERSION 10 /* increment whenever you change the interface structure! */
 /* interface version 4 added GetRemAddr()
  * interface version 5 added EnableKeepAlive() -- rgerhards, 2009-06-02
  * interface version 6 changed return of CheckConnection from void to rsRetVal -- alorbach, 2012-09-06
  * interface version 7 changed signature ofGetRempoteIP() -- rgerhards, 2013-01-21
  * interface version 8 added keep alive parameter set functions
  * interface version 9 changed signature of Connect() -- dsa, 2016-11-14
+ * interface version 10 added SetGnutlsPriorityString() -- PascalWithopf, 2017-08-08
  */
 
 /* interface  for the select call */
diff -up rsyslog-8.24.0/runtime/nsd_ptcp.c.v36tls rsyslog-8.24.0/runtime/nsd_ptcp.c
--- rsyslog-8.24.0/runtime/nsd_ptcp.c.v36tls	2017-01-10 09:00:04.000000000 +0000
+++ rsyslog-8.24.0/runtime/nsd_ptcp.c	2019-08-19 17:37:07.879166693 +0100
@@ -176,6 +176,23 @@ finalize_it:
 }
 
 
+/* Set priorityString
+ * PascalWithopf 2017-08-18 */
+static rsRetVal
+SetGnutlsPriorityString(nsd_t __attribute__((unused)) *pNsd, uchar *iVal)
+{
+	DEFiRet;
+	if(iVal != NULL) {
+		LogError(0, RS_RET_VALUE_NOT_SUPPORTED, "error: "
+		"gnutlsPriorityString '%s' not supported by ptcp netstream "
+		"driver", iVal);
+		ABORT_FINALIZE(RS_RET_VALUE_NOT_SUPPORTED);
+	}
+finalize_it:
+	RETiRet;
+}
+
+
 /* Set the permitted peers. This is a dummy, always returning an
  * error because we do not support fingerprint authentication.
  * rgerhards, 2008-05-17
@@ -535,6 +552,7 @@ LstnInit(netstrms_t *pNS, void *pUsr, rs
 		CHKiRet(pNS->Drvr.SetMode(pNewNsd, netstrms.GetDrvrMode(pNS)));
 		CHKiRet(pNS->Drvr.SetAuthMode(pNewNsd, netstrms.GetDrvrAuthMode(pNS)));
 		CHKiRet(pNS->Drvr.SetPermPeers(pNewNsd, netstrms.GetDrvrPermPeers(pNS)));
+		CHKiRet(pNS->Drvr.SetGnutlsPriorityString(pNewNsd, netstrms.GetDrvrGnutlsPriorityString(pNS)));
 		CHKiRet(netstrms.CreateStrm(pNS, &pNewStrm));
 		pNewStrm->pDrvrData = (nsd_t*) pNewNsd;
 		pNewNsd = NULL;
@@ -854,6 +872,7 @@ CODESTARTobjQueryInterface(nsd_ptcp)
 	pIf->SetSock = SetSock;
 	pIf->SetMode = SetMode;
 	pIf->SetAuthMode = SetAuthMode;
+	pIf->SetGnutlsPriorityString = SetGnutlsPriorityString;
 	pIf->SetPermPeers = SetPermPeers;
 	pIf->Rcv = Rcv;
 	pIf->Send = Send;
diff -up rsyslog-8.24.0/runtime/tcpsrv.c.v36tls rsyslog-8.24.0/runtime/tcpsrv.c
--- rsyslog-8.24.0/runtime/tcpsrv.c.v36tls	2019-08-19 17:37:07.874166693 +0100
+++ rsyslog-8.24.0/runtime/tcpsrv.c	2019-08-19 17:37:07.880166693 +0100
@@ -470,6 +470,9 @@ SessAccept(tcpsrv_t *pThis, tcpLstnPortL
 	}
 
 	/* we found a free spot and can construct our session object */
+	if(pThis->gnutlsPriorityString != NULL) {
+		CHKiRet(netstrm.SetGnutlsPriorityString(pNewStrm, pThis->gnutlsPriorityString));
+	}
 	CHKiRet(tcps_sess.Construct(&pSess));
 	CHKiRet(tcps_sess.SetTcpsrv(pSess, pThis));
 	CHKiRet(tcps_sess.SetLstnInfo(pSess, pLstnInfo));
@@ -1001,6 +1004,8 @@ tcpsrvConstructFinalize(tcpsrv_t *pThis)
 		CHKiRet(netstrms.SetDrvrAuthMode(pThis->pNS, pThis->pszDrvrAuthMode));
 	if(pThis->pPermPeers != NULL)
 		CHKiRet(netstrms.SetDrvrPermPeers(pThis->pNS, pThis->pPermPeers));
+	if(pThis->gnutlsPriorityString != NULL)
+		CHKiRet(netstrms.SetDrvrGnutlsPriorityString(pThis->pNS, pThis->gnutlsPriorityString));
 	CHKiRet(netstrms.ConstructFinalize(pThis->pNS));
 
 	/* set up listeners */
@@ -1173,6 +1178,16 @@ SetKeepAliveTime(tcpsrv_t *pThis, int iV
 }
 
 static rsRetVal
+SetGnutlsPriorityString(tcpsrv_t *pThis, uchar *iVal)
+{
+	DEFiRet;
+	DBGPRINTF("tcpsrv: gnutlsPriorityString set to %s\n",
+		(iVal == NULL) ? "(null)" : (const char*) iVal);
+	pThis->gnutlsPriorityString = iVal;
+	RETiRet;
+}
+
+static rsRetVal
 SetOnMsgReceive(tcpsrv_t *pThis, rsRetVal (*OnMsgReceive)(tcps_sess_t*, uchar*, int))
 {
 	DEFiRet;
@@ -1414,6 +1429,7 @@ CODESTARTobjQueryInterface(tcpsrv)
 	pIf->SetKeepAliveIntvl = SetKeepAliveIntvl;
 	pIf->SetKeepAliveProbes = SetKeepAliveProbes;
 	pIf->SetKeepAliveTime = SetKeepAliveTime;
+	pIf->SetGnutlsPriorityString = SetGnutlsPriorityString;
 	pIf->SetUsrP = SetUsrP;
 	pIf->SetInputName = SetInputName;
 	pIf->SetOrigin = SetOrigin;
diff -up rsyslog-8.24.0/runtime/tcpsrv.h.v36tls rsyslog-8.24.0/runtime/tcpsrv.h
--- rsyslog-8.24.0/runtime/tcpsrv.h.v36tls	2019-08-19 17:37:07.874166693 +0100
+++ rsyslog-8.24.0/runtime/tcpsrv.h	2019-08-19 17:37:07.880166693 +0100
@@ -61,6 +61,7 @@ struct tcpsrv_s {
 	int iKeepAliveTime;	/**< socket layer KEEPALIVE timeout */
 	netstrms_t *pNS;	/**< pointer to network stream subsystem */
 	int iDrvrMode;		/**< mode of the stream driver to use */
+	uchar *gnutlsPriorityString;	/**< priority string for gnutls */
 	uchar *pszDrvrAuthMode;	/**< auth mode of the stream driver to use */
 	uchar *pszDrvrName;	/**< name of stream driver to use */
 	uchar *pszInputName;	/**< value to be used as input name */
@@ -169,6 +170,8 @@ BEGINinterface(tcpsrv) /* name must also
 	rsRetVal (*SetKeepAliveTime)(tcpsrv_t*, int);
 	/* added v18 */
 	rsRetVal (*SetbSPFramingFix)(tcpsrv_t*, sbool);
+	/* added v19 -- PascalWithopf, 2017-08-08 */
+	rsRetVal (*SetGnutlsPriorityString)(tcpsrv_t*, uchar*);
 	/* added v21 -- Preserve case in fromhost, 2018-08-16 */
 	rsRetVal (*SetPreserveCase)(tcpsrv_t *pThis, int bPreserveCase);
 ENDinterface(tcpsrv)
diff -up rsyslog-8.24.0/tools/omfwd.c.v36tls rsyslog-8.24.0/tools/omfwd.c
--- rsyslog-8.24.0/tools/omfwd.c.v36tls	2019-08-19 17:37:07.848166695 +0100
+++ rsyslog-8.24.0/tools/omfwd.c	2019-08-19 17:37:07.881166693 +0100
@@ -91,6 +91,7 @@ typedef struct _instanceData {
 	int iKeepAliveIntvl;
 	int iKeepAliveProbes;
 	int iKeepAliveTime;
+	uchar *gnutlsPriorityString;
 
 #	define	FORW_UDP 0
 #	define	FORW_TCP 1
@@ -138,6 +139,7 @@ typedef struct configSettings_s {
 	int iKeepAliveIntvl;
 	int iKeepAliveProbes;
 	int iKeepAliveTime;
+	uchar *gnutlsPriorityString;
 	permittedPeers_t *pPermPeers;
 } configSettings_t;
 static configSettings_t cs;
@@ -169,6 +171,7 @@ static struct cnfparamdescr actpdescr[]
 	{ "keepalive.probes", eCmdHdlrPositiveInt, 0 },
 	{ "keepalive.time", eCmdHdlrPositiveInt, 0 },
 	{ "keepalive.interval", eCmdHdlrPositiveInt, 0 },
+	{ "gnutlsprioritystring", eCmdHdlrString, 0 },
 	{ "streamdriver", eCmdHdlrGetWord, 0 },
 	{ "streamdrivermode", eCmdHdlrInt, 0 },
 	{ "streamdriverauthmode", eCmdHdlrGetWord, 0 },
@@ -717,6 +720,9 @@ static rsRetVal TCPSendInit(void *pvData
 			CHKiRet(netstrm.SetDrvrPermPeers(pWrkrData->pNetstrm, pData->pPermPeers));
 		}
 		/* params set, now connect */
+		if(pData->gnutlsPriorityString != NULL) {
+			CHKiRet(netstrm.SetGnutlsPriorityString(pWrkrData->pNetstrm, pData->gnutlsPriorityString));
+		}
 		CHKiRet(netstrm.Connect(pWrkrData->pNetstrm, glbl.GetDefPFFamily(),
 			(uchar*)pData->port, (uchar*)pData->target, pData->device));
 
@@ -960,6 +966,7 @@ setInstParamDefaults(instanceData *pData
 	pData->iKeepAliveProbes = 0;
 	pData->iKeepAliveIntvl = 0;
 	pData->iKeepAliveTime = 0;
+	pData->gnutlsPriorityString = NULL;
 	pData->bResendLastOnRecon = 0; 
 	pData->bSendToAll = -1;  /* unspecified */
 	pData->iUDPSendDelay = 0;
@@ -1046,6 +1053,8 @@ CODESTARTnewActInst
 			pData->iKeepAliveIntvl = (int) pvals[i].val.d.n;
 		} else if(!strcmp(actpblk.descr[i].name, "keepalive.time")) {
 			pData->iKeepAliveTime = (int) pvals[i].val.d.n;
+		} else if(!strcmp(actpblk.descr[i].name, "gnutlsprioritystring")) {
+			pData->gnutlsPriorityString = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
 		} else if(!strcmp(actpblk.descr[i].name, "streamdriver")) {
 			pData->pszStrmDrvr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
 		} else if(!strcmp(actpblk.descr[i].name, "streamdrivermode")) {