]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/conn-ssl.c
fbf796c79ab3f41da09269abb1d615f06810eb64
[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         }
410         /*
411          * The intermediate (long) cast is here to avoid a warning like:
412          * "cast to pointer from integer of different size" on 64-bit platforms.
413          * There doesn't seem to be an alternate GNUTLS API we could use instead, see e.g.
414          * http://www.mail-archive.com/help-gnutls@gnu.org/msg00286.html
415          */
416         gnutls_transport_set_ptr(c->ssl_state.gnutls_session, (gnutls_transport_ptr_t) (long) c->sock);
417         ret = gnutls_credentials_set(c->ssl_state.gnutls_session, GNUTLS_CRD_CERTIFICATE, x509_cred);
418         if (ret < 0) {
419                 Log(LOG_ERR, "gnutls_credentials_set: %s", gnutls_strerror(ret));
420                 ConnSSL_Free(c);
421         }
422         gnutls_dh_set_prime_bits(c->ssl_state.gnutls_session, DH_BITS);
423 #endif
424         Conn_OPTION_ADD(c, CONN_SSL);
425         return true;
426 }
427
428
429 bool
430 ConnSSL_PrepareConnect(CONNECTION *c, UNUSED CONF_SERVER *s)
431 {
432         bool ret;
433 #ifdef HAVE_LIBGNUTLS
434         int err;
435
436         err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_CLIENT);
437         if (err) {
438                 Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err));
439                 return false;
440         }
441 #endif
442         ret = ConnSSL_Init_SSL(c);
443         if (!ret)
444                 return false;
445         Conn_OPTION_ADD(c, CONN_SSL_CONNECT);
446 #ifdef HAVE_LIBSSL
447         assert(c->ssl_state.ssl);
448         SSL_set_verify(c->ssl_state.ssl, SSL_VERIFY_NONE, NULL);
449 #endif
450         return true;
451 }
452
453
454 /*
455   Check an Handle Error return code after failed calls to ssl/tls functions.
456   OpenSSL:
457   SSL_connect(), SSL_accept(), SSL_do_handshake(), SSL_read(), SSL_peek(), or SSL_write() on ssl.
458   GNUTLS:
459   gnutlsssl_read(), gnutls_write() or gnutls_handshake().
460   Return: -1 on fatal error, 0 if we can try again later.
461  */
462 static int
463 ConnSSL_HandleError( CONNECTION *c, const int code, const char *fname )
464 {
465 #ifdef HAVE_LIBSSL
466         int ret = SSL_ERROR_SYSCALL;
467         unsigned long sslerr;
468         int real_errno = errno;
469
470         ret = SSL_get_error(c->ssl_state.ssl, code);
471         switch (ret) {
472         case SSL_ERROR_WANT_READ:
473                 io_event_del(c->sock, IO_WANTWRITE);
474                 Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
475                 return 0;       /* try again later */
476         case SSL_ERROR_WANT_WRITE:
477                 io_event_del(c->sock, IO_WANTREAD);
478                 Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */
479         case SSL_ERROR_NONE:
480                 return 0;       /* try again later */
481         case SSL_ERROR_ZERO_RETURN:
482                 LogDebug("TLS/SSL connection shut down normally");
483                 break;
484         /*
485         SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT, SSL_ERROR_WANT_X509_LOOKUP
486         */
487         case SSL_ERROR_SYSCALL:
488                 sslerr = ERR_get_error();
489                 if (sslerr) {
490                         Log( LOG_ERR, "%s: %s", fname, ERR_error_string(sslerr, NULL ));
491                 } else {
492
493                         switch (code) { /* EOF that violated protocol */
494                         case 0:
495                                 Log(LOG_ERR, "%s: Client Disconnected", fname );
496                                 break;
497                         case -1: /* low level socket I/O error, check errno */
498                                 Log(LOG_ERR, "%s: %s", fname, strerror(real_errno));
499                         }
500                 }
501                 break;
502         case SSL_ERROR_SSL:
503                 LogOpenSSLError("TLS/SSL Protocol Error", fname);
504                 break;
505         default:
506                 Log( LOG_ERR, "%s: Unknown error %d!", fname, ret);
507         }
508         ConnSSL_Free(c);
509         return -1;
510 #endif
511 #ifdef HAVE_LIBGNUTLS
512         switch (code) {
513         case GNUTLS_E_AGAIN:
514         case GNUTLS_E_INTERRUPTED:
515                 if (gnutls_record_get_direction(c->ssl_state.gnutls_session)) {
516                         Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE);
517                         io_event_del(c->sock, IO_WANTREAD);
518                 } else {
519                         Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
520                         io_event_del(c->sock, IO_WANTWRITE);
521                 }
522                 break;
523         default:
524                 assert(code < 0);
525                 if (gnutls_error_is_fatal(code)) {
526                         Log(LOG_ERR, "%s: %s", fname, gnutls_strerror(code));
527                         ConnSSL_Free(c);
528                         return -1;
529                 }
530         }
531         return 0;
532 #endif
533 }
534
535
536 static void
537 ConnSSL_LogCertInfo( CONNECTION *c )
538 {
539 #ifdef HAVE_LIBSSL
540         SSL *ssl = c->ssl_state.ssl;
541
542         assert(ssl);
543
544         Log(LOG_INFO, "New %s connection using cipher %s on socket %d.",
545                 SSL_get_version(ssl), SSL_get_cipher(ssl), c->sock);
546 #endif
547 #ifdef HAVE_LIBGNUTLS
548         gnutls_session_t sess = c->ssl_state.gnutls_session;
549         gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
550
551         Log(LOG_INFO, "New %s connection using cipher %s-%s on socket %d.",
552             gnutls_protocol_get_name(gnutls_protocol_get_version(sess)),
553             gnutls_cipher_get_name(cipher),
554             gnutls_mac_get_name(gnutls_mac_get(sess)), c->sock);
555 #endif
556 }
557
558
559 /*
560  Accept incoming SSL connection.
561  Return Values:
562          1: SSL Connection established
563          0: try again
564         -1: SSL Connection not established due to fatal error.
565 */
566 int
567 ConnSSL_Accept( CONNECTION *c )
568 {
569         assert(c != NULL);
570         if (!Conn_OPTION_ISSET(c, CONN_SSL)) {
571 #ifdef HAVE_LIBGNUTLS
572                 int err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_SERVER);
573                 if (err) {
574                         Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err));
575                         return false;
576                 }
577 #endif
578                 LogDebug("ConnSSL_Accept: Initializing SSL data");
579                 if (!ConnSSL_Init_SSL(c))
580                         return -1;
581         }
582         return ConnectAccept(c, false );
583 }
584
585
586 int
587 ConnSSL_Connect( CONNECTION *c )
588 {
589         assert(c != NULL);
590 #ifdef HAVE_LIBSSL
591         assert(c->ssl_state.ssl);
592 #endif
593         assert(Conn_OPTION_ISSET(c, CONN_SSL));
594         return ConnectAccept(c, true);
595 }
596
597
598 /* accept/connect wrapper. if connect is true, connect to peer, otherwise wait for incoming connection */
599 static int
600 ConnectAccept( CONNECTION *c, bool connect)
601 {
602         int ret;
603 #ifdef HAVE_LIBSSL
604         SSL *ssl = c->ssl_state.ssl;
605         assert(ssl != NULL);
606
607         ret = connect ? SSL_connect(ssl) : SSL_accept(ssl);
608         if (1 != ret)
609                 return ConnSSL_HandleError(c, ret, connect ? "SSL_connect": "SSL_accept");
610 #endif
611 #ifdef HAVE_LIBGNUTLS
612         (void) connect;
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;
620 }
621
622
623 ssize_t
624 ConnSSL_Write(CONNECTION *c, const void *buf, size_t count)
625 {
626         ssize_t bw;
627
628         Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
629
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)
638                 return bw;
639         if (ConnSSL_HandleError( c, bw, "ConnSSL_Write") == 0)
640                 errno = EAGAIN; /* try again */
641         return -1;
642 }
643
644
645 ssize_t
646 ConnSSL_Read(CONNECTION *c, void * buf, size_t count)
647 {
648         ssize_t br;
649
650         Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
651 #ifdef HAVE_LIBSSL
652         br = (ssize_t) SSL_read(c->ssl_state.ssl, buf, count);
653         if (br > 0)     /* on EOF we have to call ConnSSL_HandleError(), see SSL_read(3) */
654                 return br;
655 #endif
656 #ifdef HAVE_LIBGNUTLS
657         br = gnutls_read(c->ssl_state.gnutls_session, buf, count);
658         if (br >= 0)    /* on EOF we must _not_ call ConnSSL_HandleError, see gnutls_record_recv(3) */
659                 return br;
660 #endif
661         /* error on read: switch ConnSSL_HandleError() return values -> 0 is "try again", so return -1 and set EAGAIN */
662         if (ConnSSL_HandleError(c, br, "ConnSSL_Read") == 0) {
663                 errno = EAGAIN;
664                 return -1;
665         }
666         return 0;
667 }
668
669
670 bool
671 ConnSSL_GetCipherInfo(CONNECTION *c, char *buf, size_t len)
672 {
673 #ifdef HAVE_LIBSSL
674         char *nl;
675         SSL *ssl = c->ssl_state.ssl;
676
677         if (!ssl)
678                 return false;
679         *buf = 0;
680         SSL_CIPHER_description(SSL_get_current_cipher(ssl), buf, len);
681         nl = strchr(buf, '\n');
682         if (nl)
683                 *nl = 0;
684         return true;
685 #endif
686 #ifdef HAVE_LIBGNUTLS
687         if (Conn_OPTION_ISSET(c, CONN_SSL)) {
688                 const char *name_cipher, *name_mac, *name_proto, *name_keyexchange;
689                 unsigned keysize;
690
691                 gnutls_session_t sess = c->ssl_state.gnutls_session;
692                 gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
693                 name_cipher = gnutls_cipher_get_name(cipher);
694                 name_mac = gnutls_mac_get_name(gnutls_mac_get(sess));
695                 keysize = gnutls_cipher_get_key_size(cipher) * 8;
696                 name_proto = gnutls_protocol_get_name(gnutls_protocol_get_version(sess));
697                 name_keyexchange = gnutls_kx_get_name(gnutls_kx_get(sess));
698
699                 return snprintf(buf, len, "%s-%s%15s Kx=%s      Enc=%s(%u) Mac=%s",
700                         name_cipher, name_mac, name_proto, name_keyexchange, name_cipher, keysize, name_mac) > 0;
701         }
702         return false;
703 #endif
704 }
705
706
707 #endif /* SSL_SUPPORT */
708 /* -eof- */
709
710