2 Copyright (C) 2006-2021 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/>.
22 #include <gnutls/x509.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
32 #include "pwmd-error.h"
35 #include "util-misc.h"
36 #include "util-string.h"
42 #define WAIT_INTERVAL 50000
43 #define TEST_TIMEOUT(timeout, ret, start, rc) \
46 if (ret == GNUTLS_E_AGAIN) \
48 time_t now = time (NULL); \
49 if (timeout && now - start >= timeout) \
51 rc = gpg_error (GPG_ERR_ETIMEDOUT); \
52 ret = GNUTLS_E_TIMEDOUT; \
55 struct timeval wtv = { 0, WAIT_INTERVAL }; \
56 select (0, NULL, NULL, NULL, &wtv); \
58 if (ret != GNUTLS_E_INTERRUPTED) \
63 static gnutls_dh_params_t dh_params
;
64 static gnutls_certificate_credentials_t x509_cred
;
69 tls_fingerprint (gnutls_session_t ses
)
71 gnutls_x509_crt_t crt
;
72 const gnutls_datum_t
*cert_list
;
74 unsigned char buf
[32];
75 size_t len
= sizeof (buf
);
77 gnutls_x509_crt_init (&crt
);
80 log_write ("%s(%i): %s(): %s", __FILE__
, __LINE__
, __FUNCTION__
,
81 gnutls_strerror (GNUTLS_E_MEMORY_ERROR
));
85 cert_list
= gnutls_certificate_get_peers (ses
, &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
);
100 verify_client_certificate (unsigned status
)
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
;
130 tls_init_client (int fd
, int timeout
, const char *prio
)
134 const char *prio_error
;
135 gnutls_kx_algorithm_t kx
;
137 struct tls_s
*tls
= xcalloc (1, sizeof (struct tls_s
));
141 log_write ("%s(%i): %s: %s", __FILE__
, __LINE__
, __FUNCTION__
,
146 ret
= gnutls_init (&tls
->ses
, GNUTLS_SERVER
);
147 if (ret
!= GNUTLS_E_SUCCESS
)
150 ret
= gnutls_priority_set_direct (tls
->ses
, prio
, &prio_error
);
151 if (ret
!= GNUTLS_E_SUCCESS
)
154 ret
= gnutls_credentials_set (tls
->ses
, GNUTLS_CRD_CERTIFICATE
, x509_cred
);
155 if (ret
!= GNUTLS_E_SUCCESS
)
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
);
168 while (ret
== GNUTLS_E_AGAIN
|| ret
== GNUTLS_E_INTERRUPTED
);
170 if (ret
!= GNUTLS_E_SUCCESS
)
173 ret
= gnutls_certificate_verify_peers2 (tls
->ses
, &status
);
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
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
);
193 log_write ("%s", rc
? pwmd_strerror(rc
) : gnutls_strerror (ret
));
194 gnutls_deinit (tls
->ses
);
201 tls_log (int level
, const char *msg
)
203 log_write ("TLS: %i: %s", level
, msg
);
207 tls_audit_log (gnutls_session_t s
, const char *msg
)
210 log_write ("TLS: %s", msg
);
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
);
224 struct timeval tv
= { 0, WAIT_INTERVAL
};
230 n
= select (client
->thd
->fd
+1, &fds
, NULL
, NULL
, &tv
);
231 if (n
== 0 && tls
->nl
)
235 memcpy (data
, c
, sizeof(c
));
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
);
252 while (ret
< 0 && gnutls_error_is_fatal (ret
) == 0);
256 gnutls_kx_algorithm_t kx
;
261 memcpy (data
, c
, sizeof (c
));
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
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
));
280 TEST_TIMEOUT (client
->thd
->timeout
, ret
, start
, rc
);
284 while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
288 log_write ("TLS: %s", gnutls_strerror (ret
));
292 tls
->nl
= ((char *)data
)[ret
-1] == '\n';
298 tls_write_hook (assuan_context_t ctx
, assuan_fd_t fd
, const void *data
,
301 struct client_s
*client
= assuan_get_pointer (ctx
);
303 time_t start
= time (NULL
);
313 ret
= gnutls_record_send (client
->thd
->tls
->ses
, data
, len
);
314 TEST_TIMEOUT (client
->thd
->timeout
, ret
, start
, rc
);
318 while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
321 log_write ("TLS: %s", gnutls_strerror (ret
));
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
;
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
));
350 if (config_get_boolean ("global", "tls_use_crl"))
352 tmp
= config_get_string ("global", "tls_crl_file");
354 tmp
= str_asprintf ("%s/crl.pem", homedir
);
357 char *tmp2
= expand_homedir (tmp
);
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
));
376 n
= gnutls_certificate_set_x509_crl_file (x509_cred
, tmp
,
377 GNUTLS_X509_FMT_PEM
);
380 log_write ("%s: %s", tmp
, gnutls_strerror (n
));
389 tmp
= config_get_string ("global", "tls_ca_file");
391 tmp
= str_asprintf ("%s/ca-cert.pem", homedir
);
394 char *tmp2
= expand_homedir (tmp
);
402 log_write ("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror (rc
));
406 n
= gnutls_certificate_set_x509_trust_file (x509_cred
, tmp
,
407 GNUTLS_X509_FMT_PEM
);
410 log_write ("%s: %s", tmp
, gnutls_strerror (n
));
416 server_cert
= config_get_string ("global", "tls_server_cert_file");
418 server_cert
= str_asprintf ("%s/server-cert.pem", homedir
);
421 tmp
= expand_homedir (server_cert
);
429 log_write ("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror (rc
));
433 server_key
= config_get_string ("global", "tls_server_key_file");
435 server_key
= str_asprintf ("%s/server-key.pem", homedir
);
438 tmp
= expand_homedir (server_key
);
447 log_write ("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror (rc
));
451 n
= gnutls_certificate_set_x509_key_file (x509_cred
, server_cert
, server_key
,
452 GNUTLS_X509_FMT_PEM
);
455 if (n
!= GNUTLS_E_SUCCESS
)
457 log_write ("%s", gnutls_strerror (n
));
461 tmp
= config_get_string ("global", "tls_dh_params_file");
464 char *tmp2
= expand_homedir (tmp
);
467 log_write ("%s: %s", tmp
, pwmd_strerror (GPG_ERR_ENOMEM
));
475 n
= gnutls_dh_params_init (&dh_params
);
480 n
= gnutls_load_file (tmp
, &data
);
483 n
= gnutls_dh_params_import_pkcs3 (dh_params
, &data
,
484 GNUTLS_X509_FMT_PEM
);
486 gnutls_certificate_set_dh_params (x509_cred
, dh_params
);
488 wipememory (data
.data
, 0, data
.size
);
493 if (n
!= GNUTLS_E_SUCCESS
)
495 log_write ("%s: %s", tmp
, gnutls_strerror (n
));
506 tls_deinit_params ();
508 pthread_cleanup_pop (1); // tls_mutex
509 pthread_cleanup_pop (1); // rcfile_mutex
518 gnutls_dh_params_deinit (dh_params
);
524 gnutls_certificate_free_credentials (x509_cred
);
530 do_tls_validate_access (struct client_s
*client
, const char *section
)
532 char **access
= config_get_list (section
, "allowed");
536 if (!access
|| !*access
)
537 return GPG_ERR_EACCES
;
539 for (p
= access
; p
&& *p
; p
++)
544 if (*fp
&& *fp
== '+' && *(fp
+ 1) == 0) // allow all connections
550 if (*fp
== '!' || *fp
== '-')
561 if (!strcasecmp (client
->thd
->tls
->fp
, fp
))
562 allowed
= not ? 0 : 1;
566 return allowed
? 0 : GPG_ERR_EACCES
;
570 tls_validate_access (struct client_s
*client
, const char *filename
)
572 gpg_error_t rc
= do_tls_validate_access (client
, "global");
575 rc
= do_tls_validate_access (client
, filename
);
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
);
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");
604 int *fd
= ipv6
? &tls6_fd
: &tls_fd
;
606 if (term
|| config_get_boolean ("global", "enable_tcp") == 0)
610 shutdown (tls6_fd
, SHUT_RDWR
);
617 shutdown (tls_fd
, SHUT_RDWR
);
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
));
637 for (n
= 0, p
= servinfo
; p
!= NULL
; p
= p
->ai_next
)
641 if ((ipv6
&& p
->ai_family
!= AF_INET6
)
642 || (!ipv6
&& p
->ai_family
!= AF_INET
))
645 if ((*fd
= socket (p
->ai_family
, p
->ai_socktype
, p
->ai_protocol
)) == -1)
647 log_write ("socket(): %s", strerror (errno
));
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
);
659 if (bind (*fd
, p
->ai_addr
, p
->ai_addrlen
) == -1)
662 log_write ("bind(): port %u: %s", port
,
663 pwmd_strerror (gpg_error_from_errno (errno
)));
671 freeaddrinfo (servinfo
);
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
,
681 log_write ("setsockopt(): %s",
682 pwmd_strerror (gpg_error_from_errno (errno
)));
690 if (listen (*fd
, 128) == -1)
692 log_write ("listen(): %s", strerror (errno
));
699 start_stop_tls_with_protocol (0, 1);
712 tls_start_stop (int term
)
714 char *s
= config_get_string ("global", "tcp_bind");
720 if (!strcmp (s
, "any"))
722 b
= start_stop_tls_with_protocol (0, term
);
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
);
736 gpg_error_t rc
= tls_init_params ();
739 start_stop_tls_with_protocol (0, 1);