Change cipher defaults
[ngircd-alex.git] / src / ngircd / conn-ssl.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c) 2005-2008 Florian Westphal <fw@strlen.de>
4  */
5
6 #include "portab.h"
7
8 /**
9  * @file
10  * SSL wrapper functions
11  */
12
13 #include "imp.h"
14 #include "conf-ssl.h"
15
16 #ifdef SSL_SUPPORT
17
18 #include "io.h"
19 #include <assert.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <errno.h>
24
25 #define CONN_MODULE
26 #include "conn.h"
27 #include "conf.h"
28 #include "conn-func.h"
29 #include "conn-ssl.h"
30 #include "log.h"
31
32 #include "exp.h"
33 #include "defines.h"
34
35 extern struct SSLOptions Conf_SSLOptions;
36
37 #ifdef HAVE_LIBSSL
38 #include <openssl/err.h>
39 #include <openssl/rand.h>
40
41 static SSL_CTX * ssl_ctx;
42 static DH *dh_params;
43
44 static bool ConnSSL_LoadServerKey_openssl PARAMS(( SSL_CTX *c ));
45 #endif
46
47 #ifdef HAVE_LIBGNUTLS
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <fcntl.h>
51 #include <unistd.h>
52 #include <gnutls/x509.h>
53
54 #define DH_BITS 2048
55 #define DH_BITS_MIN 1024
56
57 #define MAX_HASH_SIZE   64      /* from gnutls-int.h */
58
59 static gnutls_certificate_credentials_t x509_cred;
60 static gnutls_dh_params_t dh_params;
61 static gnutls_priority_t priorities_cache;
62 static bool ConnSSL_LoadServerKey_gnutls PARAMS(( void ));
63 #endif
64
65 #define SHA1_STRING_LEN (20 * 2 + 1)
66
67 static bool ConnSSL_Init_SSL PARAMS(( CONNECTION *c ));
68 static int ConnectAccept PARAMS(( CONNECTION *c, bool connect ));
69 static int ConnSSL_HandleError PARAMS(( CONNECTION *c, const int code, const char *fname ));
70
71 #ifdef HAVE_LIBGNUTLS
72 static char * openreadclose(const char *name, size_t *len)
73 {
74         char *buf = NULL;
75         struct stat s;
76         ssize_t br;
77         int fd = open(name, O_RDONLY);
78         if (fd < 0) {
79                 Log(LOG_ERR, "Could not open %s: %s", name, strerror(errno));
80                 return NULL;
81         }
82         if (fstat(fd, &s)) {
83                 Log(LOG_ERR, "Could not fstat %s: %s", name, strerror(errno));
84                 goto out;
85         }
86         if (!S_ISREG(s.st_mode)) {
87                 Log(LOG_ERR, "%s: Not a regular file", name);
88                 goto out;
89         }
90         if (s.st_size <= 0) {
91                 Log(LOG_ERR, "%s: invalid file length (size %ld <= 0)", name, (long) s.st_size);
92                 goto out;
93         }
94         buf = malloc(s.st_size);
95         if (!buf) {
96                 Log(LOG_ERR, "Could not malloc %lu bytes for file %s: %s", s.st_size, name, strerror(errno));
97                 goto out;
98         }
99         br = read(fd, buf, s.st_size);
100         if (br != (ssize_t)s.st_size) {
101                 Log(LOG_ERR, "Could not read file %s: read returned %ld, expected %ld: %s",
102                         name, (long) br, (long) s.st_size, br == -1 ? strerror(errno):"short read?!");
103                 memset(buf, 0, s.st_size);
104                 free(buf);
105                 buf = NULL;
106         } else {
107                 *len = br;
108         }
109 out:
110         close(fd);
111         return buf;
112 }
113 #endif
114
115
116 #ifdef HAVE_LIBSSL
117 /**
118  * Log OpenSSL error message.
119  *
120  * @param msg The error message.
121  * @param info Additional information text or NULL.
122  */
123 static void
124 LogOpenSSLError(const char *error, const char *info)
125 {
126         unsigned long err = ERR_get_error();
127         char * errmsg = err
128                 ? ERR_error_string(err, NULL)
129                 : "Unable to determine error";
130
131         assert(error != NULL);
132
133         if (info)
134                 Log(LOG_ERR, "%s: %s (%s)", error, info, errmsg);
135         else
136                 Log(LOG_ERR, "%s: %s", error, errmsg);
137 }
138
139
140 static int
141 pem_passwd_cb(char *buf, int size, int rwflag, void *password)
142 {
143         array *pass = password;
144         int passlen;
145
146         (void)rwflag;           /* rwflag is unused if DEBUG is not set. */
147         assert(rwflag == 0);    /* 0 -> callback used for decryption.
148                                  * See SSL_CTX_set_default_passwd_cb(3) */
149
150         passlen = (int) array_bytes(pass);
151
152         LogDebug("pem_passwd_cb buf size %d, array size %d", size, passlen);
153         assert(passlen >= 0);
154         if (passlen <= 0) {
155                 Log(LOG_ERR, "PEM password required but not set [in pem_passwd_cb()]!");
156                 return 0;
157         }
158         size = passlen > size ? size : passlen;
159         memcpy(buf, (char *)(array_start(pass)), size);
160         return size;
161 }
162
163
164 static int
165 Verify_openssl(UNUSED int preverify_ok, UNUSED X509_STORE_CTX *x509_ctx)
166 {
167         return 1;
168 }
169 #endif
170
171
172 static bool
173 Load_DH_params(void)
174 {
175 #ifdef HAVE_LIBSSL
176         FILE *fp;
177         bool ret = true;
178
179         if (!Conf_SSLOptions.DHFile) {
180                 Log(LOG_NOTICE, "Configuration option \"DHFile\" not set!");
181                 return false;
182         }
183         fp = fopen(Conf_SSLOptions.DHFile, "r");
184         if (!fp) {
185                 Log(LOG_ERR, "%s: %s", Conf_SSLOptions.DHFile, strerror(errno));
186                 return false;
187         }
188         dh_params = PEM_read_DHparams(fp, NULL, NULL, NULL);
189         if (!dh_params) {
190                 Log(LOG_ERR, "%s: Failed to read SSL DH parameters!",
191                     Conf_SSLOptions.DHFile);
192                 ret = false;
193         }
194         fclose(fp);
195         return ret;
196 #endif
197 #ifdef HAVE_LIBGNUTLS
198         bool need_dhgenerate = true;
199         int err;
200         gnutls_dh_params_t tmp_dh_params;
201
202         err = gnutls_dh_params_init(&tmp_dh_params);
203         if (err < 0) {
204                 Log(LOG_ERR, "Failed to initialize SSL DH parameters: %s",
205                     gnutls_strerror(err));
206                 return false;
207         }
208         if (Conf_SSLOptions.DHFile) {
209                 gnutls_datum_t dhparms;
210                 size_t size;
211                 dhparms.data = (unsigned char *) openreadclose(Conf_SSLOptions.DHFile, &size);
212                 if (dhparms.data) {
213                         dhparms.size = size;
214                         err = gnutls_dh_params_import_pkcs3(tmp_dh_params, &dhparms, GNUTLS_X509_FMT_PEM);
215                         if (err == 0)
216                                 need_dhgenerate = false;
217                         else
218                                 Log(LOG_ERR,
219                                     "Failed to initialize SSL DH parameters: %s",
220                                     gnutls_strerror(err));
221
222                         memset(dhparms.data, 0, size);
223                         free(dhparms.data);
224                 }
225         }
226         if (need_dhgenerate) {
227                 Log(LOG_WARNING,
228                     "DHFile not set, generating %u bit DH parameters. This may take a while ...",
229                     DH_BITS);
230                 err = gnutls_dh_params_generate2(tmp_dh_params, DH_BITS);
231                 if (err < 0) {
232                         Log(LOG_ERR, "Failed to generate SSL DH parameters: %s",
233                             gnutls_strerror(err));
234                         return false;
235                 }
236         }
237         dh_params = tmp_dh_params;
238         return true;
239 #endif
240 }
241
242
243 void ConnSSL_Free(CONNECTION *c)
244 {
245 #ifdef HAVE_LIBSSL
246         SSL *ssl = c->ssl_state.ssl;
247         if (ssl) {
248                 SSL_shutdown(ssl);
249                 SSL_free(ssl);
250                 c->ssl_state.ssl = NULL;
251                 if (c->ssl_state.fingerprint) {
252                         free(c->ssl_state.fingerprint);
253                         c->ssl_state.fingerprint = NULL;
254                 }
255         }
256 #endif
257 #ifdef HAVE_LIBGNUTLS
258         gnutls_session_t sess = c->ssl_state.gnutls_session;
259         if (Conn_OPTION_ISSET(c, CONN_SSL)) {
260                 gnutls_bye(sess, GNUTLS_SHUT_RDWR);
261                 gnutls_deinit(sess);
262         }
263 #endif
264         assert(Conn_OPTION_ISSET(c, CONN_SSL));
265         /* can't just set bitmask to 0 -- there are other, non-ssl related flags, e.g. CONN_ZIP. */
266         Conn_OPTION_DEL(c, CONN_SSL_FLAGS_ALL);
267 }
268
269
270 bool
271 ConnSSL_InitLibrary( void )
272 {
273         if (!Conf_SSLInUse()) {
274                 LogDebug("SSL not in use, skipping initialization.");
275                 return true;
276         }
277
278 #ifdef HAVE_LIBSSL
279         SSL_CTX *newctx;
280
281         if (!ssl_ctx) {
282                 SSL_library_init();
283                 SSL_load_error_strings();
284         }
285
286         if (!RAND_status()) {
287                 Log(LOG_ERR, "OpenSSL PRNG not seeded: /dev/urandom missing?");
288                 /*
289                  * it is probably best to fail and let the user install EGD or
290                  * a similar program if no kernel random device is available.
291                  * According to OpenSSL RAND_egd(3): "The automatic query of
292                  * /var/run/egd-pool et al was added in OpenSSL 0.9.7";
293                  * so it makes little sense to deal with PRNGD seeding ourselves.
294                  */
295                 array_free(&Conf_SSLOptions.ListenPorts);
296                 return false;
297         }
298
299         newctx = SSL_CTX_new(SSLv23_method());
300         if (!newctx) {
301                 LogOpenSSLError("Failed to create SSL context", NULL);
302                 array_free(&Conf_SSLOptions.ListenPorts);
303                 return false;
304         }
305
306         if (!ConnSSL_LoadServerKey_openssl(newctx))
307                 goto out;
308
309         if (SSL_CTX_set_cipher_list(newctx, Conf_SSLOptions.CipherList) == 0) {
310                 Log(LOG_ERR, "Failed to apply OpenSSL cipher list \"%s\"!",
311                     Conf_SSLOptions.CipherList);
312                 goto out;
313         }
314
315         SSL_CTX_set_options(newctx, SSL_OP_SINGLE_DH_USE|SSL_OP_NO_SSLv2);
316         SSL_CTX_set_mode(newctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
317         SSL_CTX_set_verify(newctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
318                            Verify_openssl);
319         SSL_CTX_free(ssl_ctx);
320         ssl_ctx = newctx;
321         Log(LOG_INFO, "%s initialized.", SSLeay_version(SSLEAY_VERSION));
322         return true;
323 out:
324         SSL_CTX_free(newctx);
325         array_free(&Conf_SSLOptions.ListenPorts);
326         return false;
327 #endif
328 #ifdef HAVE_LIBGNUTLS
329         int err;
330         static bool initialized;
331
332         if (initialized) {
333                 /* TODO: cannot reload gnutls keys: can't simply free x509
334                  * context -- it may still be in use */
335                 return false;
336         }
337
338         err = gnutls_global_init();
339         if (err) {
340                 Log(LOG_ERR, "Failed to initialize GnuTLS: %s",
341                     gnutls_strerror(err));
342                 goto out;
343         }
344
345         if (!ConnSSL_LoadServerKey_gnutls())
346                 goto out;
347
348         if (gnutls_priority_init(&priorities_cache, Conf_SSLOptions.CipherList,
349                                  NULL) != GNUTLS_E_SUCCESS) {
350                 Log(LOG_ERR,
351                     "Failed to apply GnuTLS cipher list \"%s\"!",
352                     Conf_SSLOptions.CipherList);
353                 goto out;
354         }
355
356         Log(LOG_INFO, "GnuTLS %s initialized.", gnutls_check_version(NULL));
357         initialized = true;
358         return true;
359 out:
360         array_free(&Conf_SSLOptions.ListenPorts);
361         return false;
362 #endif
363 }
364
365
366 #ifdef HAVE_LIBGNUTLS
367 static bool
368 ConnSSL_LoadServerKey_gnutls(void)
369 {
370         int err;
371         const char *cert_file;
372
373         err = gnutls_certificate_allocate_credentials(&x509_cred);
374         if (err < 0) {
375                 Log(LOG_ERR, "Failed to allocate certificate credentials: %s",
376                     gnutls_strerror(err));
377                 return false;
378         }
379
380         cert_file = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile;
381         if (!cert_file) {
382                 Log(LOG_ERR, "No SSL server key configured!");
383                 return false;
384         }
385
386         if (array_bytes(&Conf_SSLOptions.KeyFilePassword))
387                 Log(LOG_WARNING,
388                     "Ignoring SSL \"KeyFilePassword\": Not supported by GnuTLS.");
389
390         if (!Load_DH_params())
391                 return false;
392
393         gnutls_certificate_set_dh_params(x509_cred, dh_params);
394         err = gnutls_certificate_set_x509_key_file(x509_cred, cert_file, Conf_SSLOptions.KeyFile, GNUTLS_X509_FMT_PEM);
395         if (err < 0) {
396                 Log(LOG_ERR,
397                     "Failed to set certificate key file (cert %s, key %s): %s",
398                     cert_file,
399                     Conf_SSLOptions.KeyFile ? Conf_SSLOptions.KeyFile : "(NULL)",
400                     gnutls_strerror(err));
401                 return false;
402         }
403         return true;
404 }
405 #endif
406
407
408 #ifdef HAVE_LIBSSL
409 static bool
410 ConnSSL_LoadServerKey_openssl(SSL_CTX *ctx)
411 {
412         char *cert_key;
413
414         assert(ctx);
415         if (!Conf_SSLOptions.KeyFile) {
416                 Log(LOG_ERR, "No SSL server key configured!");
417                 return false;
418         }
419
420         SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
421         SSL_CTX_set_default_passwd_cb_userdata(ctx, &Conf_SSLOptions.KeyFilePassword);
422
423         if (SSL_CTX_use_PrivateKey_file(ctx, Conf_SSLOptions.KeyFile, SSL_FILETYPE_PEM) != 1) {
424                 array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
425                 LogOpenSSLError("Failed to add private key", Conf_SSLOptions.KeyFile);
426                 return false;
427         }
428
429         cert_key = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile;
430         if (SSL_CTX_use_certificate_chain_file(ctx, cert_key) != 1) {
431                 array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
432                 LogOpenSSLError("Failed to load certificate chain", cert_key);
433                 return false;
434         }
435
436         array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
437
438         if (!SSL_CTX_check_private_key(ctx)) {
439                 LogOpenSSLError("Server private key does not match certificate", NULL);
440                 return false;
441         }
442         if (Load_DH_params()) {
443                 if (SSL_CTX_set_tmp_dh(ctx, dh_params) != 1)
444                         LogOpenSSLError("Error setting DH parameters", Conf_SSLOptions.DHFile);
445                 /* don't return false here: the non-DH modes will still work */
446                 DH_free(dh_params);
447                 dh_params = NULL;
448         }
449         return true;
450 }
451
452
453 #endif
454 static bool
455 ConnSSL_Init_SSL(CONNECTION *c)
456 {
457         int ret;
458
459         LogDebug("Initializing SSL ...");
460         assert(c != NULL);
461
462 #ifdef HAVE_LIBSSL
463         if (!ssl_ctx) {
464                 Log(LOG_ERR,
465                     "Can't initialize SSL context, OpenSSL initialization failed at startup!");
466                 return false;
467         }
468         assert(c->ssl_state.ssl == NULL);
469         assert(c->ssl_state.fingerprint == NULL);
470
471         c->ssl_state.ssl = SSL_new(ssl_ctx);
472         if (!c->ssl_state.ssl) {
473                 LogOpenSSLError("Failed to create SSL structure", NULL);
474                 return false;
475         }
476         Conn_OPTION_ADD(c, CONN_SSL);
477
478         ret = SSL_set_fd(c->ssl_state.ssl, c->sock);
479         if (ret != 1) {
480                 LogOpenSSLError("Failed to set SSL file descriptor", NULL);
481                 ConnSSL_Free(c);
482                 return false;
483         }
484 #endif
485 #ifdef HAVE_LIBGNUTLS
486         Conn_OPTION_ADD(c, CONN_SSL);
487         ret = gnutls_priority_set(c->ssl_state.gnutls_session, priorities_cache);
488         if (ret != GNUTLS_E_SUCCESS) {
489                 Log(LOG_ERR, "Failed to set GnuTLS session priorities: %s",
490                     gnutls_strerror(ret));
491                 ConnSSL_Free(c);
492                 return false;
493         }
494         /*
495          * The intermediate (long) cast is here to avoid a warning like:
496          * "cast to pointer from integer of different size" on 64-bit platforms.
497          * There doesn't seem to be an alternate GNUTLS API we could use instead, see e.g.
498          * http://www.mail-archive.com/help-gnutls@gnu.org/msg00286.html
499          */
500         gnutls_transport_set_ptr(c->ssl_state.gnutls_session,
501                                  (gnutls_transport_ptr_t) (long) c->sock);
502         gnutls_certificate_server_set_request(c->ssl_state.gnutls_session,
503                                               GNUTLS_CERT_REQUEST);
504         ret = gnutls_credentials_set(c->ssl_state.gnutls_session,
505                                      GNUTLS_CRD_CERTIFICATE, x509_cred);
506         if (ret != 0) {
507                 Log(LOG_ERR, "Failed to set SSL credentials: %s",
508                     gnutls_strerror(ret));
509                 ConnSSL_Free(c);
510                 return false;
511         }
512         gnutls_dh_set_prime_bits(c->ssl_state.gnutls_session, DH_BITS_MIN);
513 #endif
514         return true;
515 }
516
517
518 bool
519 ConnSSL_PrepareConnect(CONNECTION *c, UNUSED CONF_SERVER *s)
520 {
521         bool ret;
522 #ifdef HAVE_LIBGNUTLS
523         int err;
524
525         err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_CLIENT);
526         if (err) {
527                 Log(LOG_ERR, "Failed to initialize new SSL session: %s",
528                     gnutls_strerror(err));
529                 return false;
530         }
531 #endif
532         ret = ConnSSL_Init_SSL(c);
533         if (!ret)
534                 return false;
535         Conn_OPTION_ADD(c, CONN_SSL_CONNECT);
536 #ifdef HAVE_LIBSSL
537         assert(c->ssl_state.ssl);
538         SSL_set_verify(c->ssl_state.ssl, SSL_VERIFY_NONE, NULL);
539 #endif
540         return true;
541 }
542
543
544 /**
545  * Check and handle error return codes after failed calls to SSL functions.
546  *
547  * OpenSSL:
548  * SSL_connect(), SSL_accept(), SSL_do_handshake(), SSL_read(), SSL_peek(), or
549  * SSL_write() on ssl.
550  *
551  * GnuTLS:
552  * gnutlsssl_read(), gnutls_write() or gnutls_handshake().
553  *
554  * @param c The connection handle.
555  * @prarm code The return code.
556  * @param fname The name of the function in which the error occurred.
557  * @return -1 on fatal errors, 0 if we can try again later.
558  */
559 static int
560 ConnSSL_HandleError(CONNECTION * c, const int code, const char *fname)
561 {
562 #ifdef HAVE_LIBSSL
563         int ret = SSL_ERROR_SYSCALL;
564         unsigned long sslerr;
565         int real_errno = errno;
566
567         ret = SSL_get_error(c->ssl_state.ssl, code);
568
569         switch (ret) {
570         case SSL_ERROR_WANT_READ:
571                 io_event_del(c->sock, IO_WANTWRITE);
572                 Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
573                 return 0;       /* try again later */
574         case SSL_ERROR_WANT_WRITE:
575                 io_event_del(c->sock, IO_WANTREAD);
576                 Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */
577         case SSL_ERROR_NONE:
578                 return 0;       /* try again later */
579         case SSL_ERROR_ZERO_RETURN:
580                 LogDebug("SSL connection shut down normally.");
581                 break;
582         case SSL_ERROR_SYSCALL:
583                 /* SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT,
584                  * and SSL_ERROR_WANT_X509_LOOKUP */
585                 sslerr = ERR_get_error();
586                 if (sslerr) {
587                         Log(LOG_ERR, "SSL error: %s [in %s()]!",
588                             ERR_error_string(sslerr, NULL), fname);
589                 } else {
590                         switch (code) { /* EOF that violated protocol */
591                         case 0:
592                                 Log(LOG_ERR,
593                                     "SSL error, client disconnected [in %s()]!",
594                                     fname);
595                                 break;
596                         case -1:        /* low level socket I/O error, check errno */
597                                 Log(LOG_ERR, "SSL error: %s [in %s()]!",
598                                     strerror(real_errno), fname);
599                         }
600                 }
601                 break;
602         case SSL_ERROR_SSL:
603                 LogOpenSSLError("SSL protocol error", fname);
604                 break;
605         default:
606                 Log(LOG_ERR, "Unknown SSL error %d [in %s()]!", ret, fname);
607         }
608         ConnSSL_Free(c);
609         return -1;
610 #endif
611 #ifdef HAVE_LIBGNUTLS
612         switch (code) {
613         case GNUTLS_E_AGAIN:
614         case GNUTLS_E_INTERRUPTED:
615                 if (gnutls_record_get_direction(c->ssl_state.gnutls_session)) {
616                         Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE);
617                         io_event_del(c->sock, IO_WANTREAD);
618                 } else {
619                         Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
620                         io_event_del(c->sock, IO_WANTWRITE);
621                 }
622                 break;
623         default:
624                 assert(code < 0);
625                 if (gnutls_error_is_fatal(code)) {
626                         Log(LOG_ERR, "SSL error: %s [%s].",
627                             gnutls_strerror(code), fname);
628                         ConnSSL_Free(c);
629                         return -1;
630                 }
631         }
632         return 0;
633 #endif
634 }
635
636
637 static void
638 ConnSSL_LogCertInfo( CONNECTION *c )
639 {
640 #ifdef HAVE_LIBSSL
641         SSL *ssl = c->ssl_state.ssl;
642
643         assert(ssl);
644
645         Log(LOG_INFO, "Connection %d: initialized %s using cipher %s.",
646                 c->sock, SSL_get_version(ssl), SSL_get_cipher(ssl));
647 #endif
648 #ifdef HAVE_LIBGNUTLS
649         gnutls_session_t sess = c->ssl_state.gnutls_session;
650         gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
651
652         Log(LOG_INFO, "Connection %d: initialized %s using cipher %s-%s.",
653             c->sock,
654             gnutls_protocol_get_name(gnutls_protocol_get_version(sess)),
655             gnutls_cipher_get_name(cipher),
656             gnutls_mac_get_name(gnutls_mac_get(sess)));
657 #endif
658 }
659
660
661 /*
662  Accept incoming SSL connection.
663  Return Values:
664          1: SSL Connection established
665          0: try again
666         -1: SSL Connection not established due to fatal error.
667 */
668 int
669 ConnSSL_Accept( CONNECTION *c )
670 {
671         assert(c != NULL);
672         if (!Conn_OPTION_ISSET(c, CONN_SSL)) {
673 #ifdef HAVE_LIBGNUTLS
674                 int err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_SERVER);
675                 if (err) {
676                         Log(LOG_ERR, "Failed to initialize new SSL session: %s",
677                             gnutls_strerror(err));
678                         return false;
679                 }
680 #endif
681                 if (!ConnSSL_Init_SSL(c))
682                         return -1;
683         }
684         return ConnectAccept(c, false );
685 }
686
687
688 int
689 ConnSSL_Connect( CONNECTION *c )
690 {
691         assert(c != NULL);
692 #ifdef HAVE_LIBSSL
693         assert(c->ssl_state.ssl);
694 #endif
695         assert(Conn_OPTION_ISSET(c, CONN_SSL));
696         return ConnectAccept(c, true);
697 }
698
699 static int
700 ConnSSL_InitCertFp( CONNECTION *c )
701 {
702         const char hex[] = "0123456789abcdef";
703         int i;
704
705 #ifdef HAVE_LIBSSL
706         unsigned char digest[EVP_MAX_MD_SIZE];
707         unsigned int digest_size;
708         X509 *cert;
709
710         cert = SSL_get_peer_certificate(c->ssl_state.ssl);
711         if (!cert)
712                 return 0;
713
714         if (!X509_digest(cert, EVP_sha1(), digest, &digest_size)) {
715                 X509_free(cert);
716                 return 0;
717         }
718
719         X509_free(cert);
720 #endif /* HAVE_LIBSSL */
721 #ifdef HAVE_LIBGNUTLS
722         gnutls_x509_crt_t cert;
723         unsigned int cert_list_size;
724         const gnutls_datum_t *cert_list;
725         unsigned char digest[MAX_HASH_SIZE];
726         size_t digest_size;
727
728         if (gnutls_certificate_type_get(c->ssl_state.gnutls_session) != GNUTLS_CRT_X509)
729                 return 0;
730
731         if (gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS)
732                 return 0;
733
734         cert_list_size = 0;
735         cert_list = gnutls_certificate_get_peers(c->ssl_state.gnutls_session,
736                                                  &cert_list_size);
737         if (!cert_list) {
738                 gnutls_x509_crt_deinit(cert);
739                 return 0;
740         }
741         
742         if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) != GNUTLS_E_SUCCESS) {
743                 gnutls_x509_crt_deinit(cert);
744                 return 0;
745         }
746
747         digest_size = sizeof(digest);
748         if (gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, digest, &digest_size)) {
749                 gnutls_x509_crt_deinit(cert);
750                 return 0;
751         }
752
753         gnutls_x509_crt_deinit(cert);
754 #endif /* HAVE_LIBGNUTLS */
755
756         assert(c->ssl_state.fingerprint == NULL);
757
758         c->ssl_state.fingerprint = malloc(SHA1_STRING_LEN);
759         if (!c->ssl_state.fingerprint)
760                 return 0;
761
762         for (i = 0; i < (int)digest_size; i++) {
763                 c->ssl_state.fingerprint[i * 2] = hex[digest[i] / 16];
764                 c->ssl_state.fingerprint[i * 2 + 1] = hex[digest[i] % 16];
765         }
766         c->ssl_state.fingerprint[i * 2] = '\0';
767
768         return 1;
769 }
770
771 /* accept/connect wrapper. if connect is true, connect to peer, otherwise wait for incoming connection */
772 static int
773 ConnectAccept( CONNECTION *c, bool connect)
774 {
775         int ret;
776 #ifdef HAVE_LIBSSL
777         SSL *ssl = c->ssl_state.ssl;
778         assert(ssl != NULL);
779
780         ret = connect ? SSL_connect(ssl) : SSL_accept(ssl);
781         if (1 != ret)
782                 return ConnSSL_HandleError(c, ret, connect ? "SSL_connect": "SSL_accept");
783 #endif
784 #ifdef HAVE_LIBGNUTLS
785         (void) connect;
786         ret = gnutls_handshake(c->ssl_state.gnutls_session);
787         if (ret)
788                 return ConnSSL_HandleError(c, ret, "gnutls_handshake");
789 #endif /* _GNUTLS */
790         (void)ConnSSL_InitCertFp(c);
791
792         Conn_OPTION_DEL(c, (CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ|CONN_SSL_CONNECT));
793         ConnSSL_LogCertInfo(c);
794
795         Conn_StartLogin(CONNECTION2ID(c));
796         return 1;
797 }
798
799
800 ssize_t
801 ConnSSL_Write(CONNECTION *c, const void *buf, size_t count)
802 {
803         ssize_t bw;
804
805         Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
806
807         assert(count > 0);
808 #ifdef HAVE_LIBSSL
809         bw = (ssize_t) SSL_write(c->ssl_state.ssl, buf, count);
810 #endif
811 #ifdef HAVE_LIBGNUTLS
812         bw = gnutls_write(c->ssl_state.gnutls_session, buf, count);
813 #endif
814         if (bw > 0)
815                 return bw;
816         if (ConnSSL_HandleError( c, bw, "ConnSSL_Write") == 0)
817                 errno = EAGAIN; /* try again */
818         return -1;
819 }
820
821
822 ssize_t
823 ConnSSL_Read(CONNECTION *c, void * buf, size_t count)
824 {
825         ssize_t br;
826
827         Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
828 #ifdef HAVE_LIBSSL
829         br = (ssize_t) SSL_read(c->ssl_state.ssl, buf, count);
830         if (br > 0)     /* on EOF we have to call ConnSSL_HandleError(), see SSL_read(3) */
831                 return br;
832 #endif
833 #ifdef HAVE_LIBGNUTLS
834         br = gnutls_read(c->ssl_state.gnutls_session, buf, count);
835         if (br >= 0)    /* on EOF we must _not_ call ConnSSL_HandleError, see gnutls_record_recv(3) */
836                 return br;
837 #endif
838         /* error on read: switch ConnSSL_HandleError() return values -> 0 is "try again", so return -1 and set EAGAIN */
839         if (ConnSSL_HandleError(c, br, "ConnSSL_Read") == 0) {
840                 errno = EAGAIN;
841                 return -1;
842         }
843         return 0;
844 }
845
846
847 bool
848 ConnSSL_GetCipherInfo(CONNECTION *c, char *buf, size_t len)
849 {
850 #ifdef HAVE_LIBSSL
851         char *nl;
852         SSL *ssl = c->ssl_state.ssl;
853
854         if (!ssl)
855                 return false;
856         *buf = 0;
857         SSL_CIPHER_description(SSL_get_current_cipher(ssl), buf, len);
858         nl = strchr(buf, '\n');
859         if (nl)
860                 *nl = 0;
861         return true;
862 #endif
863 #ifdef HAVE_LIBGNUTLS
864         if (Conn_OPTION_ISSET(c, CONN_SSL)) {
865                 const char *name_cipher, *name_mac, *name_proto, *name_keyexchange;
866                 unsigned keysize;
867
868                 gnutls_session_t sess = c->ssl_state.gnutls_session;
869                 gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
870                 name_cipher = gnutls_cipher_get_name(cipher);
871                 name_mac = gnutls_mac_get_name(gnutls_mac_get(sess));
872                 keysize = gnutls_cipher_get_key_size(cipher) * 8;
873                 name_proto = gnutls_protocol_get_name(gnutls_protocol_get_version(sess));
874                 name_keyexchange = gnutls_kx_get_name(gnutls_kx_get(sess));
875
876                 return snprintf(buf, len, "%s-%s%15s Kx=%s      Enc=%s(%u) Mac=%s",
877                         name_cipher, name_mac, name_proto, name_keyexchange, name_cipher, keysize, name_mac) > 0;
878         }
879         return false;
880 #endif
881 }
882
883 char *
884 ConnSSL_GetCertFp(CONNECTION *c)
885 {
886         return c->ssl_state.fingerprint;
887 }
888
889 bool
890 ConnSSL_SetCertFp(CONNECTION *c, const char *fingerprint)
891 {
892         assert (c != NULL);
893         c->ssl_state.fingerprint = strndup(fingerprint, SHA1_STRING_LEN - 1);
894         return c->ssl_state.fingerprint != NULL;
895 }
896 #else
897
898 bool
899 ConnSSL_InitLibrary(void)
900 {
901         return true;
902 }
903
904 #endif /* SSL_SUPPORT */
905 /* -eof- */
906
907