More cancellation fixes.
[libpwmd.git] / src / tls.c
bloba83f707492307aee71f16e2a08686e27d3a119fc
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>
29 #ifdef HAVE_STRINGS_H
30 #include <strings.h>
31 #endif
33 #include "pwmd-error.h"
34 #include <gcrypt.h>
35 #include "mem.h"
36 #include "util-misc.h"
37 #include "util-string.h"
38 #include "common.h"
39 #include "tls.h"
40 #include "mutex.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 tv = { 0, WAIT_INTERVAL }; \
56 select (0, NULL, NULL, NULL, &tv); \
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;
66 static char *
67 tls_fingerprint (gnutls_session_t ses)
69 gnutls_x509_crt_t crt;
70 const gnutls_datum_t *cert_list;
71 unsigned count;
72 unsigned char buf[32];
73 size_t len = sizeof (buf);
75 gnutls_x509_crt_init (&crt);
76 if (!crt)
78 log_write ("%s(%i): %s(): %s", __FILE__, __LINE__, __FUNCTION__,
79 gnutls_strerror (GNUTLS_E_MEMORY_ERROR));
80 return NULL;
83 cert_list = gnutls_certificate_get_peers (ses, &count);
84 if (count)
86 gnutls_x509_crt_import (crt, &cert_list[0], GNUTLS_X509_FMT_DER);
87 gnutls_x509_crt_get_fingerprint (crt, GNUTLS_DIG_SHA256, buf, &len);
88 gnutls_x509_crt_deinit (crt);
90 return len ? bin2hex (buf, len) : NULL;
93 gnutls_x509_crt_deinit (crt);
94 return NULL;
97 static int
98 verify_client_certificate (unsigned status)
100 if (!status)
101 return 0;
103 if (status & GNUTLS_CERT_REVOKED)
104 log_write (_("client certificate is revoked"));
106 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
107 log_write (_("client certificate has no signer"));
109 if (status & GNUTLS_CERT_SIGNATURE_FAILURE)
110 log_write (_("client certificate signature verification failed"));
112 if (status & GNUTLS_CERT_EXPIRED)
113 log_write (_("client certificate expired"));
115 if (status & GNUTLS_CERT_SIGNER_NOT_CA)
116 log_write (_("client certificate signer is not from CA"));
118 if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
119 log_write (_("client certificate has insecure algorithm"));
121 if (status & GNUTLS_CERT_INVALID)
122 log_write (_("client certificate is invalid"));
124 return GNUTLS_E_CERTIFICATE_ERROR;
127 struct tls_s *
128 tls_init_client (int fd, int timeout, const char *prio)
130 int ret;
131 unsigned status;
132 const char *prio_error;
133 gnutls_kx_algorithm_t kx;
134 gpg_error_t rc = 0;
135 struct tls_s *tls = xcalloc (1, sizeof (struct tls_s));
137 if (!tls)
139 log_write ("%s(%i): %s: %s", __FILE__, __LINE__, __FUNCTION__,
140 strerror (ENOMEM));
141 return NULL;
144 ret = gnutls_init (&tls->ses, GNUTLS_SERVER);
145 if (ret != GNUTLS_E_SUCCESS)
146 goto fail;
148 ret = gnutls_priority_set_direct (tls->ses, prio, &prio_error);
149 if (ret != GNUTLS_E_SUCCESS)
150 goto fail;
152 ret = gnutls_credentials_set (tls->ses, GNUTLS_CRD_CERTIFICATE, x509_cred);
153 if (ret != GNUTLS_E_SUCCESS)
154 goto fail;
156 gnutls_certificate_server_set_request (tls->ses, GNUTLS_CERT_REQUIRE);
157 gnutls_transport_set_ptr (tls->ses, (gnutls_transport_ptr_t) fd);
158 time_t start = time (NULL);
161 ret = gnutls_handshake (tls->ses);
162 TEST_TIMEOUT (timeout, ret, start, rc);
163 if (rc)
164 goto fail;
166 while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
168 if (ret != GNUTLS_E_SUCCESS)
169 goto fail;
171 ret = gnutls_certificate_verify_peers2 (tls->ses, &status);
172 if (ret)
173 goto fail;
175 kx = gnutls_kx_get (tls->ses);
176 tls->fp = tls_fingerprint (tls->ses);
177 log_write ("PROTO=%s CIPHER=%s MAC=%s KX=%s(%d) FP=%s",
178 gnutls_protocol_get_name (gnutls_protocol_get_version
179 (tls->ses)),
180 gnutls_cipher_get_name (gnutls_cipher_get (tls->ses)),
181 gnutls_mac_get_name (gnutls_mac_get (tls->ses)),
182 gnutls_kx_get_name (kx), gnutls_dh_get_prime_bits (tls->ses),
183 tls->fp ? tls->fp : "N/A");
184 ret = verify_client_certificate (status);
185 if (ret)
186 goto fail;
188 return tls;
190 fail:
191 log_write ("%s", rc ? pwmd_strerror(rc) : gnutls_strerror (ret));
192 gnutls_deinit (tls->ses);
193 xfree (tls->fp);
194 xfree (tls);
195 return NULL;
198 void
199 tls_log (int level, const char *msg)
201 log_write ("TLS: %i: %s", level, msg);
204 void
205 tls_audit_log (gnutls_session_t s, const char *msg)
207 (void)s;
208 log_write ("TLS: %s", msg);
211 ssize_t
212 tls_read_hook (assuan_context_t ctx, assuan_fd_t fd, void *data, size_t len)
214 struct client_s *client = assuan_get_pointer (ctx);
215 struct tls_s *tls = client->thd->tls;
216 time_t start = time (NULL);
217 ssize_t ret;
221 gpg_error_t rc = 0;
222 struct timeval tv = { 0, 0 };
223 fd_set fds;
224 int n;
226 FD_ZERO (&fds);
227 FD_SET (fd, &fds);
228 n = select (client->thd->fd+1, &fds, NULL, NULL, &tv);
229 if (n == 0 && tls->nl)
231 char c[] = "#\n";
233 memcpy (data, c, sizeof(c));
234 ret = strlen (c);
235 break;
238 ret = gnutls_record_recv (tls->ses, data, len);
239 if (ret == GNUTLS_E_REHANDSHAKE)
241 tls->rehandshake = 0;
245 ret = gnutls_handshake (tls->ses);
246 TEST_TIMEOUT (client->thd->timeout, ret, start, rc);
247 if (rc)
248 break;
250 while (ret < 0 && gnutls_error_is_fatal (ret) == 0);
252 if (!ret)
254 gnutls_kx_algorithm_t kx;
255 char c[] = "# \n";
257 if (tls->nl)
259 memcpy (data, c, sizeof (c));
260 ret = strlen (c);
262 else
263 ret = GNUTLS_E_AGAIN;
265 kx = gnutls_kx_get (tls->ses);
266 log_write ("PROTO=%s CIPHER=%s MAC=%s KX=%s(%d)",
267 gnutls_protocol_get_name (gnutls_protocol_get_version
268 (tls->ses)),
269 gnutls_cipher_get_name (gnutls_cipher_get (tls->ses)),
270 gnutls_mac_get_name (gnutls_mac_get (tls->ses)),
271 gnutls_kx_get_name (kx), gnutls_dh_get_prime_bits (tls->ses));
272 if (!tls->nl)
273 continue;
275 break;
278 TEST_TIMEOUT (client->thd->timeout, ret, start, rc);
279 if (rc)
280 break;
282 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
284 if (ret < 0)
286 log_write ("TLS: %s", gnutls_strerror (ret));
287 ret = 0;
289 else if (ret > 0)
290 tls->nl = ((char *)data)[ret-1] == '\n';
292 return ret;
295 ssize_t
296 tls_write_hook (assuan_context_t ctx, assuan_fd_t fd, const void *data,
297 size_t len)
299 struct client_s *client = assuan_get_pointer (ctx);
300 ssize_t ret;
301 time_t start = time (NULL);
305 gpg_error_t rc = 0;
307 ret = gnutls_record_send (client->thd->tls->ses, data, len);
308 TEST_TIMEOUT (client->thd->timeout, ret, start, rc);
309 if (rc)
310 break;
312 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
314 if (ret < 0)
315 log_write ("TLS: %s", gnutls_strerror (ret));
317 return ret;
320 gpg_error_t
321 tls_init_params ()
323 int n;
324 char *tmp, *tmp2;
325 gpg_error_t rc = GPG_ERR_GENERAL;
326 static pthread_mutex_t tls_mutex = PTHREAD_MUTEX_INITIALIZER;
328 if (x509_cred)
329 return 0;
331 MUTEX_LOCK(&tls_mutex);
332 pthread_cleanup_push (release_mutex_cb, &tls_mutex);
333 tls_deinit_params ();
334 n = gnutls_certificate_allocate_credentials (&x509_cred);
335 if (n != GNUTLS_E_SUCCESS)
337 log_write ("%s", gnutls_strerror (n));
338 x509_cred = NULL;
339 goto fail;
342 tmp = str_asprintf ("%s/ca-cert.pem", homedir);
343 if (!tmp)
345 rc = GPG_ERR_ENOMEM;
346 log_write ("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror (rc));
347 goto fail;
350 n = gnutls_certificate_set_x509_trust_file (x509_cred, tmp,
351 GNUTLS_X509_FMT_PEM);
352 if (n < 0)
354 log_write ("%s: %s", tmp, gnutls_strerror (n));
355 xfree (tmp);
356 goto fail;
359 xfree (tmp);
360 tmp = str_asprintf ("%s/server-cert.pem", homedir);
361 if (!tmp)
363 rc = GPG_ERR_ENOMEM;
364 log_write ("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror (rc));
365 goto fail;
368 tmp2 = str_asprintf ("%s/server-key.pem", homedir);
369 if (!tmp2)
371 xfree (tmp);
372 rc = GPG_ERR_ENOMEM;
373 log_write ("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror (rc));
374 goto fail;
377 n = gnutls_certificate_set_x509_key_file (x509_cred, tmp, tmp2,
378 GNUTLS_X509_FMT_PEM);
379 xfree (tmp);
380 xfree (tmp2);
381 if (n != GNUTLS_E_SUCCESS)
383 log_write ("%s", gnutls_strerror (n));
384 goto fail;
387 tmp = config_get_string ("global", "tls_dh_params_file");
388 if (tmp)
390 tmp2 = expand_homedir (tmp);
391 if (!tmp2)
393 xfree (tmp);
394 log_write ("%s: %s", tmp, pwmd_strerror (GPG_ERR_ENOMEM));
395 rc = GPG_ERR_ENOMEM;
396 goto fail;
399 xfree (tmp);
400 tmp = tmp2;
401 n = gnutls_dh_params_init (&dh_params);
402 if (!n)
404 gnutls_datum_t data;
406 n = gnutls_load_file (tmp, &data);
407 if (!n)
409 n = gnutls_dh_params_import_pkcs3 (dh_params, &data,
410 GNUTLS_X509_FMT_PEM);
411 if (!n)
412 gnutls_certificate_set_dh_params (x509_cred, dh_params);
414 wipememory (data.data, 0, data.size);
415 free (data.data);
419 if (n != GNUTLS_E_SUCCESS)
421 log_write ("%s: %s", tmp, gnutls_strerror (n));
422 xfree (tmp);
423 goto fail;
425 xfree (tmp);
428 rc = 0;
430 fail:
431 if (rc)
432 tls_deinit_params ();
434 pthread_cleanup_pop (1);
435 return rc;
438 void
439 tls_deinit_params ()
441 if (dh_params)
443 gnutls_dh_params_deinit (dh_params);
444 dh_params = NULL;
447 if (x509_cred)
449 gnutls_certificate_free_credentials (x509_cred);
450 x509_cred = NULL;
454 static gpg_error_t
455 do_tls_validate_access (struct client_s *client, const char *section)
457 char **access = config_get_list (section, "allowed");
458 char **p;
459 int allowed = 0;
461 if (!access || !*access)
462 return GPG_ERR_EACCES;
464 for (p = access; p && *p; p++)
466 int not = 0;
467 char *fp = *p;
469 if (*fp && *fp == '+' && *(fp + 1) == 0) // allow all connections
471 allowed = 1;
472 continue;
475 if (*fp == '!' || *fp == '-')
477 not = 1;
478 fp++;
479 if (!*fp)
480 break;
483 if (*fp++ != '#')
484 continue;
486 if (!strcasecmp (client->thd->tls->fp, fp))
487 allowed = not ? 0 : 1;
490 strv_free (access);
491 return allowed ? 0 : GPG_ERR_EACCES;
494 gpg_error_t
495 tls_validate_access (struct client_s *client, const char *filename)
497 gpg_error_t rc = do_tls_validate_access (client, "global");
499 if (!rc && filename)
500 rc = do_tls_validate_access (client, filename);
502 return rc;
505 void
506 tls_rehandshake ()
508 unsigned t, i;
510 MUTEX_LOCK (&cn_mutex);
511 t = slist_length (cn_thread_list);
512 for (i = 0; i < t; i++)
514 struct client_thread_s *thd = slist_nth_data (cn_thread_list, i);
516 if (thd->remote && thd->tls)
517 thd->tls->rehandshake = 1;
519 MUTEX_UNLOCK (&cn_mutex);