Fix a few 'gcc -fanalyzer' warnings.
[pwmd.git] / src / tls.c
blobd00a8e053266b99db92388552f8311afe2d8bc26
1 /*
2 Copyright (C) 2006-2023 Ben Kibbey <bjk@luxsci.net>
4 This file is part of pwmd.
6 Pwmd is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 Pwmd is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
22 #include <gnutls/x509.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netdb.h>
28 #ifdef HAVE_STRINGS_H
29 #include <strings.h>
30 #endif
32 #include "pwmd-error.h"
33 #include <gcrypt.h>
34 #include "mem.h"
35 #include "util-misc.h"
36 #include "util-string.h"
37 #include "common.h"
38 #include "tls.h"
39 #include "mutex.h"
40 #include "rcfile.h"
42 #define WAIT_INTERVAL 50000
43 #define TEST_TIMEOUT(timeout, ret, start, rc) \
44 do { \
45 rc = 0; \
46 if (ret == GNUTLS_E_AGAIN) \
47 { \
48 time_t now = time (NULL); \
49 if (timeout && now - start >= timeout) \
50 { \
51 rc = gpg_error (GPG_ERR_ETIMEDOUT); \
52 ret = GNUTLS_E_TIMEDOUT; \
53 break; \
54 } \
55 struct timeval wtv = { 0, WAIT_INTERVAL }; \
56 select (0, NULL, NULL, NULL, &wtv); \
57 } \
58 if (ret != GNUTLS_E_INTERRUPTED) \
59 break; \
60 } \
61 while (0)
63 static gnutls_dh_params_t dh_params;
64 static gnutls_certificate_credentials_t x509_cred;
65 int tls_fd;
66 int tls6_fd;
68 static char *
69 tls_fingerprint (gnutls_session_t ses)
71 gnutls_x509_crt_t crt;
72 const gnutls_datum_t *cert_list;
73 unsigned count;
74 unsigned char buf[32];
75 size_t len = sizeof (buf);
77 gnutls_x509_crt_init (&crt);
78 if (!crt)
80 log_write ("%s(%i): %s(): %s", __FILE__, __LINE__, __FUNCTION__,
81 gnutls_strerror (GNUTLS_E_MEMORY_ERROR));
82 return NULL;
85 cert_list = gnutls_certificate_get_peers (ses, &count);
86 if (count)
88 gnutls_x509_crt_import (crt, &cert_list[0], GNUTLS_X509_FMT_DER);
89 gnutls_x509_crt_get_fingerprint (crt, GNUTLS_DIG_SHA256, buf, &len);
90 gnutls_x509_crt_deinit (crt);
92 return len ? bin2hex (buf, len) : NULL;
95 gnutls_x509_crt_deinit (crt);
96 return NULL;
99 static int
100 verify_client_certificate (unsigned status)
102 if (!status)
103 return 0;
105 if (status & GNUTLS_CERT_REVOKED)
106 log_write (_("client certificate is revoked"));
108 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
109 log_write (_("client certificate has no signer"));
111 if (status & GNUTLS_CERT_SIGNATURE_FAILURE)
112 log_write (_("client certificate signature verification failed"));
114 if (status & GNUTLS_CERT_EXPIRED)
115 log_write (_("client certificate expired"));
117 if (status & GNUTLS_CERT_SIGNER_NOT_CA)
118 log_write (_("client certificate signer is not from CA"));
120 if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
121 log_write (_("client certificate has insecure algorithm"));
123 if (status & GNUTLS_CERT_INVALID)
124 log_write (_("client certificate is invalid"));
126 return GNUTLS_E_CERTIFICATE_ERROR;
129 struct tls_s *
130 tls_init_client (int fd, int timeout, const char *prio)
132 int ret;
133 unsigned status;
134 const char *prio_error;
135 gnutls_kx_algorithm_t kx;
136 gpg_error_t rc = 0;
137 struct tls_s *tls = xcalloc (1, sizeof (struct tls_s));
139 if (!tls)
141 log_write ("%s(%i): %s: %s", __FILE__, __LINE__, __FUNCTION__,
142 strerror (ENOMEM));
143 return NULL;
146 ret = gnutls_init (&tls->ses, GNUTLS_SERVER);
147 if (ret != GNUTLS_E_SUCCESS)
148 goto fail;
150 ret = gnutls_priority_set_direct (tls->ses, prio, &prio_error);
151 if (ret != GNUTLS_E_SUCCESS)
152 goto fail;
154 ret = gnutls_credentials_set (tls->ses, GNUTLS_CRD_CERTIFICATE, x509_cred);
155 if (ret != GNUTLS_E_SUCCESS)
156 goto fail;
158 gnutls_certificate_server_set_request (tls->ses, GNUTLS_CERT_REQUIRE);
159 gnutls_transport_set_ptr (tls->ses, (gnutls_transport_ptr_t) fd);
160 time_t start = time (NULL);
163 ret = gnutls_handshake (tls->ses);
164 TEST_TIMEOUT (timeout, ret, start, rc);
165 if (rc)
166 goto fail;
168 while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
170 if (ret != GNUTLS_E_SUCCESS)
171 goto fail;
173 ret = gnutls_certificate_verify_peers2 (tls->ses, &status);
174 if (ret)
175 goto fail;
177 kx = gnutls_kx_get (tls->ses);
178 tls->fp = tls_fingerprint (tls->ses);
179 log_write ("PROTO=%s CIPHER=%s MAC=%s KX=%s(%d) FP=%s",
180 gnutls_protocol_get_name (gnutls_protocol_get_version
181 (tls->ses)),
182 gnutls_cipher_get_name (gnutls_cipher_get (tls->ses)),
183 gnutls_mac_get_name (gnutls_mac_get (tls->ses)),
184 gnutls_kx_get_name (kx), gnutls_dh_get_prime_bits (tls->ses),
185 tls->fp ? tls->fp : "N/A");
186 ret = verify_client_certificate (status);
187 if (ret)
188 goto fail;
190 return tls;
192 fail:
193 log_write ("%s", rc ? pwmd_strerror(rc) : gnutls_strerror (ret));
194 gnutls_deinit (tls->ses);
195 xfree (tls->fp);
196 xfree (tls);
197 return NULL;
200 void
201 tls_log (int level, const char *msg)
203 log_write ("TLS: %i: %s", level, msg);
206 void
207 tls_audit_log (gnutls_session_t s, const char *msg)
209 (void)s;
210 log_write ("TLS: %s", msg);
213 ssize_t
214 tls_read_hook (assuan_context_t ctx, assuan_fd_t fd, void *data, size_t len)
216 struct client_s *client = assuan_get_pointer (ctx);
217 struct tls_s *tls = client->thd->tls;
218 time_t start = time (NULL);
219 ssize_t ret;
223 gpg_error_t rc = 0;
224 struct timeval tv = { 0, WAIT_INTERVAL};
225 fd_set fds;
226 int n;
228 FD_ZERO (&fds);
229 FD_SET (fd, &fds);
230 n = select (client->thd->fd+1, &fds, NULL, NULL, &tv);
231 if (n == 0 && tls->nl)
233 char c[] = "#\n";
235 memcpy (data, c, sizeof(c));
236 ret = strlen (c);
237 break;
240 ret = gnutls_record_recv (tls->ses, data, len);
241 if (ret == GNUTLS_E_REHANDSHAKE)
243 tls->rehandshake = 0;
247 ret = gnutls_handshake (tls->ses);
248 TEST_TIMEOUT (client->thd->timeout, ret, start, rc);
249 if (rc)
250 break;
252 while (ret < 0 && gnutls_error_is_fatal (ret) == 0);
254 if (!ret)
256 gnutls_kx_algorithm_t kx;
257 char c[] = "# \n";
259 if (tls->nl)
261 memcpy (data, c, sizeof (c));
262 ret = strlen (c);
264 else
265 ret = GNUTLS_E_AGAIN;
267 kx = gnutls_kx_get (tls->ses);
268 log_write ("PROTO=%s CIPHER=%s MAC=%s KX=%s(%d)",
269 gnutls_protocol_get_name (gnutls_protocol_get_version
270 (tls->ses)),
271 gnutls_cipher_get_name (gnutls_cipher_get (tls->ses)),
272 gnutls_mac_get_name (gnutls_mac_get (tls->ses)),
273 gnutls_kx_get_name (kx), gnutls_dh_get_prime_bits (tls->ses));
274 if (!tls->nl)
275 continue;
277 break;
280 TEST_TIMEOUT (client->thd->timeout, ret, start, rc);
281 if (rc)
282 break;
284 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
286 if (ret < 0)
288 log_write ("TLS: %s", gnutls_strerror (ret));
289 ret = 0;
291 else if (ret > 0)
292 tls->nl = ((char *)data)[ret-1] == '\n';
294 return ret;
297 ssize_t
298 tls_write_hook (assuan_context_t ctx, assuan_fd_t fd, const void *data,
299 size_t len)
301 struct client_s *client = assuan_get_pointer (ctx);
302 ssize_t ret;
303 time_t start = time (NULL);
305 if (client->disco)
306 return -1;
308 (void)fd;
311 gpg_error_t rc = 0;
313 ret = gnutls_record_send (client->thd->tls->ses, data, len);
314 TEST_TIMEOUT (client->thd->timeout, ret, start, rc);
315 if (rc)
316 break;
318 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
320 if (ret < 0)
321 log_write ("TLS: %s", gnutls_strerror (ret));
323 return ret;
326 static gpg_error_t
327 tls_init_params ()
329 int n;
330 char *tmp, *server_cert = NULL, *server_key = NULL;
331 gpg_error_t rc = GPG_ERR_GENERAL;
332 static pthread_mutex_t tls_mutex = PTHREAD_MUTEX_INITIALIZER;
334 if (x509_cred)
335 return 0;
337 MUTEX_LOCK(&tls_mutex);
338 pthread_cleanup_push (release_mutex_cb, &tls_mutex);
339 MUTEX_LOCK (&rcfile_mutex);
340 pthread_cleanup_push (release_mutex_cb, &rcfile_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 if (config_get_boolean ("global", "tls_use_crl"))
352 tmp = config_get_string ("global", "tls_crl_file");
353 if (!tmp)
354 tmp = str_asprintf ("%s/crl.pem", homedir);
355 else
357 char *tmp2 = expand_homedir (tmp);
358 xfree (tmp);
359 tmp = tmp2;
362 if (!tmp)
364 rc = GPG_ERR_ENOMEM;
365 goto fail;
368 if (access (tmp, R_OK) == -1 && errno == ENOENT)
370 rc = gpg_error_from_errno (errno);
371 log_write ("%s: %s", tmp, pwmd_strerror (rc));
372 goto fail;
374 else
376 n = gnutls_certificate_set_x509_crl_file (x509_cred, tmp,
377 GNUTLS_X509_FMT_PEM);
378 if (n < 0)
380 log_write ("%s: %s", tmp, gnutls_strerror (n));
381 xfree (tmp);
382 goto fail;
386 xfree (tmp);
389 tmp = config_get_string ("global", "tls_ca_file");
390 if (!tmp)
391 tmp = str_asprintf ("%s/ca-cert.pem", homedir);
392 else
394 char *tmp2 = expand_homedir (tmp);
395 xfree (tmp);
396 tmp = tmp2;
399 if (!tmp)
401 rc = GPG_ERR_ENOMEM;
402 log_write ("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror (rc));
403 goto fail;
406 n = gnutls_certificate_set_x509_trust_file (x509_cred, tmp,
407 GNUTLS_X509_FMT_PEM);
408 if (n < 0)
410 log_write ("%s: %s", tmp, gnutls_strerror (n));
411 xfree (tmp);
412 goto fail;
415 xfree (tmp);
416 server_cert = config_get_string ("global", "tls_server_cert_file");
417 if (!server_cert)
418 server_cert = str_asprintf ("%s/server-cert.pem", homedir);
419 else
421 tmp = expand_homedir (server_cert);
422 xfree (server_cert);
423 server_cert = tmp;
426 if (!server_cert)
428 rc = GPG_ERR_ENOMEM;
429 log_write ("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror (rc));
430 goto fail;
433 server_key = config_get_string ("global", "tls_server_key_file");
434 if (!server_key)
435 server_key = str_asprintf ("%s/server-key.pem", homedir);
436 else
438 tmp = expand_homedir (server_key);
439 xfree (server_key);
440 server_key = tmp;
443 if (!server_key)
445 xfree (server_cert);
446 rc = GPG_ERR_ENOMEM;
447 log_write ("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror (rc));
448 goto fail;
451 n = gnutls_certificate_set_x509_key_file (x509_cred, server_cert, server_key,
452 GNUTLS_X509_FMT_PEM);
453 xfree (server_cert);
454 xfree (server_key);
455 if (n != GNUTLS_E_SUCCESS)
457 log_write ("%s", gnutls_strerror (n));
458 goto fail;
461 tmp = config_get_string ("global", "tls_dh_params_file");
462 if (tmp)
464 char *tmp2 = expand_homedir (tmp);
465 if (!tmp2)
467 log_write ("%s: %s", tmp, pwmd_strerror (GPG_ERR_ENOMEM));
468 xfree (tmp);
469 rc = GPG_ERR_ENOMEM;
470 goto fail;
473 xfree (tmp);
474 tmp = tmp2;
475 n = gnutls_dh_params_init (&dh_params);
476 if (!n)
478 gnutls_datum_t data;
480 n = gnutls_load_file (tmp, &data);
481 if (!n)
483 n = gnutls_dh_params_import_pkcs3 (dh_params, &data,
484 GNUTLS_X509_FMT_PEM);
485 if (!n)
486 gnutls_certificate_set_dh_params (x509_cred, dh_params);
488 wipememory (data.data, 0, data.size);
489 free (data.data);
493 if (n != GNUTLS_E_SUCCESS)
495 log_write ("%s: %s", tmp, gnutls_strerror (n));
496 xfree (tmp);
497 goto fail;
499 xfree (tmp);
502 rc = 0;
504 fail:
505 if (rc)
506 tls_deinit_params ();
508 pthread_cleanup_pop (1); // tls_mutex
509 pthread_cleanup_pop (1); // rcfile_mutex
510 return rc;
513 void
514 tls_deinit_params ()
516 if (dh_params)
518 gnutls_dh_params_deinit (dh_params);
519 dh_params = NULL;
522 if (x509_cred)
524 gnutls_certificate_free_credentials (x509_cred);
525 x509_cred = NULL;
529 static gpg_error_t
530 do_tls_validate_access (struct client_s *client, const char *section)
532 char **access = config_get_list (section, "allowed");
533 char **p;
534 int allowed = 0;
536 if (!access || !*access)
537 return GPG_ERR_EACCES;
539 for (p = access; p && *p; p++)
541 int not = 0;
542 char *fp = *p;
544 if (*fp && *fp == '+' && *(fp + 1) == 0) // allow all connections
546 allowed = 1;
547 continue;
550 if (*fp == '!' || *fp == '-')
552 not = 1;
553 fp++;
554 if (!*fp)
555 break;
558 if (*fp++ != '#')
559 continue;
561 if (!strcasecmp (client->thd->tls->fp, fp))
562 allowed = not ? 0 : 1;
565 strv_free (access);
566 return allowed ? 0 : GPG_ERR_EACCES;
569 gpg_error_t
570 tls_validate_access (struct client_s *client, const char *filename)
572 gpg_error_t rc = do_tls_validate_access (client, "global");
574 if (!rc && filename)
575 rc = do_tls_validate_access (client, filename);
577 return rc;
580 void
581 tls_rehandshake ()
583 unsigned t, i;
585 MUTEX_LOCK (&cn_mutex);
586 t = slist_length (cn_thread_list);
587 for (i = 0; i < t; i++)
589 struct client_thread_s *thd = slist_nth_data (cn_thread_list, i);
591 if (thd->remote && thd->tls)
592 thd->tls->rehandshake = 1;
594 MUTEX_UNLOCK (&cn_mutex);
597 static int
598 start_stop_tls_with_protocol (int ipv6, int term)
600 struct addrinfo hints, *servinfo, *p;
601 int port = config_get_integer ("global", "tcp_port");
602 char buf[7];
603 int n;
604 int *fd = ipv6 ? &tls6_fd : &tls_fd;
606 if (term || config_get_boolean ("global", "enable_tcp") == 0)
608 if (tls6_fd != -1)
610 shutdown (tls6_fd, SHUT_RDWR);
611 close (tls6_fd);
612 tls6_fd = -1;
615 if (tls_fd != -1)
617 shutdown (tls_fd, SHUT_RDWR);
618 close (tls_fd);
619 tls_fd = -1;
622 return 0;
625 memset (&hints, 0, sizeof (hints));
626 hints.ai_family = ipv6 ? AF_INET6 : AF_INET;
627 hints.ai_socktype = SOCK_STREAM;
628 hints.ai_flags = AI_PASSIVE;
629 snprintf (buf, sizeof (buf), "%i", port);
631 if ((n = getaddrinfo (NULL, buf, &hints, &servinfo)) == -1)
633 log_write ("getaddrinfo(): %s", gai_strerror (n));
634 return 0;
637 for (n = 0, p = servinfo; p != NULL; p = p->ai_next)
639 int r = 1;
641 if ((ipv6 && p->ai_family != AF_INET6)
642 || (!ipv6 && p->ai_family != AF_INET))
643 continue;
645 if ((*fd = socket (p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
647 log_write ("socket(): %s", strerror (errno));
648 continue;
651 if (setsockopt (*fd, SOL_SOCKET, SO_REUSEADDR, &r, sizeof (int)) == -1)
653 log_write ("setsockopt(): %s",
654 pwmd_strerror (gpg_error_from_errno (errno)));
655 freeaddrinfo (servinfo);
656 goto fail;
659 if (bind (*fd, p->ai_addr, p->ai_addrlen) == -1)
661 close (*fd);
662 log_write ("bind(): port %u: %s", port,
663 pwmd_strerror (gpg_error_from_errno (errno)));
664 continue;
667 n++;
668 break;
671 freeaddrinfo (servinfo);
673 if (!n)
674 goto fail;
676 #if HAVE_DECL_SO_BINDTODEVICE != 0
677 char *tmp = config_get_string ("global", "tcp_interface");
678 if (tmp && setsockopt (*fd, SOL_SOCKET, SO_BINDTODEVICE, tmp,
679 strlen (tmp)) == -1)
681 log_write ("setsockopt(): %s",
682 pwmd_strerror (gpg_error_from_errno (errno)));
683 xfree (tmp);
684 goto fail;
687 xfree (tmp);
688 #endif
690 if (listen (*fd, 128) == -1)
692 log_write ("listen(): %s", strerror (errno));
693 goto fail;
696 return 1;
698 fail:
699 start_stop_tls_with_protocol (0, 1);
700 if (tls_fd != -1)
701 close (tls_fd);
703 if (tls6_fd != -1)
704 close (tls6_fd);
706 tls_fd = -1;
707 tls6_fd = -1;
708 return 0;
712 tls_start_stop (int term)
714 char *s = config_get_string ("global", "tcp_bind");
715 int b;
717 if (!s)
718 return 0;
720 if (!strcmp (s, "any"))
722 b = start_stop_tls_with_protocol (0, term);
723 if (b)
724 b = start_stop_tls_with_protocol (1, term);
726 else if (!strcmp (s, "ipv4"))
727 b = start_stop_tls_with_protocol (0, term);
728 else if (!strcmp (s, "ipv6"))
729 b = start_stop_tls_with_protocol (1, term);
730 else
731 b = 0;
733 xfree (s);
734 if (!term && b)
736 gpg_error_t rc = tls_init_params ();
737 if (rc)
739 start_stop_tls_with_protocol (0, 1);
740 return 0;
744 return b;