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