Reindent to GNU coding style.
[pwmd.git] / src / tls.c
blobe0428d095de7b90fdc072056cbeef9c0b09c2b19
1 /*
2 Copyright (C) 2008 Ben Kibbey <bjk@luxsci.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
18 #include <gnutls/x509.h>
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include "pwmd-error.h"
25 #include "mem.h"
26 #include "util-misc.h"
27 #include "util-string.h"
28 #include "common.h"
29 #include "tls.h"
30 #include "mutex.h"
32 static char *
33 tls_fingerprint (gnutls_session_t ses)
35 gnutls_x509_crt_t crt;
36 const gnutls_datum_t *cert_list;
37 unsigned count;
38 unsigned char buf[20];
39 size_t len = sizeof (buf);
41 gnutls_x509_crt_init (&crt);
42 if (!crt)
44 log_write ("%s(%i): %s(): %s", __FILE__, __LINE__, __FUNCTION__,
45 gnutls_strerror (GNUTLS_E_MEMORY_ERROR));
46 return NULL;
49 cert_list = gnutls_certificate_get_peers (ses, &count);
50 if (count)
52 gnutls_x509_crt_import (crt, &cert_list[0], GNUTLS_X509_FMT_DER);
53 gnutls_x509_crt_get_fingerprint (crt, GNUTLS_DIG_SHA1, buf, &len);
56 gnutls_x509_crt_deinit (crt);
57 return bin2hex (buf, len);
60 static int
61 verify_client_certificate (unsigned status)
63 if (!status)
64 return 0;
66 if (status & GNUTLS_CERT_INVALID)
67 log_write (_("client certificate is invalid"));
69 if (status & GNUTLS_CERT_REVOKED)
70 log_write (_("client certificate is revoked"));
72 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
73 log_write (_("client certificate has no signer"));
75 if (status & GNUTLS_CERT_SIGNER_NOT_CA)
76 log_write (_("client certificate signer is not from CA"));
78 if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
79 log_write (_("client certificate has insecure algorithm"));
81 return GNUTLS_E_CERTIFICATE_ERROR;
84 struct tls_s *
85 tls_init (int fd, const char *prio)
87 struct tls_s *tls = xcalloc (1, sizeof (struct tls_s));
88 int ret;
89 unsigned status;
90 const char *prio_error;
91 gnutls_kx_algorithm_t kx;
93 if (!tls)
95 log_write ("%s(%i): %s: %s", __FILE__, __LINE__, __FUNCTION__,
96 strerror (ENOMEM));
97 return NULL;
100 ret = gnutls_init (&tls->ses, GNUTLS_SERVER);
101 if (ret != GNUTLS_E_SUCCESS)
102 goto fail;
104 ret = gnutls_priority_set_direct (tls->ses, prio, &prio_error);
105 if (ret != GNUTLS_E_SUCCESS)
106 goto fail;
108 ret = gnutls_credentials_set (tls->ses, GNUTLS_CRD_CERTIFICATE, x509_cred);
109 if (ret != GNUTLS_E_SUCCESS)
110 goto fail;
112 gnutls_certificate_server_set_request (tls->ses, GNUTLS_CERT_REQUIRE);
113 gnutls_transport_set_ptr (tls->ses, (gnutls_transport_ptr_t) fd);
114 ret = gnutls_handshake (tls->ses);
115 if (ret != GNUTLS_E_SUCCESS)
116 goto fail;
118 ret = gnutls_certificate_verify_peers2 (tls->ses, &status);
119 if (ret)
120 goto fail;
122 kx = gnutls_kx_get (tls->ses);
123 tls->fp = tls_fingerprint (tls->ses);
124 log_write ("PROTO=%s CIPHER=%s MAC=%s KX=%s(%d) FP=%s",
125 gnutls_protocol_get_name (gnutls_protocol_get_version
126 (tls->ses)),
127 gnutls_cipher_get_name (gnutls_cipher_get (tls->ses)),
128 gnutls_mac_get_name (gnutls_mac_get (tls->ses)),
129 gnutls_kx_get_name (kx), gnutls_dh_get_prime_bits (tls->ses),
130 tls->fp ? tls->fp : "N/A");
131 ret = verify_client_certificate (status);
132 if (ret)
133 goto fail;
135 return tls;
137 fail:
138 log_write ("%s", gnutls_strerror (ret));
139 gnutls_deinit (tls->ses);
140 xfree (tls->fp);
141 xfree (tls);
142 return NULL;
145 /* From the documentation. */
147 tls_get_params (gnutls_session_t ses, gnutls_params_type_t type,
148 gnutls_params_st * st)
150 if (type == GNUTLS_PARAMS_RSA_EXPORT)
151 st->params.rsa_export = rsa_params;
152 else if (type == GNUTLS_PARAMS_DH)
153 st->params.dh = dh_params;
154 else
155 return -1;
157 st->type = type;
158 st->deinit = 0;
159 return 0;
162 void
163 tls_log (int level, const char *msg)
165 log_write ("TLS: %i: %s", level, msg);
168 ssize_t
169 tls_read_hook (assuan_context_t ctx, assuan_fd_t fd, void *data, size_t len)
171 struct client_s *client = assuan_get_pointer (ctx);
172 ssize_t ret;
176 ret = gnutls_record_recv (client->thd->tls->ses, data, len);
178 if (ret == GNUTLS_E_REHANDSHAKE)
180 ret = gnutls_rehandshake (client->thd->tls->ses);
181 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED ||
182 ret == GNUTLS_A_NO_RENEGOTIATION)
184 log_write ("%s", gnutls_strerror (ret));
185 continue;
188 if (ret != GNUTLS_E_SUCCESS)
190 log_write ("%s", gnutls_strerror (ret));
191 ret = 0;
192 break;
195 ret = gnutls_handshake (client->thd->tls->ses);
196 if (ret != GNUTLS_E_SUCCESS)
198 log_write ("%s", gnutls_strerror (ret));
199 ret = 0;
200 break;
203 continue;
206 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
208 if (ret < 0)
210 log_write ("%s", gnutls_strerror (ret));
211 ret = 0;
214 return ret;
217 ssize_t
218 tls_write_hook (assuan_context_t ctx, assuan_fd_t fd, const void *data,
219 size_t len)
221 struct client_s *client = assuan_get_pointer (ctx);
222 ssize_t ret;
226 struct timeval tv = { 0, 50000 };
228 ret = gnutls_record_send (client->thd->tls->ses, data, len);
229 if (ret == GNUTLS_E_AGAIN)
230 select (0, NULL, NULL, NULL, &tv);
232 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
234 return ret;
237 gpg_error_t
238 tls_init_params ()
240 int n;
241 char *tmp, *tmp2;
242 gpg_error_t rc = GPG_ERR_UNKNOWN_ERRNO;
244 n = gnutls_certificate_allocate_credentials (&x509_cred);
245 if (n != GNUTLS_E_SUCCESS)
247 log_write ("%s", gnutls_strerror (n));
248 x509_cred = NULL;
249 goto fail;
252 MUTEX_LOCK (&rcfile_mutex);
254 if (config_get_boolean ("global", "tls_use_crl"))
256 MUTEX_UNLOCK (&rcfile_mutex);
257 tmp = str_asprintf ("%s/crl.pem", homedir);
258 if (!tmp)
260 rc = GPG_ERR_ENOMEM;
261 goto fail;
264 if (access (tmp, R_OK) == -1 && errno == ENOENT)
265 log_write ("%s: %s", tmp, gnutls_strerror (n));
266 else
268 n = gnutls_certificate_set_x509_crl_file (x509_cred, tmp,
269 GNUTLS_X509_FMT_PEM);
270 if (n < 0)
272 log_write ("%s: %s", tmp, gnutls_strerror (n));
273 xfree (tmp);
274 goto fail;
278 xfree (tmp);
280 else
281 MUTEX_UNLOCK (&rcfile_mutex);
283 tmp = str_asprintf ("%s/ca-cert.pem", homedir);
284 if (!tmp)
286 rc = GPG_ERR_ENOMEM;
287 goto fail;
290 n = gnutls_certificate_set_x509_trust_file (x509_cred, tmp,
291 GNUTLS_X509_FMT_PEM);
292 if (n < 0)
294 log_write ("%s: %s", tmp, gnutls_strerror (n));
295 xfree (tmp);
296 goto fail;
299 xfree (tmp);
300 tmp = str_asprintf ("%s/server-cert.pem", homedir);
301 if (!tmp)
303 rc = GPG_ERR_ENOMEM;
304 goto fail;
307 tmp2 = str_asprintf ("%s/server-key.pem", homedir);
308 if (!tmp2)
310 xfree (tmp);
311 log_write ("%s(%i): %s", __FILE__, __LINE__, strerror (ENOMEM));
312 goto fail;
315 n = gnutls_certificate_set_x509_key_file (x509_cred, tmp, tmp2,
316 GNUTLS_X509_FMT_PEM);
317 xfree (tmp);
318 xfree (tmp2);
319 if (n != GNUTLS_E_SUCCESS)
321 log_write ("%s", gnutls_strerror (n));
322 goto fail;
325 log_write ("%s", _("Generating key exchange parameters..."));
326 n = gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
327 if (n)
329 log_write ("%s", pwmd_strerror (n));
330 goto fail;
333 n = gnutls_dh_params_init (&dh_params);
334 if (n != GNUTLS_E_SUCCESS)
336 log_write ("%s", gnutls_strerror (n));
337 goto fail;
340 n = gnutls_dh_params_generate2 (dh_params, 1024);
341 if (n != GNUTLS_E_SUCCESS)
343 log_write ("%s", gnutls_strerror (n));
344 goto fail;
347 gnutls_certificate_set_dh_params (x509_cred, dh_params);
348 n = gnutls_rsa_params_init (&rsa_params);
349 if (n != GNUTLS_E_SUCCESS)
351 log_write ("%s", gnutls_strerror (n));
352 goto fail;
355 n = gnutls_rsa_params_generate2 (rsa_params, 512);
356 if (n != GNUTLS_E_SUCCESS)
358 log_write ("%s", gnutls_strerror (n));
359 goto fail;
362 gnutls_certificate_set_rsa_export_params (x509_cred, rsa_params);
363 gnutls_certificate_set_params_function (x509_cred, tls_get_params);
364 return 0;
366 fail:
367 return rc;
370 void
371 tls_deinit_params ()
373 if (dh_params)
375 gnutls_dh_params_deinit (dh_params);
376 dh_params = NULL;
379 if (rsa_params)
381 gnutls_rsa_params_deinit (rsa_params);
382 rsa_params = NULL;
385 if (x509_cred)
387 gnutls_certificate_free_credentials (x509_cred);
388 x509_cred = NULL;
392 gpg_error_t
393 tls_validate_access (struct client_s *cl, const char *filename)
395 char **access = config_get_list (filename, "tls_access");
396 char **p;
397 int allow = 0, deny = 0;
399 if (!access || !*access)
400 return GPG_ERR_INV_USER_ID;
402 for (p = access; p && *p; p++)
404 int not = 0;
405 char *fp = *p;
407 if (*fp && *fp == '+' && *(fp + 1) == 0)
409 allow = 1;
410 continue;
413 if (*fp == '!')
415 not = 1;
416 fp++;
417 if (!*fp)
418 break;
421 if (!strcasecmp (cl->thd->tls->fp, fp))
423 if (not)
425 deny = 1;
426 break;
429 strv_free (access);
430 return 0;
434 /* Not allowed. */
435 strv_free (access);
436 return allow && !deny ? 0 : GPG_ERR_INV_USER_ID;