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