]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/conn-ssl.c
Fix pem_passwd_cb(): unused variable "rwflag" (OpenSSL)
[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", Conf_SSLOptions.DHFile);
165                 ret = false;
166         }
167         fclose(fp);
168         return ret;
169 #endif
170 #ifdef HAVE_LIBGNUTLS
171         bool need_dhgenerate = true;
172         int err;
173         gnutls_dh_params_t tmp_dh_params;
174
175         err = gnutls_dh_params_init(&tmp_dh_params);
176         if (err < 0) {
177                 Log(LOG_ERR, "gnutls_dh_params_init: %s", gnutls_strerror(err));
178                 return false;
179         }
180         if (Conf_SSLOptions.DHFile) {
181                 gnutls_datum_t dhparms;
182                 size_t size;
183                 dhparms.data = (unsigned char *) openreadclose(Conf_SSLOptions.DHFile, &size);
184                 if (dhparms.data) {
185                         dhparms.size = size;
186                         err = gnutls_dh_params_import_pkcs3(tmp_dh_params, &dhparms, GNUTLS_X509_FMT_PEM);
187                         if (err == 0)
188                                 need_dhgenerate = false;
189                         else
190                                 Log(LOG_ERR, "gnutls_dh_params_init: %s", gnutls_strerror(err));
191
192                         memset(dhparms.data, 0, size);
193                         free(dhparms.data);
194                 }
195         }
196         if (need_dhgenerate) {
197                 Log(LOG_WARNING, "SSLDHFile not set, generating %u bit DH parameters. This may take a while...", DH_BITS);
198                 err = gnutls_dh_params_generate2(tmp_dh_params, DH_BITS);
199                 if (err < 0) {
200                         Log(LOG_ERR, "gnutls_dh_params_generate2: %s", gnutls_strerror(err));
201                         return false;
202                 }
203         }
204         dh_params = tmp_dh_params;
205         return true;
206 #endif
207 }
208
209
210 void ConnSSL_Free(CONNECTION *c)
211 {
212 #ifdef HAVE_LIBSSL
213         SSL *ssl = c->ssl_state.ssl;
214         if (ssl) {
215                 SSL_shutdown(ssl);
216                 SSL_free(ssl);
217                 c->ssl_state.ssl = NULL;
218         }
219 #endif
220 #ifdef HAVE_LIBGNUTLS
221         gnutls_session_t sess = c->ssl_state.gnutls_session;
222         if (Conn_OPTION_ISSET(c, CONN_SSL)) {
223                 gnutls_bye(sess, GNUTLS_SHUT_RDWR);
224                 gnutls_deinit(sess);
225         }
226 #endif
227         assert(Conn_OPTION_ISSET(c, CONN_SSL));
228         Conn_OPTION_DEL(c, (CONN_SSL_CONNECT|CONN_SSL|CONN_SSL_WANT_WRITE));
229 }
230
231
232 bool
233 ConnSSL_InitLibrary( void )
234 {
235 #ifdef HAVE_LIBSSL
236         SSL_CTX *newctx;
237
238         if (!ssl_ctx) {
239                 SSL_library_init();
240                 SSL_load_error_strings();
241         }
242
243         if (!RAND_status()) {
244                 Log(LOG_ERR, "OpenSSL PRNG not seeded: /dev/urandom missing?");
245                 /*
246                  * it is probably best to fail and let the user install EGD or a similar program if no kernel random device is available.
247                  * According to OpenSSL RAND_egd(3): "The automatic query of /var/run/egd-pool et al was added in OpenSSL 0.9.7";
248                  * so it makes little sense to deal with PRNGD seeding ourselves.
249                  */
250                 return false;
251         }
252
253         newctx = SSL_CTX_new(SSLv23_method());
254         if (!newctx) {
255                 LogOpenSSLError("SSL_CTX_new()", NULL);
256                 return false;
257         }
258
259         if (!ConnSSL_LoadServerKey_openssl(newctx))
260                 goto out;
261
262         SSL_CTX_set_options(newctx, SSL_OP_SINGLE_DH_USE|SSL_OP_NO_SSLv2);
263         SSL_CTX_set_mode(newctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
264         SSL_CTX_free(ssl_ctx);
265         ssl_ctx = newctx;
266         Log(LOG_INFO, "%s initialized", SSLeay_version(SSLEAY_VERSION));
267         return true;
268 out:
269         SSL_CTX_free(newctx);
270         return false;
271 #endif
272 #ifdef HAVE_LIBGNUTLS
273         int err;
274         static bool initialized;
275         if (initialized) /* TODO: cannot reload gnutls keys: can't simply free x509 context -- it may still be in use */
276                 return false;
277
278         err = gnutls_global_init();
279         if (err) {
280                 Log(LOG_ERR, "gnutls_global_init(): %s", gnutls_strerror(err));
281                 return false;
282         }
283         if (!ConnSSL_LoadServerKey_gnutls())
284                 return false;
285         Log(LOG_INFO, "gnutls %s initialized", gnutls_check_version(NULL));
286         initialized = true;
287         return true;
288 #endif
289 }
290
291
292 #ifdef HAVE_LIBGNUTLS
293 static bool
294 ConnSSL_LoadServerKey_gnutls(void)
295 {
296         int err;
297         const char *cert_file;
298
299         err = gnutls_certificate_allocate_credentials(&x509_cred);
300         if (err < 0) {
301                 Log(LOG_ERR, "gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err));
302                 return false;
303         }
304
305         cert_file = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile;
306         if (!cert_file) {
307                 Log(LOG_ERR, "Neither Key nor certificate File set");
308                 return false;
309         }
310
311         if (array_bytes(&Conf_SSLOptions.KeyFilePassword))
312                 Log(LOG_WARNING, "Ignoring KeyFilePassword: Not supported by GNUTLS");
313
314         if (!Load_DH_params())
315                 return false;
316
317         gnutls_certificate_set_dh_params(x509_cred, dh_params);
318         err = gnutls_certificate_set_x509_key_file(x509_cred, cert_file, Conf_SSLOptions.KeyFile, GNUTLS_X509_FMT_PEM);
319         if (err < 0) {
320                 Log(LOG_ERR, "gnutls_certificate_set_x509_key_file (cert %s, key %s): %s",
321                                 cert_file, Conf_SSLOptions.KeyFile ? Conf_SSLOptions.KeyFile : "(NULL)", gnutls_strerror(err));
322                 return false;
323         }
324         return true;
325 }
326 #endif
327
328
329 #ifdef HAVE_LIBSSL
330 static bool
331 ConnSSL_LoadServerKey_openssl(SSL_CTX *ctx)
332 {
333         char *cert_key;
334
335         assert(ctx);
336         if (!Conf_SSLOptions.KeyFile) {
337                 Log(LOG_NOTICE, "No SSL Server Key configured, ssl disabled");
338                 return false;
339         }
340
341         SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
342         SSL_CTX_set_default_passwd_cb_userdata(ctx, &Conf_SSLOptions.KeyFilePassword);
343
344         if (SSL_CTX_use_PrivateKey_file(ctx, Conf_SSLOptions.KeyFile, SSL_FILETYPE_PEM) != 1) {
345                 array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
346                 LogOpenSSLError("SSL_CTX_use_PrivateKey_file",  Conf_SSLOptions.KeyFile);
347                 return false;
348         }
349
350         cert_key = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile;
351         if (SSL_CTX_use_certificate_chain_file(ctx, cert_key) != 1) {
352                 array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
353                 LogOpenSSLError("SSL_CTX_use_certificate_file", cert_key);
354                 return false;
355         }
356
357         array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
358
359         if (!SSL_CTX_check_private_key(ctx)) {
360                 LogOpenSSLError("Server Private Key does not match certificate", NULL);
361                 return false;
362         }
363         if (Load_DH_params()) {
364                 if (SSL_CTX_set_tmp_dh(ctx, dh_params) != 1)
365                         LogOpenSSLError("Error setting DH Parameters", Conf_SSLOptions.DHFile);
366                 /* don't return false here: the non-DH modes will still work */
367                 DH_free(dh_params);
368                 dh_params = NULL;
369         }
370         return true;
371 }
372
373
374 #endif
375 static bool
376 ConnSSL_Init_SSL(CONNECTION *c)
377 {
378         int ret;
379         assert(c != NULL);
380 #ifdef HAVE_LIBSSL
381         assert(ssl_ctx);
382         if (!ssl_ctx)   /* NULL when library initialization failed */
383                 return false;
384
385         assert(c->ssl_state.ssl == NULL);
386
387         c->ssl_state.ssl = SSL_new(ssl_ctx);
388         if (!c->ssl_state.ssl) {
389                 LogOpenSSLError("SSL_new()", NULL);
390                 return false;
391         }
392
393         ret = SSL_set_fd(c->ssl_state.ssl, c->sock);
394         if (ret != 1) {
395                 LogOpenSSLError("SSL_set_fd()", NULL);
396                 ConnSSL_Free(c);
397                 return false;
398         }
399 #endif
400 #ifdef HAVE_LIBGNUTLS
401         ret = gnutls_set_default_priority(c->ssl_state.gnutls_session);
402         if (ret < 0) {
403                 Log(LOG_ERR, "gnutls_set_default_priority: %s", gnutls_strerror(ret));
404                 ConnSSL_Free(c);
405         }
406         /*
407          * The intermediate (long) cast is here to avoid a warning like:
408          * "cast to pointer from integer of different size" on 64-bit platforms.
409          * There doesn't seem to be an alternate GNUTLS API we could use instead, see e.g.
410          * http://www.mail-archive.com/help-gnutls@gnu.org/msg00286.html
411          */
412         gnutls_transport_set_ptr(c->ssl_state.gnutls_session, (gnutls_transport_ptr_t) (long) c->sock);
413         ret = gnutls_credentials_set(c->ssl_state.gnutls_session, GNUTLS_CRD_CERTIFICATE, x509_cred);
414         if (ret < 0) {
415                 Log(LOG_ERR, "gnutls_credentials_set: %s", gnutls_strerror(ret));
416                 ConnSSL_Free(c);
417         }
418         gnutls_dh_set_prime_bits(c->ssl_state.gnutls_session, DH_BITS);
419 #endif
420         Conn_OPTION_ADD(c, CONN_SSL);
421         return true;
422 }
423
424
425 bool
426 ConnSSL_PrepareConnect(CONNECTION *c, UNUSED CONF_SERVER *s)
427 {
428         bool ret;
429 #ifdef HAVE_LIBGNUTLS
430         int err;
431 #endif
432         assert(c != NULL);
433         assert(s != NULL);
434 #ifdef HAVE_LIBGNUTLS
435         err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_CLIENT);
436         if (err) {
437                 Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err));
438                 return false;
439         }
440 #endif
441         ret = ConnSSL_Init_SSL(c);
442         if (!ret)
443                 return false;
444         Conn_OPTION_ADD(c, CONN_SSL_CONNECT);
445 #ifdef HAVE_LIBSSL
446         assert(c->ssl_state.ssl);
447         SSL_set_verify(c->ssl_state.ssl, SSL_VERIFY_NONE, NULL);
448 #endif
449         return true;
450 }
451
452
453 /*
454   Check an Handle Error return code after failed calls to ssl/tls functions.
455   OpenSSL:
456   SSL_connect(), SSL_accept(), SSL_do_handshake(), SSL_read(), SSL_peek(), or SSL_write() on ssl.
457   GNUTLS:
458   gnutlsssl_read(), gnutls_write() or gnutls_handshake().
459   Return: -1 on fatal error, 0 if we can try again later.
460  */
461 static int
462 ConnSSL_HandleError( CONNECTION *c, const int code, const char *fname )
463 {
464 #ifdef HAVE_LIBSSL
465         int ret = SSL_ERROR_SYSCALL;
466         unsigned long sslerr;
467         int real_errno = errno;
468
469         assert( fname );
470
471         ret = SSL_get_error(c->ssl_state.ssl, code);
472         switch (ret) {
473         case SSL_ERROR_WANT_READ:
474                 io_event_del(c->sock, IO_WANTWRITE);
475                 Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
476                 return 0;       /* try again later */
477         case SSL_ERROR_WANT_WRITE:
478                 io_event_del(c->sock, IO_WANTREAD);
479                 Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */
480         case SSL_ERROR_NONE:
481                 return 0;       /* try again later */
482         case SSL_ERROR_ZERO_RETURN:     /* TLS/SSL Connection was shut down */
483                 LogOpenSSLError("TLS/SSL Connection shutdown", fname);
484                 break;
485         /*
486         SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT, SSL_ERROR_WANT_X509_LOOKUP
487         */
488         case SSL_ERROR_SYSCALL:
489                 sslerr = ERR_get_error();
490                 if (sslerr) {
491                         Log( LOG_ERR, "%s: %s", fname, ERR_error_string(sslerr, NULL ));
492                 } else {
493
494                         switch (code) { /* EOF that violated protocol */
495                         case 0:
496                                 Log(LOG_ERR, "%s: Client Disconnected", fname );
497                                 break;
498                         case -1: /* low level socket I/O error, check errno */
499                                 Log(LOG_ERR, "%s: %s", fname, strerror(real_errno));
500                         }
501                 }
502                 break;
503         case SSL_ERROR_SSL:
504                 LogOpenSSLError("TLS/SSL Protocol Error", fname);
505                 break;
506         default:
507                 Log( LOG_ERR, "%s: Unknown error %d!", fname, ret);
508         }
509         ConnSSL_Free(c);
510         return -1;
511 #endif
512 #ifdef HAVE_LIBGNUTLS
513         switch (code) {
514         case GNUTLS_E_AGAIN:
515         case GNUTLS_E_INTERRUPTED:
516         if (gnutls_record_get_direction(c->ssl_state.gnutls_session)) { /* need write */
517                 io_event_del(c->sock, IO_WANTREAD);
518                 Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */
519                 break;
520         } else { /* need read */
521                 io_event_del(c->sock, IO_WANTWRITE);
522                 Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
523                 break;
524         }
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( c );
545         assert( ssl );
546
547         Log( LOG_INFO, "New %s connection using cipher %s on socket %d",
548                 SSL_get_version(ssl), SSL_get_cipher(ssl), c->sock);
549 #endif
550 #ifdef HAVE_LIBGNUTLS
551         gnutls_session_t sess = c->ssl_state.gnutls_session;
552         gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
553
554         Log( LOG_INFO, "New %s connection using cipher %s-%s on socket %d",
555                 gnutls_protocol_get_name(gnutls_protocol_get_version(sess)),
556                 gnutls_cipher_get_name(cipher), 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 #ifdef HAVE_LIBSSL
573         if (!c->ssl_state.ssl) {
574 #endif
575 #ifdef HAVE_LIBGNUTLS
576         if (!Conn_OPTION_ISSET(c, CONN_SSL)) {
577                 int err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_SERVER);
578                 if (err) {
579                         Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err));
580                         return false;
581                 }
582 #endif
583                 LogDebug("ConnSSL_Accept: Initializing SSL data");
584                 if (!ConnSSL_Init_SSL(c))
585                         return -1;
586         }
587         return ConnectAccept(c, false );
588 }
589
590
591 int
592 ConnSSL_Connect( CONNECTION *c )
593 {
594         assert(c != NULL);
595 #ifdef HAVE_LIBSSL
596         assert(c->ssl_state.ssl);
597 #endif
598 #ifdef HAVE_LIBGNUTLS
599         assert(Conn_OPTION_ISSET(c, CONN_SSL));
600 #endif
601         return ConnectAccept(c, true);
602 }
603
604
605 /* accept/connect wrapper. if connect is true, connect to peer, otherwise wait for incoming connection */
606 static int
607 ConnectAccept( CONNECTION *c, bool connect)
608 {
609         int ret;
610 #ifdef HAVE_LIBSSL
611         SSL *ssl = c->ssl_state.ssl;
612         assert(ssl != NULL);
613
614         ret = connect ? SSL_connect(ssl) : SSL_accept(ssl);
615         if (1 != ret)
616                 return ConnSSL_HandleError(c, ret, connect ? "SSL_connect": "SSL_accept");
617 #endif
618 #ifdef HAVE_LIBGNUTLS
619         (void) connect;
620         assert(Conn_OPTION_ISSET(c, CONN_SSL));
621         ret = gnutls_handshake(c->ssl_state.gnutls_session);
622         if (ret)
623                 return ConnSSL_HandleError(c, ret, "gnutls_handshake");
624 #endif /* _GNUTLS */
625         Conn_OPTION_DEL(c, (CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ|CONN_SSL_CONNECT));
626         ConnSSL_LogCertInfo(c);
627         return 1;
628 }
629
630
631 ssize_t
632 ConnSSL_Write(CONNECTION *c, const void *buf, size_t count)
633 {
634         ssize_t bw;
635
636         Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
637
638         assert(count > 0);
639 #ifdef HAVE_LIBSSL
640         bw = (ssize_t) SSL_write(c->ssl_state.ssl, buf, count);
641 #endif
642 #ifdef HAVE_LIBGNUTLS
643         bw = gnutls_write(c->ssl_state.gnutls_session, buf, count);
644 #endif
645         if ( bw > 0 ) return bw;
646         if (ConnSSL_HandleError( c, bw, "ConnSSL_Write") == 0)
647                 errno = EAGAIN; /* try again */
648         return -1;
649 }
650
651
652 ssize_t
653 ConnSSL_Read(CONNECTION *c, void * buf, size_t count)
654 {
655         ssize_t br;
656
657         Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
658 #ifdef HAVE_LIBSSL
659         br = (ssize_t) SSL_read(c->ssl_state.ssl, buf, count);
660         if (br > 0)     /* on EOF we have to call ConnSSL_HandleError(), see SSL_read(3) */
661                 return br;
662 #endif
663 #ifdef HAVE_LIBGNUTLS
664         br = gnutls_read(c->ssl_state.gnutls_session, buf, count);
665         if (br >= 0)    /* on EOF we must _not_ call ConnSSL_HandleError, see gnutls_record_recv(3) */
666                 return br;
667 #endif
668         /* error on read: switch ConnSSL_HandleError() return values -> 0 is "try again", so return -1 and set EAGAIN */
669         if (ConnSSL_HandleError(c, br, "ConnSSL_Read") == 0) {
670                 errno = EAGAIN;
671                 return -1;
672         }
673         return 0;
674 }
675
676
677 bool
678 ConnSSL_GetCipherInfo(CONNECTION *c, char *buf, size_t len)
679 {
680 #ifdef HAVE_LIBSSL
681         char *nl;
682
683         SSL *ssl;
684         assert(c != NULL);
685         assert(len >= 128);
686         ssl = c->ssl_state.ssl;
687         if (!ssl)
688                 return false;
689         *buf = 0;
690         SSL_CIPHER_description(SSL_get_current_cipher(ssl), buf, len);
691         nl = strchr(buf, '\n');
692         if (nl)
693                 *nl = 0;
694         return true;
695 #endif
696 #ifdef HAVE_LIBGNUTLS
697         assert(c != NULL);
698         assert(len >= 128);
699         if (Conn_OPTION_ISSET(c, CONN_SSL)) {
700                 const char *name_cipher, *name_mac, *name_proto, *name_keyexchange;
701                 unsigned keysize;
702
703                 gnutls_session_t sess = c->ssl_state.gnutls_session;
704                 gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
705                 name_cipher = gnutls_cipher_get_name(cipher);
706                 name_mac = gnutls_mac_get_name(gnutls_mac_get(sess));
707                 keysize = gnutls_cipher_get_key_size(cipher) * 8;
708                 name_proto = gnutls_protocol_get_name(gnutls_protocol_get_version(sess));
709                 name_keyexchange = gnutls_kx_get_name(gnutls_kx_get(sess));
710
711                 return snprintf(buf, len, "%s-%s%15s Kx=%s      Enc=%s(%u) Mac=%s",
712                         name_cipher, name_mac, name_proto, name_keyexchange, name_cipher, keysize, name_mac) > 0;
713         }
714         return false;
715 #endif
716 }
717
718
719 #endif /* SSL_SUPPORT */
720 /* -eof- */
721
722