Resend pinentry options during PASSWD and SAVE.
[libpwmd.git] / src / tls.c
blob7171d73327004151785e79f6dce41a11dbdefa97
1 /*
2 Copyright (C) 2012, 2013, 2014, 2015
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of libpwmd.
7 Libpwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Libpwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <fcntl.h>
33 #ifdef HAVE_STRINGS_H
34 #include <strings.h>
35 #endif
37 #include "types.h"
38 #include "misc.h"
40 #define DEFAULT_TLS_PRIORITY "SECURE256:SECURE192:SECURE128:-VERS-SSL3.0"
41 #define WAIT_INTERVAL 50000
42 #define TEST_TIMEOUT(pwm, timeout, ret, start, rc) \
43 do { \
44 if (ret == GNUTLS_E_AGAIN || pwm->cancel) \
45 { \
46 time_t now = time (NULL); \
47 if (pwm->cancel || (timeout && now - start >= timeout)) \
48 { \
49 if (pwm->cancel) \
50 rc = gpg_error (GPG_ERR_CANCELED); \
51 else \
52 rc = gpg_error (GPG_ERR_ETIMEDOUT); \
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 void
64 tls_free (pwm_t *pwm)
66 struct tls_s *tls = pwm->tcp->tls;
67 int ret = 0;
69 if (!tls)
70 return;
72 pwmd_free (tls->ca);
73 pwmd_free (tls->cert);
74 pwmd_free (tls->key);
75 pwmd_free (tls->priority);
76 pwmd_free (tls->server_fp);
78 if (tls->session)
80 time_t start = time (NULL);
84 gpg_error_t rc = 0;
86 ret = gnutls_bye (tls->session, GNUTLS_SHUT_WR);
87 TEST_TIMEOUT (pwm, tls->timeout, ret, start, rc);
88 if (rc)
89 break;
91 while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
93 gnutls_deinit (tls->session);
95 else if (pwm->fd != -1)
97 close (pwm->fd);
98 pwm->fd = -1;
101 if (tls->x509)
102 gnutls_certificate_free_credentials (tls->x509);
104 tls->session = NULL;
105 tls->x509 = NULL;
106 pwmd_free (tls);
107 pwm->tls_error = ret;
110 ssize_t
111 read_hook_tls (pwm_t *pwm, assuan_fd_t fd, void *data, size_t len)
113 struct tls_s *tls = pwm->tcp->tls;
115 if (*tls->fd == -1)
116 return -1;
118 ssize_t ret;
119 time_t start = time (NULL);
121 rehandshake:
124 gpg_error_t rc = 0;
126 ret = gnutls_record_recv (tls->session, data, len);
127 if (ret == GNUTLS_E_REHANDSHAKE)
129 ret = gnutls_rehandshake (tls->session);
130 if (ret == GNUTLS_E_GOT_APPLICATION_DATA)
131 goto rehandshake;
132 else if (ret != GNUTLS_E_SUCCESS)
134 pwm->tls_error = ret;
135 ret = 0;
136 break;
141 ret = gnutls_handshake (tls->session);
142 rc = 0;
143 TEST_TIMEOUT (pwm, tls->timeout, ret, start, rc);
144 if (rc)
146 close (*tls->fd);
147 *tls->fd = -1;
148 errno = ETIMEDOUT;
149 return -1;
152 while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
154 pwm->tls_error = ret;
155 continue;
158 TEST_TIMEOUT (pwm, tls->timeout, ret, start, rc);
159 if (rc)
161 close (*tls->fd);
162 *tls->fd = -1;
163 errno = ETIMEDOUT;
164 return -1;
167 while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
169 if (ret < 0)
170 pwm->tls_error = ret;
172 if (!ret)
173 return 0;
174 else if (ret == GNUTLS_E_PREMATURE_TERMINATION)
175 errno = EPIPE;
177 return ret < 0 ? -1 : ret;
180 ssize_t
181 write_hook_tls (pwm_t *pwm, assuan_fd_t fd, const void *data, size_t len)
183 struct tls_s *tls = pwm->tcp->tls;
185 /* This is probably the BYE command after a previous call timed
186 * out. If not done, the time(2) call seems to hang.*/
187 if (*tls->fd == -1)
188 return -1;
190 ssize_t ret;
191 time_t start = time (NULL);
195 gpg_error_t rc = 0;
197 ret = gnutls_record_send (tls->session, data, len);
198 TEST_TIMEOUT (pwm, tls->timeout, ret, start, rc);
199 if (rc)
201 close (*tls->fd);
202 *tls->fd = -1;
203 errno = ETIMEDOUT;
204 return -1;
207 while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
209 if (ret < 0)
210 pwm->tls_error = ret;
212 if (!ret)
213 return 0;
214 else if (ret == GNUTLS_E_PREMATURE_TERMINATION)
215 errno = EPIPE;
217 return ret < 0 ? -1 : ret;
220 static gpg_error_t
221 tls_fingerprint (pwm_t *pwm, char **result)
223 gnutls_session_t ses = pwm->tcp->tls->session;
224 gnutls_x509_crt_t crt;
225 const gnutls_datum_t *cert_list;
226 unsigned count;
227 unsigned char buf[32];
228 size_t len = sizeof (buf);
230 *result = NULL;
231 gnutls_x509_crt_init (&crt);
232 if (!crt)
233 return GPG_ERR_ENOMEM;
235 cert_list = gnutls_certificate_get_peers (ses, &count);
236 if (count)
238 pwm->tls_error = gnutls_x509_crt_import (crt, &cert_list[0],
239 GNUTLS_X509_FMT_DER);
240 if (!pwm->tls_error)
241 gnutls_x509_crt_get_fingerprint (crt, GNUTLS_DIG_SHA256, buf, &len);
244 gnutls_x509_crt_deinit (crt);
245 if (!count)
247 pwm->tls_error = GNUTLS_CERT_INVALID;
248 return GPG_ERR_MISSING_CERT;
251 if (!pwm->tls_error)
252 *result = bin2hex (buf, len);
254 return !pwm->tls_error ? 0 : GPG_ERR_ENOMEM;
257 static gpg_error_t
258 verify_server_certificate (unsigned status)
260 if (status & GNUTLS_CERT_REVOKED)
262 fprintf (stderr, "server certificate is revoked\n");
263 return GPG_ERR_CERT_REVOKED;
266 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
268 fprintf (stderr, "server certificate has no signer\n");
269 return GPG_ERR_NO_SIGNATURE_SCHEME;
272 if (status & GNUTLS_CERT_SIGNATURE_FAILURE)
274 fprintf (stderr, "server certificate signature verification failed\n");
275 return GPG_ERR_BAD_SIGNATURE;
278 if (status & GNUTLS_CERT_EXPIRED)
280 fprintf (stderr, "server certificate expired\n");
281 return GPG_ERR_CERT_EXPIRED;
284 if (status & GNUTLS_CERT_SIGNER_NOT_CA)
286 fprintf (stderr, "server certificate signer is not from CA\n");
287 return GPG_ERR_BAD_CA_CERT;
290 if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
292 fprintf (stderr, "server certificate has insecure algorithm\n");
293 return GPG_ERR_UNSUPPORTED_ALGORITHM;
296 if (status)
298 fprintf (stderr, "server certificate is invalid: %u\n", status);
299 return GPG_ERR_BAD_CERT;
302 return 0;
305 static gpg_error_t
306 verify_certificate (pwm_t *pwm)
308 unsigned int status;
309 const gnutls_datum_t *cert_list;
310 unsigned int cert_list_size;
311 int i;
312 gnutls_x509_crt_t cert;
313 gpg_error_t rc = 0;
315 i = gnutls_certificate_verify_peers2 (pwm->tcp->tls->session, &status);
316 if (i < 0)
318 pwm->tls_error = i;
319 return GPG_ERR_BAD_CERT;
322 rc = verify_server_certificate (status);
323 if (rc)
324 return rc;
326 if (gnutls_certificate_type_get (pwm->tcp->tls->session) != GNUTLS_CRT_X509)
327 return GPG_ERR_UNSUPPORTED_CERT;
329 if (gnutls_x509_crt_init (&cert) < 0)
330 return gpg_error_from_errno (ENOMEM);
332 cert_list = gnutls_certificate_get_peers (pwm->tcp->tls->session,
333 &cert_list_size);
334 if (!cert_list)
336 rc = GPG_ERR_MISSING_CERT;
337 goto done;
340 for (i = 0; i < cert_list_size; i++)
342 pwm->tls_error = gnutls_x509_crt_import (cert, &cert_list[i],
343 GNUTLS_X509_FMT_DER);
344 if (pwm->tls_error < 0)
346 rc = GPG_ERR_BAD_CERT_CHAIN;
347 goto done;
350 if (gnutls_x509_crt_get_expiration_time (cert) < time (0))
352 rc = GPG_ERR_CERT_EXPIRED;
353 goto done;
356 if (gnutls_x509_crt_get_activation_time (cert) > time (0))
358 rc = GPG_ERR_CERT_TOO_YOUNG;
359 goto done;
362 if (pwm->tcp->tls->verify)
364 if (!gnutls_x509_crt_check_hostname (cert, pwm->tcp->host))
366 rc = GPG_ERR_BAD_CERT_CHAIN;
367 goto done;
372 if (pwm->tcp->tls->server_fp)
374 char *result;
376 rc = tls_fingerprint (pwm, &result);
377 if (!rc)
379 if (!result || !*result ||
380 strcasecmp (result, pwm->tcp->tls->server_fp))
381 rc = GPG_ERR_BAD_CERT;
383 pwmd_free (result);
387 done:
388 gnutls_x509_crt_deinit (cert);
389 return rc;
392 static gpg_error_t
393 tls_init (pwm_t * pwm)
395 gpg_error_t rc;
396 int ret;
397 const char *errstr;
399 ret = gnutls_certificate_allocate_credentials (&pwm->tcp->tls->x509);
400 if (ret)
402 pwm->tls_error = ret;
403 return gpg_error_from_errno (ENOMEM);
406 /* The client certificate must be signed by the CA of the pwmd server
407 * certificate in order for the client to authenticate successfully. Man in
408 * the middle attacks are still possible if the attacker is running a pwmd
409 * that doesn't require client certificate authentication. So require the
410 * client to verify the server certificate.
412 ret = gnutls_certificate_set_x509_trust_file (pwm->tcp->tls->x509,
413 pwm->tcp->tls->ca,
414 GNUTLS_X509_FMT_PEM);
415 if (ret == -1)
417 rc = GPG_ERR_INV_CERT_OBJ;
418 goto fail;
421 ret = gnutls_certificate_set_x509_key_file (pwm->tcp->tls->x509,
422 pwm->tcp->tls->cert,
423 pwm->tcp->tls->key,
424 GNUTLS_X509_FMT_PEM);
425 if (ret != GNUTLS_E_SUCCESS)
427 pwm->tls_error = ret;
428 rc = GPG_ERR_INV_CERT_OBJ;
429 goto fail;
432 ret = gnutls_init (&pwm->tcp->tls->session, GNUTLS_CLIENT);
433 if (ret != GNUTLS_E_SUCCESS)
435 pwm->tls_error = ret;
436 rc = GPG_ERR_INV_CERT_OBJ;
437 goto fail;
440 ret = gnutls_priority_set_direct (pwm->tcp->tls->session,
441 pwm->tcp->tls->priority
442 ? pwm->tcp->tls->priority
443 : DEFAULT_TLS_PRIORITY,
444 &errstr);
445 if (ret != GNUTLS_E_SUCCESS)
447 pwm->tls_error = ret;
448 rc = GPG_ERR_INV_CERT_OBJ;
449 goto fail;
452 ret = gnutls_credentials_set (pwm->tcp->tls->session, GNUTLS_CRD_CERTIFICATE,
453 pwm->tcp->tls->x509);
454 if (ret != GNUTLS_E_SUCCESS)
456 pwm->tls_error = ret;
457 rc = GPG_ERR_INV_CERT_OBJ;
458 goto fail;
461 gnutls_transport_set_ptr (pwm->tcp->tls->session,
462 (gnutls_transport_ptr_t) pwm->fd);
463 if (fcntl (pwm->fd, F_SETFL, O_NONBLOCK) == -1)
465 rc = gpg_error_from_errno (errno);
466 goto fail;
469 time_t start = time (NULL);
472 ret = gnutls_handshake (pwm->tcp->tls->session);
473 rc = 0;
474 TEST_TIMEOUT (pwm, pwm->tcp->tls->timeout, ret, start, rc);
475 if (rc)
476 goto fail;
478 while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
480 if (ret != GNUTLS_E_SUCCESS)
482 pwm->tls_error = ret;
483 rc = GPG_ERR_INV_CERT_OBJ;
484 goto fail;
487 rc = verify_certificate (pwm);
489 fail:
490 if (rc)
492 /* Keep the original error since it maybe overwritten during TLS
493 * shutdown. */
494 ret = pwm->tls_error;
495 /* The session may not have completed a handshake. Will crash during
496 * gnutls_bye(). */
497 gnutls_deinit (pwm->tcp->tls->session);
498 pwm->tcp->tls->session = NULL;
499 free_tcp (pwm);
500 pwm->tls_error = ret;
503 return rc;
506 gpg_error_t
507 _do_tls_connect (pwm_t * pwm, const char *host, int port,
508 const char *cert, const char *key, const char *cacert,
509 const char *prio, const char *server_fp, int verify)
511 struct tcp_s *tcp;
512 gpg_error_t rc;
514 if (!cert || !key || !cacert)
515 return GPG_ERR_INV_ARG;
517 tcp = pwmd_calloc (1, sizeof (struct tcp_s));
518 if (!tcp)
519 return GPG_ERR_ENOMEM;
521 pthread_cond_init (&tcp->dns_cond, NULL);
522 pthread_mutex_init (&tcp->dns_mutex, NULL);
523 pwm->tcp = tcp;
524 tcp->port = port;
525 tcp->host = pwmd_strdup (host);
526 if (!tcp->host)
528 rc = GPG_ERR_ENOMEM;
529 goto fail;
532 tcp->tls = pwmd_calloc (1, sizeof (struct tls_s));
533 if (!tcp->tls)
535 rc = GPG_ERR_ENOMEM;
536 goto fail;
539 tcp->tls->timeout = pwm->socket_timeout;
540 tcp->tls->verify = verify;
541 tcp->tls->cert = pwmd_strdup (cert);
542 if (!tcp->tls->cert)
544 rc = GPG_ERR_ENOMEM;
545 goto fail;
548 tcp->tls->key = pwmd_strdup (key);
549 if (!tcp->tls->key)
551 rc = GPG_ERR_ENOMEM;
552 goto fail;
555 tcp->tls->ca = pwmd_strdup (cacert);
556 if (!tcp->tls->ca)
558 rc = GPG_ERR_ENOMEM;
559 goto fail;
562 if (prio)
564 tcp->tls->priority = pwmd_strdup (prio);
565 if (!tcp->tls->priority)
567 rc = GPG_ERR_ENOMEM;
568 goto fail;
572 if (server_fp)
574 tcp->tls->server_fp = pwmd_strdup (server_fp);
575 if (!tcp->tls->server_fp)
577 rc = GPG_ERR_ENOMEM;
578 goto fail;
582 rc = tcp_connect_common (pwm);
583 if (!rc)
585 rc = tls_init (pwm);
586 if (!rc)
588 pwm->tcp->fd = pwm->tcp->tls->fd = &pwm->fd;
589 rc = assuan_socket_connect_fd (pwm->ctx, pwm->fd, 0);
593 fail:
594 if (rc)
595 free_tcp (pwm);
597 return rc;
601 * tls[46]://[hostname][:port]
603 gpg_error_t
604 _parse_tls_url (const char *str, char **host, int *port)
606 *port = 6466;
607 return parse_hostname_common (str, host, port);