Blob


1 /*
2 * ngIRCd -- The Next Generation IRC Daemon
3 *
4 * SSL wrapper functions.
5 * Copyright (c) 2005-2008 Florian Westphal <fw@strlen.de>
6 */
8 #include "portab.h"
9 #include "imp.h"
10 #include "conf-ssl.h"
12 #ifdef SSL_SUPPORT
14 #include "io.h"
15 #include <assert.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <errno.h>
21 #define CONN_MODULE
22 #include "conn.h"
23 #include "conf.h"
24 #include "conn-func.h"
25 #include "conn-ssl.h"
26 #include "log.h"
28 #include "exp.h"
29 #include "defines.h"
31 extern struct SSLOptions Conf_SSLOptions;
33 #ifdef HAVE_LIBSSL
34 #include <openssl/err.h>
35 #include <openssl/rand.h>
37 static SSL_CTX * ssl_ctx;
38 static DH *dh_params;
40 static bool ConnSSL_LoadServerKey_openssl PARAMS(( SSL_CTX *c ));
41 #endif
43 #ifdef HAVE_LIBGNUTLS
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <unistd.h>
48 #include <gnutls/x509.h>
50 #define DH_BITS 1024
51 static gnutls_certificate_credentials_t x509_cred;
52 static gnutls_dh_params_t dh_params;
54 static bool ConnSSL_LoadServerKey_gnutls PARAMS(( void ));
55 #endif
57 static bool ConnSSL_Init_SSL PARAMS(( CONNECTION *c ));
58 static int ConnectAccept PARAMS(( CONNECTION *c, bool connect ));
59 static int ConnSSL_HandleError PARAMS(( CONNECTION *c, const int code, const char *fname ));
61 #ifdef HAVE_LIBGNUTLS
62 static char * openreadclose(const char *name, size_t *len)
63 {
64 char *buf = NULL;
65 struct stat s;
66 ssize_t br;
67 int fd = open(name, O_RDONLY);
68 if (fd < 0) {
69 Log(LOG_ERR, "Could not open %s: %s", name, strerror(errno));
70 return NULL;
71 }
72 if (fstat(fd, &s)) {
73 Log(LOG_ERR, "Could not fstat %s: %s", name, strerror(errno));
74 goto out;
75 }
76 if (!S_ISREG(s.st_mode)) {
77 Log(LOG_ERR, "%s: Not a regular file", name);
78 goto out;
79 }
80 if (s.st_size <= 0) {
81 Log(LOG_ERR, "%s: invalid file length (size %ld <= 0)", name, (long) s.st_size);
82 goto out;
83 }
84 buf = malloc(s.st_size);
85 if (!buf) {
86 Log(LOG_ERR, "Could not malloc %lu bytes for file %s: %s", s.st_size, name, strerror(errno));
87 goto out;
88 }
89 br = read(fd, buf, s.st_size);
90 if (br != (ssize_t)s.st_size) {
91 Log(LOG_ERR, "Could not read file %s: read returned %ld, expected %ld: %s",
92 name, (long) br, (long) s.st_size, br == -1 ? strerror(errno):"short read?!");
93 memset(buf, 0, s.st_size);
94 free(buf);
95 buf = NULL;
96 } else {
97 *len = br;
98 }
99 out:
100 close(fd);
101 return buf;
103 #endif
106 #ifdef HAVE_LIBSSL
107 static void
108 LogOpenSSLError( const char *msg, const char *msg2 )
110 unsigned long err = ERR_get_error();
111 char * errmsg = err ? ERR_error_string(err, NULL) : "Unable to determine error";
113 if (!msg) msg = "SSL Error";
114 if (msg2)
115 Log( LOG_ERR, "%s: %s: %s", msg, msg2, errmsg);
116 else
117 Log( LOG_ERR, "%s: %s", msg, errmsg);
121 static int
122 pem_passwd_cb(char *buf, int size, int rwflag, void *password)
124 array *pass = password;
125 int passlen;
126 assert(rwflag == 0); /* 0 -> callback used for decryption. See SSL_CTX_set_default_passwd_cb(3) */
128 passlen = (int) array_bytes(pass);
130 LogDebug("pem_passwd_cb buf size %d, array size %d", size, passlen);
131 assert(passlen >= 0);
132 if (passlen <= 0) {
133 Log(LOG_ERR, "pem_passwd_cb: password required, but not set");
134 return 0;
136 size = passlen > size ? size : passlen;
137 memcpy(buf, (char *)(array_start(pass)), size);
138 return size;
140 #endif
143 static bool
144 Load_DH_params(void)
146 #ifdef HAVE_LIBSSL
147 FILE *fp;
148 bool ret = true;
150 if (!Conf_SSLOptions.DHFile) {
151 Log(LOG_NOTICE, "Configuration option \"SSLDHFile\" not set");
152 return false;
154 fp = fopen(Conf_SSLOptions.DHFile, "r");
155 if (!fp) {
156 Log(LOG_ERR, "%s: %s", Conf_SSLOptions.DHFile, strerror(errno));
157 return false;
159 dh_params = PEM_read_DHparams(fp, NULL, NULL, NULL);
160 if (!dh_params) {
161 Log(LOG_ERR, "%s: PEM_read_DHparams failed", Conf_SSLOptions.DHFile);
162 ret = false;
164 fclose(fp);
165 return ret;
166 #endif
167 #ifdef HAVE_LIBGNUTLS
168 bool need_dhgenerate = true;
169 int err;
170 gnutls_dh_params_t tmp_dh_params;
172 err = gnutls_dh_params_init(&tmp_dh_params);
173 if (err < 0) {
174 Log(LOG_ERR, "gnutls_dh_params_init: %s", gnutls_strerror(err));
175 return false;
177 if (Conf_SSLOptions.DHFile) {
178 gnutls_datum_t dhparms;
179 size_t size;
180 dhparms.data = (unsigned char *) openreadclose(Conf_SSLOptions.DHFile, &size);
181 if (dhparms.data) {
182 dhparms.size = size;
183 err = gnutls_dh_params_import_pkcs3(tmp_dh_params, &dhparms, GNUTLS_X509_FMT_PEM);
184 if (err == 0)
185 need_dhgenerate = false;
186 else
187 Log(LOG_ERR, "gnutls_dh_params_init: %s", gnutls_strerror(err));
189 memset(dhparms.data, 0, size);
190 free(dhparms.data);
193 if (need_dhgenerate) {
194 Log(LOG_WARNING, "SSLDHFile not set, generating %u bit DH parameters. This may take a while...", DH_BITS);
195 err = gnutls_dh_params_generate2(tmp_dh_params, DH_BITS);
196 if (err < 0) {
197 Log(LOG_ERR, "gnutls_dh_params_generate2: %s", gnutls_strerror(err));
198 return false;
201 dh_params = tmp_dh_params;
202 return true;
203 #endif
207 void ConnSSL_Free(CONNECTION *c)
209 #ifdef HAVE_LIBSSL
210 SSL *ssl = c->ssl_state.ssl;
211 if (ssl) {
212 SSL_shutdown(ssl);
213 SSL_free(ssl);
214 c->ssl_state.ssl = NULL;
216 #endif
217 #ifdef HAVE_LIBGNUTLS
218 gnutls_session_t sess = c->ssl_state.gnutls_session;
219 if (Conn_OPTION_ISSET(c, CONN_SSL)) {
220 gnutls_bye(sess, GNUTLS_SHUT_RDWR);
221 gnutls_deinit(sess);
223 #endif
224 assert(Conn_OPTION_ISSET(c, CONN_SSL));
225 Conn_OPTION_DEL(c, (CONN_SSL_CONNECT|CONN_SSL|CONN_SSL_WANT_WRITE));
229 bool
230 ConnSSL_InitLibrary( void )
232 #ifdef HAVE_LIBSSL
233 SSL_CTX *newctx;
235 if (!ssl_ctx) {
236 SSL_library_init();
237 SSL_load_error_strings();
240 if (!RAND_status()) {
241 Log(LOG_ERR, "OpenSSL PRNG not seeded: /dev/urandom missing?");
242 /*
243 * it is probably best to fail and let the user install EGD or a similar program if no kernel random device is available.
244 * According to OpenSSL RAND_egd(3): "The automatic query of /var/run/egd-pool et al was added in OpenSSL 0.9.7";
245 * so it makes little sense to deal with PRNGD seeding ourselves.
246 */
247 return false;
250 newctx = SSL_CTX_new(SSLv23_method());
251 if (!newctx) {
252 LogOpenSSLError("SSL_CTX_new()", NULL);
253 return false;
256 if (!ConnSSL_LoadServerKey_openssl(newctx))
257 goto out;
259 SSL_CTX_set_options(newctx, SSL_OP_SINGLE_DH_USE|SSL_OP_NO_SSLv2);
260 SSL_CTX_set_mode(newctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
261 SSL_CTX_free(ssl_ctx);
262 ssl_ctx = newctx;
263 Log(LOG_INFO, "%s initialized", SSLeay_version(SSLEAY_VERSION));
264 return true;
265 out:
266 SSL_CTX_free(newctx);
267 return false;
268 #endif
269 #ifdef HAVE_LIBGNUTLS
270 int err;
271 static bool initialized;
272 if (initialized) /* TODO: cannot reload gnutls keys: can't simply free x509 context -- it may still be in use */
273 return false;
275 err = gnutls_global_init();
276 if (err) {
277 Log(LOG_ERR, "gnutls_global_init(): %s", gnutls_strerror(err));
278 return false;
280 if (!ConnSSL_LoadServerKey_gnutls())
281 return false;
282 Log(LOG_INFO, "gnutls %s initialized", gnutls_check_version(NULL));
283 initialized = true;
284 return true;
285 #endif
289 #ifdef HAVE_LIBGNUTLS
290 static bool
291 ConnSSL_LoadServerKey_gnutls(void)
293 int err;
294 const char *cert_file;
296 err = gnutls_certificate_allocate_credentials(&x509_cred);
297 if (err < 0) {
298 Log(LOG_ERR, "gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err));
299 return false;
302 cert_file = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile;
303 if (!cert_file) {
304 Log(LOG_ERR, "Neither Key nor certificate File set");
305 return false;
308 if (array_bytes(&Conf_SSLOptions.KeyFilePassword))
309 Log(LOG_WARNING, "Ignoring KeyFilePassword: Not supported by GNUTLS");
311 if (!Load_DH_params())
312 return false;
314 gnutls_certificate_set_dh_params(x509_cred, dh_params);
315 err = gnutls_certificate_set_x509_key_file(x509_cred, cert_file, Conf_SSLOptions.KeyFile, GNUTLS_X509_FMT_PEM);
316 if (err < 0) {
317 Log(LOG_ERR, "gnutls_certificate_set_x509_key_file (cert %s, key %s): %s",
318 cert_file, Conf_SSLOptions.KeyFile ? Conf_SSLOptions.KeyFile : "(NULL)", gnutls_strerror(err));
319 return false;
321 return true;
323 #endif
326 #ifdef HAVE_LIBSSL
327 static bool
328 ConnSSL_LoadServerKey_openssl(SSL_CTX *ctx)
330 char *cert_key;
332 assert(ctx);
333 if (!Conf_SSLOptions.KeyFile) {
334 Log(LOG_NOTICE, "No SSL Server Key configured, ssl disabled");
335 return false;
338 SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
339 SSL_CTX_set_default_passwd_cb_userdata(ctx, &Conf_SSLOptions.KeyFilePassword);
341 if (SSL_CTX_use_PrivateKey_file(ctx, Conf_SSLOptions.KeyFile, SSL_FILETYPE_PEM) != 1) {
342 array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
343 LogOpenSSLError("SSL_CTX_use_PrivateKey_file", Conf_SSLOptions.KeyFile);
344 return false;
347 cert_key = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile;
348 if (SSL_CTX_use_certificate_chain_file(ctx, cert_key) != 1) {
349 array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
350 LogOpenSSLError("SSL_CTX_use_certificate_file", cert_key);
351 return false;
354 array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
356 if (!SSL_CTX_check_private_key(ctx)) {
357 LogOpenSSLError("Server Private Key does not match certificate", NULL);
358 return false;
360 if (Load_DH_params()) {
361 if (SSL_CTX_set_tmp_dh(ctx, dh_params) != 1)
362 LogOpenSSLError("Error setting DH Parameters", Conf_SSLOptions.DHFile);
363 /* don't return false here: the non-DH modes will still work */
364 DH_free(dh_params);
365 dh_params = NULL;
367 return true;
371 #endif
372 static bool
373 ConnSSL_Init_SSL(CONNECTION *c)
375 int ret;
376 assert(c != NULL);
377 #ifdef HAVE_LIBSSL
378 assert(ssl_ctx);
379 if (!ssl_ctx) /* NULL when library initialization failed */
380 return false;
382 assert(c->ssl_state.ssl == NULL);
384 c->ssl_state.ssl = SSL_new(ssl_ctx);
385 if (!c->ssl_state.ssl) {
386 LogOpenSSLError("SSL_new()", NULL);
387 return false;
390 ret = SSL_set_fd(c->ssl_state.ssl, c->sock);
391 if (ret != 1) {
392 LogOpenSSLError("SSL_set_fd()", NULL);
393 ConnSSL_Free(c);
394 return false;
396 #endif
397 #ifdef HAVE_LIBGNUTLS
398 ret = gnutls_set_default_priority(c->ssl_state.gnutls_session);
399 if (ret < 0) {
400 Log(LOG_ERR, "gnutls_set_default_priority: %s", gnutls_strerror(ret));
401 ConnSSL_Free(c);
403 gnutls_transport_set_ptr(c->ssl_state.gnutls_session, (gnutls_transport_ptr_t) c->sock);
404 ret = gnutls_credentials_set(c->ssl_state.gnutls_session, GNUTLS_CRD_CERTIFICATE, x509_cred);
405 if (ret < 0) {
406 Log(LOG_ERR, "gnutls_credentials_set: %s", gnutls_strerror(ret));
407 ConnSSL_Free(c);
409 gnutls_dh_set_prime_bits(c->ssl_state.gnutls_session, DH_BITS);
410 #endif
411 Conn_OPTION_ADD(c, CONN_SSL);
412 return true;
416 bool
417 ConnSSL_PrepareConnect(CONNECTION *c, UNUSED CONF_SERVER *s)
419 bool ret;
420 #ifdef HAVE_LIBGNUTLS
421 int err;
422 #endif
423 assert(c != NULL);
424 assert(s != NULL);
425 #ifdef HAVE_LIBGNUTLS
426 err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_CLIENT);
427 if (err) {
428 Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err));
429 return false;
431 #endif
432 ret = ConnSSL_Init_SSL(c);
433 if (!ret)
434 return false;
435 Conn_OPTION_ADD(c, CONN_SSL_CONNECT);
436 #ifdef HAVE_LIBSSL
437 assert(c->ssl_state.ssl);
438 SSL_set_verify(c->ssl_state.ssl, SSL_VERIFY_NONE, NULL);
439 #endif
440 return true;
444 /*
445 Check an Handle Error return code after failed calls to ssl/tls functions.
446 OpenSSL:
447 SSL_connect(), SSL_accept(), SSL_do_handshake(), SSL_read(), SSL_peek(), or SSL_write() on ssl.
448 GNUTLS:
449 gnutlsssl_read(), gnutls_write() or gnutls_handshake().
450 Return: -1 on fatal error, 0 if we can try again later.
451 */
452 static int
453 ConnSSL_HandleError( CONNECTION *c, const int code, const char *fname )
455 #ifdef HAVE_LIBSSL
456 int ret = SSL_ERROR_SYSCALL;
457 unsigned long sslerr;
458 int real_errno = errno;
460 assert( fname );
462 ret = SSL_get_error(c->ssl_state.ssl, code);
463 switch (ret) {
464 case SSL_ERROR_WANT_READ:
465 io_event_del(c->sock, IO_WANTWRITE);
466 Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
467 return 0; /* try again later */
468 case SSL_ERROR_WANT_WRITE:
469 io_event_del(c->sock, IO_WANTREAD);
470 Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */
471 case SSL_ERROR_NONE:
472 return 0; /* try again later */
473 case SSL_ERROR_ZERO_RETURN: /* TLS/SSL Connection was shut down */
474 LogOpenSSLError("TLS/SSL Connection shutdown", fname);
475 break;
476 /*
477 SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT, SSL_ERROR_WANT_X509_LOOKUP
478 */
479 case SSL_ERROR_SYSCALL:
480 sslerr = ERR_get_error();
481 if (sslerr) {
482 Log( LOG_ERR, "%s: %s", fname, ERR_error_string(sslerr, NULL ));
483 } else {
485 switch (code) { /* EOF that violated protocol */
486 case 0:
487 Log(LOG_ERR, "%s: Client Disconnected", fname );
488 break;
489 case -1: /* low level socket I/O error, check errno */
490 Log(LOG_ERR, "%s: %s", fname, strerror(real_errno));
493 break;
494 case SSL_ERROR_SSL:
495 LogOpenSSLError("TLS/SSL Protocol Error", fname);
496 break;
497 default:
498 Log( LOG_ERR, "%s: Unknown error %d!", fname, ret);
500 ConnSSL_Free(c);
501 return -1;
502 #endif
503 #ifdef HAVE_LIBGNUTLS
504 switch (code) {
505 case GNUTLS_E_AGAIN:
506 case GNUTLS_E_INTERRUPTED:
507 if (gnutls_record_get_direction(c->ssl_state.gnutls_session)) { /* need write */
508 io_event_del(c->sock, IO_WANTREAD);
509 Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */
510 break;
511 } else { /* need read */
512 io_event_del(c->sock, IO_WANTWRITE);
513 Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
514 break;
516 default:
517 assert(code < 0);
518 if (gnutls_error_is_fatal(code)) {
519 Log(LOG_ERR, "%s: %s", fname, gnutls_strerror(code));
520 ConnSSL_Free(c);
521 return -1;
524 return 0;
525 #endif
529 static void
530 ConnSSL_LogCertInfo( CONNECTION *c )
532 #ifdef HAVE_LIBSSL
533 SSL *ssl = c->ssl_state.ssl;
535 assert( c );
536 assert( ssl );
538 Log( LOG_INFO, "New %s connection using cipher %s on socket %d",
539 SSL_get_version(ssl), SSL_get_cipher(ssl), c->sock);
540 #endif
541 #ifdef HAVE_LIBGNUTLS
542 gnutls_credentials_type_t cred;
543 gnutls_session_t sess = c->ssl_state.gnutls_session;
544 gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
546 Log( LOG_INFO, "New %s connection using cipher %s-%s on socket %d",
547 gnutls_protocol_get_name(gnutls_protocol_get_version(sess)),
548 gnutls_cipher_get_name(cipher), gnutls_mac_get_name(gnutls_mac_get(sess)), c->sock);
549 #endif
553 /*
554 Accept incoming SSL connection.
555 Return Values:
556 1: SSL Connection established
557 0: try again
558 -1: SSL Connection not established due to fatal error.
559 */
560 int
561 ConnSSL_Accept( CONNECTION *c )
563 assert(c != NULL);
564 #ifdef HAVE_LIBSSL
565 if (!c->ssl_state.ssl) {
566 #endif
567 #ifdef HAVE_LIBGNUTLS
568 if (!Conn_OPTION_ISSET(c, CONN_SSL)) {
569 int err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_SERVER);
570 if (err) {
571 Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err));
572 return false;
574 #endif
575 LogDebug("ConnSSL_Accept: Initializing SSL data");
576 if (!ConnSSL_Init_SSL(c))
577 return -1;
579 return ConnectAccept(c, false );
583 int
584 ConnSSL_Connect( CONNECTION *c )
586 assert(c != NULL);
587 #ifdef HAVE_LIBSSL
588 assert(c->ssl_state.ssl);
589 #endif
590 #ifdef HAVE_LIBGNUTLS
591 assert(Conn_OPTION_ISSET(c, CONN_SSL));
592 #endif
593 return ConnectAccept(c, true);
597 /* accept/connect wrapper. if connect is true, connect to peer, otherwise wait for incoming connection */
598 static int
599 ConnectAccept( CONNECTION *c, bool connect)
601 int ret;
602 #ifdef HAVE_LIBSSL
603 SSL *ssl = c->ssl_state.ssl;
604 assert(ssl != NULL);
606 ret = connect ? SSL_connect(ssl) : SSL_accept(ssl);
607 if (1 != ret)
608 return ConnSSL_HandleError(c, ret, connect ? "SSL_connect": "SSL_accept");
609 #endif
610 #ifdef HAVE_LIBGNUTLS
611 (void) connect;
612 assert(Conn_OPTION_ISSET(c, CONN_SSL));
613 ret = gnutls_handshake(c->ssl_state.gnutls_session);
614 if (ret)
615 return ConnSSL_HandleError(c, ret, "gnutls_handshake");
616 #endif /* _GNUTLS */
617 Conn_OPTION_DEL(c, (CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ|CONN_SSL_CONNECT));
618 ConnSSL_LogCertInfo(c);
619 return 1;
623 ssize_t
624 ConnSSL_Write(CONNECTION *c, const void *buf, size_t count)
626 ssize_t bw;
628 Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
630 assert(count > 0);
631 #ifdef HAVE_LIBSSL
632 bw = (ssize_t) SSL_write(c->ssl_state.ssl, buf, count);
633 #endif
634 #ifdef HAVE_LIBGNUTLS
635 bw = gnutls_write(c->ssl_state.gnutls_session, buf, count);
636 #endif
637 if ( bw > 0 ) return bw;
638 if (ConnSSL_HandleError( c, bw, "ConnSSL_Write") == 0)
639 errno = EAGAIN; /* try again */
640 return -1;
644 ssize_t
645 ConnSSL_Read(CONNECTION *c, void * buf, size_t count)
647 ssize_t br;
649 Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
650 #ifdef HAVE_LIBSSL
651 br = (ssize_t) SSL_read(c->ssl_state.ssl, buf, count);
652 if (br > 0) /* on EOF we have to call ConnSSL_HandleError(), see SSL_read(3) */
653 return br;
654 #endif
655 #ifdef HAVE_LIBGNUTLS
656 br = gnutls_read(c->ssl_state.gnutls_session, buf, count);
657 if (br >= 0) /* on EOF we must _not_ call ConnSSL_HandleError, see gnutls_record_recv(3) */
658 return br;
659 #endif
660 /* error on read: switch ConnSSL_HandleError() return values -> 0 is "try again", so return -1 and set EAGAIN */
661 if (ConnSSL_HandleError(c, br, "ConnSSL_Read") == 0) {
662 errno = EAGAIN;
663 return -1;
665 return 0;
669 bool
670 ConnSSL_GetCipherInfo(CONNECTION *c, char *buf, size_t len)
672 #ifdef HAVE_LIBSSL
673 char *nl;
675 SSL *ssl;
676 assert(c != NULL);
677 assert(len >= 128);
678 ssl = c->ssl_state.ssl;
679 if (!ssl)
680 return false;
681 *buf = 0;
682 SSL_CIPHER_description(SSL_get_current_cipher(ssl), buf, len);
683 nl = strchr(buf, '\n');
684 if (nl)
685 *nl = 0;
686 return true;
687 #endif
688 #ifdef HAVE_LIBGNUTLS
689 assert(c != NULL);
690 assert(len >= 128);
691 if (Conn_OPTION_ISSET(c, CONN_SSL)) {
692 const char *name_cipher, *name_mac, *name_proto, *name_keyexchange;
693 unsigned keysize;
695 gnutls_session_t sess = c->ssl_state.gnutls_session;
696 gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
697 name_cipher = gnutls_cipher_get_name(cipher);
698 name_mac = gnutls_mac_get_name(gnutls_mac_get(sess));
699 keysize = gnutls_cipher_get_key_size(cipher) * 8;
700 name_proto = gnutls_protocol_get_name(gnutls_protocol_get_version(sess));
701 name_keyexchange = gnutls_kx_get_name(gnutls_kx_get(sess));
703 return snprintf(buf, len, "%s-%s%15s Kx=%s Enc=%s(%u) Mac=%s",
704 name_cipher, name_mac, name_proto, name_keyexchange, name_cipher, keysize, name_mac) > 0;
706 return false;
707 #endif
711 #endif /* SSL_SUPPORT */
712 /* -eof- */