28#include <radcli/radcli.h>
47#include <gnutls/gnutls.h>
48#include <gnutls/dtls.h>
52#define DEFAULT_DTLS_SECRET "radius/dtls"
53#define DEFAULT_TLS_SECRET "radsec"
55typedef struct tls_int_st {
58 struct sockaddr_storage our_sockaddr;
59 gnutls_session_t session;
62 unsigned need_restart;
63 unsigned skip_hostname_check;
69typedef struct tls_st {
70 gnutls_psk_client_credentials_t psk_cred;
71 gnutls_certificate_credentials_t x509_cred;
72 struct tls_int_st ctx;
77static void restart_session(rc_handle *rh, tls_st *st);
79static int tls_get_fd(
void *ptr,
struct sockaddr *our_sockaddr)
82 return st->ctx.sockfd;
85static ssize_t tls_sendto(
void *ptr,
int sockfd,
86 const void *buf,
size_t len,
87 int flags,
const struct sockaddr *dest_addr,
93 if (st->ctx.need_restart != 0) {
94 restart_session(st->rh, st);
97 ret = gnutls_record_send(st->ctx.session, buf, len);
98 if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) {
104 rc_log(LOG_ERR,
"%s: error in sending: %s", __func__,
105 gnutls_strerror(ret));
107 st->ctx.need_restart = 1;
111 st->ctx.last_msg = time(0);
115static int tls_lock(
void *ptr)
119 return pthread_mutex_lock(&st->ctx.lock);
122static int tls_unlock(
void *ptr)
126 return pthread_mutex_unlock(&st->ctx.lock);
129static ssize_t tls_recvfrom(
void *ptr,
int sockfd,
130 void *buf,
size_t len,
131 int flags,
struct sockaddr *src_addr,
137 ret = gnutls_record_recv(st->ctx.session, buf, len);
138 if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED ||
139 ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED || ret == GNUTLS_E_HEARTBEAT_PONG_RECEIVED) {
144 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED) {
145 rc_log(LOG_ERR,
"%s: received alert: %s", __func__,
146 gnutls_alert_get_name(gnutls_alert_get(st->ctx.session)));
164 rc_log(LOG_ERR,
"%s: error in receiving: %s", __func__,
165 gnutls_strerror(ret));
167 st->ctx.need_restart = 1;
171 st->ctx.last_msg = time(0);
178static int cert_verify_callback(gnutls_session_t session)
182 struct tls_int_st *ctx;
186 ctx = gnutls_session_get_ptr(session);
188 return GNUTLS_E_CERTIFICATE_ERROR;
190 if (ctx->skip_hostname_check)
191 ret = gnutls_certificate_verify_peers2(session, &status);
193 ret = gnutls_certificate_verify_peers3(session, ctx->hostname, &status);
195 rc_log(LOG_ERR,
"%s: error in certificate verification: %s",
196 __func__, gnutls_strerror(ret));
197 return GNUTLS_E_CERTIFICATE_ERROR;
202 gnutls_certificate_verification_status_print(status,
203 gnutls_certificate_type_get
207 return GNUTLS_E_CERTIFICATE_ERROR;
209 rc_log(LOG_INFO,
"%s: certificate: %s", __func__, out.data);
210 gnutls_free(out.data);
211 return GNUTLS_E_CERTIFICATE_ERROR;
217static void deinit_session(tls_int_st *ses)
219 if (ses->init != 0) {
221 pthread_mutex_destroy(&ses->lock);
222 if (ses->sockfd != -1)
225 gnutls_deinit(ses->session);
229static int init_session(rc_handle *rh, tls_int_st *ses,
230 const char *hostname,
unsigned port,
231 struct sockaddr_storage *our_sockaddr,
236 struct addrinfo *info;
239 unsigned cred_set = 0;
240 tls_st *st = rh->so.ptr;
245 pthread_mutex_init(&ses->lock, NULL);
246 sockfd = socket(our_sockaddr->ss_family, (secflags&SEC_FLAG_DTLS)?SOCK_DGRAM:SOCK_STREAM, 0);
249 "%s: cannot open socket", __func__);
254 if (our_sockaddr->ss_family == AF_INET)
255 ((
struct sockaddr_in *)our_sockaddr)->sin_port = 0;
257 ((
struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
259 ses->sockfd = sockfd;
263 flags = GNUTLS_CLIENT;
264 if (secflags&SEC_FLAG_DTLS)
265 flags |= GNUTLS_DATAGRAM;
266 ret = gnutls_init(&ses->session, flags);
269 "%s: error in gnutls_init(): %s", __func__, gnutls_strerror(ret));
274 memcpy(&ses->our_sockaddr, our_sockaddr,
sizeof(*our_sockaddr));
275 if (!(secflags&SEC_FLAG_DTLS)) {
277 gnutls_handshake_set_timeout(ses->session, timeout*1000);
279 gnutls_handshake_set_timeout(ses->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
283 gnutls_dtls_set_timeouts(ses->session, 1000, timeout*1000);
286 gnutls_transport_set_int(ses->session, sockfd);
287 gnutls_session_set_ptr(ses->session, ses);
289 gnutls_heartbeat_enable(ses->session, GNUTLS_HB_LOCAL_ALLOWED_TO_SEND);
292 if (p && (strcasecmp(p,
"false") == 0 || strcasecmp(p,
"no"))) {
293 ses->skip_hostname_check = 1;
296 if (st && st->psk_cred) {
298 gnutls_credentials_set(ses->session,
299 GNUTLS_CRD_PSK, st->psk_cred);
301 ret = gnutls_priority_set_direct(ses->session,
"NORMAL:-KX-ALL:+ECDHE-PSK:+DHE-PSK:+PSK:-VERS-TLS1.0", NULL);
305 "%s: error in setting PSK priorities: %s",
306 __func__, gnutls_strerror(ret));
312 gnutls_credentials_set(ses->session,
313 GNUTLS_CRD_CERTIFICATE,
317 gnutls_set_default_priority(ses->session);
320 gnutls_server_name_set(ses->session, GNUTLS_NAME_DNS,
321 hostname, strlen(hostname));
324 rc_getaddrinfo(hostname, PW_AI_AUTH);
327 rc_log(LOG_ERR,
"%s: cannot resolve %s", __func__,
333 if (info->ai_addr->sa_family == AF_INET)
334 ((
struct sockaddr_in *)info->ai_addr)->sin_port =
337 ((
struct sockaddr_in6 *)info->ai_addr)->sin6_port =
340 rc_log(LOG_ERR,
"%s: no port specified for server %s",
346 strlcpy(ses->hostname, hostname,
sizeof(ses->hostname));
351 "%s: neither tls-ca-file or a PSK key are configured",
358 ret = connect(sockfd, info->ai_addr, info->ai_addrlen);
363 rc_log(LOG_CRIT,
"%s: cannot connect to %s: %s",
364 __func__, hostname, strerror(e));
369 "%s: performing TLS/DTLS handshake with [%s]:%d",
370 __func__, hostname, port);
372 ret = gnutls_handshake(ses->session);
373 if (ret == GNUTLS_E_LARGE_PACKET)
375 }
while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
378 rc_log(LOG_ERR,
"%s: error in handshake: %s",
379 __func__, gnutls_strerror(ret));
393#define TIME_ALIVE 120
395static void restart_session(rc_handle *rh, tls_st *st)
397 struct tls_int_st tmps;
398 time_t now = time(0);
402 if (now - st->ctx.last_restart < TIME_ALIVE)
405 st->ctx.last_restart = now;
407 timeout = rc_conf_int(rh,
"radius_timeout");
410 ret = init_session(rh, &tmps, st->ctx.hostname, st->ctx.port, &st->ctx.our_sockaddr, timeout, st->flags);
412 rc_log(LOG_ERR,
"%s: error in re-initializing DTLS", __func__);
416 if (tmps.sockfd == st->ctx.sockfd)
418 deinit_session(&st->ctx);
419 memcpy(&st->ctx, &tmps,
sizeof(tmps));
420 st->ctx.need_restart = 0;
442 if (st->ctx.init != 0) {
443 return st->ctx.sockfd;
467 time_t now = time(0);
475 if (st->ctx.init != 0) {
476 if (st->ctx.need_restart != 0) {
477 restart_session(rh, st);
478 }
else if (now - st->ctx.last_msg > TIME_ALIVE) {
479 ret = gnutls_heartbeat_ping(st->ctx.session, 64, 4, GNUTLS_HEARTBEAT_WAIT);
481 restart_session(rh, st);
483 st->ctx.last_msg = now;
495void rc_deinit_tls(rc_handle * rh)
497 tls_st *st = rh->so.ptr;
504 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
505 rc_log(LOG_ERR,
"rc_send_server: namespace %s set failed", ns);
509 if (st->ctx.init != 0)
510 deinit_session(&st->ctx);
512 gnutls_certificate_free_credentials(st->x509_cred);
514 gnutls_psk_free_client_credentials(st->psk_cred);
516 if(-1 == rc_reset_netns(&ns_def_hdl))
517 rc_log(LOG_ERR,
"rc_send_server: namespace %s reset failed", ns);
531int rc_init_tls(rc_handle * rh,
unsigned flags)
535 struct sockaddr_storage our_sockaddr;
536 const char *ca_file =
rc_conf_str(rh,
"tls-ca-file");
537 const char *cert_file =
rc_conf_str(rh,
"tls-cert-file");
538 const char *key_file =
rc_conf_str(rh,
"tls-key-file");
539 const char *pskkey = NULL;
546 memset(&rh->so, 0,
sizeof(rh->so));
550 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
551 rc_log(LOG_ERR,
"rc_send_server: namespace %s set failed", ns);
556 if (flags & SEC_FLAG_DTLS) {
558 rh->so.static_secret = DEFAULT_DTLS_SECRET;
561 rh->so.static_secret = DEFAULT_TLS_SECRET;
566 st = calloc(1,
sizeof(tls_st));
577 if (ca_file || (key_file && cert_file)) {
578 ret = gnutls_certificate_allocate_credentials(&st->x509_cred);
582 "%s: error in setting X.509 credentials: %s",
583 __func__, gnutls_strerror(ret));
589 gnutls_certificate_set_x509_trust_file(st->x509_cred,
591 GNUTLS_X509_FMT_PEM);
595 "%s: error in setting X.509 trust file: %s: %s",
596 __func__, gnutls_strerror(ret), ca_file);
601 if (cert_file && key_file) {
603 gnutls_certificate_set_x509_key_file(st->x509_cred,
606 GNUTLS_X509_FMT_PEM);
610 "%s: error in setting X.509 cert and key files: %s: %s - %s",
611 __func__, gnutls_strerror(ret), cert_file, key_file);
616 gnutls_certificate_set_verify_function(st->x509_cred,
617 cert_verify_callback);
622 if (authservers == NULL) {
624 "%s: cannot find authserver", __func__);
628 if (authservers->max > 1) {
631 "%s: too many auth servers for TLS/DTLS; only one is allowed",
635 strlcpy(hostname, authservers->name[0],
sizeof(hostname));
636 port = authservers->port[0];
637 if (authservers->secret[0])
638 pskkey = authservers->secret[0];
640 if (pskkey && pskkey[0] != 0) {
643 gnutls_datum_t hexkey;
646 if (strncmp(pskkey,
"psk@", 4) != 0) {
649 "%s: server secret is set but does not start with 'psk@'",
655 if ((p = strchr(pskkey,
'@')) == NULL) {
658 "%s: PSK key is not in 'username@hexkey' format",
663 username_len = p - pskkey;
664 if (username_len + 1 >
sizeof(username)) {
666 "%s: PSK username too big", __func__);
671 strlcpy(username, pskkey, username_len + 1);
674 hexkey.data = (uint8_t*)p;
675 hexkey.size = strlen(p);
677 ret = gnutls_psk_allocate_client_credentials(&st->psk_cred);
681 "%s: error in setting PSK credentials: %s",
682 __func__, gnutls_strerror(ret));
687 gnutls_psk_set_client_credentials(st->psk_cred,
693 "%s: error in setting PSK key: %s",
694 __func__, gnutls_strerror(ret));
699 ret = init_session(rh, &st->ctx, hostname, port, &our_sockaddr, 0, flags);
705 rh->so.get_fd = tls_get_fd;
706 rh->so.sendto = tls_sendto;
707 rh->so.recvfrom = tls_recvfrom;
708 rh->so.lock = tls_lock;
709 rh->so.unlock = tls_unlock;
711 if(-1 == rc_reset_netns(&ns_def_hdl)) {
712 rc_log(LOG_ERR,
"rc_send_server: namespace %s reset failed", ns);
719 if (st->ctx.init != 0)
720 deinit_session(&st->ctx);
722 gnutls_certificate_free_credentials(st->x509_cred);
724 gnutls_psk_free_client_credentials(st->psk_cred);
728 if(-1 == rc_reset_netns(&ns_def_hdl))
729 rc_log(LOG_ERR,
"rc_send_server: namespace %s reset failed", ns);
void rc_own_bind_addr(rc_handle *rh, struct sockaddr_storage *lia)
char * rc_conf_str(rc_handle const *rh, char const *optname)
SERVER * rc_conf_srv(rc_handle const *rh, char const *optname)
@ RC_SOCKET_DTLS
DTLS socket.
@ RC_SOCKET_TLS
TLS socket.
int rc_tls_fd(rc_handle *rh)
int rc_check_tls(rc_handle *rh)