Add copy-on-write support.
[pwmd.git] / src / tls.c
blob648c2640da8dfbe470d9f1a26b9f26ba704f8d8f
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
3 2016
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of pwmd.
8 Pwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Pwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
21 #include <gnutls/x509.h>
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netdb.h>
32 #ifdef HAVE_STRINGS_H
33 #include <strings.h>
34 #endif
36 #include "pwmd-error.h"
37 #include <gcrypt.h>
38 #include "mem.h"
39 #include "util-misc.h"
40 #include "util-string.h"
41 #include "common.h"
42 #include "tls.h"
43 #include "mutex.h"
44 #include "rcfile.h"
46 #define WAIT_INTERVAL 50000
47 #define TEST_TIMEOUT(timeout, ret, start, rc) \
48 do { \
49 rc = 0; \
50 if (ret == GNUTLS_E_AGAIN) \
51 { \
52 time_t now = time (NULL); \
53 if (timeout && now - start >= timeout) \
54 { \
55 rc = gpg_error (GPG_ERR_ETIMEDOUT); \
56 ret = GNUTLS_E_TIMEDOUT; \
57 break; \
58 } \
59 struct timeval wtv = { 0, WAIT_INTERVAL }; \
60 select (0, NULL, NULL, NULL, &wtv); \
61 } \
62 if (ret != GNUTLS_E_INTERRUPTED) \
63 break; \
64 } \
65 while (0)
67 static gnutls_dh_params_t dh_params;
68 static gnutls_certificate_credentials_t x509_cred;
70 static char *
71 tls_fingerprint (gnutls_session_t ses)
73 gnutls_x509_crt_t crt;
74 const gnutls_datum_t *cert_list;
75 unsigned count;
76 unsigned char buf[32];
77 size_t len = sizeof (buf);
79 gnutls_x509_crt_init (&crt);
80 if (!crt)
82 log_write ("%s(%i): %s(): %s", __FILE__, __LINE__, __FUNCTION__,
83 gnutls_strerror (GNUTLS_E_MEMORY_ERROR));
84 return NULL;
87 cert_list = gnutls_certificate_get_peers (ses, &count);
88 if (count)
90 gnutls_x509_crt_import (crt, &cert_list[0], GNUTLS_X509_FMT_DER);
91 gnutls_x509_crt_get_fingerprint (crt, GNUTLS_DIG_SHA256, buf, &len);
92 gnutls_x509_crt_deinit (crt);
94 return len ? bin2hex (buf, len) : NULL;
97 gnutls_x509_crt_deinit (crt);
98 return NULL;
101 static int
102 verify_client_certificate (unsigned status)
104 if (!status)
105 return 0;
107 if (status & GNUTLS_CERT_REVOKED)
108 log_write (_("client certificate is revoked"));
110 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
111 log_write (_("client certificate has no signer"));
113 if (status & GNUTLS_CERT_SIGNATURE_FAILURE)
114 log_write (_("client certificate signature verification failed"));
116 if (status & GNUTLS_CERT_EXPIRED)
117 log_write (_("client certificate expired"));
119 if (status & GNUTLS_CERT_SIGNER_NOT_CA)
120 log_write (_("client certificate signer is not from CA"));
122 if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
123 log_write (_("client certificate has insecure algorithm"));
125 if (status & GNUTLS_CERT_INVALID)
126 log_write (_("client certificate is invalid"));
128 return GNUTLS_E_CERTIFICATE_ERROR;
131 struct tls_s *
132 tls_init_client (int fd, int timeout, const char *prio)
134 int ret;
135 unsigned status;
136 const char *prio_error;
137 gnutls_kx_algorithm_t kx;
138 gpg_error_t rc = 0;
139 struct tls_s *tls = xcalloc (1, sizeof (struct tls_s));
141 if (!tls)
143 log_write ("%s(%i): %s: %s", __FILE__, __LINE__, __FUNCTION__,
144 strerror (ENOMEM));
145 return NULL;
148 ret = gnutls_init (&tls->ses, GNUTLS_SERVER);
149 if (ret != GNUTLS_E_SUCCESS)
150 goto fail;
152 ret = gnutls_priority_set_direct (tls->ses, prio, &prio_error);
153 if (ret != GNUTLS_E_SUCCESS)
154 goto fail;
156 ret = gnutls_credentials_set (tls->ses, GNUTLS_CRD_CERTIFICATE, x509_cred);
157 if (ret != GNUTLS_E_SUCCESS)
158 goto fail;
160 gnutls_certificate_server_set_request (tls->ses, GNUTLS_CERT_REQUIRE);
161 gnutls_transport_set_ptr (tls->ses, (gnutls_transport_ptr_t) fd);
162 time_t start = time (NULL);
165 ret = gnutls_handshake (tls->ses);
166 TEST_TIMEOUT (timeout, ret, start, rc);
167 if (rc)
168 goto fail;
170 while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
172 if (ret != GNUTLS_E_SUCCESS)
173 goto fail;
175 ret = gnutls_certificate_verify_peers2 (tls->ses, &status);
176 if (ret)
177 goto fail;
179 kx = gnutls_kx_get (tls->ses);
180 tls->fp = tls_fingerprint (tls->ses);
181 log_write ("PROTO=%s CIPHER=%s MAC=%s KX=%s(%d) FP=%s",
182 gnutls_protocol_get_name (gnutls_protocol_get_version
183 (tls->ses)),
184 gnutls_cipher_get_name (gnutls_cipher_get (tls->ses)),
185 gnutls_mac_get_name (gnutls_mac_get (tls->ses)),
186 gnutls_kx_get_name (kx), gnutls_dh_get_prime_bits (tls->ses),
187 tls->fp ? tls->fp : "N/A");
188 ret = verify_client_certificate (status);
189 if (ret)
190 goto fail;
192 return tls;
194 fail:
195 log_write ("%s", rc ? pwmd_strerror(rc) : gnutls_strerror (ret));
196 gnutls_deinit (tls->ses);
197 xfree (tls->fp);
198 xfree (tls);
199 return NULL;
202 void
203 tls_log (int level, const char *msg)
205 log_write ("TLS: %i: %s", level, msg);
208 void
209 tls_audit_log (gnutls_session_t s, const char *msg)
211 (void)s;
212 log_write ("TLS: %s", msg);
215 ssize_t
216 tls_read_hook (assuan_context_t ctx, assuan_fd_t fd, void *data, size_t len)
218 struct client_s *client = assuan_get_pointer (ctx);
219 struct tls_s *tls = client->thd->tls;
220 time_t start = time (NULL);
221 ssize_t ret;
225 gpg_error_t rc = 0;
226 struct timeval tv = { 0, 0 };
227 fd_set fds;
228 int n;
230 FD_ZERO (&fds);
231 FD_SET (fd, &fds);
232 n = select (client->thd->fd+1, &fds, NULL, NULL, &tv);
233 if (n == 0 && tls->nl)
235 char c[] = "#\n";
237 memcpy (data, c, sizeof(c));
238 ret = strlen (c);
239 break;
242 ret = gnutls_record_recv (tls->ses, data, len);
243 if (ret == GNUTLS_E_REHANDSHAKE)
245 tls->rehandshake = 0;
249 ret = gnutls_handshake (tls->ses);
250 TEST_TIMEOUT (client->thd->timeout, ret, start, rc);
251 if (rc)
252 break;
254 while (ret < 0 && gnutls_error_is_fatal (ret) == 0);
256 if (!ret)
258 gnutls_kx_algorithm_t kx;
259 char c[] = "# \n";
261 if (tls->nl)
263 memcpy (data, c, sizeof (c));
264 ret = strlen (c);
266 else
267 ret = GNUTLS_E_AGAIN;
269 kx = gnutls_kx_get (tls->ses);
270 log_write ("PROTO=%s CIPHER=%s MAC=%s KX=%s(%d)",
271 gnutls_protocol_get_name (gnutls_protocol_get_version
272 (tls->ses)),
273 gnutls_cipher_get_name (gnutls_cipher_get (tls->ses)),
274 gnutls_mac_get_name (gnutls_mac_get (tls->ses)),
275 gnutls_kx_get_name (kx), gnutls_dh_get_prime_bits (tls->ses));
276 if (!tls->nl)
277 continue;
279 break;
282 TEST_TIMEOUT (client->thd->timeout, ret, start, rc);
283 if (rc)
284 break;
286 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
288 if (ret < 0)
290 log_write ("TLS: %s", gnutls_strerror (ret));
291 ret = 0;
293 else if (ret > 0)
294 tls->nl = ((char *)data)[ret-1] == '\n';
296 return ret;
299 ssize_t
300 tls_write_hook (assuan_context_t ctx, assuan_fd_t fd, const void *data,
301 size_t len)
303 struct client_s *client = assuan_get_pointer (ctx);
304 ssize_t ret;
305 time_t start = time (NULL);
307 if (client->disco)
308 return -1;
310 (void)fd;
313 gpg_error_t rc = 0;
315 ret = gnutls_record_send (client->thd->tls->ses, data, len);
316 TEST_TIMEOUT (client->thd->timeout, ret, start, rc);
317 if (rc)
318 break;
320 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
322 if (ret < 0)
323 log_write ("TLS: %s", gnutls_strerror (ret));
325 return ret;
328 static gpg_error_t
329 tls_init_params ()
331 int n;
332 char *tmp, *tmp2;
333 gpg_error_t rc = GPG_ERR_GENERAL;
334 static pthread_mutex_t tls_mutex = PTHREAD_MUTEX_INITIALIZER;
336 if (x509_cred)
337 return 0;
339 MUTEX_LOCK(&tls_mutex);
340 pthread_cleanup_push (release_mutex_cb, &tls_mutex);
341 tls_deinit_params ();
342 n = gnutls_certificate_allocate_credentials (&x509_cred);
343 if (n != GNUTLS_E_SUCCESS)
345 log_write ("%s", gnutls_strerror (n));
346 x509_cred = NULL;
347 goto fail;
350 tmp = str_asprintf ("%s/ca-cert.pem", homedir);
351 if (!tmp)
353 rc = GPG_ERR_ENOMEM;
354 log_write ("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror (rc));
355 goto fail;
358 n = gnutls_certificate_set_x509_trust_file (x509_cred, tmp,
359 GNUTLS_X509_FMT_PEM);
360 if (n < 0)
362 log_write ("%s: %s", tmp, gnutls_strerror (n));
363 xfree (tmp);
364 goto fail;
367 xfree (tmp);
368 tmp = str_asprintf ("%s/server-cert.pem", homedir);
369 if (!tmp)
371 rc = GPG_ERR_ENOMEM;
372 log_write ("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror (rc));
373 goto fail;
376 tmp2 = str_asprintf ("%s/server-key.pem", homedir);
377 if (!tmp2)
379 xfree (tmp);
380 rc = GPG_ERR_ENOMEM;
381 log_write ("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror (rc));
382 goto fail;
385 n = gnutls_certificate_set_x509_key_file (x509_cred, tmp, tmp2,
386 GNUTLS_X509_FMT_PEM);
387 xfree (tmp);
388 xfree (tmp2);
389 if (n != GNUTLS_E_SUCCESS)
391 log_write ("%s", gnutls_strerror (n));
392 goto fail;
395 tmp = config_get_string ("global", "tls_dh_params_file");
396 if (tmp)
398 tmp2 = expand_homedir (tmp);
399 if (!tmp2)
401 log_write ("%s: %s", tmp, pwmd_strerror (GPG_ERR_ENOMEM));
402 xfree (tmp);
403 rc = GPG_ERR_ENOMEM;
404 goto fail;
407 xfree (tmp);
408 tmp = tmp2;
409 n = gnutls_dh_params_init (&dh_params);
410 if (!n)
412 gnutls_datum_t data;
414 n = gnutls_load_file (tmp, &data);
415 if (!n)
417 n = gnutls_dh_params_import_pkcs3 (dh_params, &data,
418 GNUTLS_X509_FMT_PEM);
419 if (!n)
420 gnutls_certificate_set_dh_params (x509_cred, dh_params);
422 wipememory (data.data, 0, data.size);
423 free (data.data);
427 if (n != GNUTLS_E_SUCCESS)
429 log_write ("%s: %s", tmp, gnutls_strerror (n));
430 xfree (tmp);
431 goto fail;
433 xfree (tmp);
436 rc = 0;
438 fail:
439 if (rc)
440 tls_deinit_params ();
442 pthread_cleanup_pop (1);
443 return rc;
446 void
447 tls_deinit_params ()
449 if (dh_params)
451 gnutls_dh_params_deinit (dh_params);
452 dh_params = NULL;
455 if (x509_cred)
457 gnutls_certificate_free_credentials (x509_cred);
458 x509_cred = NULL;
462 static gpg_error_t
463 do_tls_validate_access (struct client_s *client, const char *section)
465 char **access = config_get_list (section, "allowed");
466 char **p;
467 int allowed = 0;
469 if (!access || !*access)
470 return GPG_ERR_EACCES;
472 for (p = access; p && *p; p++)
474 int not = 0;
475 char *fp = *p;
477 if (*fp && *fp == '+' && *(fp + 1) == 0) // allow all connections
479 allowed = 1;
480 continue;
483 if (*fp == '!' || *fp == '-')
485 not = 1;
486 fp++;
487 if (!*fp)
488 break;
491 if (*fp++ != '#')
492 continue;
494 if (!strcasecmp (client->thd->tls->fp, fp))
495 allowed = not ? 0 : 1;
498 strv_free (access);
499 return allowed ? 0 : GPG_ERR_EACCES;
502 gpg_error_t
503 tls_validate_access (struct client_s *client, const char *filename)
505 gpg_error_t rc = do_tls_validate_access (client, "global");
507 if (!rc && filename)
508 rc = do_tls_validate_access (client, filename);
510 return rc;
513 void
514 tls_rehandshake ()
516 unsigned t, i;
518 MUTEX_LOCK (&cn_mutex);
519 t = slist_length (cn_thread_list);
520 for (i = 0; i < t; i++)
522 struct client_thread_s *thd = slist_nth_data (cn_thread_list, i);
524 if (thd->remote && thd->tls)
525 thd->tls->rehandshake = 1;
527 MUTEX_UNLOCK (&cn_mutex);
530 static int
531 start_stop_tls_with_protocol (int ipv6, int term)
533 struct addrinfo hints, *servinfo, *p;
534 int port = config_get_integer ("global", "tcp_port");
535 char buf[7];
536 int n;
537 int *fd = ipv6 ? &tls6_fd : &tls_fd;
539 if (term || config_get_boolean ("global", "enable_tcp") == 0)
541 if (tls6_fd != -1)
543 shutdown (tls6_fd, SHUT_RDWR);
544 close (tls6_fd);
545 tls6_fd = -1;
548 if (tls_fd != -1)
550 shutdown (tls_fd, SHUT_RDWR);
551 close (tls_fd);
552 tls_fd = -1;
555 return 0;
558 memset (&hints, 0, sizeof (hints));
559 hints.ai_family = ipv6 ? AF_INET6 : AF_INET;
560 hints.ai_socktype = SOCK_STREAM;
561 hints.ai_flags = AI_PASSIVE;
562 snprintf (buf, sizeof (buf), "%i", port);
564 if ((n = getaddrinfo (NULL, buf, &hints, &servinfo)) == -1)
566 log_write ("getaddrinfo(): %s", gai_strerror (n));
567 return 0;
570 for (n = 0, p = servinfo; p != NULL; p = p->ai_next)
572 int r = 1;
574 if ((ipv6 && p->ai_family != AF_INET6)
575 || (!ipv6 && p->ai_family != AF_INET))
576 continue;
578 if ((*fd = socket (p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
580 log_write ("socket(): %s", strerror (errno));
581 continue;
584 if (setsockopt (*fd, SOL_SOCKET, SO_REUSEADDR, &r, sizeof (int)) == -1)
586 log_write ("setsockopt(): %s",
587 pwmd_strerror (gpg_error_from_errno (errno)));
588 freeaddrinfo (servinfo);
589 goto fail;
592 if (bind (*fd, p->ai_addr, p->ai_addrlen) == -1)
594 close (*fd);
595 log_write ("bind(): %s",
596 pwmd_strerror (gpg_error_from_errno (errno)));
597 continue;
600 n++;
601 break;
604 freeaddrinfo (servinfo);
606 if (!n)
607 goto fail;
609 #if HAVE_DECL_SO_BINDTODEVICE != 0
610 char *tmp = config_get_string ("global", "tcp_interface");
611 if (tmp && setsockopt (*fd, SOL_SOCKET, SO_BINDTODEVICE, tmp,
612 strlen (tmp)) == -1)
614 log_write ("setsockopt(): %s",
615 pwmd_strerror (gpg_error_from_errno (errno)));
616 xfree (tmp);
617 goto fail;
620 xfree (tmp);
621 #endif
623 if (listen (*fd, 128) == -1)
625 log_write ("listen(): %s", strerror (errno));
626 goto fail;
629 return 1;
631 fail:
632 start_stop_tls_with_protocol (0, 1);
633 if (tls_fd != -1)
634 close (tls_fd);
636 if (tls6_fd != -1)
637 close (tls6_fd);
639 tls_fd = -1;
640 tls6_fd = -1;
641 return 0;
645 tls_start_stop (int term)
647 char *s = config_get_string ("global", "tcp_bind");
648 int b;
650 if (!s)
651 return 0;
653 if (!strcmp (s, "any"))
655 b = start_stop_tls_with_protocol (0, term);
656 if (b)
657 b = start_stop_tls_with_protocol (1, term);
659 else if (!strcmp (s, "ipv4"))
660 b = start_stop_tls_with_protocol (0, term);
661 else if (!strcmp (s, "ipv6"))
662 b = start_stop_tls_with_protocol (1, term);
663 else
664 b = 0;
666 xfree (s);
667 if (!term && b)
669 gpg_error_t rc = tls_init_params ();
670 if (rc)
672 start_stop_tls_with_protocol (0, 1);
673 return 0;
677 return b;