s/GPG_ERR_CONFLICT/GPG_ERR_EEXIST.
[libpwmd.git] / src / tls.c
blobb66701eac7a1865e2821a684eb8c2bbc89213cb9
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 if (ret == GNUTLS_E_AGAIN) \
46 { \
47 time_t now = time (NULL); \
48 if (timeout && now - start >= timeout) \
49 { \
50 rc = gpg_error (GPG_ERR_ETIMEDOUT); \
51 break; \
52 } \
53 struct timeval tv = { 0, WAIT_INTERVAL }; \
54 select (0, NULL, NULL, NULL, &tv); \
55 } \
56 if (ret != GNUTLS_E_INTERRUPTED) \
57 break; \
58 } \
59 while (0)
61 static char *
62 tls_fingerprint (gnutls_session_t ses)
64 gnutls_x509_crt_t crt;
65 const gnutls_datum_t *cert_list;
66 unsigned count;
67 unsigned char buf[32];
68 size_t len = sizeof (buf);
70 gnutls_x509_crt_init (&crt);
71 if (!crt)
73 log_write ("%s(%i): %s(): %s", __FILE__, __LINE__, __FUNCTION__,
74 gnutls_strerror (GNUTLS_E_MEMORY_ERROR));
75 return NULL;
78 cert_list = gnutls_certificate_get_peers (ses, &count);
79 if (count)
81 gnutls_x509_crt_import (crt, &cert_list[0], GNUTLS_X509_FMT_DER);
82 gnutls_x509_crt_get_fingerprint (crt, GNUTLS_DIG_SHA256, buf, &len);
83 gnutls_x509_crt_deinit (crt);
85 return len ? bin2hex (buf, len) : NULL;
88 gnutls_x509_crt_deinit (crt);
89 return NULL;
92 static int
93 verify_client_certificate (unsigned status)
95 if (!status)
96 return 0;
98 if (status & GNUTLS_CERT_REVOKED)
99 log_write (_("client certificate is revoked"));
101 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
102 log_write (_("client certificate has no signer"));
104 if (status & GNUTLS_CERT_SIGNATURE_FAILURE)
105 log_write (_("client certificate signature verification failed"));
107 if (status & GNUTLS_CERT_EXPIRED)
108 log_write (_("client certificate expired"));
110 if (status & GNUTLS_CERT_SIGNER_NOT_CA)
111 log_write (_("client certificate signer is not from CA"));
113 if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
114 log_write (_("client certificate has insecure algorithm"));
116 if (status & GNUTLS_CERT_INVALID)
117 log_write (_("client certificate is invalid"));
119 return GNUTLS_E_CERTIFICATE_ERROR;
122 struct tls_s *
123 tls_init (int fd, int timeout, const char *prio)
125 struct tls_s *tls = xcalloc (1, sizeof (struct tls_s));
126 int ret;
127 unsigned status;
128 const char *prio_error;
129 gnutls_kx_algorithm_t kx;
130 gpg_error_t rc = 0;
132 if (!tls)
134 log_write ("%s(%i): %s: %s", __FILE__, __LINE__, __FUNCTION__,
135 strerror (ENOMEM));
136 return NULL;
139 ret = gnutls_init (&tls->ses, GNUTLS_SERVER);
140 if (ret != GNUTLS_E_SUCCESS)
141 goto fail;
143 ret = gnutls_priority_set_direct (tls->ses, prio, &prio_error);
144 if (ret != GNUTLS_E_SUCCESS)
145 goto fail;
147 ret = gnutls_credentials_set (tls->ses, GNUTLS_CRD_CERTIFICATE, x509_cred);
148 if (ret != GNUTLS_E_SUCCESS)
149 goto fail;
151 gnutls_certificate_server_set_request (tls->ses, GNUTLS_CERT_REQUIRE);
152 gnutls_transport_set_ptr (tls->ses, (gnutls_transport_ptr_t) fd);
153 time_t start = time (NULL);
156 ret = gnutls_handshake (tls->ses);
157 TEST_TIMEOUT (timeout, ret, start, rc);
158 if (rc)
159 goto fail;
161 while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
163 if (ret != GNUTLS_E_SUCCESS)
164 goto fail;
166 ret = gnutls_certificate_verify_peers2 (tls->ses, &status);
167 if (ret)
168 goto fail;
170 kx = gnutls_kx_get (tls->ses);
171 tls->fp = tls_fingerprint (tls->ses);
172 log_write ("PROTO=%s CIPHER=%s MAC=%s KX=%s(%d) FP=%s",
173 gnutls_protocol_get_name (gnutls_protocol_get_version
174 (tls->ses)),
175 gnutls_cipher_get_name (gnutls_cipher_get (tls->ses)),
176 gnutls_mac_get_name (gnutls_mac_get (tls->ses)),
177 gnutls_kx_get_name (kx), gnutls_dh_get_prime_bits (tls->ses),
178 tls->fp ? tls->fp : "N/A");
179 ret = verify_client_certificate (status);
180 if (ret)
181 goto fail;
183 return tls;
185 fail:
186 log_write ("%s", rc ? pwmd_strerror(rc) : gnutls_strerror (ret));
187 gnutls_deinit (tls->ses);
188 xfree (tls->fp);
189 xfree (tls);
190 return NULL;
193 void
194 tls_log (int level, const char *msg)
196 log_write ("TLS: %i: %s", level, msg);
199 void
200 tls_audit_log (gnutls_session_t s, const char *msg)
202 (void)s;
203 log_write ("TLS: %s", msg);
206 ssize_t
207 tls_read_hook (assuan_context_t ctx, assuan_fd_t fd, void *data, size_t len)
209 struct client_s *client = assuan_get_pointer (ctx);
210 time_t start = time (NULL);
211 ssize_t ret;
213 rehandshake:
216 gpg_error_t rc = 0;
218 ret = gnutls_record_recv (client->thd->tls->ses, data, len);
219 if (ret == GNUTLS_E_REHANDSHAKE)
221 ret = gnutls_rehandshake (client->thd->tls->ses);
222 if (ret == GNUTLS_E_GOT_APPLICATION_DATA)
223 goto rehandshake;
224 else if (ret != GNUTLS_E_SUCCESS)
226 log_write ("%s", gnutls_strerror (ret));
227 ret = 0;
228 break;
233 ret = gnutls_handshake (client->thd->tls->ses);
234 rc = 0;
235 TEST_TIMEOUT (client->thd->timeout, ret, start, rc);
236 if (rc)
238 log_write ("%s", gnutls_strerror (ret));
239 ret = 0;
240 close (client->thd->fd);
241 client->thd->fd = -1;
242 break;
245 while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
247 if (rc)
248 break;
250 continue;
253 TEST_TIMEOUT (client->thd->timeout, ret, start, rc);
254 if (rc)
256 errno = ETIMEDOUT;
257 close (client->thd->fd);
258 client->thd->fd = -1;
259 return -1;
262 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
264 if (ret < 0)
266 log_write ("%s", gnutls_strerror (ret));
267 ret = 0;
270 return ret;
273 ssize_t
274 tls_write_hook (assuan_context_t ctx, assuan_fd_t fd, const void *data,
275 size_t len)
277 struct client_s *client = assuan_get_pointer (ctx);
278 ssize_t ret;
279 time_t start = time (NULL);
283 gpg_error_t rc = 0;
285 ret = gnutls_record_send (client->thd->tls->ses, data, len);
286 TEST_TIMEOUT (client->thd->timeout, ret, start, rc);
287 if (rc)
289 errno = ETIMEDOUT;
290 close (client->thd->fd);
291 client->thd->fd = -1;
292 return -1;
295 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
297 return ret;
300 static int
301 parse_dh_sec_level (const char *str, gpg_error_t *rc)
303 *rc = 0;
305 if (!str)
306 return gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH, GNUTLS_SEC_PARAM_MEDIUM);
308 if (!strcasecmp (str, "low"))
309 return gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LOW);
310 else if (!strcasecmp (str, "medium"))
311 return gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH, GNUTLS_SEC_PARAM_MEDIUM);
312 else if (!strcasecmp (str, "high"))
313 return gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH, GNUTLS_SEC_PARAM_HIGH);
314 else if (!strcasecmp (str, "ultra"))
315 return gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH, GNUTLS_SEC_PARAM_ULTRA);
317 *rc = GPG_ERR_INV_VALUE;
318 return GNUTLS_SEC_PARAM_UNKNOWN;
321 gpg_error_t
322 tls_init_params (const char *dh_sec_level)
324 int n;
325 char *tmp, *tmp2;
326 gpg_error_t rc = GPG_ERR_UNKNOWN_ERRNO;
327 static pthread_mutex_t tls_mutex = PTHREAD_MUTEX_INITIALIZER;
328 int bits = parse_dh_sec_level (dh_sec_level, &rc);
330 if (rc)
332 log_write ("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror (rc));
333 return rc;
336 MUTEX_LOCK(&tls_mutex);
337 tls_deinit_params ();
338 rc = GPG_ERR_UNKNOWN_ERRNO;
339 n = gnutls_certificate_allocate_credentials (&x509_cred);
340 if (n != GNUTLS_E_SUCCESS)
342 log_write ("%s", gnutls_strerror (n));
343 x509_cred = NULL;
344 goto fail;
347 tmp = str_asprintf ("%s/ca-cert.pem", homedir);
348 if (!tmp)
350 rc = GPG_ERR_ENOMEM;
351 log_write ("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror (rc));
352 goto fail;
355 n = gnutls_certificate_set_x509_trust_file (x509_cred, tmp,
356 GNUTLS_X509_FMT_PEM);
357 if (n < 0)
359 log_write ("%s: %s", tmp, gnutls_strerror (n));
360 xfree (tmp);
361 goto fail;
364 xfree (tmp);
365 tmp = str_asprintf ("%s/server-cert.pem", homedir);
366 if (!tmp)
368 rc = GPG_ERR_ENOMEM;
369 log_write ("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror (rc));
370 goto fail;
373 tmp2 = str_asprintf ("%s/server-key.pem", homedir);
374 if (!tmp2)
376 xfree (tmp);
377 rc = ENOMEM;
378 log_write ("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror (rc));
379 goto fail;
382 n = gnutls_certificate_set_x509_key_file (x509_cred, tmp, tmp2,
383 GNUTLS_X509_FMT_PEM);
384 xfree (tmp);
385 xfree (tmp2);
386 if (n != GNUTLS_E_SUCCESS)
388 log_write ("%s", gnutls_strerror (n));
389 goto fail;
392 log_write ("%s", _("(Re)generating key exchange parameters..."));
393 n = gnutls_dh_params_init (&dh_params);
394 if (n != GNUTLS_E_SUCCESS)
395 goto fail;
397 n = gnutls_dh_params_generate2 (dh_params, bits);
398 if (n != GNUTLS_E_SUCCESS)
400 log_write ("%s", gnutls_strerror (n));
401 goto fail;
404 gnutls_certificate_set_dh_params (x509_cred, dh_params);
405 MUTEX_UNLOCK(&tls_mutex);
406 return 0;
408 fail:
409 tls_deinit_params ();
410 MUTEX_UNLOCK(&tls_mutex);
411 return rc;
414 void
415 tls_deinit_params ()
417 if (dh_params)
419 gnutls_dh_params_deinit (dh_params);
420 dh_params = NULL;
423 if (x509_cred)
425 gnutls_certificate_free_credentials (x509_cred);
426 x509_cred = NULL;
430 static gpg_error_t
431 do_tls_validate_access (struct client_s *client, const char *section)
433 char **access = config_get_list (section, "allowed");
434 char **p;
435 int allowed = 0;
437 if (!access || !*access)
438 return GPG_ERR_EACCES;
440 for (p = access; p && *p; p++)
442 int not = 0;
443 char *fp = *p;
445 if (*fp && *fp == '+' && *(fp + 1) == 0) // allow all connections
447 allowed = 1;
448 continue;
451 if (*fp == '!' || *fp == '-')
453 not = 1;
454 fp++;
455 if (!*fp)
456 break;
459 if (*fp++ != '#')
460 continue;
462 if (!strcasecmp (client->thd->tls->fp, fp))
463 allowed = not ? 0 : 1;
466 strv_free (access);
467 return allowed ? 0 : GPG_ERR_EACCES;
470 gpg_error_t
471 tls_validate_access (struct client_s *client, const char *filename)
473 gpg_error_t rc = do_tls_validate_access (client, "global");
475 if (!rc && filename)
476 rc = do_tls_validate_access (client, filename);
478 return rc;