]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/conn-ssl.c
SSL/TLS: clear all ssl realted flags on shutdown
[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:     /* TLS/SSL Connection was shut down */
488                 LogOpenSSLError("TLS/SSL Connection shutdown", fname);
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)) { /* need write */
522                 io_event_del(c->sock, IO_WANTREAD);
523                 Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */
524                 break;
525         } else { /* need read */
526                 io_event_del(c->sock, IO_WANTWRITE);
527                 Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
528                 break;
529         }
530         default:
531                 assert(code < 0);
532                 if (gnutls_error_is_fatal(code)) {
533                         Log(LOG_ERR, "%s: %s", fname, gnutls_strerror(code));
534                         ConnSSL_Free(c);
535                         return -1;
536                 }
537         }
538         return 0;
539 #endif
540 }
541
542
543 static void
544 ConnSSL_LogCertInfo( CONNECTION *c )
545 {
546 #ifdef HAVE_LIBSSL
547         SSL *ssl = c->ssl_state.ssl;
548
549         assert( c );
550         assert( ssl );
551
552         Log(LOG_INFO, "New %s connection using cipher %s on socket %d.",
553                 SSL_get_version(ssl), SSL_get_cipher(ssl), c->sock);
554 #endif
555 #ifdef HAVE_LIBGNUTLS
556         gnutls_session_t sess = c->ssl_state.gnutls_session;
557         gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
558
559         Log(LOG_INFO, "New %s connection using cipher %s-%s on socket %d.",
560             gnutls_protocol_get_name(gnutls_protocol_get_version(sess)),
561             gnutls_cipher_get_name(cipher),
562             gnutls_mac_get_name(gnutls_mac_get(sess)), c->sock);
563 #endif
564 }
565
566
567 /*
568  Accept incoming SSL connection.
569  Return Values:
570          1: SSL Connection established
571          0: try again
572         -1: SSL Connection not established due to fatal error.
573 */
574 int
575 ConnSSL_Accept( CONNECTION *c )
576 {
577         assert(c != NULL);
578 #ifdef HAVE_LIBSSL
579         if (!c->ssl_state.ssl) {
580 #endif
581 #ifdef HAVE_LIBGNUTLS
582         if (!Conn_OPTION_ISSET(c, CONN_SSL)) {
583                 int err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_SERVER);
584                 if (err) {
585                         Log(LOG_ERR, "gnutls_init: %s", gnutls_strerror(err));
586                         return false;
587                 }
588 #endif
589                 LogDebug("ConnSSL_Accept: Initializing SSL data");
590                 if (!ConnSSL_Init_SSL(c))
591                         return -1;
592         }
593         return ConnectAccept(c, false );
594 }
595
596
597 int
598 ConnSSL_Connect( CONNECTION *c )
599 {
600         assert(c != NULL);
601 #ifdef HAVE_LIBSSL
602         assert(c->ssl_state.ssl);
603 #endif
604 #ifdef HAVE_LIBGNUTLS
605         assert(Conn_OPTION_ISSET(c, CONN_SSL));
606 #endif
607         return ConnectAccept(c, true);
608 }
609
610
611 /* accept/connect wrapper. if connect is true, connect to peer, otherwise wait for incoming connection */
612 static int
613 ConnectAccept( CONNECTION *c, bool connect)
614 {
615         int ret;
616 #ifdef HAVE_LIBSSL
617         SSL *ssl = c->ssl_state.ssl;
618         assert(ssl != NULL);
619
620         ret = connect ? SSL_connect(ssl) : SSL_accept(ssl);
621         if (1 != ret)
622                 return ConnSSL_HandleError(c, ret, connect ? "SSL_connect": "SSL_accept");
623 #endif
624 #ifdef HAVE_LIBGNUTLS
625         (void) connect;
626         assert(Conn_OPTION_ISSET(c, CONN_SSL));
627         ret = gnutls_handshake(c->ssl_state.gnutls_session);
628         if (ret)
629                 return ConnSSL_HandleError(c, ret, "gnutls_handshake");
630 #endif /* _GNUTLS */
631         Conn_OPTION_DEL(c, (CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ|CONN_SSL_CONNECT));
632         ConnSSL_LogCertInfo(c);
633         return 1;
634 }
635
636
637 ssize_t
638 ConnSSL_Write(CONNECTION *c, const void *buf, size_t count)
639 {
640         ssize_t bw;
641
642         Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
643
644         assert(count > 0);
645 #ifdef HAVE_LIBSSL
646         bw = (ssize_t) SSL_write(c->ssl_state.ssl, buf, count);
647 #endif
648 #ifdef HAVE_LIBGNUTLS
649         bw = gnutls_write(c->ssl_state.gnutls_session, buf, count);
650 #endif
651         if ( bw > 0 ) return bw;
652         if (ConnSSL_HandleError( c, bw, "ConnSSL_Write") == 0)
653                 errno = EAGAIN; /* try again */
654         return -1;
655 }
656
657
658 ssize_t
659 ConnSSL_Read(CONNECTION *c, void * buf, size_t count)
660 {
661         ssize_t br;
662
663         Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
664 #ifdef HAVE_LIBSSL
665         br = (ssize_t) SSL_read(c->ssl_state.ssl, buf, count);
666         if (br > 0)     /* on EOF we have to call ConnSSL_HandleError(), see SSL_read(3) */
667                 return br;
668 #endif
669 #ifdef HAVE_LIBGNUTLS
670         br = gnutls_read(c->ssl_state.gnutls_session, buf, count);
671         if (br >= 0)    /* on EOF we must _not_ call ConnSSL_HandleError, see gnutls_record_recv(3) */
672                 return br;
673 #endif
674         /* error on read: switch ConnSSL_HandleError() return values -> 0 is "try again", so return -1 and set EAGAIN */
675         if (ConnSSL_HandleError(c, br, "ConnSSL_Read") == 0) {
676                 errno = EAGAIN;
677                 return -1;
678         }
679         return 0;
680 }
681
682
683 bool
684 ConnSSL_GetCipherInfo(CONNECTION *c, char *buf, size_t len)
685 {
686 #ifdef HAVE_LIBSSL
687         char *nl;
688
689         SSL *ssl;
690         assert(c != NULL);
691         assert(len >= 128);
692         ssl = c->ssl_state.ssl;
693         if (!ssl)
694                 return false;
695         *buf = 0;
696         SSL_CIPHER_description(SSL_get_current_cipher(ssl), buf, len);
697         nl = strchr(buf, '\n');
698         if (nl)
699                 *nl = 0;
700         return true;
701 #endif
702 #ifdef HAVE_LIBGNUTLS
703         assert(c != NULL);
704         assert(len >= 128);
705         if (Conn_OPTION_ISSET(c, CONN_SSL)) {
706                 const char *name_cipher, *name_mac, *name_proto, *name_keyexchange;
707                 unsigned keysize;
708
709                 gnutls_session_t sess = c->ssl_state.gnutls_session;
710                 gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
711                 name_cipher = gnutls_cipher_get_name(cipher);
712                 name_mac = gnutls_mac_get_name(gnutls_mac_get(sess));
713                 keysize = gnutls_cipher_get_key_size(cipher) * 8;
714                 name_proto = gnutls_protocol_get_name(gnutls_protocol_get_version(sess));
715                 name_keyexchange = gnutls_kx_get_name(gnutls_kx_get(sess));
716
717                 return snprintf(buf, len, "%s-%s%15s Kx=%s      Enc=%s(%u) Mac=%s",
718                         name_cipher, name_mac, name_proto, name_keyexchange, name_cipher, keysize, name_mac) > 0;
719         }
720         return false;
721 #endif
722 }
723
724
725 #endif /* SSL_SUPPORT */
726 /* -eof- */
727
728