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