]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/conn-ssl.c
SSL/TLS: fix error path in gnutls ssl ctx allocation
[ngircd-alex.git] / src / ngircd / conn-ssl.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  *
4  * SSL wrapper functions.
5  * Copyright (c) 2005-2008 Florian Westphal <fw@strlen.de>
6  */
7
8 #include "portab.h"
9 #include "imp.h"
10 #include "conf-ssl.h"
11
12 #ifdef SSL_SUPPORT
13
14 #include "io.h"
15 #include <assert.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <errno.h>
20
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"
27
28 #include "exp.h"
29 #include "defines.h"
30
31 extern struct SSLOptions Conf_SSLOptions;
32
33 #ifdef HAVE_LIBSSL
34 #include <openssl/err.h>
35 #include <openssl/rand.h>
36
37 static SSL_CTX * ssl_ctx;
38 static DH *dh_params;
39
40 static bool ConnSSL_LoadServerKey_openssl PARAMS(( SSL_CTX *c ));
41 #endif
42
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>
49
50 #define DH_BITS 1024
51 static gnutls_certificate_credentials_t x509_cred;
52 static gnutls_dh_params_t dh_params;
53
54 static bool ConnSSL_LoadServerKey_gnutls PARAMS(( void ));
55 #endif
56
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 ));
60
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;
102 }
103 #endif
104
105
106 #ifdef HAVE_LIBSSL
107 static void
108 LogOpenSSLError( const char *msg, const char *msg2 )
109 {
110         unsigned long err = ERR_get_error();
111         char * errmsg = err ? ERR_error_string(err, NULL) : "Unable to determine error";
112
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);
118 }
119
120
121 static int
122 pem_passwd_cb(char *buf, int size, int rwflag, void *password)
123 {
124         array *pass = password;
125         int passlen;
126
127         (void)rwflag;           /* rwflag is unused if DEBUG is not set. */
128         assert(rwflag == 0);    /* 0 -> callback used for decryption.
129                                  * See SSL_CTX_set_default_passwd_cb(3) */
130
131         passlen = (int) array_bytes(pass);
132
133         LogDebug("pem_passwd_cb buf size %d, array size %d", size, passlen);
134         assert(passlen >= 0);
135         if (passlen <= 0) {
136                 Log(LOG_ERR, "pem_passwd_cb: password required, but not set");
137                 return 0;
138         }
139         size = passlen > size ? size : passlen;
140         memcpy(buf, (char *)(array_start(pass)), size);
141         return size;
142 }
143 #endif
144
145
146 static bool
147 Load_DH_params(void)
148 {
149 #ifdef HAVE_LIBSSL
150         FILE *fp;
151         bool ret = true;
152
153         if (!Conf_SSLOptions.DHFile) {
154                 Log(LOG_NOTICE, "Configuration option \"SSLDHFile\" not set!");
155                 return false;
156         }
157         fp = fopen(Conf_SSLOptions.DHFile, "r");
158         if (!fp) {
159                 Log(LOG_ERR, "%s: %s", Conf_SSLOptions.DHFile, strerror(errno));
160                 return false;
161         }
162         dh_params = PEM_read_DHparams(fp, NULL, NULL, NULL);
163         if (!dh_params) {
164                 Log(LOG_ERR, "%s: PEM_read_DHparams failed!",
165                     Conf_SSLOptions.DHFile);
166                 ret = false;
167         }
168         fclose(fp);
169         return ret;
170 #endif
171 #ifdef HAVE_LIBGNUTLS
172         bool need_dhgenerate = true;
173         int err;
174         gnutls_dh_params_t tmp_dh_params;
175
176         err = gnutls_dh_params_init(&tmp_dh_params);
177         if (err < 0) {
178                 Log(LOG_ERR, "gnutls_dh_params_init: %s", gnutls_strerror(err));
179                 return false;
180         }
181         if (Conf_SSLOptions.DHFile) {
182                 gnutls_datum_t dhparms;
183                 size_t size;
184                 dhparms.data = (unsigned char *) openreadclose(Conf_SSLOptions.DHFile, &size);
185                 if (dhparms.data) {
186                         dhparms.size = size;
187                         err = gnutls_dh_params_import_pkcs3(tmp_dh_params, &dhparms, GNUTLS_X509_FMT_PEM);
188                         if (err == 0)
189                                 need_dhgenerate = false;
190                         else
191                                 Log(LOG_ERR, "gnutls_dh_params_init: %s", gnutls_strerror(err));
192
193                         memset(dhparms.data, 0, size);
194                         free(dhparms.data);
195                 }
196         }
197         if (need_dhgenerate) {
198                 Log(LOG_WARNING,
199                     "SSLDHFile not set, generating %u bit DH parameters. This may take a while ...",
200                     DH_BITS);
201                 err = gnutls_dh_params_generate2(tmp_dh_params, DH_BITS);
202                 if (err < 0) {
203                         Log(LOG_ERR, "gnutls_dh_params_generate2: %s", gnutls_strerror(err));
204                         return false;
205                 }
206         }
207         dh_params = tmp_dh_params;
208         return true;
209 #endif
210 }
211
212
213 void ConnSSL_Free(CONNECTION *c)
214 {
215 #ifdef HAVE_LIBSSL
216         SSL *ssl = c->ssl_state.ssl;
217         if (ssl) {
218                 SSL_shutdown(ssl);
219                 SSL_free(ssl);
220                 c->ssl_state.ssl = NULL;
221         }
222 #endif
223 #ifdef HAVE_LIBGNUTLS
224         gnutls_session_t sess = c->ssl_state.gnutls_session;
225         if (Conn_OPTION_ISSET(c, CONN_SSL)) {
226                 gnutls_bye(sess, GNUTLS_SHUT_RDWR);
227                 gnutls_deinit(sess);
228         }
229 #endif
230         assert(Conn_OPTION_ISSET(c, CONN_SSL));
231         /* can't just set bitmask to 0 -- there are other, non-ssl related flags, e.g. CONN_ZIP. */
232         Conn_OPTION_DEL(c, CONN_SSL_FLAGS_ALL);
233 }
234
235
236 bool
237 ConnSSL_InitLibrary( void )
238 {
239 #ifdef HAVE_LIBSSL
240         SSL_CTX *newctx;
241
242         if (!ssl_ctx) {
243                 SSL_library_init();
244                 SSL_load_error_strings();
245         }
246
247         if (!RAND_status()) {
248                 Log(LOG_ERR, "OpenSSL PRNG not seeded: /dev/urandom missing?");
249                 /*
250                  * it is probably best to fail and let the user install EGD or a similar program if no kernel random device is available.
251                  * According to OpenSSL RAND_egd(3): "The automatic query of /var/run/egd-pool et al was added in OpenSSL 0.9.7";
252                  * so it makes little sense to deal with PRNGD seeding ourselves.
253                  */
254                 return false;
255         }
256
257         newctx = SSL_CTX_new(SSLv23_method());
258         if (!newctx) {
259                 LogOpenSSLError("SSL_CTX_new()", NULL);
260                 return false;
261         }
262
263         if (!ConnSSL_LoadServerKey_openssl(newctx))
264                 goto out;
265
266         SSL_CTX_set_options(newctx, SSL_OP_SINGLE_DH_USE|SSL_OP_NO_SSLv2);
267         SSL_CTX_set_mode(newctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
268         SSL_CTX_free(ssl_ctx);
269         ssl_ctx = newctx;
270         Log(LOG_INFO, "%s initialized.", SSLeay_version(SSLEAY_VERSION));
271         return true;
272 out:
273         SSL_CTX_free(newctx);
274         return false;
275 #endif
276 #ifdef HAVE_LIBGNUTLS
277         int err;
278         static bool initialized;
279         if (initialized) /* TODO: cannot reload gnutls keys: can't simply free x509 context -- it may still be in use */
280                 return false;
281
282         err = gnutls_global_init();
283         if (err) {
284                 Log(LOG_ERR, "gnutls_global_init(): %s", gnutls_strerror(err));
285                 return false;
286         }
287         if (!ConnSSL_LoadServerKey_gnutls())
288                 return false;
289         Log(LOG_INFO, "gnutls %s initialized.", gnutls_check_version(NULL));
290         initialized = true;
291         return true;
292 #endif
293 }
294
295
296 #ifdef HAVE_LIBGNUTLS
297 static bool
298 ConnSSL_LoadServerKey_gnutls(void)
299 {
300         int err;
301         const char *cert_file;
302
303         err = gnutls_certificate_allocate_credentials(&x509_cred);
304         if (err < 0) {
305                 Log(LOG_ERR, "gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err));
306                 return false;
307         }
308
309         cert_file = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile;
310         if (!cert_file) {
311                 Log(LOG_NOTICE, "No SSL server key configured, SSL disabled.");
312                 return false;
313         }
314
315         if (array_bytes(&Conf_SSLOptions.KeyFilePassword))
316                 Log(LOG_WARNING,
317                     "Ignoring KeyFilePassword: Not supported by GNUTLS.");
318
319         if (!Load_DH_params())
320                 return false;
321
322         gnutls_certificate_set_dh_params(x509_cred, dh_params);
323         err = gnutls_certificate_set_x509_key_file(x509_cred, cert_file, Conf_SSLOptions.KeyFile, GNUTLS_X509_FMT_PEM);
324         if (err < 0) {
325                 Log(LOG_ERR, "gnutls_certificate_set_x509_key_file (cert %s, key %s): %s",
326                                 cert_file, Conf_SSLOptions.KeyFile ? Conf_SSLOptions.KeyFile : "(NULL)", gnutls_strerror(err));
327                 return false;
328         }
329         return true;
330 }
331 #endif
332
333
334 #ifdef HAVE_LIBSSL
335 static bool
336 ConnSSL_LoadServerKey_openssl(SSL_CTX *ctx)
337 {
338         char *cert_key;
339
340         assert(ctx);
341         if (!Conf_SSLOptions.KeyFile) {
342                 Log(LOG_NOTICE, "No SSL server key configured, SSL disabled.");
343                 return false;
344         }
345
346         SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
347         SSL_CTX_set_default_passwd_cb_userdata(ctx, &Conf_SSLOptions.KeyFilePassword);
348
349         if (SSL_CTX_use_PrivateKey_file(ctx, Conf_SSLOptions.KeyFile, SSL_FILETYPE_PEM) != 1) {
350                 array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
351                 LogOpenSSLError("SSL_CTX_use_PrivateKey_file",  Conf_SSLOptions.KeyFile);
352                 return false;
353         }
354
355         cert_key = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile;
356         if (SSL_CTX_use_certificate_chain_file(ctx, cert_key) != 1) {
357                 array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
358                 LogOpenSSLError("SSL_CTX_use_certificate_file", cert_key);
359                 return false;
360         }
361
362         array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
363
364         if (!SSL_CTX_check_private_key(ctx)) {
365                 LogOpenSSLError("Server Private Key does not match certificate", NULL);
366                 return false;
367         }
368         if (Load_DH_params()) {
369                 if (SSL_CTX_set_tmp_dh(ctx, dh_params) != 1)
370                         LogOpenSSLError("Error setting DH Parameters", Conf_SSLOptions.DHFile);
371                 /* don't return false here: the non-DH modes will still work */
372                 DH_free(dh_params);
373                 dh_params = NULL;
374         }
375         return true;
376 }
377
378
379 #endif
380 static bool
381 ConnSSL_Init_SSL(CONNECTION *c)
382 {
383         int ret;
384         assert(c != NULL);
385 #ifdef HAVE_LIBSSL
386         if (!ssl_ctx)   /* NULL when library initialization failed */
387                 return false;
388
389         assert(c->ssl_state.ssl == NULL);
390
391         c->ssl_state.ssl = SSL_new(ssl_ctx);
392         if (!c->ssl_state.ssl) {
393                 LogOpenSSLError("SSL_new()", NULL);
394                 return false;
395         }
396
397         ret = SSL_set_fd(c->ssl_state.ssl, c->sock);
398         if (ret != 1) {
399                 LogOpenSSLError("SSL_set_fd()", NULL);
400                 ConnSSL_Free(c);
401                 return false;
402         }
403 #endif
404 #ifdef HAVE_LIBGNUTLS
405         ret = gnutls_set_default_priority(c->ssl_state.gnutls_session);
406         if (ret < 0) {
407                 Log(LOG_ERR, "gnutls_set_default_priority: %s", gnutls_strerror(ret));
408                 ConnSSL_Free(c);
409                 return false;
410         }
411         /*
412          * The intermediate (long) cast is here to avoid a warning like:
413          * "cast to pointer from integer of different size" on 64-bit platforms.
414          * There doesn't seem to be an alternate GNUTLS API we could use instead, see e.g.
415          * http://www.mail-archive.com/help-gnutls@gnu.org/msg00286.html
416          */
417         gnutls_transport_set_ptr(c->ssl_state.gnutls_session, (gnutls_transport_ptr_t) (long) c->sock);
418         ret = gnutls_credentials_set(c->ssl_state.gnutls_session, GNUTLS_CRD_CERTIFICATE, x509_cred);
419         if (ret < 0) {
420                 Log(LOG_ERR, "gnutls_credentials_set: %s", gnutls_strerror(ret));
421                 ConnSSL_Free(c);
422                 return false;
423         }
424         gnutls_dh_set_prime_bits(c->ssl_state.gnutls_session, DH_BITS);
425 #endif
426         Conn_OPTION_ADD(c, CONN_SSL);
427         return true;
428 }
429
430
431 bool
432 ConnSSL_PrepareConnect(CONNECTION *c, UNUSED CONF_SERVER *s)
433 {
434         bool ret;
435 #ifdef HAVE_LIBGNUTLS
436         int err;
437
438         err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_CLIENT);
439         if (err) {
440                 Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err));
441                 return false;
442         }
443 #endif
444         ret = ConnSSL_Init_SSL(c);
445         if (!ret)
446                 return false;
447         Conn_OPTION_ADD(c, CONN_SSL_CONNECT);
448 #ifdef HAVE_LIBSSL
449         assert(c->ssl_state.ssl);
450         SSL_set_verify(c->ssl_state.ssl, SSL_VERIFY_NONE, NULL);
451 #endif
452         return true;
453 }
454
455
456 /*
457   Check an Handle Error return code after failed calls to ssl/tls functions.
458   OpenSSL:
459   SSL_connect(), SSL_accept(), SSL_do_handshake(), SSL_read(), SSL_peek(), or SSL_write() on ssl.
460   GNUTLS:
461   gnutlsssl_read(), gnutls_write() or gnutls_handshake().
462   Return: -1 on fatal error, 0 if we can try again later.
463  */
464 static int
465 ConnSSL_HandleError( CONNECTION *c, const int code, const char *fname )
466 {
467 #ifdef HAVE_LIBSSL
468         int ret = SSL_ERROR_SYSCALL;
469         unsigned long sslerr;
470         int real_errno = errno;
471
472         ret = SSL_get_error(c->ssl_state.ssl, code);
473         switch (ret) {
474         case SSL_ERROR_WANT_READ:
475                 io_event_del(c->sock, IO_WANTWRITE);
476                 Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
477                 return 0;       /* try again later */
478         case SSL_ERROR_WANT_WRITE:
479                 io_event_del(c->sock, IO_WANTREAD);
480                 Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */
481         case SSL_ERROR_NONE:
482                 return 0;       /* try again later */
483         case SSL_ERROR_ZERO_RETURN:
484                 LogDebug("TLS/SSL connection shut down normally");
485                 break;
486         /*
487         SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT, SSL_ERROR_WANT_X509_LOOKUP
488         */
489         case SSL_ERROR_SYSCALL:
490                 sslerr = ERR_get_error();
491                 if (sslerr) {
492                         Log( LOG_ERR, "%s: %s", fname, ERR_error_string(sslerr, NULL ));
493                 } else {
494
495                         switch (code) { /* EOF that violated protocol */
496                         case 0:
497                                 Log(LOG_ERR, "%s: Client Disconnected", fname );
498                                 break;
499                         case -1: /* low level socket I/O error, check errno */
500                                 Log(LOG_ERR, "%s: %s", fname, strerror(real_errno));
501                         }
502                 }
503                 break;
504         case SSL_ERROR_SSL:
505                 LogOpenSSLError("TLS/SSL Protocol Error", fname);
506                 break;
507         default:
508                 Log( LOG_ERR, "%s: Unknown error %d!", fname, ret);
509         }
510         ConnSSL_Free(c);
511         return -1;
512 #endif
513 #ifdef HAVE_LIBGNUTLS
514         switch (code) {
515         case GNUTLS_E_AGAIN:
516         case GNUTLS_E_INTERRUPTED:
517                 if (gnutls_record_get_direction(c->ssl_state.gnutls_session)) {
518                         Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE);
519                         io_event_del(c->sock, IO_WANTREAD);
520                 } else {
521                         Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
522                         io_event_del(c->sock, IO_WANTWRITE);
523                 }
524                 break;
525         default:
526                 assert(code < 0);
527                 if (gnutls_error_is_fatal(code)) {
528                         Log(LOG_ERR, "%s: %s", fname, gnutls_strerror(code));
529                         ConnSSL_Free(c);
530                         return -1;
531                 }
532         }
533         return 0;
534 #endif
535 }
536
537
538 static void
539 ConnSSL_LogCertInfo( CONNECTION *c )
540 {
541 #ifdef HAVE_LIBSSL
542         SSL *ssl = c->ssl_state.ssl;
543
544         assert(ssl);
545
546         Log(LOG_INFO, "New %s connection using cipher %s on socket %d.",
547                 SSL_get_version(ssl), SSL_get_cipher(ssl), c->sock);
548 #endif
549 #ifdef HAVE_LIBGNUTLS
550         gnutls_session_t sess = c->ssl_state.gnutls_session;
551         gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
552
553         Log(LOG_INFO, "New %s connection using cipher %s-%s on socket %d.",
554             gnutls_protocol_get_name(gnutls_protocol_get_version(sess)),
555             gnutls_cipher_get_name(cipher),
556             gnutls_mac_get_name(gnutls_mac_get(sess)), c->sock);
557 #endif
558 }
559
560
561 /*
562  Accept incoming SSL connection.
563  Return Values:
564          1: SSL Connection established
565          0: try again
566         -1: SSL Connection not established due to fatal error.
567 */
568 int
569 ConnSSL_Accept( CONNECTION *c )
570 {
571         assert(c != NULL);
572         if (!Conn_OPTION_ISSET(c, CONN_SSL)) {
573 #ifdef HAVE_LIBGNUTLS
574                 int err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_SERVER);
575                 if (err) {
576                         Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err));
577                         return false;
578                 }
579 #endif
580                 LogDebug("ConnSSL_Accept: Initializing SSL data");
581                 if (!ConnSSL_Init_SSL(c))
582                         return -1;
583         }
584         return ConnectAccept(c, false );
585 }
586
587
588 int
589 ConnSSL_Connect( CONNECTION *c )
590 {
591         assert(c != NULL);
592 #ifdef HAVE_LIBSSL
593         assert(c->ssl_state.ssl);
594 #endif
595         assert(Conn_OPTION_ISSET(c, CONN_SSL));
596         return ConnectAccept(c, true);
597 }
598
599
600 /* accept/connect wrapper. if connect is true, connect to peer, otherwise wait for incoming connection */
601 static int
602 ConnectAccept( CONNECTION *c, bool connect)
603 {
604         int ret;
605 #ifdef HAVE_LIBSSL
606         SSL *ssl = c->ssl_state.ssl;
607         assert(ssl != NULL);
608
609         ret = connect ? SSL_connect(ssl) : SSL_accept(ssl);
610         if (1 != ret)
611                 return ConnSSL_HandleError(c, ret, connect ? "SSL_connect": "SSL_accept");
612 #endif
613 #ifdef HAVE_LIBGNUTLS
614         (void) connect;
615         ret = gnutls_handshake(c->ssl_state.gnutls_session);
616         if (ret)
617                 return ConnSSL_HandleError(c, ret, "gnutls_handshake");
618 #endif /* _GNUTLS */
619         Conn_OPTION_DEL(c, (CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ|CONN_SSL_CONNECT));
620         ConnSSL_LogCertInfo(c);
621         return 1;
622 }
623
624
625 ssize_t
626 ConnSSL_Write(CONNECTION *c, const void *buf, size_t count)
627 {
628         ssize_t bw;
629
630         Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
631
632         assert(count > 0);
633 #ifdef HAVE_LIBSSL
634         bw = (ssize_t) SSL_write(c->ssl_state.ssl, buf, count);
635 #endif
636 #ifdef HAVE_LIBGNUTLS
637         bw = gnutls_write(c->ssl_state.gnutls_session, buf, count);
638 #endif
639         if (bw > 0)
640                 return bw;
641         if (ConnSSL_HandleError( c, bw, "ConnSSL_Write") == 0)
642                 errno = EAGAIN; /* try again */
643         return -1;
644 }
645
646
647 ssize_t
648 ConnSSL_Read(CONNECTION *c, void * buf, size_t count)
649 {
650         ssize_t br;
651
652         Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
653 #ifdef HAVE_LIBSSL
654         br = (ssize_t) SSL_read(c->ssl_state.ssl, buf, count);
655         if (br > 0)     /* on EOF we have to call ConnSSL_HandleError(), see SSL_read(3) */
656                 return br;
657 #endif
658 #ifdef HAVE_LIBGNUTLS
659         br = gnutls_read(c->ssl_state.gnutls_session, buf, count);
660         if (br >= 0)    /* on EOF we must _not_ call ConnSSL_HandleError, see gnutls_record_recv(3) */
661                 return br;
662 #endif
663         /* error on read: switch ConnSSL_HandleError() return values -> 0 is "try again", so return -1 and set EAGAIN */
664         if (ConnSSL_HandleError(c, br, "ConnSSL_Read") == 0) {
665                 errno = EAGAIN;
666                 return -1;
667         }
668         return 0;
669 }
670
671
672 bool
673 ConnSSL_GetCipherInfo(CONNECTION *c, char *buf, size_t len)
674 {
675 #ifdef HAVE_LIBSSL
676         char *nl;
677         SSL *ssl = c->ssl_state.ssl;
678
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         if (Conn_OPTION_ISSET(c, CONN_SSL)) {
690                 const char *name_cipher, *name_mac, *name_proto, *name_keyexchange;
691                 unsigned keysize;
692
693                 gnutls_session_t sess = c->ssl_state.gnutls_session;
694                 gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
695                 name_cipher = gnutls_cipher_get_name(cipher);
696                 name_mac = gnutls_mac_get_name(gnutls_mac_get(sess));
697                 keysize = gnutls_cipher_get_key_size(cipher) * 8;
698                 name_proto = gnutls_protocol_get_name(gnutls_protocol_get_version(sess));
699                 name_keyexchange = gnutls_kx_get_name(gnutls_kx_get(sess));
700
701                 return snprintf(buf, len, "%s-%s%15s Kx=%s      Enc=%s(%u) Mac=%s",
702                         name_cipher, name_mac, name_proto, name_keyexchange, name_cipher, keysize, name_mac) > 0;
703         }
704         return false;
705 #endif
706 }
707
708
709 #endif /* SSL_SUPPORT */
710 /* -eof- */
711
712