47#include <gnutls/gnutls.h>
48#include <gnutls/dtls.h>
53#define DEFAULT_DTLS_SECRET "radius/dtls"
54#define DEFAULT_TLS_SECRET "radsec"
56typedef struct tls_int_st {
59 struct sockaddr_storage our_sockaddr;
60 gnutls_session_t session;
63 unsigned handshake_done;
67 unsigned need_restart;
68 unsigned skip_hostname_check;
74typedef struct tls_st {
75 gnutls_psk_client_credentials_t psk_cred;
76 gnutls_certificate_credentials_t x509_cred;
77 struct tls_int_st ctx;
83static int restart_session(rc_handle *rh, tls_st *st);
87static int tls_get_fd(
void *ptr,
struct sockaddr *our_sockaddr)
90 if (st->ctx.need_restart != 0) {
91 if (restart_session(st->rh, st) < 0)
94 return st->ctx.sockfd;
99static int tls_get_active_fd(
void *ptr)
102 return st->ctx.sockfd;
120static int tls_wait_or_give_up(tls_st *st,
short events,
const char *what)
122 double start_time = rc_getmtime();
123 int timeout =
rc_conf_int(st->rh,
"radius_timeout");
128 for (; timeout > 0; timeout -= (int)(rc_getmtime() - start_time)) {
129 struct pollfd pfd = { st->ctx.sockfd, events, 0 };
130 int ret = poll(&pfd, 1, timeout * 1000);
136 if (errno != EINTR) {
137 rc_log(LOG_ERR,
"%s: poll: %s", __func__, strerror(errno));
143 rc_log(LOG_ERR,
"%s: timeout waiting to %s TLS data", __func__, what);
146 st->ctx.need_restart = 1;
152static ssize_t tls_sendto(
void *ptr,
int sockfd,
153 const void *buf,
size_t len,
154 int flags,
const struct sockaddr *dest_addr,
160 if (st->ctx.need_restart != 0) {
161 if (restart_session(st->rh, st) < 0) {
168 ret = gnutls_record_send(st->ctx.session, buf, len);
169 if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) {
170 if (tls_wait_or_give_up(st, POLLOUT,
"send") < 0)
176 rc_log(LOG_ERR,
"%s: error in sending: %s", __func__,
177 gnutls_strerror(ret));
179 st->ctx.need_restart = 1;
186 st->ctx.last_msg = time(0);
192static int tls_lock(
void *ptr)
196 return pthread_mutex_lock(&st->ctx.lock);
201static int tls_unlock(
void *ptr)
205 return pthread_mutex_unlock(&st->ctx.lock);
210static ssize_t tls_recvfrom(
void *ptr,
int sockfd,
211 void *buf,
size_t len,
212 int flags,
struct sockaddr *src_addr,
219 ret = gnutls_record_recv(st->ctx.session, buf, len);
220 if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED ||
221 ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED || ret == GNUTLS_E_HEARTBEAT_PONG_RECEIVED) {
222 if (tls_wait_or_give_up(st, POLLIN,
"receive") < 0)
229 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED) {
230 rc_log(LOG_ERR,
"%s: received alert: %s", __func__,
231 gnutls_alert_get_name(gnutls_alert_get(st->ctx.session)));
249 rc_log(LOG_ERR,
"%s: error in receiving: %s", __func__,
250 gnutls_strerror(ret));
252 st->ctx.need_restart = 1;
256 st->ctx.last_msg = time(0);
265static int cert_verify_callback(gnutls_session_t session)
269 struct tls_int_st *ctx;
273 ctx = gnutls_session_get_ptr(session);
275 return GNUTLS_E_CERTIFICATE_ERROR;
277 if (ctx->skip_hostname_check)
278 ret = gnutls_certificate_verify_peers2(session, &status);
280 ret = gnutls_certificate_verify_peers3(session, ctx->hostname, &status);
282 rc_log(LOG_ERR,
"%s: error in certificate verification: %s",
283 __func__, gnutls_strerror(ret));
284 return GNUTLS_E_CERTIFICATE_ERROR;
289 gnutls_certificate_verification_status_print(status,
290 gnutls_certificate_type_get
294 return GNUTLS_E_CERTIFICATE_ERROR;
296 rc_log(LOG_INFO,
"%s: certificate: %s", __func__, out.data);
297 gnutls_free(out.data);
298 return GNUTLS_E_CERTIFICATE_ERROR;
306static void deinit_session(tls_int_st *ses)
308 if (ses->init != 0) {
318 if (ses->sockfd != -1 && ses->handshake_done) {
320 ret = gnutls_bye(ses->session, GNUTLS_SHUT_WR);
321 }
while (ret == GNUTLS_E_INTERRUPTED);
323 gnutls_deinit(ses->session);
325 pthread_mutex_destroy(&ses->lock);
326 if (ses->sockfd != -1)
333static int init_session(rc_handle *rh, tls_int_st *ses,
334 const char *hostname,
unsigned port,
335 struct sockaddr_storage *our_sockaddr,
339 int sockfd, ret, e, sock_flags;
340 struct addrinfo *info;
343 unsigned cred_set = 0;
344 tls_st *st = rh->so.ptr;
348 ses->handshake_done = 0;
350 pthread_mutex_init(&ses->lock, NULL);
351 sockfd = socket(our_sockaddr->ss_family, (secflags&SEC_FLAG_DTLS)?SOCK_DGRAM:SOCK_STREAM, 0);
354 "%s: cannot open socket", __func__);
359 if (our_sockaddr->ss_family == AF_INET)
360 ((
struct sockaddr_in *)our_sockaddr)->sin_port = 0;
362 ((
struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
364 ses->sockfd = sockfd;
368 flags = GNUTLS_CLIENT;
369 if (secflags&SEC_FLAG_DTLS)
370 flags |= GNUTLS_DATAGRAM;
371 ret = gnutls_init(&ses->session, flags);
374 "%s: error in gnutls_init(): %s", __func__, gnutls_strerror(ret));
379 memcpy(&ses->our_sockaddr, our_sockaddr,
sizeof(*our_sockaddr));
380 if (!(secflags&SEC_FLAG_DTLS)) {
382 gnutls_handshake_set_timeout(ses->session, timeout*1000);
384 gnutls_handshake_set_timeout(ses->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
388 gnutls_dtls_set_timeouts(ses->session, 1000, timeout*1000);
391 gnutls_transport_set_int(ses->session, sockfd);
392 gnutls_session_set_ptr(ses->session, ses);
394 gnutls_heartbeat_enable(ses->session, GNUTLS_HB_LOCAL_ALLOWED_TO_SEND);
397 if (p && (strcasecmp(p,
"false") == 0 || strcasecmp(p,
"no") == 0)) {
398 ses->skip_hostname_check = 1;
401 if (st && st->psk_cred) {
403 gnutls_credentials_set(ses->session,
404 GNUTLS_CRD_PSK, st->psk_cred);
406 ret = gnutls_priority_set_direct(ses->session,
"NORMAL:-KX-ALL:+ECDHE-PSK:+DHE-PSK:+PSK:-VERS-TLS1.0", NULL);
410 "%s: error in setting PSK priorities: %s",
411 __func__, gnutls_strerror(ret));
417 gnutls_credentials_set(ses->session,
418 GNUTLS_CRD_CERTIFICATE,
422 gnutls_set_default_priority(ses->session);
425 gnutls_server_name_set(ses->session, GNUTLS_NAME_DNS,
426 hostname, strlen(hostname));
429 rc_getaddrinfo(hostname, PW_AI_AUTH);
432 rc_log(LOG_ERR,
"%s: cannot resolve %s", __func__,
438 if (info->ai_addr->sa_family == AF_INET)
439 ((
struct sockaddr_in *)info->ai_addr)->sin_port =
442 ((
struct sockaddr_in6 *)info->ai_addr)->sin6_port =
445 rc_log(LOG_ERR,
"%s: no port specified for server %s",
451 strlcpy(ses->hostname, hostname,
sizeof(ses->hostname));
456 "%s: neither tls-ca-file or a PSK key are configured",
463 ret = connect(sockfd, info->ai_addr, info->ai_addrlen);
468 rc_log(LOG_CRIT,
"%s: cannot connect to %s: %s",
469 __func__, hostname, strerror(e));
479 sock_flags = fcntl(sockfd, F_GETFL, 0);
480 if (sock_flags == -1 ||
481 fcntl(sockfd, F_SETFL, sock_flags | O_NONBLOCK) == -1) {
484 rc_log(LOG_CRIT,
"%s: cannot set socket non-blocking: %s",
485 __func__, strerror(e));
490 "%s: performing TLS/DTLS handshake with [%s]:%d",
491 __func__, hostname, port);
493 ret = gnutls_handshake(ses->session);
494 if (ret == GNUTLS_E_LARGE_PACKET)
496 }
while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
499 rc_log(LOG_ERR,
"%s: error in handshake: %s",
500 __func__, gnutls_strerror(ret));
505 ses->handshake_done = 1;
516#define TIME_ALIVE 120
519static int restart_session(rc_handle *rh, tls_st *st)
522 struct tls_int_st tmps = { 0 };
523 time_t now = time(0);
532 if (now - st->ctx.last_restart < TIME_ALIVE && !st->ctx.need_restart)
535 st->ctx.last_restart = now;
540 ret = init_session(rh, &tmps, st->ctx.hostname, st->ctx.port, &st->ctx.our_sockaddr, timeout, st->flags);
542 rc_log(LOG_ERR,
"%s: error in re-initializing TLS session", __func__);
546 if (tmps.sockfd == st->ctx.sockfd)
548 deinit_session(&st->ctx);
549 memcpy(&st->ctx, &tmps,
sizeof(tmps));
550 st->ctx.need_restart = 0;
573 if (st->ctx.init != 0) {
574 return st->ctx.sockfd;
600 time_t now = time(0);
608 if (st->ctx.init != 0) {
609 if (st->ctx.need_restart != 0) {
610 restart_session(rh, st);
611 }
else if (now - st->ctx.last_msg > TIME_ALIVE) {
612 ret = gnutls_heartbeat_ping(st->ctx.session, 64, 4, GNUTLS_HEARTBEAT_WAIT);
614 restart_session(rh, st);
616 st->ctx.last_msg = now;
628void rc_deinit_tls(rc_handle * rh)
630 tls_st *st = rh->so.ptr;
637 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
638 rc_log(LOG_ERR,
"rc_send_server: namespace %s set failed", ns);
642 if (st->ctx.init != 0)
643 deinit_session(&st->ctx);
645 gnutls_certificate_free_credentials(st->x509_cred);
647 gnutls_psk_free_client_credentials(st->psk_cred);
649 if(-1 == rc_reset_netns(&ns_def_hdl))
650 rc_log(LOG_ERR,
"rc_send_server: namespace %s reset failed", ns);
664int rc_init_tls(rc_handle * rh,
unsigned flags)
668 struct sockaddr_storage our_sockaddr;
669 const char *ca_file =
rc_conf_str(rh,
"tls-ca-file");
670 const char *cert_file =
rc_conf_str(rh,
"tls-cert-file");
671 const char *key_file =
rc_conf_str(rh,
"tls-key-file");
672 const char *pskkey = NULL;
679 memset(&rh->so, 0,
sizeof(rh->so));
683 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
684 rc_log(LOG_ERR,
"rc_send_server: namespace %s set failed", ns);
689 if (flags & SEC_FLAG_DTLS) {
691 rh->so.static_secret = DEFAULT_DTLS_SECRET;
694 rh->so.static_secret = DEFAULT_TLS_SECRET;
697 rc_own_bind_addr(rh, &our_sockaddr);
699 st = calloc(1,
sizeof(tls_st));
710 if (ca_file || (key_file && cert_file)) {
711 ret = gnutls_certificate_allocate_credentials(&st->x509_cred);
715 "%s: error in setting X.509 credentials: %s",
716 __func__, gnutls_strerror(ret));
722 gnutls_certificate_set_x509_trust_file(st->x509_cred,
724 GNUTLS_X509_FMT_PEM);
728 "%s: error in setting X.509 trust file: %s: %s",
729 __func__, gnutls_strerror(ret), ca_file);
734 if (cert_file && key_file) {
736 gnutls_certificate_set_x509_key_file(st->x509_cred,
739 GNUTLS_X509_FMT_PEM);
743 "%s: error in setting X.509 cert and key files: %s: %s - %s",
744 __func__, gnutls_strerror(ret), cert_file, key_file);
749 gnutls_certificate_set_verify_function(st->x509_cred,
750 cert_verify_callback);
755 if (authservers == NULL) {
757 "%s: cannot find authserver", __func__);
761 if (authservers->max > 1) {
764 "%s: too many auth servers for TLS/DTLS; only one is allowed",
768 strlcpy(hostname, authservers->name[0],
sizeof(hostname));
769 port = authservers->port[0];
770 if (authservers->secret[0])
771 pskkey = authservers->secret[0];
773 if (pskkey && pskkey[0] != 0) {
776 gnutls_datum_t hexkey;
779 if (strncmp(pskkey,
"psk@", 4) != 0) {
782 "%s: server secret is set but does not start with 'psk@'",
788 if ((p = strchr(pskkey,
'@')) == NULL) {
791 "%s: PSK key is not in 'username@hexkey' format",
796 username_len = p - pskkey;
797 if (username_len + 1 >
sizeof(username)) {
799 "%s: PSK username too big", __func__);
804 strlcpy(username, pskkey, username_len + 1);
807 hexkey.data = (uint8_t*)p;
808 hexkey.size = strlen(p);
810 ret = gnutls_psk_allocate_client_credentials(&st->psk_cred);
814 "%s: error in setting PSK credentials: %s",
815 __func__, gnutls_strerror(ret));
820 gnutls_psk_set_client_credentials(st->psk_cred,
826 "%s: error in setting PSK key: %s",
827 __func__, gnutls_strerror(ret));
835 strlcpy(st->ctx.hostname, hostname,
sizeof(st->ctx.hostname));
837 memcpy(&st->ctx.our_sockaddr, &our_sockaddr,
sizeof(our_sockaddr));
838 st->ctx.need_restart = 1;
840 rh->so.get_fd = tls_get_fd;
841 rh->so.get_active_fd = tls_get_active_fd;
842 rh->so.sendto = tls_sendto;
843 rh->so.recvfrom = tls_recvfrom;
844 rh->so.lock = tls_lock;
845 rh->so.unlock = tls_unlock;
847 if(-1 == rc_reset_netns(&ns_def_hdl)) {
848 rc_log(LOG_ERR,
"rc_send_server: namespace %s reset failed", ns);
856 if (st->ctx.init != 0)
857 deinit_session(&st->ctx);
859 gnutls_certificate_free_credentials(st->x509_cred);
861 gnutls_psk_free_client_credentials(st->psk_cred);
866 if(-1 == rc_reset_netns(&ns_def_hdl))
867 rc_log(LOG_ERR,
"rc_send_server: namespace %s reset failed", ns);
int rc_conf_int(rc_handle const *rh, char const *optname)
Get the value of a config option as an integer.
char * rc_conf_str(rc_handle const *rh, char const *optname)
Get the value of a config option.
SERVER * rc_conf_srv(rc_handle const *rh, char const *optname)
Get the value of a config option.
@ RC_SOCKET_DTLS
DTLS socket.
@ RC_SOCKET_TLS
TLS socket.
int rc_tls_fd(rc_handle *rh)
Returns the file descriptor of the TLS/DTLS session.
int rc_check_tls(rc_handle *rh)
Check established TLS/DTLS channels for operation and reconnect if needed.
Public API of the radcli library.