1 /* nsd_gtls.c
2  *
3  * An implementation of the nsd interface for GnuTLS.
4  *
5  * Copyright (C) 2007-2021 Rainer Gerhards and Adiscon GmbH.
6  *
7  * This file is part of the rsyslog runtime library.
8  *
9  * The rsyslog runtime library is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * The rsyslog runtime library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with the rsyslog runtime library.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * A copy of the GPL can be found in the file "COPYING" in this distribution.
23  * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
24  */
25 #include "config.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <string.h>
30 #include <gnutls/gnutls.h>
31 #include <gnutls/x509.h>
32 #if GNUTLS_VERSION_NUMBER <= 0x020b00
33 #	include <gcrypt.h>
34 #endif
35 #include <errno.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <pthread.h>
40 
41 #include "rsyslog.h"
42 #include "syslogd-types.h"
43 #include "module-template.h"
44 #include "cfsysline.h"
45 #include "obj.h"
46 #include "stringbuf.h"
47 #include "errmsg.h"
48 #include "net.h"
49 #include "datetime.h"
50 #include "netstrm.h"
51 #include "netstrms.h"
52 #include "nsd_ptcp.h"
53 #include "nsdsel_gtls.h"
54 #include "nsd_gtls.h"
55 #include "unicode-helper.h"
56 
57 /* things to move to some better place/functionality - TODO */
58 #define CRLFILE "crl.pem"
59 
60 
61 #if GNUTLS_VERSION_NUMBER <= 0x020b00
62 GCRY_THREAD_OPTION_PTHREAD_IMPL;
63 #endif
64 MODULE_TYPE_LIB
65 MODULE_TYPE_KEEP
66 
67 /* static data */
68 DEFobjStaticHelpers
69 DEFobjCurrIf(glbl)
70 DEFobjCurrIf(net)
71 DEFobjCurrIf(datetime)
72 DEFobjCurrIf(nsd_ptcp)
73 
74 /* Static Helper variables for certless communication */
75 static gnutls_anon_client_credentials_t anoncred;	/**< client anon credentials */
76 static gnutls_anon_server_credentials_t anoncredSrv;	/**< server anon credentials */
77 static int dhBits = 2048;	/**< number of bits for Diffie-Hellman key */
78 static int dhMinBits = 512;	/**< minimum number of bits for Diffie-Hellman key */
79 
80 static pthread_mutex_t mutGtlsStrerror;
81 /*< a mutex protecting the potentially non-reentrant gtlStrerror() function */
82 
83 static gnutls_dh_params_t dh_params; /**< server DH parameters for anon mode */
84 
85 /* a macro to abort if GnuTLS error is not acceptable. We split this off from
86  * CHKgnutls() to avoid some Coverity report in cases where we know GnuTLS
87  * failed. Note: gnuRet must already be set accordingly!
88  */
89 #define ABORTgnutls { \
90 		uchar *pErr = gtlsStrerror(gnuRet); \
91 		LogError(0, RS_RET_GNUTLS_ERR, "unexpected GnuTLS error %d in %s:%d: %s\n", \
92 	gnuRet, __FILE__, __LINE__, pErr); \
93 		free(pErr); \
94 		ABORT_FINALIZE(RS_RET_GNUTLS_ERR); \
95 }
96 /* a macro to check GnuTLS calls against unexpected errors */
97 #define CHKgnutls(x) { \
98 	gnuRet = (x); \
99 	if(gnuRet == GNUTLS_E_FILE_ERROR) { \
100 		LogError(0, RS_RET_GNUTLS_ERR, "error reading file - a common cause is that the " \
101 			"file  does not exist"); \
102 		ABORT_FINALIZE(RS_RET_GNUTLS_ERR); \
103 	} else if(gnuRet != 0) { \
104 		ABORTgnutls; \
105 	} \
106 }
107 
108 
109 /* ------------------------------ GnuTLS specifics ------------------------------ */
110 
111 /* This defines a log function to be provided to GnuTLS. It hopefully
112  * helps us track down hard to find problems.
113  * rgerhards, 2008-06-20
114  */
logFunction(int level,const char * msg)115 static void logFunction(int level, const char *msg)
116 {
117 	dbgprintf("GnuTLS log msg, level %d: %s\n", level, msg);
118 }
119 
120 /* read in the whole content of a file. The caller is responsible for
121  * freeing the buffer. To prevent DOS, this function can NOT read
122  * files larger than 1MB (which still is *very* large).
123  * rgerhards, 2008-05-26
124  */
125 static rsRetVal
readFile(const uchar * const pszFile,gnutls_datum_t * const pBuf)126 readFile(const uchar *const pszFile, gnutls_datum_t *const pBuf)
127 {
128 	int fd;
129 	struct stat stat_st;
130 	DEFiRet;
131 
132 	assert(pszFile != NULL);
133 	assert(pBuf != NULL);
134 
135 	pBuf->data = NULL;
136 
137 	if((fd = open((char*)pszFile, O_RDONLY)) == -1) {
138 		LogError(errno, RS_RET_FILE_NOT_FOUND, "can not read file '%s'", pszFile);
139 		ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
140 	}
141 
142 	if(fstat(fd, &stat_st) == -1) {
143 		LogError(errno, RS_RET_FILE_NO_STAT, "can not stat file '%s'", pszFile);
144 		ABORT_FINALIZE(RS_RET_FILE_NO_STAT);
145 	}
146 
147 	/* 1MB limit */
148 	if(stat_st.st_size > 1024 * 1024) {
149 		LogError(0, RS_RET_FILE_TOO_LARGE, "file '%s' too large, max 1MB", pszFile);
150 		ABORT_FINALIZE(RS_RET_FILE_TOO_LARGE);
151 	}
152 
153 	CHKmalloc(pBuf->data = malloc(stat_st.st_size));
154 	pBuf->size = stat_st.st_size;
155 	if(read(fd,  pBuf->data, stat_st.st_size) != stat_st.st_size) {
156 		LogError(0, RS_RET_IO_ERROR, "error or incomplete read of file '%s'", pszFile);
157 		ABORT_FINALIZE(RS_RET_IO_ERROR);
158 	}
159 
160 finalize_it:
161 	if(fd != -1)
162 		close(fd);
163 	if(iRet != RS_RET_OK) {
164 		if(pBuf->data != NULL) {
165 			free(pBuf->data);
166 			pBuf->data = NULL;
167 			pBuf->size = 0;
168 			}
169 	}
170 	RETiRet;
171 }
172 
173 
174 /* Load the certificate and the private key into our own store. We need to do
175  * this in the client case, to support fingerprint authentication. In that case,
176  * we may be presented no matching root certificate, but we must provide ours.
177  * The only way to do that is via the cert callback interface, but for it we
178  * need to load certificates into our private store.
179  * rgerhards, 2008-05-26
180  */
181 static rsRetVal
gtlsLoadOurCertKey(nsd_gtls_t * pThis)182 gtlsLoadOurCertKey(nsd_gtls_t *pThis)
183 {
184 	DEFiRet;
185 	int gnuRet;
186 	gnutls_datum_t data = { NULL, 0 };
187 	const uchar *keyFile;
188 	const uchar *certFile;
189 
190 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
191 
192 	certFile = (pThis->pszCertFile == NULL) ? glbl.GetDfltNetstrmDrvrCertFile() : pThis->pszCertFile;
193 	keyFile = (pThis->pszKeyFile == NULL) ? glbl.GetDfltNetstrmDrvrKeyFile() : pThis->pszKeyFile;
194 
195 	if(certFile == NULL || keyFile == NULL) {
196 		/* in this case, we can not set our certificate. If we are
197 		 * a client and the server is running in "anon" auth mode, this
198 		 * may be well acceptable. In other cases, we will see some
199 		 * more error messages down the road. -- rgerhards, 2008-07-02
200 		 */
201 		dbgprintf("gtlsLoadOurCertKey our certificate is not set, file name values are cert: '%s', key: '%s'\n",
202 			  certFile, keyFile);
203 		ABORT_FINALIZE(RS_RET_CERTLESS);
204 	}
205 
206 	/* try load certificate */
207 	CHKiRet(readFile(certFile, &data));
208 	pThis->nOurCerts = sizeof(pThis->pOurCerts) / sizeof(gnutls_x509_crt_t);
209 	gnuRet = gnutls_x509_crt_list_import(pThis->pOurCerts, &pThis->nOurCerts,
210 		&data, GNUTLS_X509_FMT_PEM,  GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
211 	if(gnuRet < 0) {
212 		ABORTgnutls;
213 	}
214 	pThis->bOurCertIsInit = 1;
215 	free(data.data);
216 	data.data = NULL;
217 
218 	/* try load private key */
219 	CHKiRet(readFile(keyFile, &data));
220 	CHKgnutls(gnutls_x509_privkey_init(&pThis->ourKey));
221 	pThis->bOurKeyIsInit = 1;
222 	CHKgnutls(gnutls_x509_privkey_import(pThis->ourKey, &data, GNUTLS_X509_FMT_PEM));
223 	free(data.data);
224 
225 
226 finalize_it:
227 	if(iRet == RS_RET_CERTLESS) {
228 		dbgprintf("gtlsLoadOurCertKey certless exit\n");
229 		pThis->bOurCertIsInit = 0;
230 		pThis->bOurKeyIsInit = 0;
231 	} else if(iRet != RS_RET_OK) {
232 		dbgprintf("gtlsLoadOurCertKey error exit\n");
233 		if(data.data != NULL)
234 			free(data.data);
235 		if(pThis->bOurCertIsInit) {
236 			for(unsigned i=0; i<pThis->nOurCerts; ++i) {
237 				gnutls_x509_crt_deinit(pThis->pOurCerts[i]);
238 			}
239 			pThis->bOurCertIsInit = 0;
240 		}
241 		if(pThis->bOurKeyIsInit) {
242 			gnutls_x509_privkey_deinit(pThis->ourKey);
243 			pThis->bOurKeyIsInit = 0;
244 		}
245 	} else {
246 		dbgprintf("gtlsLoadOurCertKey Successfully Loaded cert '%s' and key: '%s'\n", certFile, keyFile);
247 	}
248 	RETiRet;
249 }
250 
251 
252 /* This callback must be associated with a session by calling
253  * gnutls_certificate_client_set_retrieve_function(session, cert_callback),
254  * before a handshake. We will always return the configured certificate,
255  * even if it does not match the peer's trusted CAs. This is necessary
256  * to use self-signed certs in fingerprint mode. And, yes, this usage
257  * of the callback is quite a hack. But it seems the only way to
258  * obey to the IETF -transport-tls I-D.
259  * Note: GnuTLS requires the function to return 0 on success and
260  * -1 on failure.
261  * rgerhards, 2008-05-27
262  */
263 static int
gtlsClientCertCallback(gnutls_session_t session,const gnutls_datum_t * req_ca_rdn,int nreqs,const gnutls_pk_algorithm_t * sign_algos,int sign_algos_length,gnutls_retr2_st * st)264 gtlsClientCertCallback(gnutls_session_t session,
265 	__attribute__((unused)) const gnutls_datum_t* req_ca_rdn,
266 	int __attribute__((unused)) nreqs,
267 	__attribute__((unused)) const gnutls_pk_algorithm_t* sign_algos,
268 	int __attribute__((unused)) sign_algos_length,
269 #if HAVE_GNUTLS_CERTIFICATE_SET_RETRIEVE_FUNCTION
270 	gnutls_retr2_st* st
271 #else
272 	gnutls_retr_st *st
273 #endif
274 	)
275 {
276 	nsd_gtls_t *pThis;
277 
278 	pThis = (nsd_gtls_t*) gnutls_session_get_ptr(session);
279 
280 #if HAVE_GNUTLS_CERTIFICATE_SET_RETRIEVE_FUNCTION
281 	st->cert_type = GNUTLS_CRT_X509;
282 #else
283 	st->type = GNUTLS_CRT_X509;
284 #endif
285 	st->ncerts = pThis->nOurCerts;
286 	st->cert.x509 = pThis->pOurCerts;
287 	st->key.x509 = pThis->ourKey;
288 	st->deinit_all = 0;
289 
290 	return 0;
291 }
292 
293 
294 /* This function extracts some information about this session's peer
295  * certificate. Works for X.509 certificates only. Adds all
296  * of the info to a cstr_t, which is handed over to the caller.
297  * Caller must destruct it when no longer needed.
298  * rgerhards, 2008-05-21
299  */
300 static rsRetVal
gtlsGetCertInfo(nsd_gtls_t * const pThis,cstr_t ** ppStr)301 gtlsGetCertInfo(nsd_gtls_t *const pThis, cstr_t **ppStr)
302 {
303 	uchar szBufA[1024];
304 	uchar *szBuf = szBufA;
305 	size_t szBufLen = sizeof(szBufA), tmp;
306 	unsigned int algo, bits;
307 	time_t expiration_time, activation_time;
308 	const gnutls_datum_t *cert_list;
309 	unsigned cert_list_size = 0;
310 	gnutls_x509_crt_t cert;
311 	cstr_t *pStr = NULL;
312 	int gnuRet;
313 	DEFiRet;
314 	unsigned iAltName;
315 
316 	assert(ppStr != NULL);
317 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
318 
319 	if(gnutls_certificate_type_get(pThis->sess) != GNUTLS_CRT_X509)
320 		return RS_RET_TLS_CERT_ERR;
321 
322 	cert_list = gnutls_certificate_get_peers(pThis->sess, &cert_list_size);
323 	CHKiRet(rsCStrConstructFromszStrf(&pStr, "peer provided %d certificate(s). ", cert_list_size));
324 
325 	if(cert_list_size > 0) {
326 		/* we only print information about the first certificate */
327 		CHKgnutls(gnutls_x509_crt_init(&cert));
328 		CHKgnutls(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER));
329 
330 		expiration_time = gnutls_x509_crt_get_expiration_time(cert);
331 		activation_time = gnutls_x509_crt_get_activation_time(cert);
332 		ctime_r(&activation_time, (char*)szBuf);
333 		szBuf[ustrlen(szBuf) - 1] = '\0'; /* strip linefeed */
334 		CHKiRet(rsCStrAppendStrf(pStr, "Certificate 1 info: "
335 			"certificate valid from %s ", szBuf));
336 		ctime_r(&expiration_time, (char*)szBuf);
337 		szBuf[ustrlen(szBuf) - 1] = '\0'; /* strip linefeed */
338 		CHKiRet(rsCStrAppendStrf(pStr, "to %s; ", szBuf));
339 
340 		/* Extract some of the public key algorithm's parameters */
341 		algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits);
342 		CHKiRet(rsCStrAppendStrf(pStr, "Certificate public key: %s; ",
343 			gnutls_pk_algorithm_get_name(algo)));
344 
345 		/* names */
346 		tmp = szBufLen;
347 		if(gnutls_x509_crt_get_dn(cert, (char*)szBuf, &tmp)
348 		    == GNUTLS_E_SHORT_MEMORY_BUFFER) {
349 			szBufLen = tmp;
350 			szBuf = malloc(tmp);
351 			gnutls_x509_crt_get_dn(cert, (char*)szBuf, &tmp);
352 		}
353 		CHKiRet(rsCStrAppendStrf(pStr, "DN: %s; ", szBuf));
354 
355 		tmp = szBufLen;
356 		if(gnutls_x509_crt_get_issuer_dn(cert, (char*)szBuf, &tmp)
357 		    == GNUTLS_E_SHORT_MEMORY_BUFFER) {
358 			szBufLen = tmp;
359 			szBuf = realloc((szBuf == szBufA) ? NULL : szBuf, tmp);
360 			gnutls_x509_crt_get_issuer_dn(cert, (char*)szBuf, &tmp);
361 		}
362 		CHKiRet(rsCStrAppendStrf(pStr, "Issuer DN: %s; ", szBuf));
363 
364 		/* dNSName alt name */
365 		iAltName = 0;
366 		while(1) { /* loop broken below */
367 			tmp = szBufLen;
368 			gnuRet = gnutls_x509_crt_get_subject_alt_name(cert, iAltName,
369 					szBuf, &tmp, NULL);
370 			if(gnuRet == GNUTLS_E_SHORT_MEMORY_BUFFER) {
371 				szBufLen = tmp;
372 				szBuf = realloc((szBuf == szBufA) ? NULL : szBuf, tmp);
373 				continue;
374 			} else if(gnuRet < 0)
375 				break;
376 			else if(gnuRet == GNUTLS_SAN_DNSNAME) {
377 				/* we found it! */
378 				CHKiRet(rsCStrAppendStrf(pStr, "SAN:DNSname: %s; ", szBuf));
379 				/* do NOT break, because there may be multiple dNSName's! */
380 			}
381 			++iAltName;
382 		}
383 
384 		gnutls_x509_crt_deinit(cert);
385 	}
386 
387 	cstrFinalize(pStr);
388 	*ppStr = pStr;
389 
390 finalize_it:
391 	if(iRet != RS_RET_OK) {
392 		if(pStr != NULL)
393 			rsCStrDestruct(&pStr);
394 	}
395 	if(szBuf != szBufA)
396 		free(szBuf);
397 
398 	RETiRet;
399 }
400 
401 
402 
403 #if 0 /* we may need this in the future - code needs to be looked at then! */
404 /* This function will print some details of the
405  * given pThis->sess.
406  */
407 static rsRetVal
408 print_info(nsd_gtls_t *pThis)
409 {
410 	const char *tmp;
411 	gnutls_credentials_type cred;
412 	gnutls_kx_algorithm kx;
413 	DEFiRet;
414 
415 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
416 	/* print the key exchange's algorithm name
417 	*/
418 	kx = gnutls_kx_get(pThis->sess);
419 	tmp = gnutls_kx_get_name(kx);
420 	dbgprintf("- Key Exchange: %s\n", tmp);
421 
422 	/* Check the authentication type used and switch
423 	* to the appropriate.
424 	*/
425 	cred = gnutls_auth_get_type(pThis->sess);
426 	switch (cred) {
427 	case GNUTLS_CRD_ANON:       /* anonymous authentication */
428 		dbgprintf("- Anonymous DH using prime of %d bits\n",
429 		gnutls_dh_get_prime_bits(pThis->sess));
430 		break;
431 	case GNUTLS_CRD_CERTIFICATE:        /* certificate authentication */
432 		/* Check if we have been using ephemeral Diffie Hellman.
433 		*/
434 		if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) {
435 		 dbgprintf("\n- Ephemeral DH using prime of %d bits\n",
436 			gnutls_dh_get_prime_bits(pThis->sess));
437 		}
438 
439 		/* if the certificate list is available, then
440 		* print some information about it.
441 		*/
442 		gtlsPrintCert(pThis);
443 		break;
444 	case GNUTLS_CRD_SRP:        /* certificate authentication */
445 		dbgprintf("GNUTLS_CRD_SRP/IA");
446 		break;
447 	case GNUTLS_CRD_PSK:        /* certificate authentication */
448 		dbgprintf("GNUTLS_CRD_PSK");
449 		break;
450 	case GNUTLS_CRD_IA:        /* certificate authentication */
451 		dbgprintf("GNUTLS_CRD_IA");
452 		break;
453 	} /* switch */
454 
455 	/* print the protocol's name (ie TLS 1.0) */
456 	tmp = gnutls_protocol_get_name(gnutls_protocol_get_version(pThis->sess));
457 	dbgprintf("- Protocol: %s\n", tmp);
458 
459 	/* print the certificate type of the peer.
460 	* ie X.509
461 	*/
462 	tmp = gnutls_certificate_type_get_name(
463 	gnutls_certificate_type_get(pThis->sess));
464 
465 	dbgprintf("- Certificate Type: %s\n", tmp);
466 
467 	/* print the compression algorithm (if any)
468 	*/
469 	tmp = gnutls_compression_get_name( gnutls_compression_get(pThis->sess));
470 	dbgprintf("- Compression: %s\n", tmp);
471 
472 	/* print the name of the cipher used.
473 	* ie 3DES.
474 	*/
475 	tmp = gnutls_cipher_get_name(gnutls_cipher_get(pThis->sess));
476 	dbgprintf("- Cipher: %s\n", tmp);
477 
478 	/* Print the MAC algorithms name.
479 	* ie SHA1
480 	*/
481 	tmp = gnutls_mac_get_name(gnutls_mac_get(pThis->sess));
482 	dbgprintf("- MAC: %s\n", tmp);
483 
484 	RETiRet;
485 }
486 #endif
487 
488 
489 /* Convert a fingerprint to printable data. The  conversion is carried out
490  * according IETF I-D syslog-transport-tls-12. The fingerprint string is
491  * returned in a new cstr object. It is the caller's responsibility to
492  * destruct that object.
493  * rgerhards, 2008-05-08
494  */
495 static rsRetVal
GenFingerprintStr(uchar * pFingerprint,size_t sizeFingerprint,cstr_t ** ppStr)496 GenFingerprintStr(uchar *pFingerprint, size_t sizeFingerprint, cstr_t **ppStr)
497 {
498 	cstr_t *pStr = NULL;
499 	uchar buf[4];
500 	size_t i;
501 	DEFiRet;
502 
503 	CHKiRet(rsCStrConstruct(&pStr));
504 	CHKiRet(rsCStrAppendStrWithLen(pStr, (uchar*)"SHA1", 4));
505 	for(i = 0 ; i < sizeFingerprint ; ++i) {
506 		snprintf((char*)buf, sizeof(buf), ":%2.2X", pFingerprint[i]);
507 		CHKiRet(rsCStrAppendStrWithLen(pStr, buf, 3));
508 	}
509 	cstrFinalize(pStr);
510 
511 	*ppStr = pStr;
512 
513 finalize_it:
514 	if(iRet != RS_RET_OK) {
515 		if(pStr != NULL)
516 			rsCStrDestruct(&pStr);
517 	}
518 	RETiRet;
519 }
520 
521 
522 /* a thread-safe variant of gnutls_strerror
523  * The caller must free the returned string.
524  * rgerhards, 2008-04-30
525  */
gtlsStrerror(int error)526 uchar *gtlsStrerror(int error)
527 {
528 	uchar *pErr;
529 
530 	pthread_mutex_lock(&mutGtlsStrerror);
531 	pErr = (uchar*) strdup(gnutls_strerror(error));
532 	pthread_mutex_unlock(&mutGtlsStrerror);
533 
534 	return pErr;
535 }
536 
537 
538 /* try to receive a record from the remote peer. This works with
539  * our own abstraction and handles local buffering and EAGAIN.
540  * See details on local buffering in Rcv(9 header-comment.
541  * This function MUST only be called when the local buffer is
542  * empty. Calling it otherwise will cause losss of current buffer
543  * data.
544  * rgerhards, 2008-06-24
545  */
546 rsRetVal
gtlsRecordRecv(nsd_gtls_t * pThis)547 gtlsRecordRecv(nsd_gtls_t *pThis)
548 {
549 	ssize_t lenRcvd;
550 	DEFiRet;
551 
552 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
553 	DBGPRINTF("gtlsRecordRecv: start\n");
554 
555 	lenRcvd = gnutls_record_recv(pThis->sess, pThis->pszRcvBuf, NSD_GTLS_MAX_RCVBUF);
556 	if(lenRcvd >= 0) {
557 		DBGPRINTF("gtlsRecordRecv: gnutls_record_recv received %zd bytes\n", lenRcvd);
558 		pThis->lenRcvBuf = lenRcvd;
559 		pThis->ptrRcvBuf = 0;
560 
561 		/* Check for additional data in SSL buffer */
562 		size_t stBytesLeft = gnutls_record_check_pending(pThis->sess);
563 		if (stBytesLeft > 0 ){
564 			DBGPRINTF("gtlsRecordRecv: %zd Bytes pending after gnutls_record_recv, expand buffer.\n",
565 				stBytesLeft);
566 			/* realloc buffer size and preserve char content */
567 			char *const newbuf = realloc(pThis->pszRcvBuf, NSD_GTLS_MAX_RCVBUF+stBytesLeft);
568 			CHKmalloc(newbuf);
569 			pThis->pszRcvBuf = newbuf;
570 
571 			/* 2nd read will read missing bytes from the current SSL Packet */
572 			lenRcvd = gnutls_record_recv(pThis->sess, pThis->pszRcvBuf+NSD_GTLS_MAX_RCVBUF, stBytesLeft);
573 			if(lenRcvd > 0) {
574 				DBGPRINTF("gtlsRecordRecv: 2nd SSL_read received %zd bytes\n",
575 					(NSD_GTLS_MAX_RCVBUF+lenRcvd));
576 				pThis->lenRcvBuf = NSD_GTLS_MAX_RCVBUF+lenRcvd;
577 			} else {
578 				goto sslerr;
579 			}
580 		}
581 	} else if(lenRcvd == GNUTLS_E_AGAIN || lenRcvd == GNUTLS_E_INTERRUPTED) {
582 sslerr:
583 		pThis->rtryCall = gtlsRtry_recv;
584 		dbgprintf("GnuTLS receive requires a retry (this most probably is OK and no error condition)\n");
585 		ABORT_FINALIZE(RS_RET_RETRY);
586 	} else {
587 		int gnuRet = lenRcvd;
588 		ABORTgnutls;
589 	}
590 
591 finalize_it:
592 	dbgprintf("gtlsRecordRecv return. nsd %p, iRet %d, lenRcvd %d, lenRcvBuf %d, ptrRcvBuf %d\n",
593 	pThis, iRet, (int) lenRcvd, pThis->lenRcvBuf, pThis->ptrRcvBuf);
594 	RETiRet;
595 }
596 
597 
598 /* add our own certificate to the certificate set, so that the peer
599  * can identify us. Please note that we try to use mutual authentication,
600  * so we always add a cert, even if we are in the client role (later,
601  * this may be controlled by a config setting).
602  * rgerhards, 2008-05-15
603  */
604 static rsRetVal
gtlsAddOurCert(nsd_gtls_t * const pThis)605 gtlsAddOurCert(nsd_gtls_t *const pThis)
606 {
607 	int gnuRet = 0;
608 	const uchar *keyFile;
609 	const uchar *certFile;
610 	uchar *pGnuErr; /* for GnuTLS error reporting */
611 	DEFiRet;
612 
613 	certFile = (pThis->pszCertFile == NULL) ? glbl.GetDfltNetstrmDrvrCertFile() : pThis->pszCertFile;
614 	keyFile = (pThis->pszKeyFile == NULL) ? glbl.GetDfltNetstrmDrvrKeyFile() : pThis->pszKeyFile;
615 	dbgprintf("GTLS certificate file: '%s'\n", certFile);
616 	dbgprintf("GTLS key file: '%s'\n", keyFile);
617 	if(certFile == NULL) {
618 		LogMsg(0, RS_RET_CERT_MISSING, LOG_WARNING, "warning: certificate file is not set");
619 	}
620 	if(keyFile == NULL) {
621 		LogMsg(0, RS_RET_CERTKEY_MISSING, LOG_WARNING, "warning: key file is not set");
622 	}
623 
624 	/* set certificate in gnutls */
625 	if(certFile != NULL && keyFile != NULL) {
626 		CHKgnutls(gnutls_certificate_set_x509_key_file(pThis->xcred, (char*)certFile, (char*)keyFile,
627 			GNUTLS_X509_FMT_PEM));
628 	}
629 
630 finalize_it:
631 	if(iRet != RS_RET_OK && iRet != RS_RET_CERT_MISSING && iRet != RS_RET_CERTKEY_MISSING) {
632 		pGnuErr = gtlsStrerror(gnuRet);
633 		errno = 0;
634 		LogError(0, iRet, "error adding our certificate. GnuTLS error %d, message: '%s', "
635 				"key: '%s', cert: '%s'", gnuRet, pGnuErr, keyFile, certFile);
636 		free(pGnuErr);
637 	}
638 	RETiRet;
639 }
640 
641 /*
642 * removecomment ifdef out if needed
643 */
644 #ifdef false
645 
print_cipher_suite_list(const char * priorities)646 static void print_cipher_suite_list(const char *priorities)
647 {
648 	size_t i;
649 	int ret;
650 	unsigned int idx;
651 	const char *name;
652 	const char *err;
653 	unsigned char id[2];
654 	gnutls_protocol_t version;
655 	gnutls_priority_t pcache;
656 
657 	if (priorities != NULL) {
658 		printf("print_cipher_suite_list: Cipher suites for %s\n", priorities);
659 
660 		ret = gnutls_priority_init(&pcache, priorities, &err);
661 		if (ret < 0) {
662 			fprintf(stderr, "print_cipher_suite_list: Syntax error at: %s\n", err);
663 			exit(1);
664 		}
665 
666 		for (i = 0;; i++) {
667 			ret = gnutls_priority_get_cipher_suite_index(pcache, i, &idx);
668 			if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
669 				break;
670 			if (ret == GNUTLS_E_UNKNOWN_CIPHER_SUITE)
671 				continue;
672 
673 			name = gnutls_cipher_suite_info(idx, id, NULL, NULL, NULL, &version);
674 
675 			if (name != NULL)
676 				dbgprintf("print_cipher_suite_list: %-50s\t0x%02x, 0x%02x\t%s\n",
677 				name, (unsigned char) id[0],
678 				(unsigned char) id[1],
679 				gnutls_protocol_get_name(version));
680 		}
681 
682 		return;
683 	}
684 }
685 #endif
686 
687 /* initialize GnuTLS credential structure (certs etc) */
688 static rsRetVal
gtlsInitCred(nsd_gtls_t * const pThis)689 gtlsInitCred(nsd_gtls_t *const pThis )
690 {
691 	int gnuRet;
692 	const uchar *cafile;
693 	DEFiRet;
694 
695 	/* X509 stuff */
696 	CHKgnutls(gnutls_certificate_allocate_credentials(&pThis->xcred));
697 
698 	/* sets the trusted cas file */
699 	cafile = (pThis->pszCAFile == NULL) ? glbl.GetDfltNetstrmDrvrCAF() : pThis->pszCAFile;
700 	if(cafile == NULL) {
701 		LogMsg(0, RS_RET_CA_CERT_MISSING, LOG_WARNING,
702 			"Warning: CA certificate is not set");
703 	} else {
704 		dbgprintf("GTLS CA file: '%s'\n", cafile);
705 		gnuRet = gnutls_certificate_set_x509_trust_file(pThis->xcred, (char*)cafile, GNUTLS_X509_FMT_PEM);
706 		if(gnuRet == GNUTLS_E_FILE_ERROR) {
707 			LogError(0, RS_RET_GNUTLS_ERR,
708 				"error reading certificate file '%s' - a common cause is that the "
709 				"file  does not exist", cafile);
710 			ABORT_FINALIZE(RS_RET_GNUTLS_ERR);
711 		} else if(gnuRet < 0) {
712 			/* TODO; a more generic error-tracking function (this one based on CHKgnutls()) */
713 			uchar *pErr = gtlsStrerror(gnuRet);
714 			LogError(0, RS_RET_GNUTLS_ERR, "unexpected GnuTLS error %d in %s:%d: %s\n",
715 			gnuRet, __FILE__, __LINE__, pErr);
716 			free(pErr);
717 			ABORT_FINALIZE(RS_RET_GNUTLS_ERR);
718 		}
719 	}
720 
721 
722 finalize_it:
723 	RETiRet;
724 }
725 
726 
727 /* globally initialize GnuTLS */
728 static rsRetVal
gtlsGlblInit(void)729 gtlsGlblInit(void)
730 {
731 	int gnuRet;
732 	DEFiRet;
733 
734 	dbgprintf("gtlsGlblInit: Running Version: '%#010x'\n", GNUTLS_VERSION_NUMBER);
735 
736 	/* gcry_control must be called first, so that the thread system is correctly set up */
737 	#if GNUTLS_VERSION_NUMBER <= 0x020b00
738 	gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
739 	#endif
740 	CHKgnutls(gnutls_global_init());
741 
742 	if(GetGnuTLSLoglevel() > 0){
743 		gnutls_global_set_log_function(logFunction);
744 		gnutls_global_set_log_level(GetGnuTLSLoglevel());
745 		/* 0 (no) to 9 (most), 10 everything */
746 	}
747 
748 	/* Init Anon cipher helpers */
749 	CHKgnutls(gnutls_dh_params_init(&dh_params));
750 	CHKgnutls(gnutls_dh_params_generate2(dh_params, dhBits));
751 
752 	/* Allocate ANON Client Cred */
753 	CHKgnutls(gnutls_anon_allocate_client_credentials(&anoncred));
754 
755 	/* Allocate ANON Server Cred */
756 	CHKgnutls(gnutls_anon_allocate_server_credentials(&anoncredSrv));
757 	gnutls_anon_set_server_dh_params(anoncredSrv, dh_params);
758 
759 finalize_it:
760 	RETiRet;
761 }
762 
763 static rsRetVal
gtlsInitSession(nsd_gtls_t * pThis)764 gtlsInitSession(nsd_gtls_t *pThis)
765 {
766 	DEFiRet;
767 	int gnuRet = 0;
768 	gnutls_session_t session;
769 
770 	gnutls_init(&session, GNUTLS_SERVER);
771 	pThis->bHaveSess = 1;
772 	pThis->bIsInitiator = 0;
773 	pThis->sess = session;
774 
775 	/* Moved CertKey Loading to top */
776 #	if HAVE_GNUTLS_CERTIFICATE_SET_RETRIEVE_FUNCTION
777 	/* store a pointer to ourselfs (needed by callback) */
778 	gnutls_session_set_ptr(pThis->sess, (void*)pThis);
779 	iRet = gtlsLoadOurCertKey(pThis); /* first load .pem files */
780 	if(iRet == RS_RET_OK) {
781 		dbgprintf("gtlsInitSession: enable certificate checking (VerifyDepth=%d)\n", pThis->DrvrVerifyDepth);
782 		gnutls_certificate_set_retrieve_function(pThis->xcred, gtlsClientCertCallback);
783 		if (pThis->DrvrVerifyDepth != 0){
784 			gnutls_certificate_set_verify_limits(pThis->xcred, 8200, pThis->DrvrVerifyDepth);
785 		}
786 	} else if(iRet == RS_RET_CERTLESS) {
787 		dbgprintf("gtlsInitSession: certificates not configured, not loaded.\n");
788 	} else {
789 		ABORT_FINALIZE(iRet); /* we have an error case! */
790 	}
791 #	endif
792 
793 	/* avoid calling all the priority functions, since the defaults are adequate. */
794 	CHKgnutls(gnutls_credentials_set(pThis->sess, GNUTLS_CRD_CERTIFICATE, pThis->xcred));
795 
796 	/* check for anon authmode */
797 	if (pThis->authMode == GTLS_AUTH_CERTANON) {
798 		dbgprintf("gtlsInitSession: anon authmode, gnutls_credentials_set GNUTLS_CRD_ANON\n");
799 		CHKgnutls(gnutls_credentials_set(pThis->sess, GNUTLS_CRD_ANON, anoncredSrv));
800 		gnutls_dh_set_prime_bits(pThis->sess, dhMinBits);
801 	}
802 
803 	/* request client certificate if any.  */
804 	gnutls_certificate_server_set_request( pThis->sess, GNUTLS_CERT_REQUEST);
805 
806 
807 finalize_it:
808 	if(iRet != RS_RET_OK && iRet != RS_RET_CERTLESS) {
809 		LogError(0, iRet, "gtlsInitSession failed to INIT Session %d", gnuRet);
810 	}
811 
812 	RETiRet;
813 }
814 
815 
816 /* Obtain the CN from the DN field and hand it back to the caller
817  * (which is responsible for destructing it). We try to follow
818  * RFC2253 as far as it makes sense for our use-case. This function
819  * is considered a compromise providing good-enough correctness while
820  * limiting code size and complexity. If a problem occurs, we may enhance
821  * this function. A (pointer to a) certificate must be caller-provided.
822  * If no CN is contained in the cert, no string is returned
823  * (*ppstrCN remains NULL). *ppstrCN MUST be NULL on entry!
824  * rgerhards, 2008-05-22
825  */
826 static rsRetVal
gtlsGetCN(gnutls_x509_crt_t * pCert,cstr_t ** ppstrCN)827 gtlsGetCN(gnutls_x509_crt_t *pCert, cstr_t **ppstrCN)
828 {
829 	DEFiRet;
830 	int gnuRet;
831 	int i;
832 	int bFound;
833 	cstr_t *pstrCN = NULL;
834 	size_t size;
835 	/* big var the last, so we hope to have all we usually neeed within one mem cache line */
836 	uchar szDN[1024]; /* this should really be large enough for any non-malicious case... */
837 
838 	assert(pCert != NULL);
839 	assert(ppstrCN != NULL);
840 	assert(*ppstrCN == NULL);
841 
842 	size = sizeof(szDN);
843 	CHKgnutls(gnutls_x509_crt_get_dn(*pCert, (char*)szDN, &size));
844 
845 	/* now search for the CN part */
846 	i = 0;
847 	bFound = 0;
848 	while(!bFound && szDN[i] != '\0') {
849 		/* note that we do not overrun our string due to boolean shortcut
850 		 * operations. If we have '\0', the if does not match and evaluation
851 		 * stops. Order of checks is obviously important!
852 		 */
853 		if(szDN[i] == 'C' && szDN[i+1] == 'N' && szDN[i+2] == '=') {
854 			bFound = 1;
855 			i += 2;
856 		}
857 		i++;
858 
859 	}
860 
861 	if(!bFound) {
862 		FINALIZE; /* we are done */
863 	}
864 
865 	/* we found a common name, now extract it */
866 	CHKiRet(cstrConstruct(&pstrCN));
867 	while(szDN[i] != '\0' && szDN[i] != ',') {
868 		if(szDN[i] == '\\') {
869 			/* hex escapes are not implemented */
870 			++i; /* escape char processed */
871 			if(szDN[i] == '\0')
872 				ABORT_FINALIZE(RS_RET_CERT_INVALID_DN);
873 			CHKiRet(cstrAppendChar(pstrCN, szDN[i]));
874 		} else {
875 			CHKiRet(cstrAppendChar(pstrCN, szDN[i]));
876 		}
877 		++i; /* char processed */
878 	}
879 	cstrFinalize(pstrCN);
880 
881 	/* we got it - we ignore the rest of the DN string (if any). So we may
882 	 * not detect if it contains more than one CN
883 	 */
884 
885 	*ppstrCN = pstrCN;
886 
887 finalize_it:
888 	if(iRet != RS_RET_OK) {
889 		if(pstrCN != NULL)
890 			cstrDestruct(&pstrCN);
891 	}
892 
893 	RETiRet;
894 }
895 
896 
897 /* Check the peer's ID in fingerprint auth mode.
898  * rgerhards, 2008-05-22
899  */
900 static rsRetVal
gtlsChkPeerFingerprint(nsd_gtls_t * pThis,gnutls_x509_crt_t * pCert)901 gtlsChkPeerFingerprint(nsd_gtls_t *pThis, gnutls_x509_crt_t *pCert)
902 {
903 	uchar fingerprint[20];
904 	size_t size;
905 	cstr_t *pstrFingerprint = NULL;
906 	int bFoundPositiveMatch;
907 	permittedPeers_t *pPeer;
908 	int gnuRet;
909 	DEFiRet;
910 
911 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
912 
913 	/* obtain the SHA1 fingerprint */
914 	size = sizeof(fingerprint);
915 	CHKgnutls(gnutls_x509_crt_get_fingerprint(*pCert, GNUTLS_DIG_SHA1, fingerprint, &size));
916 	CHKiRet(GenFingerprintStr(fingerprint, size, &pstrFingerprint));
917 	dbgprintf("peer's certificate SHA1 fingerprint: %s\n", cstrGetSzStrNoNULL(pstrFingerprint));
918 
919 	/* now search through the permitted peers to see if we can find a permitted one */
920 	bFoundPositiveMatch = 0;
921 	pPeer = pThis->pPermPeers;
922 	while(pPeer != NULL && !bFoundPositiveMatch) {
923 		if(!rsCStrSzStrCmp(pstrFingerprint, pPeer->pszID, strlen((char*) pPeer->pszID))) {
924 			bFoundPositiveMatch = 1;
925 		} else {
926 			pPeer = pPeer->pNext;
927 		}
928 	}
929 
930 	if(!bFoundPositiveMatch) {
931 		dbgprintf("invalid peer fingerprint, not permitted to talk to it\n");
932 		if(pThis->bReportAuthErr == 1) {
933 			errno = 0;
934 			LogError(0, RS_RET_INVALID_FINGERPRINT, "error: peer fingerprint '%s' unknown - we are "
935 					"not permitted to talk to it", cstrGetSzStrNoNULL(pstrFingerprint));
936 			pThis->bReportAuthErr = 0;
937 		}
938 		ABORT_FINALIZE(RS_RET_INVALID_FINGERPRINT);
939 	}
940 
941 finalize_it:
942 	if(pstrFingerprint != NULL)
943 		cstrDestruct(&pstrFingerprint);
944 	RETiRet;
945 }
946 
947 
948 /* Perform a match on ONE peer name obtained from the certificate. This name
949  * is checked against the set of configured credentials. *pbFoundPositiveMatch is
950  * set to 1 if the ID matches. *pbFoundPositiveMatch must have been initialized
951  * to 0 by the caller (this is a performance enhancement as we expect to be
952  * called multiple times).
953  * TODO: implemet wildcards?
954  * rgerhards, 2008-05-26
955  */
956 static rsRetVal
gtlsChkOnePeerName(nsd_gtls_t * pThis,uchar * pszPeerID,int * pbFoundPositiveMatch)957 gtlsChkOnePeerName(nsd_gtls_t *pThis, uchar *pszPeerID, int *pbFoundPositiveMatch)
958 {
959 	permittedPeers_t *pPeer;
960 	DEFiRet;
961 
962 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
963 	assert(pszPeerID != NULL);
964 	assert(pbFoundPositiveMatch != NULL);
965 
966 	if(pThis->pPermPeers) { /* do we have configured peer IDs? */
967 		pPeer = pThis->pPermPeers;
968 		while(pPeer != NULL) {
969 			CHKiRet(net.PermittedPeerWildcardMatch(pPeer, pszPeerID, pbFoundPositiveMatch));
970 			if(*pbFoundPositiveMatch)
971 				break;
972 			pPeer = pPeer->pNext;
973 		}
974 	} else {
975 		/* we do not have configured peer IDs, so we use defaults */
976 		if(   pThis->pszConnectHost
977 		   && !strcmp((char*)pszPeerID, (char*)pThis->pszConnectHost)) {
978 			*pbFoundPositiveMatch = 1;
979 		}
980 	}
981 
982 finalize_it:
983 	RETiRet;
984 }
985 
986 
987 /* Check the peer's ID in name auth mode.
988  * rgerhards, 2008-05-22
989  */
990 static rsRetVal
gtlsChkPeerName(nsd_gtls_t * pThis,gnutls_x509_crt_t * pCert)991 gtlsChkPeerName(nsd_gtls_t *pThis, gnutls_x509_crt_t *pCert)
992 {
993 	uchar lnBuf[256];
994 	char szAltName[1024]; /* this is sufficient for the DNSNAME... */
995 	int iAltName;
996 	size_t szAltNameLen;
997 	int bFoundPositiveMatch;
998 	int bHaveSAN = 0;
999 	cstr_t *pStr = NULL;
1000 	cstr_t *pstrCN = NULL;
1001 	int gnuRet;
1002 	DEFiRet;
1003 
1004 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
1005 
1006 	bFoundPositiveMatch = 0;
1007 	CHKiRet(rsCStrConstruct(&pStr));
1008 
1009 	/* first search through the dNSName subject alt names */
1010 	iAltName = 0;
1011 	while(!bFoundPositiveMatch) { /* loop broken below */
1012 		szAltNameLen = sizeof(szAltName);
1013 		gnuRet = gnutls_x509_crt_get_subject_alt_name(*pCert, iAltName,
1014 				szAltName, &szAltNameLen, NULL);
1015 		if(gnuRet < 0)
1016 			break;
1017 		else if(gnuRet == GNUTLS_SAN_DNSNAME) {
1018 			bHaveSAN = 1;
1019 			dbgprintf("subject alt dnsName: '%s'\n", szAltName);
1020 			snprintf((char*)lnBuf, sizeof(lnBuf), "DNSname: %s; ", szAltName);
1021 			CHKiRet(rsCStrAppendStr(pStr, lnBuf));
1022 			CHKiRet(gtlsChkOnePeerName(pThis, (uchar*)szAltName, &bFoundPositiveMatch));
1023 			/* do NOT break, because there may be multiple dNSName's! */
1024 		}
1025 		++iAltName;
1026 	}
1027 
1028 	/* Check also CN only if not configured per stricter RFC 6125 or no SAN present*/
1029 	if(!bFoundPositiveMatch && (!pThis->bSANpriority || !bHaveSAN)) {
1030 		CHKiRet(gtlsGetCN(pCert, &pstrCN));
1031 		if(pstrCN != NULL) { /* NULL if there was no CN present */
1032 			dbgprintf("gtls now checking auth for CN '%s'\n", cstrGetSzStrNoNULL(pstrCN));
1033 			snprintf((char*)lnBuf, sizeof(lnBuf), "CN: %s; ", cstrGetSzStrNoNULL(pstrCN));
1034 			CHKiRet(rsCStrAppendStr(pStr, lnBuf));
1035 			CHKiRet(gtlsChkOnePeerName(pThis, cstrGetSzStrNoNULL(pstrCN), &bFoundPositiveMatch));
1036 		}
1037 	}
1038 
1039 	if(!bFoundPositiveMatch) {
1040 		dbgprintf("invalid peer name, not permitted to talk to it\n");
1041 		if(pThis->bReportAuthErr == 1) {
1042 			cstrFinalize(pStr);
1043 			errno = 0;
1044 			LogError(0, RS_RET_INVALID_FINGERPRINT, "error: peer name not authorized -  "
1045 					"not permitted to talk to it. Names: %s",
1046 					cstrGetSzStrNoNULL(pStr));
1047 			pThis->bReportAuthErr = 0;
1048 		}
1049 		ABORT_FINALIZE(RS_RET_INVALID_FINGERPRINT);
1050 	}
1051 
1052 finalize_it:
1053 	if(pStr != NULL)
1054 		rsCStrDestruct(&pStr);
1055 	if(pstrCN != NULL)
1056 		rsCStrDestruct(&pstrCN);
1057 	RETiRet;
1058 }
1059 
1060 
1061 /* check the ID of the remote peer - used for both fingerprint and
1062  * name authentication. This is common code. Will call into specific
1063  * drivers once the certificate has been obtained.
1064  * rgerhards, 2008-05-08
1065  */
1066 static rsRetVal
gtlsChkPeerID(nsd_gtls_t * pThis)1067 gtlsChkPeerID(nsd_gtls_t *pThis)
1068 {
1069 	const gnutls_datum_t *cert_list;
1070 	unsigned int list_size = 0;
1071 	gnutls_x509_crt_t cert;
1072 	int bMustDeinitCert = 0;
1073 	int gnuRet;
1074 	DEFiRet;
1075 
1076 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
1077 
1078 	/* This function only works for X.509 certificates.  */
1079 	if(gnutls_certificate_type_get(pThis->sess) != GNUTLS_CRT_X509)
1080 		return RS_RET_TLS_CERT_ERR;
1081 
1082 	cert_list = gnutls_certificate_get_peers(pThis->sess, &list_size);
1083 
1084 	if(list_size < 1) {
1085 		if(pThis->bReportAuthErr == 1) {
1086 			errno = 0;
1087 			LogError(0, RS_RET_TLS_NO_CERT, "error: peer did not provide a certificate, "
1088 					"not permitted to talk to it");
1089 			pThis->bReportAuthErr = 0;
1090 		}
1091 		ABORT_FINALIZE(RS_RET_TLS_NO_CERT);
1092 	}
1093 
1094 	/* If we reach this point, we have at least one valid certificate.
1095 	 * We always use only the first certificate. As of GnuTLS documentation, the
1096 	 * first certificate always contains the remote peer's own certificate. All other
1097 	 * certificates are issuer's certificates (up the chain). We are only interested
1098 	 * in the first certificate, which is our peer. -- rgerhards, 2008-05-08
1099 	 */
1100 	CHKgnutls(gnutls_x509_crt_init(&cert));
1101 	bMustDeinitCert = 1; /* indicate cert is initialized and must be freed on exit */
1102 	CHKgnutls(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER));
1103 
1104 	/* Now we see which actual authentication code we must call.  */
1105 	if(pThis->authMode == GTLS_AUTH_CERTFINGERPRINT) {
1106 		CHKiRet(gtlsChkPeerFingerprint(pThis, &cert));
1107 	} else {
1108 		assert(pThis->authMode == GTLS_AUTH_CERTNAME);
1109 		CHKiRet(gtlsChkPeerName(pThis, &cert));
1110 	}
1111 
1112 finalize_it:
1113 	if(bMustDeinitCert)
1114 		gnutls_x509_crt_deinit(cert);
1115 
1116 	RETiRet;
1117 }
1118 
1119 
1120 /* Verify the validity of the remote peer's certificate.
1121  * rgerhards, 2008-05-21
1122  */
1123 static rsRetVal
gtlsChkPeerCertValidity(nsd_gtls_t * pThis)1124 gtlsChkPeerCertValidity(nsd_gtls_t *pThis)
1125 {
1126 	DEFiRet;
1127 	const char *pszErrCause;
1128 	int gnuRet;
1129 	cstr_t *pStr = NULL;
1130 	unsigned stateCert;
1131 	const gnutls_datum_t *cert_list;
1132 	unsigned cert_list_size = 0;
1133 	gnutls_x509_crt_t cert;
1134 	unsigned i;
1135 	time_t ttCert;
1136 	time_t ttNow;
1137 	sbool bAbort = RSFALSE;
1138 	int iAbortCode = RS_RET_OK;
1139 
1140 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
1141 
1142 	/* check if we have at least one cert */
1143 	cert_list = gnutls_certificate_get_peers(pThis->sess, &cert_list_size);
1144 	if(cert_list_size < 1) {
1145 		errno = 0;
1146 		LogError(0, RS_RET_TLS_NO_CERT,
1147 			"peer did not provide a certificate, not permitted to talk to it");
1148 		ABORT_FINALIZE(RS_RET_TLS_NO_CERT);
1149 	}
1150 #ifdef EXTENDED_CERT_CHECK_AVAILABLE
1151 	if (pThis->dataTypeCheck == GTLS_NONE) {
1152 #endif
1153 		CHKgnutls(gnutls_certificate_verify_peers2(pThis->sess, &stateCert));
1154 #ifdef EXTENDED_CERT_CHECK_AVAILABLE
1155 	} else { /* we have configured data to check in addition to cert */
1156 		gnutls_typed_vdata_st data;
1157 		data.type = GNUTLS_DT_KEY_PURPOSE_OID;
1158 		if (pThis->bIsInitiator) { /* client mode */
1159 			data.data = (uchar *)GNUTLS_KP_TLS_WWW_SERVER;
1160 		} else { /* server mode */
1161 			data.data = (uchar *)GNUTLS_KP_TLS_WWW_CLIENT;
1162 		}
1163 		data.size = ustrlen(data.data);
1164 		CHKgnutls(gnutls_certificate_verify_peers(pThis->sess, &data, 1, &stateCert));
1165 	}
1166 #endif
1167 
1168 	if(stateCert & GNUTLS_CERT_INVALID) {
1169 		/* Default abort code */
1170 		iAbortCode = RS_RET_CERT_INVALID;
1171 
1172 		/* provide error details if we have them */
1173 		if (stateCert & GNUTLS_CERT_EXPIRED ) {
1174 			dbgprintf("GnuTLS returned GNUTLS_CERT_EXPIRED, handling mode %d ...\n",
1175 				pThis->permitExpiredCerts);
1176 			/* Handle expired certs */
1177 			if (pThis->permitExpiredCerts == GTLS_EXPIRED_DENY) {
1178 				bAbort = RSTRUE;
1179 				iAbortCode = RS_RET_CERT_EXPIRED;
1180 			} else if (pThis->permitExpiredCerts == GTLS_EXPIRED_WARN) {
1181 				LogMsg(0, RS_RET_NO_ERRCODE, LOG_WARNING,
1182 					"Warning, certificate expired but expired certs are permitted");
1183 			} else {
1184 				dbgprintf("GnuTLS returned GNUTLS_CERT_EXPIRED, but expired certs are permitted.\n");
1185 			}
1186 			pszErrCause = "certificate expired";
1187 		} else if(stateCert & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1188 			pszErrCause = "signer not found";
1189 			bAbort = RSTRUE;
1190 		} else if(stateCert & GNUTLS_CERT_SIGNER_NOT_CA) {
1191 			pszErrCause = "signer is not a CA";
1192 			bAbort = RSTRUE;
1193 		} else if(stateCert & GNUTLS_CERT_INSECURE_ALGORITHM) {
1194 			pszErrCause = "insecure algorithm";
1195 			bAbort = RSTRUE;
1196 		} else if(stateCert & GNUTLS_CERT_REVOKED) {
1197 			pszErrCause = "certificate revoked";
1198 			bAbort = RSTRUE;
1199 #ifdef EXTENDED_CERT_CHECK_AVAILABLE
1200 		} else if(stateCert & GNUTLS_CERT_PURPOSE_MISMATCH) {
1201 			pszErrCause = "key purpose OID does not match";
1202 			bAbort = RSTRUE;
1203 #endif
1204 		} else {
1205 			pszErrCause = "GnuTLS returned no specific reason";
1206 			dbgprintf("GnuTLS returned no specific reason for GNUTLS_CERT_INVALID, certificate "
1207 				 "status is %d\n", stateCert);
1208 			bAbort = RSTRUE;
1209 		}
1210 	}
1211 
1212 	if (bAbort == RSTRUE) {
1213 		LogError(0, NO_ERRCODE, "not permitted to talk to peer, certificate invalid: %s",
1214 				pszErrCause);
1215 		gtlsGetCertInfo(pThis, &pStr);
1216 		LogError(0, NO_ERRCODE, "invalid cert info: %s", cstrGetSzStrNoNULL(pStr));
1217 		cstrDestruct(&pStr);
1218 		ABORT_FINALIZE(iAbortCode);
1219 	}
1220 
1221 	/* get current time for certificate validation */
1222 	if(datetime.GetTime(&ttNow) == -1)
1223 		ABORT_FINALIZE(RS_RET_SYS_ERR);
1224 
1225 	/* as it looks, we need to validate the expiration dates ourselves...
1226 	 * We need to loop through all certificates as we need to make sure the
1227 	 * interim certificates are also not expired.
1228 	 */
1229 	for(i = 0 ; i < cert_list_size ; ++i) {
1230 		CHKgnutls(gnutls_x509_crt_init(&cert));
1231 		CHKgnutls(gnutls_x509_crt_import(cert, &cert_list[i], GNUTLS_X509_FMT_DER));
1232 		ttCert = gnutls_x509_crt_get_activation_time(cert);
1233 		if(ttCert == -1)
1234 			ABORT_FINALIZE(RS_RET_TLS_CERT_ERR);
1235 		else if(ttCert > ttNow) {
1236 			LogError(0, RS_RET_CERT_NOT_YET_ACTIVE, "not permitted to talk to peer: "
1237 					"certificate %d not yet active", i);
1238 			gtlsGetCertInfo(pThis, &pStr);
1239 			LogError(0, RS_RET_CERT_NOT_YET_ACTIVE,
1240 				"invalid cert info: %s", cstrGetSzStrNoNULL(pStr));
1241 			cstrDestruct(&pStr);
1242 			ABORT_FINALIZE(RS_RET_CERT_NOT_YET_ACTIVE);
1243 		}
1244 
1245 		gnutls_x509_crt_deinit(cert);
1246 
1247 	}
1248 
1249 finalize_it:
1250 	RETiRet;
1251 }
1252 
1253 
1254 /* check if it is OK to talk to the remote peer
1255  * rgerhards, 2008-05-21
1256  */
1257 rsRetVal
gtlsChkPeerAuth(nsd_gtls_t * pThis)1258 gtlsChkPeerAuth(nsd_gtls_t *pThis)
1259 {
1260 	DEFiRet;
1261 
1262 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
1263 
1264 	/* call the actual function based on current auth mode */
1265 	switch(pThis->authMode) {
1266 		case GTLS_AUTH_CERTNAME:
1267 			/* if we check the name, we must ensure the cert is valid */
1268 			CHKiRet(gtlsChkPeerCertValidity(pThis));
1269 			CHKiRet(gtlsChkPeerID(pThis));
1270 			break;
1271 		case GTLS_AUTH_CERTFINGERPRINT:
1272 			CHKiRet(gtlsChkPeerID(pThis));
1273 			break;
1274 		case GTLS_AUTH_CERTVALID:
1275 			CHKiRet(gtlsChkPeerCertValidity(pThis));
1276 			break;
1277 		case GTLS_AUTH_CERTANON:
1278 			FINALIZE;
1279 			break;
1280 	}
1281 
1282 finalize_it:
1283 	RETiRet;
1284 }
1285 
1286 
1287 /* globally de-initialize GnuTLS */
1288 static rsRetVal
gtlsGlblExit(void)1289 gtlsGlblExit(void)
1290 {
1291 	DEFiRet;
1292 	gnutls_global_deinit();
1293 	RETiRet;
1294 }
1295 
1296 
1297 /* end a GnuTLS session
1298  * The function checks if we have a session and ends it only if so. So it can
1299  * always be called, even if there currently is no session.
1300  */
1301 static rsRetVal
gtlsEndSess(nsd_gtls_t * pThis)1302 gtlsEndSess(nsd_gtls_t *pThis)
1303 {
1304 	int gnuRet;
1305 	DEFiRet;
1306 
1307 	if(pThis->bHaveSess) {
1308 		if(pThis->bIsInitiator) {
1309 			gnuRet = gnutls_bye(pThis->sess, GNUTLS_SHUT_WR);
1310 			while(gnuRet == GNUTLS_E_INTERRUPTED || gnuRet == GNUTLS_E_AGAIN) {
1311 				gnuRet = gnutls_bye(pThis->sess, GNUTLS_SHUT_WR);
1312 			}
1313 		}
1314 		gnutls_deinit(pThis->sess);
1315 		pThis->bHaveSess = 0;
1316 	}
1317 	RETiRet;
1318 }
1319 
1320 
1321 /* a small wrapper for gnutls_transport_set_ptr(). The main intension for
1322  * creating this wrapper is to get the annoying "cast to pointer from different
1323  * size" compiler warning just once. There seems to be no way around it, see:
1324  * http://lists.gnu.org/archive/html/help-gnutls/2008-05/msg00000.html
1325  * rgerhards, 2008.05-07
1326  */
1327 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
1328 static inline void
gtlsSetTransportPtr(nsd_gtls_t * pThis,int sock)1329 gtlsSetTransportPtr(nsd_gtls_t *pThis, int sock)
1330 {
1331 	/* Note: the compiler warning for the next line is OK - see header comment! */
1332 	gnutls_transport_set_ptr(pThis->sess, (gnutls_transport_ptr_t) sock);
1333 }
1334 #pragma GCC diagnostic warning "-Wint-to-pointer-cast"
1335 
1336 /* ---------------------------- end GnuTLS specifics ---------------------------- */
1337 
1338 
1339 /* Standard-Constructor */
1340 BEGINobjConstruct(nsd_gtls) /* be sure to specify the object type also in END macro! */
1341 	iRet = nsd_ptcp.Construct(&pThis->pTcp);
1342 	pThis->bReportAuthErr = 1;
1343 ENDobjConstruct(nsd_gtls)
1344 
1345 
1346 /* destructor for the nsd_gtls object */
1347 PROTOTYPEobjDestruct(nsd_gtls);
1348 BEGINobjDestruct(nsd_gtls) /* be sure to specify the object type also in END and CODESTART macros! */
1349 CODESTARTobjDestruct(nsd_gtls)
1350 	if(pThis->iMode == 1) {
1351 		gtlsEndSess(pThis);
1352 	}
1353 
1354 	if(pThis->pTcp != NULL) {
1355 		nsd_ptcp.Destruct(&pThis->pTcp);
1356 	}
1357 
1358 	free(pThis->pszConnectHost);
1359 	free(pThis->pszRcvBuf);
1360 	free((void*) pThis->pszCAFile);
1361 
1362 	if(pThis->bOurCertIsInit)
1363 		for(unsigned i=0; i<pThis->nOurCerts; ++i) {
1364 			gnutls_x509_crt_deinit(pThis->pOurCerts[i]);
1365 		}
1366 	if(pThis->bOurKeyIsInit)
1367 		gnutls_x509_privkey_deinit(pThis->ourKey);
1368 	if(pThis->bHaveSess)
1369 		gnutls_deinit(pThis->sess);
1370 	if(pThis->xcred != NULL
1371 	   && (pThis->bIsInitiator || (!pThis->xcred_is_copy && (!pThis->bIsInitiator || pThis->bHaveSess)))
1372 	  ) {
1373 		gnutls_certificate_free_credentials(pThis->xcred);
1374 		free((void*) pThis->pszKeyFile);
1375 		free((void*) pThis->pszCertFile);
1376 	}
ENDobjDestruct(nsd_gtls)1377 ENDobjDestruct(nsd_gtls)
1378 
1379 
1380 /* Set the driver mode. For us, this has the following meaning:
1381  * 0 - work in plain tcp mode, without tls (e.g. before a STARTTLS)
1382  * 1 - work in TLS mode
1383  * rgerhards, 2008-04-28
1384  */
1385 static rsRetVal
1386 SetMode(nsd_t *pNsd, int mode)
1387 {
1388 	DEFiRet;
1389 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1390 
1391 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1392 	if(mode != 0 && mode != 1) {
1393 		LogError(0, RS_RET_INVALID_DRVR_MODE, "error: driver mode %d not supported by "
1394 				"gtls netstream driver", mode);
1395 		ABORT_FINALIZE(RS_RET_INVALID_DRVR_MODE);
1396 	}
1397 
1398 	pThis->iMode = mode;
1399 
1400 finalize_it:
1401 	RETiRet;
1402 }
1403 
1404 /* Set the authentication mode. For us, the following is supported:
1405  * anon - no certificate checks whatsoever (discouraged, but supported)
1406  * x509/certvalid - (just) check certificate validity
1407  * x509/fingerprint - certificate fingerprint
1408  * x509/name - cerfificate name check
1409  * mode == NULL is valid and defaults to x509/name
1410  * rgerhards, 2008-05-16
1411  */
1412 static rsRetVal
SetAuthMode(nsd_t * pNsd,uchar * mode)1413 SetAuthMode(nsd_t *pNsd, uchar *mode)
1414 {
1415 	DEFiRet;
1416 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1417 
1418 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1419 	if(mode == NULL || !strcasecmp((char*)mode, "x509/name")) {
1420 		pThis->authMode = GTLS_AUTH_CERTNAME;
1421 	} else if(!strcasecmp((char*) mode, "x509/fingerprint")) {
1422 		pThis->authMode = GTLS_AUTH_CERTFINGERPRINT;
1423 	} else if(!strcasecmp((char*) mode, "x509/certvalid")) {
1424 		pThis->authMode = GTLS_AUTH_CERTVALID;
1425 	} else if(!strcasecmp((char*) mode, "anon")) {
1426 		pThis->authMode = GTLS_AUTH_CERTANON;
1427 	} else {
1428 		LogError(0, RS_RET_VALUE_NOT_SUPPORTED, "error: authentication mode '%s' not supported by "
1429 				"gtls netstream driver", mode);
1430 		ABORT_FINALIZE(RS_RET_VALUE_NOT_SUPPORTED);
1431 	}
1432 
1433 	dbgprintf("SetAuthMode to %s\n", (mode != NULL ? (char*)mode : "NULL"));
1434 /* TODO: clear stored IDs! */
1435 
1436 finalize_it:
1437 	RETiRet;
1438 }
1439 
1440 
1441 /* Set the PermitExpiredCerts mode. For us, the following is supported:
1442  * on - fail if certificate is expired
1443  * off - ignore expired certificates
1444  * warn - warn if certificate is expired
1445  * alorbach, 2018-12-20
1446  */
1447 static rsRetVal
SetPermitExpiredCerts(nsd_t * pNsd,uchar * mode)1448 SetPermitExpiredCerts(nsd_t *pNsd, uchar *mode)
1449 {
1450 	DEFiRet;
1451 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1452 
1453 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1454 	/* default is set to off! */
1455 	if(mode == NULL || !strcasecmp((char*)mode, "off")) {
1456 		pThis->permitExpiredCerts = GTLS_EXPIRED_DENY;
1457 	} else if(!strcasecmp((char*) mode, "warn")) {
1458 		pThis->permitExpiredCerts = GTLS_EXPIRED_WARN;
1459 	} else if(!strcasecmp((char*) mode, "on")) {
1460 		pThis->permitExpiredCerts = GTLS_EXPIRED_PERMIT;
1461 	} else {
1462 		LogError(0, RS_RET_VALUE_NOT_SUPPORTED, "error: permitexpiredcerts mode '%s' not supported by "
1463 				"gtls netstream driver", mode);
1464 		ABORT_FINALIZE(RS_RET_VALUE_NOT_SUPPORTED);
1465 	}
1466 
1467 	dbgprintf("SetPermitExpiredCerts: Set Mode %s/%d\n",
1468 		(mode != NULL ? (char*)mode : "NULL"), pThis->permitExpiredCerts);
1469 
1470 /* TODO: clear stored IDs! */
1471 
1472 finalize_it:
1473 	RETiRet;
1474 }
1475 
1476 
1477 /* Set permitted peers. It is depending on the auth mode if this are
1478  * fingerprints or names. -- rgerhards, 2008-05-19
1479  */
1480 static rsRetVal
SetPermPeers(nsd_t * pNsd,permittedPeers_t * pPermPeers)1481 SetPermPeers(nsd_t *pNsd, permittedPeers_t *pPermPeers)
1482 {
1483 	DEFiRet;
1484 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1485 
1486 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1487 	if(pPermPeers == NULL)
1488 		FINALIZE;
1489 
1490 	if(pThis->authMode != GTLS_AUTH_CERTFINGERPRINT && pThis->authMode != GTLS_AUTH_CERTNAME) {
1491 		LogError(0, RS_RET_VALUE_NOT_IN_THIS_MODE, "authentication not supported by "
1492 			"gtls netstream driver in the configured authentication mode - ignored");
1493 		ABORT_FINALIZE(RS_RET_VALUE_NOT_IN_THIS_MODE);
1494 	}
1495 
1496 	pThis->pPermPeers = pPermPeers;
1497 
1498 finalize_it:
1499 	RETiRet;
1500 }
1501 
1502 /* gnutls priority string
1503  * PascalWithopf 2017-08-16
1504  */
1505 static rsRetVal
SetGnutlsPriorityString(nsd_t * pNsd,uchar * gnutlsPriorityString)1506 SetGnutlsPriorityString(nsd_t *pNsd, uchar *gnutlsPriorityString)
1507 {
1508 	DEFiRet;
1509 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1510 
1511 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1512 	pThis->gnutlsPriorityString = gnutlsPriorityString;
1513 	dbgprintf("gnutlsPriorityString: set to '%s'\n",
1514 		(gnutlsPriorityString != NULL ? (char*)gnutlsPriorityString : "NULL"));
1515 	RETiRet;
1516 }
1517 
1518 /* Set the driver cert extended key usage check setting
1519  * 0 - ignore contents of extended key usage
1520  * 1 - verify that cert contents is compatible with appropriate OID
1521  * jvymazal, 2019-08-16
1522  */
1523 static rsRetVal
SetCheckExtendedKeyUsage(nsd_t * pNsd,int ChkExtendedKeyUsage)1524 SetCheckExtendedKeyUsage(nsd_t *pNsd, int ChkExtendedKeyUsage)
1525 {
1526 	DEFiRet;
1527 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1528 
1529 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1530 	if(ChkExtendedKeyUsage != 0 && ChkExtendedKeyUsage != 1) {
1531 		LogError(0, RS_RET_VALUE_NOT_SUPPORTED, "error: driver ChkExtendedKeyUsage %d "
1532 				"not supported by gtls netstream driver", ChkExtendedKeyUsage);
1533 		ABORT_FINALIZE(RS_RET_VALUE_NOT_SUPPORTED);
1534 	}
1535 
1536 	pThis->dataTypeCheck = ChkExtendedKeyUsage;
1537 
1538 finalize_it:
1539 	RETiRet;
1540 }
1541 
1542 /* Set the driver name checking strictness
1543  * 0 - less strict per RFC 5280, section 4.1.2.6 - either SAN or CN match is good
1544  * 1 - more strict per RFC 6125 - if any SAN present it must match (CN is ignored)
1545  * jvymazal, 2019-08-16
1546  */
1547 static rsRetVal
SetPrioritizeSAN(nsd_t * pNsd,int prioritizeSan)1548 SetPrioritizeSAN(nsd_t *pNsd, int prioritizeSan)
1549 {
1550 	DEFiRet;
1551 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1552 
1553 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1554 	if(prioritizeSan != 0 && prioritizeSan != 1) {
1555 		LogError(0, RS_RET_VALUE_NOT_SUPPORTED, "error: driver prioritizeSan %d "
1556 				"not supported by gtls netstream driver", prioritizeSan);
1557 		ABORT_FINALIZE(RS_RET_VALUE_NOT_SUPPORTED);
1558 	}
1559 
1560 	pThis->bSANpriority = prioritizeSan;
1561 
1562 finalize_it:
1563 	RETiRet;
1564 }
1565 
1566 /* Set the driver tls  verifyDepth
1567  * alorbach, 2019-12-20
1568  */
1569 static rsRetVal
SetTlsVerifyDepth(nsd_t * pNsd,int verifyDepth)1570 SetTlsVerifyDepth(nsd_t *pNsd, int verifyDepth)
1571 {
1572 	DEFiRet;
1573 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1574 
1575 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1576 	if (verifyDepth == 0) {
1577 		FINALIZE;
1578 	}
1579 	assert(verifyDepth >= 2);
1580 	pThis->DrvrVerifyDepth = verifyDepth;
1581 
1582 finalize_it:
1583 	RETiRet;
1584 }
1585 
1586 static rsRetVal
SetTlsCAFile(nsd_t * pNsd,const uchar * const caFile)1587 SetTlsCAFile(nsd_t *pNsd, const uchar *const caFile)
1588 {
1589 	DEFiRet;
1590 	nsd_gtls_t *const pThis = (nsd_gtls_t*) pNsd;
1591 
1592 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1593 	if(caFile == NULL) {
1594 		pThis->pszCAFile = NULL;
1595 	} else {
1596 		CHKmalloc(pThis->pszCAFile = (const uchar*) strdup((const char*) caFile));
1597 	}
1598 
1599 finalize_it:
1600 	RETiRet;
1601 }
1602 
1603 static rsRetVal
SetTlsKeyFile(nsd_t * pNsd,const uchar * const pszFile)1604 SetTlsKeyFile(nsd_t *pNsd, const uchar *const pszFile)
1605 {
1606 	DEFiRet;
1607 	nsd_gtls_t *const pThis = (nsd_gtls_t*) pNsd;
1608 
1609 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1610 	if(pszFile == NULL) {
1611 		pThis->pszKeyFile = NULL;
1612 	} else {
1613 		CHKmalloc(pThis->pszKeyFile = (const uchar*) strdup((const char*) pszFile));
1614 	}
1615 
1616 finalize_it:
1617 	RETiRet;
1618 }
1619 
1620 static rsRetVal
SetTlsCertFile(nsd_t * pNsd,const uchar * const pszFile)1621 SetTlsCertFile(nsd_t *pNsd, const uchar *const pszFile)
1622 {
1623 	DEFiRet;
1624 	nsd_gtls_t *const pThis = (nsd_gtls_t*) pNsd;
1625 
1626 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1627 	if(pszFile == NULL) {
1628 		pThis->pszCertFile = NULL;
1629 	} else {
1630 		CHKmalloc(pThis->pszCertFile = (const uchar*) strdup((const char*) pszFile));
1631 	}
1632 
1633 finalize_it:
1634 	RETiRet;
1635 }
1636 
1637 /* Provide access to the underlying OS socket. This is primarily
1638  * useful for other drivers (like nsd_gtls) who utilize ourselfs
1639  * for some of their functionality. -- rgerhards, 2008-04-18
1640  */
1641 static rsRetVal
SetSock(nsd_t * pNsd,int sock)1642 SetSock(nsd_t *pNsd, int sock)
1643 {
1644 	DEFiRet;
1645 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1646 
1647 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1648 	assert(sock >= 0);
1649 
1650 	nsd_ptcp.SetSock(pThis->pTcp, sock);
1651 
1652 	RETiRet;
1653 }
1654 
1655 
1656 /* Keep Alive Options
1657  */
1658 static rsRetVal
SetKeepAliveIntvl(nsd_t * pNsd,int keepAliveIntvl)1659 SetKeepAliveIntvl(nsd_t *pNsd, int keepAliveIntvl)
1660 {
1661 	DEFiRet;
1662 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1663 
1664 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1665 	assert(keepAliveIntvl >= 0);
1666 
1667 	nsd_ptcp.SetKeepAliveIntvl(pThis->pTcp, keepAliveIntvl);
1668 
1669 	RETiRet;
1670 }
1671 
1672 
1673 /* Keep Alive Options
1674  */
1675 static rsRetVal
SetKeepAliveProbes(nsd_t * pNsd,int keepAliveProbes)1676 SetKeepAliveProbes(nsd_t *pNsd, int keepAliveProbes)
1677 {
1678 	DEFiRet;
1679 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1680 
1681 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1682 	assert(keepAliveProbes >= 0);
1683 
1684 	nsd_ptcp.SetKeepAliveProbes(pThis->pTcp, keepAliveProbes);
1685 
1686 	RETiRet;
1687 }
1688 
1689 
1690 /* Keep Alive Options
1691  */
1692 static rsRetVal
SetKeepAliveTime(nsd_t * pNsd,int keepAliveTime)1693 SetKeepAliveTime(nsd_t *pNsd, int keepAliveTime)
1694 {
1695 	DEFiRet;
1696 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1697 
1698 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1699 	assert(keepAliveTime >= 0);
1700 
1701 	nsd_ptcp.SetKeepAliveTime(pThis->pTcp, keepAliveTime);
1702 
1703 	RETiRet;
1704 }
1705 
1706 
1707 /* abort a connection. This is meant to be called immediately
1708  * before the Destruct call. -- rgerhards, 2008-03-24
1709  */
1710 static rsRetVal
Abort(nsd_t * pNsd)1711 Abort(nsd_t *pNsd)
1712 {
1713 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1714 	DEFiRet;
1715 
1716 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1717 
1718 	if(pThis->iMode == 0) {
1719 		nsd_ptcp.Abort(pThis->pTcp);
1720 	}
1721 
1722 	RETiRet;
1723 }
1724 
1725 
1726 /* Callback after netstrm obj init in nsd_ptcp - permits us to add some data */
1727 static rsRetVal
LstnInitDrvr(netstrm_t * const pThis)1728 LstnInitDrvr(netstrm_t *const pThis)
1729 {
1730 	DEFiRet;
1731 	CHKiRet(gtlsInitCred((nsd_gtls_t*) pThis->pDrvrData));
1732 	CHKiRet(gtlsAddOurCert((nsd_gtls_t*) pThis->pDrvrData));
1733 finalize_it:
1734 	RETiRet;
1735 }
1736 
1737 
1738 
1739 /* initialize the tcp socket for a listner
1740  * Here, we use the ptcp driver - because there is nothing special
1741  * at this point with GnuTLS. Things become special once we accept
1742  * a session, but not during listener setup.
1743  * gerhards, 2008-04-25
1744  */
1745 static rsRetVal ATTR_NONNULL(1,3,5)
LstnInit(netstrms_t * pNS,void * pUsr,rsRetVal (* fAddLstn)(void *,netstrm_t *),const int iSessMax,const tcpLstnParams_t * const cnf_params)1746 LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*),
1747 	 const int iSessMax, const tcpLstnParams_t *const cnf_params)
1748 {
1749 	DEFiRet;
1750 	pNS->fLstnInitDrvr = LstnInitDrvr;
1751 	iRet = nsd_ptcp.LstnInit(pNS, pUsr, fAddLstn, iSessMax, cnf_params);
1752 //finalize_it:
1753 	RETiRet;
1754 }
1755 
1756 
1757 /* This function checks if the connection is still alive - well, kind of...
1758  * This is a dummy here. For details, check function common in ptcp driver.
1759  * rgerhards, 2008-06-09
1760  */
1761 static rsRetVal
CheckConnection(nsd_t * pNsd)1762 CheckConnection(nsd_t __attribute__((unused)) *pNsd)
1763 {
1764 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1765 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
1766 
1767 	dbgprintf("CheckConnection for %p\n", pNsd);
1768 	return nsd_ptcp.CheckConnection(pThis->pTcp);
1769 }
1770 
1771 
1772 /* get the remote hostname. The returned hostname must be freed by the caller.
1773  * rgerhards, 2008-04-25
1774  */
1775 static rsRetVal
GetRemoteHName(nsd_t * pNsd,uchar ** ppszHName)1776 GetRemoteHName(nsd_t *pNsd, uchar **ppszHName)
1777 {
1778 	DEFiRet;
1779 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1780 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
1781 	iRet = nsd_ptcp.GetRemoteHName(pThis->pTcp, ppszHName);
1782 	RETiRet;
1783 }
1784 
1785 
1786 /* Provide access to the sockaddr_storage of the remote peer. This
1787  * is needed by the legacy ACL system. --- gerhards, 2008-12-01
1788  */
1789 static rsRetVal
GetRemAddr(nsd_t * pNsd,struct sockaddr_storage ** ppAddr)1790 GetRemAddr(nsd_t *pNsd, struct sockaddr_storage **ppAddr)
1791 {
1792 	DEFiRet;
1793 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1794 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
1795 	iRet = nsd_ptcp.GetRemAddr(pThis->pTcp, ppAddr);
1796 	RETiRet;
1797 }
1798 
1799 
1800 /* get the remote host's IP address. Caller must Destruct the object. */
1801 static rsRetVal
GetRemoteIP(nsd_t * pNsd,prop_t ** ip)1802 GetRemoteIP(nsd_t *pNsd, prop_t **ip)
1803 {
1804 	DEFiRet;
1805 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1806 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
1807 	iRet = nsd_ptcp.GetRemoteIP(pThis->pTcp, ip);
1808 	RETiRet;
1809 }
1810 
1811 
1812 /* accept an incoming connection request - here, we do the usual accept
1813  * handling. TLS specific handling is done thereafter (and if we run in TLS
1814  * mode at this time).
1815  * rgerhards, 2008-04-25
1816  */
1817 static rsRetVal
AcceptConnReq(nsd_t * pNsd,nsd_t ** ppNew)1818 AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew)
1819 {
1820 	DEFiRet;
1821 	int gnuRet;
1822 	nsd_gtls_t *pNew = NULL;
1823 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1824 	const char *error_position = NULL;
1825 
1826 	ISOBJ_TYPE_assert((pThis), nsd_gtls);
1827 	CHKiRet(nsd_gtlsConstruct(&pNew)); // TODO: prevent construct/destruct!
1828 	CHKiRet(nsd_ptcp.Destruct(&pNew->pTcp));
1829 	CHKiRet(nsd_ptcp.AcceptConnReq(pThis->pTcp, &pNew->pTcp));
1830 
1831 	if(pThis->iMode == 0) {
1832 		/* we are in non-TLS mode, so we are done */
1833 		*ppNew = (nsd_t*) pNew;
1834 		FINALIZE;
1835 	}
1836 	/* copy Properties to pnew first */
1837 	pNew->authMode = pThis->authMode;
1838 	pNew->permitExpiredCerts = pThis->permitExpiredCerts;
1839 	pNew->pPermPeers = pThis->pPermPeers;
1840 	pNew->gnutlsPriorityString = pThis->gnutlsPriorityString;
1841 	pNew->DrvrVerifyDepth = pThis->DrvrVerifyDepth;
1842 	pNew->dataTypeCheck = pThis->dataTypeCheck;
1843 	pNew->bSANpriority = pThis->bSANpriority;
1844 	pNew->pszCertFile = pThis->pszCertFile;
1845 	pNew->pszKeyFile = pThis->pszKeyFile;
1846 	pNew->xcred = pThis->xcred; // TODO: verify once again; xcred is read only at this stage
1847 	pNew->xcred_is_copy = 1; // do not free on pNew Destruction
1848 
1849 	/* if we reach this point, we are in TLS mode */
1850 	iRet = gtlsInitSession(pNew);
1851 	if (iRet != RS_RET_OK) {
1852 		if (iRet == RS_RET_CERTLESS) {
1853 			dbgprintf("AcceptConnReq certless mode\n");
1854 			/* Set status to OK */
1855 			iRet = RS_RET_OK;
1856 		} else {
1857 			goto finalize_it;
1858 		}
1859 	}
1860 	gtlsSetTransportPtr(pNew, ((nsd_ptcp_t*) (pNew->pTcp))->sock);
1861 
1862 	dbgprintf("AcceptConnReq bOurCertIsInit=%hu bOurKeyIsInit=%hu \n",
1863 		pNew->bOurCertIsInit, pNew->bOurKeyIsInit);
1864 
1865 	/* here is the priorityString set */
1866 	if(pNew->gnutlsPriorityString != NULL) {
1867 		dbgprintf("AcceptConnReq setting configured priority string (ciphers)\n");
1868 		if(gnutls_priority_set_direct(pNew->sess,
1869 					(const char*) pNew->gnutlsPriorityString,
1870 					&error_position)==GNUTLS_E_INVALID_REQUEST) {
1871 			LogError(0, RS_RET_GNUTLS_ERR, "Syntax Error in"
1872 					" Priority String: \"%s\"\n", error_position);
1873 		}
1874 	} else {
1875 		if(pThis->authMode == GTLS_AUTH_CERTANON) {
1876 			/* Allow ANON Ciphers */
1877 			dbgprintf("AcceptConnReq setting anon ciphers Try1: %s\n", GTLS_ANON_PRIO_NOTLSV13);
1878 			if(gnutls_priority_set_direct(pNew->sess,(const char*) GTLS_ANON_PRIO_NOTLSV13,
1879 				&error_position)==GNUTLS_E_INVALID_REQUEST) {
1880 				dbgprintf("AcceptConnReq setting anon ciphers Try2 (TLS1.3 unknown): %s\n",
1881 					GTLS_ANON_PRIO);
1882 				CHKgnutls(gnutls_priority_set_direct(pNew->sess, GTLS_ANON_PRIO, &error_position));
1883 			}
1884 			/* Uncomment for DEBUG
1885 			print_cipher_suite_list("NORMAL:+ANON-DH:+ANON-ECDH:+COMP-ALL"); */
1886 		} else {
1887 			/* Use default priorities */
1888 			dbgprintf("AcceptConnReq setting default ciphers\n");
1889 			CHKgnutls(gnutls_set_default_priority(pNew->sess));
1890 		}
1891 	}
1892 
1893 	/* we now do the handshake. This is a bit complicated, because we are
1894 	 * on non-blocking sockets. Usually, the handshake will not complete
1895 	 * immediately, so that we need to retry it some time later.
1896 	 */
1897 	gnuRet = gnutls_handshake(pNew->sess);
1898 	if(gnuRet == GNUTLS_E_AGAIN || gnuRet == GNUTLS_E_INTERRUPTED) {
1899 		pNew->rtryCall = gtlsRtry_handshake;
1900 		dbgprintf("GnuTLS handshake does not complete immediately - "
1901 			"setting to retry (this is OK and normal)\n");
1902 	} else if(gnuRet == 0) {
1903 		/* we got a handshake, now check authorization */
1904 		CHKiRet(gtlsChkPeerAuth(pNew));
1905 	} else {
1906 		uchar *pGnuErr = gtlsStrerror(gnuRet);
1907 		LogError(0, RS_RET_TLS_HANDSHAKE_ERR,
1908 			"gnutls returned error on handshake: %s\n", pGnuErr);
1909 		free(pGnuErr);
1910 		ABORT_FINALIZE(RS_RET_TLS_HANDSHAKE_ERR);
1911 	}
1912 
1913 	pNew->iMode = 1; /* this session is now in TLS mode! */
1914 
1915 	*ppNew = (nsd_t*) pNew;
1916 
1917 finalize_it:
1918 	if(iRet != RS_RET_OK) {
1919 if (error_position != NULL) {
1920 	dbgprintf("AcceptConnReq error_position=%s\n", error_position);
1921 }
1922 
1923 		if(pNew != NULL)
1924 			nsd_gtlsDestruct(&pNew);
1925 	}
1926 	RETiRet;
1927 }
1928 
1929 
1930 /* receive data from a tcp socket
1931  * The lenBuf parameter must contain the max buffer size on entry and contains
1932  * the number of octets read on exit. This function
1933  * never blocks, not even when called on a blocking socket. That is important
1934  * for client sockets, which are set to block during send, but should not
1935  * block when trying to read data. -- rgerhards, 2008-03-17
1936  * The function now follows the usual iRet calling sequence.
1937  * With GnuTLS, we may need to restart a recv() system call. If so, we need
1938  * to supply the SAME buffer on the retry. We can not assure this, as the
1939  * caller is free to call us with any buffer location (and in current
1940  * implementation, it is on the stack and extremely likely to change). To
1941  * work-around this problem, we allocate a buffer ourselfs and always receive
1942  * into that buffer. We pass data on to the caller only after we have received it.
1943  * To save some space, we allocate that internal buffer only when it is actually
1944  * needed, which means when we reach this function for the first time. To keep
1945  * the algorithm simple, we always supply data only from the internal buffer,
1946  * even if it is a single byte. As we have a stream, the caller must be prepared
1947  * to accept messages in any order, so we do not need to take care about this.
1948  * Please note that the logic also forces us to do some "faking" in select(), as
1949  * we must provide a fake "is ready for readign" status if we have data inside our
1950  * buffer. -- rgerhards, 2008-06-23
1951  */
1952 static rsRetVal
Rcv(nsd_t * pNsd,uchar * pBuf,ssize_t * pLenBuf,int * const oserr)1953 Rcv(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf, int *const oserr)
1954 {
1955 	DEFiRet;
1956 	ssize_t iBytesCopy; /* how many bytes are to be copied to the client buffer? */
1957 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
1958 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
1959 
1960 	if(pThis->bAbortConn)
1961 		ABORT_FINALIZE(RS_RET_CONNECTION_ABORTREQ);
1962 
1963 	if(pThis->iMode == 0) {
1964 		CHKiRet(nsd_ptcp.Rcv(pThis->pTcp, pBuf, pLenBuf, oserr));
1965 		FINALIZE;
1966 	}
1967 
1968 	/* --- in TLS mode now --- */
1969 
1970 	/* Buffer logic applies only if we are in TLS mode. Here we
1971 	 * assume that we will switch from plain to TLS, but never back. This
1972 	 * assumption may be unsafe, but it is the model for the time being and I
1973 	 * do not see any valid reason why we should switch back to plain TCP after
1974 	 * we were in TLS mode. However, in that case we may lose something that
1975 	 * is already in the receive buffer ... risk accepted. -- rgerhards, 2008-06-23
1976 	 */
1977 
1978 	if(pThis->pszRcvBuf == NULL) {
1979 		/* we have no buffer, so we need to malloc one */
1980 		CHKmalloc(pThis->pszRcvBuf = malloc(NSD_GTLS_MAX_RCVBUF));
1981 		pThis->lenRcvBuf = -1;
1982 	}
1983 
1984 	/* now check if we have something in our buffer. If so, we satisfy
1985 	 * the request from buffer contents.
1986 	 */
1987 	if(pThis->lenRcvBuf == -1) { /* no data present, must read */
1988 		CHKiRet(gtlsRecordRecv(pThis));
1989 	}
1990 
1991 	if(pThis->lenRcvBuf == 0) { /* EOS */
1992 		*oserr = errno;
1993 		ABORT_FINALIZE(RS_RET_CLOSED);
1994 	}
1995 
1996 	/* if we reach this point, data is present in the buffer and must be copied */
1997 	iBytesCopy = pThis->lenRcvBuf - pThis->ptrRcvBuf;
1998 	if(iBytesCopy > *pLenBuf) {
1999 		iBytesCopy = *pLenBuf;
2000 	} else {
2001 		pThis->lenRcvBuf = -1; /* buffer will be emptied below */
2002 	}
2003 
2004 	memcpy(pBuf, pThis->pszRcvBuf + pThis->ptrRcvBuf, iBytesCopy);
2005 	pThis->ptrRcvBuf += iBytesCopy;
2006 	*pLenBuf = iBytesCopy;
2007 
2008 finalize_it:
2009 	if (iRet != RS_RET_OK &&
2010 		iRet != RS_RET_RETRY) {
2011 		/* We need to free the receive buffer in error error case unless a retry is wanted. , if we
2012 		 * allocated one. -- rgerhards, 2008-12-03 -- moved here by alorbach, 2015-12-01
2013 		 */
2014 		*pLenBuf = 0;
2015 		free(pThis->pszRcvBuf);
2016 		pThis->pszRcvBuf = NULL;
2017 	}
2018 	dbgprintf("gtlsRcv return. nsd %p, iRet %d, lenRcvBuf %d, ptrRcvBuf %d\n", pThis,
2019 	iRet, pThis->lenRcvBuf, pThis->ptrRcvBuf);
2020 	RETiRet;
2021 }
2022 
2023 
2024 /* send a buffer. On entry, pLenBuf contains the number of octets to
2025  * write. On exit, it contains the number of octets actually written.
2026  * If this number is lower than on entry, only a partial buffer has
2027  * been written.
2028  * rgerhards, 2008-03-19
2029  */
2030 static rsRetVal
Send(nsd_t * pNsd,uchar * pBuf,ssize_t * pLenBuf)2031 Send(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf)
2032 {
2033 	int iSent;
2034 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
2035 	DEFiRet;
2036 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
2037 
2038 	if(pThis->bAbortConn)
2039 		ABORT_FINALIZE(RS_RET_CONNECTION_ABORTREQ);
2040 
2041 	if(pThis->iMode == 0) {
2042 		CHKiRet(nsd_ptcp.Send(pThis->pTcp, pBuf, pLenBuf));
2043 		FINALIZE;
2044 	}
2045 
2046 	/* in TLS mode now */
2047 	while(1) { /* loop broken inside */
2048 		iSent = gnutls_record_send(pThis->sess, pBuf, *pLenBuf);
2049 		if(iSent >= 0) {
2050 			*pLenBuf = iSent;
2051 			break;
2052 		}
2053 		if(iSent != GNUTLS_E_INTERRUPTED && iSent != GNUTLS_E_AGAIN) {
2054 			uchar *pErr = gtlsStrerror(iSent);
2055 			LogError(0, RS_RET_GNUTLS_ERR, "unexpected GnuTLS error %d - this "
2056 				"could be caused by a broken connection. GnuTLS reports: %s \n",
2057 				iSent, pErr);
2058 			free(pErr);
2059 			gnutls_perror(iSent);
2060 			ABORT_FINALIZE(RS_RET_GNUTLS_ERR);
2061 		}
2062 	}
2063 
2064 finalize_it:
2065 	RETiRet;
2066 }
2067 
2068 /* Enable KEEPALIVE handling on the socket.
2069  * rgerhards, 2009-06-02
2070  */
2071 static rsRetVal
EnableKeepAlive(nsd_t * pNsd)2072 EnableKeepAlive(nsd_t *pNsd)
2073 {
2074 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
2075 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
2076 	return nsd_ptcp.EnableKeepAlive(pThis->pTcp);
2077 }
2078 
2079 
2080 /*
2081  * SNI should not be used if the hostname is a bare IP address
2082  */
2083 static int
SetServerNameIfPresent(nsd_gtls_t * pThis,uchar * host)2084 SetServerNameIfPresent(nsd_gtls_t *pThis, uchar *host) {
2085 	struct sockaddr_in sa;
2086 	struct sockaddr_in6 sa6;
2087 
2088 	int inet_pton_ret = inet_pton(AF_INET, CHAR_CONVERT(host), &(sa.sin_addr));
2089 
2090 	if (inet_pton_ret == 0) { // host wasn't a bare IPv4 address: try IPv6
2091 		inet_pton_ret = inet_pton(AF_INET6, CHAR_CONVERT(host), &(sa6.sin6_addr));
2092 	}
2093 
2094 	switch(inet_pton_ret) {
2095 		case 1: // host is a valid IP address: don't use SNI
2096 			return 0;
2097 		case 0: // host isn't a valid IP address: assume it's a domain name, use SNI
2098 			return gnutls_server_name_set(pThis->sess, GNUTLS_NAME_DNS, host, ustrlen(host));
2099 		default: // unexpected error
2100 			return -1;
2101 	}
2102 
2103 }
2104 
2105 /* open a connection to a remote host (server). With GnuTLS, we always
2106  * open a plain tcp socket and then, if in TLS mode, do a handshake on it.
2107  * rgerhards, 2008-03-19
2108  */
2109 #pragma GCC diagnostic push
2110 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" /* TODO: FIX Warnings! */
2111 static rsRetVal
Connect(nsd_t * pNsd,int family,uchar * port,uchar * host,char * device)2112 Connect(nsd_t *pNsd, int family, uchar *port, uchar *host, char *device)
2113 {
2114 	nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
2115 	int sock;
2116 	int gnuRet;
2117 	const char *error_position;
2118 #	ifdef HAVE_GNUTLS_CERTIFICATE_TYPE_SET_PRIORITY
2119 	static const int cert_type_priority[2] = { GNUTLS_CRT_X509, 0 };
2120 #	endif
2121 	DEFiRet;
2122 	dbgprintf("Connect to %s:%s\n", host, port);
2123 
2124 	ISOBJ_TYPE_assert(pThis, nsd_gtls);
2125 	assert(port != NULL);
2126 	assert(host != NULL);
2127 
2128 	CHKiRet(gtlsInitCred(pThis));
2129 	CHKiRet(gtlsAddOurCert(pThis));
2130 	CHKiRet(nsd_ptcp.Connect(pThis->pTcp, family, port, host, device));
2131 
2132 	if(pThis->iMode == 0)
2133 		FINALIZE;
2134 
2135 	/* we reach this point if in TLS mode */
2136 	CHKgnutls(gnutls_init(&pThis->sess, GNUTLS_CLIENT));
2137 	pThis->bHaveSess = 1;
2138 	pThis->bIsInitiator = 1;
2139 
2140 	CHKgnutls(SetServerNameIfPresent(pThis, host));
2141 
2142 	/* in the client case, we need to set a callback that ensures our certificate
2143 	 * will be presented to the server even if it is not signed by one of the server's
2144 	 * trusted roots. This is necessary to support fingerprint authentication.
2145 	 */
2146 	/* store a pointer to ourselfs (needed by callback) */
2147 	gnutls_session_set_ptr(pThis->sess, (void*)pThis);
2148 	iRet = gtlsLoadOurCertKey(pThis); /* first load .pem files */
2149 	if(iRet == RS_RET_OK) {
2150 #		if HAVE_GNUTLS_CERTIFICATE_SET_RETRIEVE_FUNCTION
2151 		gnutls_certificate_set_retrieve_function(pThis->xcred, gtlsClientCertCallback);
2152 #		else
2153 		gnutls_certificate_client_set_retrieve_function(pThis->xcred, gtlsClientCertCallback);
2154 #		endif
2155 		dbgprintf("Connect: enable certificate checking (VerifyDepth=%d)\n", pThis->DrvrVerifyDepth);
2156 		if (pThis->DrvrVerifyDepth != 0) {
2157 			gnutls_certificate_set_verify_limits(pThis->xcred, 8200, pThis->DrvrVerifyDepth);
2158 		}
2159 	} else if(iRet == RS_RET_CERTLESS) {
2160 		dbgprintf("Connect: certificates not configured, not loaded.\n");
2161 	} else {
2162 		LogError(0, iRet, "Connect failed to INIT Session %d", gnuRet);
2163 		ABORT_FINALIZE(iRet);; /* we have an error case! */
2164 	}
2165 
2166 	/*priority string setzen*/
2167 	if(pThis->gnutlsPriorityString != NULL) {
2168 		dbgprintf("Connect: setting configured priority string (ciphers)\n");
2169 		if(gnutls_priority_set_direct(pThis->sess,
2170 					(const char*) pThis->gnutlsPriorityString,
2171 					&error_position)==GNUTLS_E_INVALID_REQUEST) {
2172 			LogError(0, RS_RET_GNUTLS_ERR, "Syntax Error in"
2173 					" Priority String: \"%s\"\n", error_position);
2174 		}
2175 	} else {
2176 		if(pThis->authMode == GTLS_AUTH_CERTANON || pThis->bOurCertIsInit == 0) {
2177 			/* Allow ANON Ciphers */
2178 			dbgprintf("Connect: setting anon ciphers Try1: %s\n", GTLS_ANON_PRIO_NOTLSV13);
2179 			if(gnutls_priority_set_direct(pThis->sess,(const char*) GTLS_ANON_PRIO_NOTLSV13,
2180 				&error_position)==GNUTLS_E_INVALID_REQUEST) {
2181 				dbgprintf("Connect: setting anon ciphers Try2 (TLS1.3 unknown): %s\n", GTLS_ANON_PRIO);
2182 				CHKgnutls(gnutls_priority_set_direct(pThis->sess, GTLS_ANON_PRIO, &error_position));
2183 			}
2184 			/* Uncomment for DEBUG
2185 			print_cipher_suite_list("NORMAL:+ANON-DH:+ANON-ECDH:+COMP-ALL"); */
2186 		} else {
2187 			/* Use default priorities */
2188 			dbgprintf("Connect: setting default ciphers\n");
2189 			CHKgnutls(gnutls_set_default_priority(pThis->sess));
2190 		}
2191 	}
2192 
2193 #	ifdef HAVE_GNUTLS_CERTIFICATE_TYPE_SET_PRIORITY
2194 	/* The gnutls_certificate_type_set_priority function is deprecated
2195 	 * and not available in recent GnuTLS versions. However, there is no
2196 	 * doc how to properly replace it with gnutls_priority_set_direct.
2197 	 * A lot of folks have simply removed it, when they also called
2198 	 * gnutls_set_default_priority. This is what we now also do. If
2199 	 * this causes problems or someone has an idea of how to replace
2200 	 * the deprecated function in a better way, please let us know!
2201 	 * In any case, we use it as long as it is available and let
2202 	 * not insult us by the deprecation warnings.
2203 	 * 2015-05-18 rgerhards
2204 	 */
2205 	CHKgnutls(gnutls_certificate_type_set_priority(pThis->sess, cert_type_priority));
2206 #	endif
2207 
2208 	/* put the x509 credentials to the current session */
2209 	CHKgnutls(gnutls_credentials_set(pThis->sess, GNUTLS_CRD_CERTIFICATE, pThis->xcred));
2210 
2211 	/* check for anon authmode */
2212 	if (pThis->authMode == GTLS_AUTH_CERTANON) {
2213 		dbgprintf("Connect: anon authmode, gnutls_credentials_set GNUTLS_CRD_ANON\n");
2214 		CHKgnutls(gnutls_credentials_set(pThis->sess, GNUTLS_CRD_ANON, anoncred));
2215 		gnutls_dh_set_prime_bits(pThis->sess, dhMinBits);
2216 	}
2217 
2218 	/* assign the socket to GnuTls */
2219 	CHKiRet(nsd_ptcp.GetSock(pThis->pTcp, &sock));
2220 	gtlsSetTransportPtr(pThis, sock);
2221 
2222 	/* we need to store the hostname as an alternate mean of authentication if no
2223 	 * permitted peer names are given. Using the hostname is quite useful. It permits
2224 	 * auto-configuration of security if a commen root cert is present. -- rgerhards, 2008-05-26
2225 	 */
2226 	CHKmalloc(pThis->pszConnectHost = (uchar*)strdup((char*)host));
2227 
2228 	/* and perform the handshake */
2229 	CHKgnutls(gnutls_handshake(pThis->sess));
2230 	dbgprintf("GnuTLS handshake succeeded\n");
2231 
2232 	/* now check if the remote peer is permitted to talk to us - ideally, we
2233 	 * should do this during the handshake, but GnuTLS does not yet provide
2234 	 * the necessary callbacks -- rgerhards, 2008-05-26
2235 	 */
2236 	CHKiRet(gtlsChkPeerAuth(pThis));
2237 
2238 finalize_it:
2239 	if(iRet != RS_RET_OK) {
2240 		if(pThis->bHaveSess) {
2241 			gnutls_deinit(pThis->sess);
2242 			pThis->bHaveSess = 0;
2243 			pThis->xcred = NULL;
2244 		}
2245 	}
2246 
2247 	RETiRet;
2248 }
2249 #pragma GCC diagnostic pop
2250 
2251 
2252 /* queryInterface function */
2253 BEGINobjQueryInterface(nsd_gtls)
2254 CODESTARTobjQueryInterface(nsd_gtls)
2255 	if(pIf->ifVersion != nsdCURR_IF_VERSION) {/* check for current version, increment on each change */
2256 		ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
2257 	}
2258 
2259 	/* ok, we have the right interface, so let's fill it
2260 	 * Please note that we may also do some backwards-compatibility
2261 	 * work here (if we can support an older interface version - that,
2262 	 * of course, also affects the "if" above).
2263 	 */
2264 	pIf->Construct = (rsRetVal(*)(nsd_t**)) nsd_gtlsConstruct;
2265 	pIf->Destruct = (rsRetVal(*)(nsd_t**)) nsd_gtlsDestruct;
2266 	pIf->Abort = Abort;
2267 	pIf->LstnInit = LstnInit;
2268 	pIf->AcceptConnReq = AcceptConnReq;
2269 	pIf->Rcv = Rcv;
2270 	pIf->Send = Send;
2271 	pIf->Connect = Connect;
2272 	pIf->SetSock = SetSock;
2273 	pIf->SetMode = SetMode;
2274 	pIf->SetAuthMode = SetAuthMode;
2275 	pIf->SetPermitExpiredCerts = SetPermitExpiredCerts;
2276 	pIf->SetPermPeers =SetPermPeers;
2277 	pIf->CheckConnection = CheckConnection;
2278 	pIf->GetRemoteHName = GetRemoteHName;
2279 	pIf->GetRemoteIP = GetRemoteIP;
2280 	pIf->GetRemAddr = GetRemAddr;
2281 	pIf->EnableKeepAlive = EnableKeepAlive;
2282 	pIf->SetKeepAliveIntvl = SetKeepAliveIntvl;
2283 	pIf->SetKeepAliveProbes = SetKeepAliveProbes;
2284 	pIf->SetKeepAliveTime = SetKeepAliveTime;
2285 	pIf->SetGnutlsPriorityString = SetGnutlsPriorityString;
2286 	pIf->SetCheckExtendedKeyUsage = SetCheckExtendedKeyUsage;
2287 	pIf->SetPrioritizeSAN = SetPrioritizeSAN;
2288 	pIf->SetTlsVerifyDepth = SetTlsVerifyDepth;
2289 	pIf->SetTlsCAFile = SetTlsCAFile;
2290 	pIf->SetTlsKeyFile = SetTlsKeyFile;
2291 	pIf->SetTlsCertFile = SetTlsCertFile;
2292 finalize_it:
2293 ENDobjQueryInterface(nsd_gtls)
2294 
2295 
2296 /* exit our class
2297  */
2298 BEGINObjClassExit(nsd_gtls, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */
2299 CODESTARTObjClassExit(nsd_gtls)
2300 	gtlsGlblExit();	/* shut down GnuTLS */
2301 
2302 	/* release objects we no longer need */
2303 	objRelease(nsd_ptcp, LM_NSD_PTCP_FILENAME);
2304 	objRelease(net, LM_NET_FILENAME);
2305 	objRelease(glbl, CORE_COMPONENT);
2306 	objRelease(datetime, CORE_COMPONENT);
2307 ENDObjClassExit(nsd_gtls)
2308 
2309 
2310 /* Initialize the nsd_gtls class. Must be called as the very first method
2311  * before anything else is called inside this class.
2312  * rgerhards, 2008-02-19
2313  */
2314 BEGINObjClassInit(nsd_gtls, 1, OBJ_IS_LOADABLE_MODULE) /* class, version */
2315 	/* request objects we use */
2316 	CHKiRet(objUse(datetime, CORE_COMPONENT));
2317 	CHKiRet(objUse(glbl, CORE_COMPONENT));
2318 	CHKiRet(objUse(net, LM_NET_FILENAME));
2319 	CHKiRet(objUse(nsd_ptcp, LM_NSD_PTCP_FILENAME));
2320 
2321 	/* now do global TLS init stuff */
2322 	CHKiRet(gtlsGlblInit());
2323 ENDObjClassInit(nsd_gtls)
2324 
2325 
2326 /* --------------- here now comes the plumbing that makes as a library module --------------- */
2327 
2328 
2329 BEGINmodExit
2330 CODESTARTmodExit
2331 	nsdsel_gtlsClassExit();
2332 	nsd_gtlsClassExit();
2333 	pthread_mutex_destroy(&mutGtlsStrerror);
2334 ENDmodExit
2335 
2336 
2337 BEGINqueryEtryPt
2338 CODESTARTqueryEtryPt
2339 CODEqueryEtryPt_STD_LIB_QUERIES
2340 ENDqueryEtryPt
2341 
2342 
2343 BEGINmodInit()
2344 CODESTARTmodInit
2345 	*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
2346 
2347 	/* Initialize all classes that are in our module - this includes ourselfs */
2348 	CHKiRet(nsd_gtlsClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */
2349 	CHKiRet(nsdsel_gtlsClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */
2350 
2351 	pthread_mutex_init(&mutGtlsStrerror, NULL);
2352 ENDmodInit
2353 /* vi:set ai:
2354  */
2355