]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/conn-ssl.c
b16c6b94e35299a54091ae9bb60dba9e1880c174
[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(Conf_SSLOptions.CipherList && *Conf_SSLOptions.CipherList) {
310                 if(SSL_CTX_set_cipher_list(newctx, Conf_SSLOptions.CipherList) == 0 ) {
311                         Log(LOG_ERR,
312                             "Failed to apply OpenSSL cipher list \"%s\"!",
313                             Conf_SSLOptions.CipherList);
314                         goto out;
315                 } else {
316                         Log(LOG_INFO,
317                             "Successfully applied OpenSSL cipher list \"%s\".",
318                             Conf_SSLOptions.CipherList);
319                 }
320         }
321
322         SSL_CTX_set_options(newctx, SSL_OP_SINGLE_DH_USE|SSL_OP_NO_SSLv2);
323         SSL_CTX_set_mode(newctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
324         SSL_CTX_set_verify(newctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
325                            Verify_openssl);
326         SSL_CTX_free(ssl_ctx);
327         ssl_ctx = newctx;
328         Log(LOG_INFO, "%s initialized.", SSLeay_version(SSLEAY_VERSION));
329         return true;
330 out:
331         SSL_CTX_free(newctx);
332         array_free(&Conf_SSLOptions.ListenPorts);
333         return false;
334 #endif
335 #ifdef HAVE_LIBGNUTLS
336         int err;
337         static bool initialized;
338
339         if (initialized) {
340                 /* TODO: cannot reload gnutls keys: can't simply free x509
341                  * context -- it may still be in use */
342                 return false;
343         }
344
345         err = gnutls_global_init();
346         if (err) {
347                 Log(LOG_ERR, "Failed to initialize GnuTLS: %s",
348                     gnutls_strerror(err));
349                 goto out;
350         }
351
352         if (!ConnSSL_LoadServerKey_gnutls())
353                 goto out;
354
355         if(Conf_SSLOptions.CipherList && *Conf_SSLOptions.CipherList) {
356                 err = gnutls_priority_init(&priorities_cache,
357                                            Conf_SSLOptions.CipherList, NULL);
358                 if (err != GNUTLS_E_SUCCESS) {
359                         Log(LOG_ERR,
360                             "Failed to apply GnuTLS cipher list \"%s\"!",
361                             Conf_SSLOptions.CipherList);
362                         goto out;
363                 }
364                 Log(LOG_INFO,
365                     "Successfully applied GnuTLS cipher list \"%s\".",
366                     Conf_SSLOptions.CipherList);
367         } else {
368                 err = gnutls_priority_init(&priorities_cache, "NORMAL", NULL);
369                 if (err != GNUTLS_E_SUCCESS) {
370                         Log(LOG_ERR,
371                             "Failed to apply GnuTLS cipher list \"NORMAL\"!");
372                         goto out;
373                 }
374         }
375
376         Log(LOG_INFO, "GnuTLS %s initialized.", gnutls_check_version(NULL));
377         initialized = true;
378         return true;
379 out:
380         array_free(&Conf_SSLOptions.ListenPorts);
381         return false;
382 #endif
383 }
384
385
386 #ifdef HAVE_LIBGNUTLS
387 static bool
388 ConnSSL_LoadServerKey_gnutls(void)
389 {
390         int err;
391         const char *cert_file;
392
393         err = gnutls_certificate_allocate_credentials(&x509_cred);
394         if (err < 0) {
395                 Log(LOG_ERR, "Failed to allocate certificate credentials: %s",
396                     gnutls_strerror(err));
397                 return false;
398         }
399
400         cert_file = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile;
401         if (!cert_file) {
402                 Log(LOG_ERR, "No SSL server key configured!");
403                 return false;
404         }
405
406         if (array_bytes(&Conf_SSLOptions.KeyFilePassword))
407                 Log(LOG_WARNING,
408                     "Ignoring SSL \"KeyFilePassword\": Not supported by GnuTLS.");
409
410         if (!Load_DH_params())
411                 return false;
412
413         gnutls_certificate_set_dh_params(x509_cred, dh_params);
414         err = gnutls_certificate_set_x509_key_file(x509_cred, cert_file, Conf_SSLOptions.KeyFile, GNUTLS_X509_FMT_PEM);
415         if (err < 0) {
416                 Log(LOG_ERR,
417                     "Failed to set certificate key file (cert %s, key %s): %s",
418                     cert_file,
419                     Conf_SSLOptions.KeyFile ? Conf_SSLOptions.KeyFile : "(NULL)",
420                     gnutls_strerror(err));
421                 return false;
422         }
423         return true;
424 }
425 #endif
426
427
428 #ifdef HAVE_LIBSSL
429 static bool
430 ConnSSL_LoadServerKey_openssl(SSL_CTX *ctx)
431 {
432         char *cert_key;
433
434         assert(ctx);
435         if (!Conf_SSLOptions.KeyFile) {
436                 Log(LOG_ERR, "No SSL server key configured!");
437                 return false;
438         }
439
440         SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
441         SSL_CTX_set_default_passwd_cb_userdata(ctx, &Conf_SSLOptions.KeyFilePassword);
442
443         if (SSL_CTX_use_PrivateKey_file(ctx, Conf_SSLOptions.KeyFile, SSL_FILETYPE_PEM) != 1) {
444                 array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
445                 LogOpenSSLError("Failed to add private key", Conf_SSLOptions.KeyFile);
446                 return false;
447         }
448
449         cert_key = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile;
450         if (SSL_CTX_use_certificate_chain_file(ctx, cert_key) != 1) {
451                 array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
452                 LogOpenSSLError("Failed to load certificate chain", cert_key);
453                 return false;
454         }
455
456         array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
457
458         if (!SSL_CTX_check_private_key(ctx)) {
459                 LogOpenSSLError("Server private key does not match certificate", NULL);
460                 return false;
461         }
462         if (Load_DH_params()) {
463                 if (SSL_CTX_set_tmp_dh(ctx, dh_params) != 1)
464                         LogOpenSSLError("Error setting DH parameters", Conf_SSLOptions.DHFile);
465                 /* don't return false here: the non-DH modes will still work */
466                 DH_free(dh_params);
467                 dh_params = NULL;
468         }
469         return true;
470 }
471
472
473 #endif
474 static bool
475 ConnSSL_Init_SSL(CONNECTION *c)
476 {
477         int ret;
478
479         LogDebug("Initializing SSL ...");
480         assert(c != NULL);
481
482 #ifdef HAVE_LIBSSL
483         if (!ssl_ctx) {
484                 Log(LOG_ERR,
485                     "Can't initialize SSL context, OpenSSL initialization failed at startup!");
486                 return false;
487         }
488         assert(c->ssl_state.ssl == NULL);
489         assert(c->ssl_state.fingerprint == NULL);
490
491         c->ssl_state.ssl = SSL_new(ssl_ctx);
492         if (!c->ssl_state.ssl) {
493                 LogOpenSSLError("Failed to create SSL structure", NULL);
494                 return false;
495         }
496         Conn_OPTION_ADD(c, CONN_SSL);
497
498         ret = SSL_set_fd(c->ssl_state.ssl, c->sock);
499         if (ret != 1) {
500                 LogOpenSSLError("Failed to set SSL file descriptor", NULL);
501                 ConnSSL_Free(c);
502                 return false;
503         }
504 #endif
505 #ifdef HAVE_LIBGNUTLS
506         Conn_OPTION_ADD(c, CONN_SSL);
507         ret = gnutls_priority_set(c->ssl_state.gnutls_session, priorities_cache);
508         if (ret != 0) {
509                 Log(LOG_ERR, "Failed to set GnuTLS session priorities: %s",
510                     gnutls_strerror(ret));
511                 ConnSSL_Free(c);
512                 return false;
513         }
514         /*
515          * The intermediate (long) cast is here to avoid a warning like:
516          * "cast to pointer from integer of different size" on 64-bit platforms.
517          * There doesn't seem to be an alternate GNUTLS API we could use instead, see e.g.
518          * http://www.mail-archive.com/help-gnutls@gnu.org/msg00286.html
519          */
520         gnutls_transport_set_ptr(c->ssl_state.gnutls_session,
521                                  (gnutls_transport_ptr_t) (long) c->sock);
522         gnutls_certificate_server_set_request(c->ssl_state.gnutls_session,
523                                               GNUTLS_CERT_REQUEST);
524         ret = gnutls_credentials_set(c->ssl_state.gnutls_session,
525                                      GNUTLS_CRD_CERTIFICATE, x509_cred);
526         if (ret != 0) {
527                 Log(LOG_ERR, "Failed to set SSL credentials: %s",
528                     gnutls_strerror(ret));
529                 ConnSSL_Free(c);
530                 return false;
531         }
532         gnutls_dh_set_prime_bits(c->ssl_state.gnutls_session, DH_BITS_MIN);
533 #endif
534         return true;
535 }
536
537
538 bool
539 ConnSSL_PrepareConnect(CONNECTION *c, UNUSED CONF_SERVER *s)
540 {
541         bool ret;
542 #ifdef HAVE_LIBGNUTLS
543         int err;
544
545         err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_CLIENT);
546         if (err) {
547                 Log(LOG_ERR, "Failed to initialize new SSL session: %s",
548                     gnutls_strerror(err));
549                 return false;
550         }
551 #endif
552         ret = ConnSSL_Init_SSL(c);
553         if (!ret)
554                 return false;
555         Conn_OPTION_ADD(c, CONN_SSL_CONNECT);
556 #ifdef HAVE_LIBSSL
557         assert(c->ssl_state.ssl);
558         SSL_set_verify(c->ssl_state.ssl, SSL_VERIFY_NONE, NULL);
559 #endif
560         return true;
561 }
562
563
564 /**
565  * Check and handle error return codes after failed calls to SSL functions.
566  *
567  * OpenSSL:
568  * SSL_connect(), SSL_accept(), SSL_do_handshake(), SSL_read(), SSL_peek(), or
569  * SSL_write() on ssl.
570  *
571  * GnuTLS:
572  * gnutlsssl_read(), gnutls_write() or gnutls_handshake().
573  *
574  * @param c The connection handle.
575  * @prarm code The return code.
576  * @param fname The name of the function in which the error occurred.
577  * @return -1 on fatal errors, 0 if we can try again later.
578  */
579 static int
580 ConnSSL_HandleError(CONNECTION * c, const int code, const char *fname)
581 {
582 #ifdef HAVE_LIBSSL
583         int ret = SSL_ERROR_SYSCALL;
584         unsigned long sslerr;
585         int real_errno = errno;
586
587         ret = SSL_get_error(c->ssl_state.ssl, code);
588
589         switch (ret) {
590         case SSL_ERROR_WANT_READ:
591                 io_event_del(c->sock, IO_WANTWRITE);
592                 Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
593                 return 0;       /* try again later */
594         case SSL_ERROR_WANT_WRITE:
595                 io_event_del(c->sock, IO_WANTREAD);
596                 Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE); /* fall through */
597         case SSL_ERROR_NONE:
598                 return 0;       /* try again later */
599         case SSL_ERROR_ZERO_RETURN:
600                 LogDebug("SSL connection shut down normally.");
601                 break;
602         case SSL_ERROR_SYSCALL:
603                 /* SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT,
604                  * and SSL_ERROR_WANT_X509_LOOKUP */
605                 sslerr = ERR_get_error();
606                 if (sslerr) {
607                         Log(LOG_ERR, "SSL error: %s [in %s()]!",
608                             ERR_error_string(sslerr, NULL), fname);
609                 } else {
610                         switch (code) { /* EOF that violated protocol */
611                         case 0:
612                                 Log(LOG_ERR,
613                                     "SSL error, client disconnected [in %s()]!",
614                                     fname);
615                                 break;
616                         case -1:        /* low level socket I/O error, check errno */
617                                 Log(LOG_ERR, "SSL error: %s [in %s()]!",
618                                     strerror(real_errno), fname);
619                         }
620                 }
621                 break;
622         case SSL_ERROR_SSL:
623                 LogOpenSSLError("SSL protocol error", fname);
624                 break;
625         default:
626                 Log(LOG_ERR, "Unknown SSL error %d [in %s()]!", ret, fname);
627         }
628         ConnSSL_Free(c);
629         return -1;
630 #endif
631 #ifdef HAVE_LIBGNUTLS
632         switch (code) {
633         case GNUTLS_E_AGAIN:
634         case GNUTLS_E_INTERRUPTED:
635                 if (gnutls_record_get_direction(c->ssl_state.gnutls_session)) {
636                         Conn_OPTION_ADD(c, CONN_SSL_WANT_WRITE);
637                         io_event_del(c->sock, IO_WANTREAD);
638                 } else {
639                         Conn_OPTION_ADD(c, CONN_SSL_WANT_READ);
640                         io_event_del(c->sock, IO_WANTWRITE);
641                 }
642                 break;
643         default:
644                 assert(code < 0);
645                 if (gnutls_error_is_fatal(code)) {
646                         Log(LOG_ERR, "SSL error: %s [%s].",
647                             gnutls_strerror(code), fname);
648                         ConnSSL_Free(c);
649                         return -1;
650                 }
651         }
652         return 0;
653 #endif
654 }
655
656
657 static void
658 ConnSSL_LogCertInfo( CONNECTION *c )
659 {
660 #ifdef HAVE_LIBSSL
661         SSL *ssl = c->ssl_state.ssl;
662
663         assert(ssl);
664
665         Log(LOG_INFO, "Connection %d: initialized %s using cipher %s.",
666                 c->sock, SSL_get_version(ssl), SSL_get_cipher(ssl));
667 #endif
668 #ifdef HAVE_LIBGNUTLS
669         gnutls_session_t sess = c->ssl_state.gnutls_session;
670         gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
671
672         Log(LOG_INFO, "Connection %d: initialized %s using cipher %s-%s.",
673             c->sock,
674             gnutls_protocol_get_name(gnutls_protocol_get_version(sess)),
675             gnutls_cipher_get_name(cipher),
676             gnutls_mac_get_name(gnutls_mac_get(sess)));
677 #endif
678 }
679
680
681 /*
682  Accept incoming SSL connection.
683  Return Values:
684          1: SSL Connection established
685          0: try again
686         -1: SSL Connection not established due to fatal error.
687 */
688 int
689 ConnSSL_Accept( CONNECTION *c )
690 {
691         assert(c != NULL);
692         if (!Conn_OPTION_ISSET(c, CONN_SSL)) {
693 #ifdef HAVE_LIBGNUTLS
694                 int err = gnutls_init(&c->ssl_state.gnutls_session, GNUTLS_SERVER);
695                 if (err) {
696                         Log(LOG_ERR, "Failed to initialize new SSL session: %s",
697                             gnutls_strerror(err));
698                         return false;
699                 }
700 #endif
701                 if (!ConnSSL_Init_SSL(c))
702                         return -1;
703         }
704         return ConnectAccept(c, false );
705 }
706
707
708 int
709 ConnSSL_Connect( CONNECTION *c )
710 {
711         assert(c != NULL);
712 #ifdef HAVE_LIBSSL
713         assert(c->ssl_state.ssl);
714 #endif
715         assert(Conn_OPTION_ISSET(c, CONN_SSL));
716         return ConnectAccept(c, true);
717 }
718
719 static int
720 ConnSSL_InitCertFp( CONNECTION *c )
721 {
722         const char hex[] = "0123456789abcdef";
723         int i;
724
725 #ifdef HAVE_LIBSSL
726         unsigned char digest[EVP_MAX_MD_SIZE];
727         unsigned int digest_size;
728         X509 *cert;
729
730         cert = SSL_get_peer_certificate(c->ssl_state.ssl);
731         if (!cert)
732                 return 0;
733
734         if (!X509_digest(cert, EVP_sha1(), digest, &digest_size)) {
735                 X509_free(cert);
736                 return 0;
737         }
738
739         X509_free(cert);
740 #endif /* HAVE_LIBSSL */
741 #ifdef HAVE_LIBGNUTLS
742         gnutls_x509_crt_t cert;
743         unsigned int cert_list_size;
744         const gnutls_datum_t *cert_list;
745         unsigned char digest[MAX_HASH_SIZE];
746         size_t digest_size;
747
748         if (gnutls_certificate_type_get(c->ssl_state.gnutls_session) != GNUTLS_CRT_X509)
749                 return 0;
750
751         if (gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS)
752                 return 0;
753
754         cert_list_size = 0;
755         cert_list = gnutls_certificate_get_peers(c->ssl_state.gnutls_session,
756                                                  &cert_list_size);
757         if (!cert_list) {
758                 gnutls_x509_crt_deinit(cert);
759                 return 0;
760         }
761         
762         if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) != GNUTLS_E_SUCCESS) {
763                 gnutls_x509_crt_deinit(cert);
764                 return 0;
765         }
766
767         digest_size = sizeof(digest);
768         if (gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, digest, &digest_size)) {
769                 gnutls_x509_crt_deinit(cert);
770                 return 0;
771         }
772
773         gnutls_x509_crt_deinit(cert);
774 #endif /* HAVE_LIBGNUTLS */
775
776         assert(c->ssl_state.fingerprint == NULL);
777
778         c->ssl_state.fingerprint = malloc(SHA1_STRING_LEN);
779         if (!c->ssl_state.fingerprint)
780                 return 0;
781
782         for (i = 0; i < (int)digest_size; i++) {
783                 c->ssl_state.fingerprint[i * 2] = hex[digest[i] / 16];
784                 c->ssl_state.fingerprint[i * 2 + 1] = hex[digest[i] % 16];
785         }
786         c->ssl_state.fingerprint[i * 2] = '\0';
787
788         return 1;
789 }
790
791 /* accept/connect wrapper. if connect is true, connect to peer, otherwise wait for incoming connection */
792 static int
793 ConnectAccept( CONNECTION *c, bool connect)
794 {
795         int ret;
796 #ifdef HAVE_LIBSSL
797         SSL *ssl = c->ssl_state.ssl;
798         assert(ssl != NULL);
799
800         ret = connect ? SSL_connect(ssl) : SSL_accept(ssl);
801         if (1 != ret)
802                 return ConnSSL_HandleError(c, ret, connect ? "SSL_connect": "SSL_accept");
803 #endif
804 #ifdef HAVE_LIBGNUTLS
805         (void) connect;
806         ret = gnutls_handshake(c->ssl_state.gnutls_session);
807         if (ret)
808                 return ConnSSL_HandleError(c, ret, "gnutls_handshake");
809 #endif /* _GNUTLS */
810         (void)ConnSSL_InitCertFp(c);
811
812         Conn_OPTION_DEL(c, (CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ|CONN_SSL_CONNECT));
813         ConnSSL_LogCertInfo(c);
814
815         Conn_StartLogin(CONNECTION2ID(c));
816         return 1;
817 }
818
819
820 ssize_t
821 ConnSSL_Write(CONNECTION *c, const void *buf, size_t count)
822 {
823         ssize_t bw;
824
825         Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
826
827         assert(count > 0);
828 #ifdef HAVE_LIBSSL
829         bw = (ssize_t) SSL_write(c->ssl_state.ssl, buf, count);
830 #endif
831 #ifdef HAVE_LIBGNUTLS
832         bw = gnutls_write(c->ssl_state.gnutls_session, buf, count);
833 #endif
834         if (bw > 0)
835                 return bw;
836         if (ConnSSL_HandleError( c, bw, "ConnSSL_Write") == 0)
837                 errno = EAGAIN; /* try again */
838         return -1;
839 }
840
841
842 ssize_t
843 ConnSSL_Read(CONNECTION *c, void * buf, size_t count)
844 {
845         ssize_t br;
846
847         Conn_OPTION_DEL(c, CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ);
848 #ifdef HAVE_LIBSSL
849         br = (ssize_t) SSL_read(c->ssl_state.ssl, buf, count);
850         if (br > 0)     /* on EOF we have to call ConnSSL_HandleError(), see SSL_read(3) */
851                 return br;
852 #endif
853 #ifdef HAVE_LIBGNUTLS
854         br = gnutls_read(c->ssl_state.gnutls_session, buf, count);
855         if (br >= 0)    /* on EOF we must _not_ call ConnSSL_HandleError, see gnutls_record_recv(3) */
856                 return br;
857 #endif
858         /* error on read: switch ConnSSL_HandleError() return values -> 0 is "try again", so return -1 and set EAGAIN */
859         if (ConnSSL_HandleError(c, br, "ConnSSL_Read") == 0) {
860                 errno = EAGAIN;
861                 return -1;
862         }
863         return 0;
864 }
865
866
867 bool
868 ConnSSL_GetCipherInfo(CONNECTION *c, char *buf, size_t len)
869 {
870 #ifdef HAVE_LIBSSL
871         char *nl;
872         SSL *ssl = c->ssl_state.ssl;
873
874         if (!ssl)
875                 return false;
876         *buf = 0;
877         SSL_CIPHER_description(SSL_get_current_cipher(ssl), buf, len);
878         nl = strchr(buf, '\n');
879         if (nl)
880                 *nl = 0;
881         return true;
882 #endif
883 #ifdef HAVE_LIBGNUTLS
884         if (Conn_OPTION_ISSET(c, CONN_SSL)) {
885                 const char *name_cipher, *name_mac, *name_proto, *name_keyexchange;
886                 unsigned keysize;
887
888                 gnutls_session_t sess = c->ssl_state.gnutls_session;
889                 gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(sess);
890                 name_cipher = gnutls_cipher_get_name(cipher);
891                 name_mac = gnutls_mac_get_name(gnutls_mac_get(sess));
892                 keysize = gnutls_cipher_get_key_size(cipher) * 8;
893                 name_proto = gnutls_protocol_get_name(gnutls_protocol_get_version(sess));
894                 name_keyexchange = gnutls_kx_get_name(gnutls_kx_get(sess));
895
896                 return snprintf(buf, len, "%s-%s%15s Kx=%s      Enc=%s(%u) Mac=%s",
897                         name_cipher, name_mac, name_proto, name_keyexchange, name_cipher, keysize, name_mac) > 0;
898         }
899         return false;
900 #endif
901 }
902
903 char *
904 ConnSSL_GetCertFp(CONNECTION *c)
905 {
906         return c->ssl_state.fingerprint;
907 }
908
909 bool
910 ConnSSL_SetCertFp(CONNECTION *c, const char *fingerprint)
911 {
912         assert (c != NULL);
913         c->ssl_state.fingerprint = strndup(fingerprint, SHA1_STRING_LEN - 1);
914         return c->ssl_state.fingerprint != NULL;
915 }
916 #else
917
918 bool
919 ConnSSL_InitLibrary(void)
920 {
921         return true;
922 }
923
924 #endif /* SSL_SUPPORT */
925 /* -eof- */
926
927