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 int 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 int tls_get_active_fd(
void *ptr)
88 return st->ctx.sockfd;
91static ssize_t tls_sendto(
void *ptr,
int sockfd,
92 const void *buf,
size_t len,
93 int flags,
const struct sockaddr *dest_addr,
99 if (st->ctx.need_restart != 0) {
100 if (restart_session(st->rh, st) < 0) {
106 ret = gnutls_record_send(st->ctx.session, buf, len);
107 if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) {
113 rc_log(LOG_ERR,
"%s: error in sending: %s", __func__,
114 gnutls_strerror(ret));
116 st->ctx.need_restart = 1;
120 st->ctx.last_msg = time(0);
124static int tls_lock(
void *ptr)
128 return pthread_mutex_lock(&st->ctx.lock);
131static int tls_unlock(
void *ptr)
135 return pthread_mutex_unlock(&st->ctx.lock);
138static ssize_t tls_recvfrom(
void *ptr,
int sockfd,
139 void *buf,
size_t len,
140 int flags,
struct sockaddr *src_addr,
146 ret = gnutls_record_recv(st->ctx.session, buf, len);
147 if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED ||
148 ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED || ret == GNUTLS_E_HEARTBEAT_PONG_RECEIVED) {
153 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED) {
154 rc_log(LOG_ERR,
"%s: received alert: %s", __func__,
155 gnutls_alert_get_name(gnutls_alert_get(st->ctx.session)));
173 rc_log(LOG_ERR,
"%s: error in receiving: %s", __func__,
174 gnutls_strerror(ret));
176 st->ctx.need_restart = 1;
180 st->ctx.last_msg = time(0);
187static int cert_verify_callback(gnutls_session_t session)
191 struct tls_int_st *ctx;
195 ctx = gnutls_session_get_ptr(session);
197 return GNUTLS_E_CERTIFICATE_ERROR;
199 if (ctx->skip_hostname_check)
200 ret = gnutls_certificate_verify_peers2(session, &status);
202 ret = gnutls_certificate_verify_peers3(session, ctx->hostname, &status);
204 rc_log(LOG_ERR,
"%s: error in certificate verification: %s",
205 __func__, gnutls_strerror(ret));
206 return GNUTLS_E_CERTIFICATE_ERROR;
211 gnutls_certificate_verification_status_print(status,
212 gnutls_certificate_type_get
216 return GNUTLS_E_CERTIFICATE_ERROR;
218 rc_log(LOG_INFO,
"%s: certificate: %s", __func__, out.data);
219 gnutls_free(out.data);
220 return GNUTLS_E_CERTIFICATE_ERROR;
226static void deinit_session(tls_int_st *ses)
228 if (ses->init != 0) {
230 pthread_mutex_destroy(&ses->lock);
231 if (ses->sockfd != -1)
234 gnutls_deinit(ses->session);
238static int init_session(rc_handle *rh, tls_int_st *ses,
239 const char *hostname,
unsigned port,
240 struct sockaddr_storage *our_sockaddr,
245 struct addrinfo *info;
248 unsigned cred_set = 0;
249 tls_st *st = rh->so.ptr;
254 pthread_mutex_init(&ses->lock, NULL);
255 sockfd = socket(our_sockaddr->ss_family, (secflags&SEC_FLAG_DTLS)?SOCK_DGRAM:SOCK_STREAM, 0);
258 "%s: cannot open socket", __func__);
263 if (our_sockaddr->ss_family == AF_INET)
264 ((
struct sockaddr_in *)our_sockaddr)->sin_port = 0;
266 ((
struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
268 ses->sockfd = sockfd;
272 flags = GNUTLS_CLIENT;
273 if (secflags&SEC_FLAG_DTLS)
274 flags |= GNUTLS_DATAGRAM;
275 ret = gnutls_init(&ses->session, flags);
278 "%s: error in gnutls_init(): %s", __func__, gnutls_strerror(ret));
283 memcpy(&ses->our_sockaddr, our_sockaddr,
sizeof(*our_sockaddr));
284 if (!(secflags&SEC_FLAG_DTLS)) {
286 gnutls_handshake_set_timeout(ses->session, timeout*1000);
288 gnutls_handshake_set_timeout(ses->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
292 gnutls_dtls_set_timeouts(ses->session, 1000, timeout*1000);
295 gnutls_transport_set_int(ses->session, sockfd);
296 gnutls_session_set_ptr(ses->session, ses);
298 gnutls_heartbeat_enable(ses->session, GNUTLS_HB_LOCAL_ALLOWED_TO_SEND);
301 if (p && (strcasecmp(p,
"false") == 0 || strcasecmp(p,
"no"))) {
302 ses->skip_hostname_check = 1;
305 if (st && st->psk_cred) {
307 gnutls_credentials_set(ses->session,
308 GNUTLS_CRD_PSK, st->psk_cred);
310 ret = gnutls_priority_set_direct(ses->session,
"NORMAL:-KX-ALL:+ECDHE-PSK:+DHE-PSK:+PSK:-VERS-TLS1.0", NULL);
314 "%s: error in setting PSK priorities: %s",
315 __func__, gnutls_strerror(ret));
321 gnutls_credentials_set(ses->session,
322 GNUTLS_CRD_CERTIFICATE,
326 gnutls_set_default_priority(ses->session);
329 gnutls_server_name_set(ses->session, GNUTLS_NAME_DNS,
330 hostname, strlen(hostname));
333 rc_getaddrinfo(hostname, PW_AI_AUTH);
336 rc_log(LOG_ERR,
"%s: cannot resolve %s", __func__,
342 if (info->ai_addr->sa_family == AF_INET)
343 ((
struct sockaddr_in *)info->ai_addr)->sin_port =
346 ((
struct sockaddr_in6 *)info->ai_addr)->sin6_port =
349 rc_log(LOG_ERR,
"%s: no port specified for server %s",
355 strlcpy(ses->hostname, hostname,
sizeof(ses->hostname));
360 "%s: neither tls-ca-file or a PSK key are configured",
367 ret = connect(sockfd, info->ai_addr, info->ai_addrlen);
372 rc_log(LOG_CRIT,
"%s: cannot connect to %s: %s",
373 __func__, hostname, strerror(e));
378 "%s: performing TLS/DTLS handshake with [%s]:%d",
379 __func__, hostname, port);
381 ret = gnutls_handshake(ses->session);
382 if (ret == GNUTLS_E_LARGE_PACKET)
384 }
while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
387 rc_log(LOG_ERR,
"%s: error in handshake: %s",
388 __func__, gnutls_strerror(ret));
402#define TIME_ALIVE 120
404static int restart_session(rc_handle *rh, tls_st *st)
406 struct tls_int_st tmps;
407 time_t now = time(0);
416 if (now - st->ctx.last_restart < TIME_ALIVE && !st->ctx.need_restart)
419 st->ctx.last_restart = now;
421 timeout = rc_conf_int(rh,
"radius_timeout");
424 ret = init_session(rh, &tmps, st->ctx.hostname, st->ctx.port, &st->ctx.our_sockaddr, timeout, st->flags);
426 rc_log(LOG_ERR,
"%s: error in re-initializing TLS session", __func__);
430 if (tmps.sockfd == st->ctx.sockfd)
432 deinit_session(&st->ctx);
433 memcpy(&st->ctx, &tmps,
sizeof(tmps));
434 st->ctx.need_restart = 0;
456 if (st->ctx.init != 0) {
457 return st->ctx.sockfd;
481 time_t now = time(0);
489 if (st->ctx.init != 0) {
490 if (st->ctx.need_restart != 0) {
491 restart_session(rh, st);
492 }
else if (now - st->ctx.last_msg > TIME_ALIVE) {
493 ret = gnutls_heartbeat_ping(st->ctx.session, 64, 4, GNUTLS_HEARTBEAT_WAIT);
495 restart_session(rh, st);
497 st->ctx.last_msg = now;
509void rc_deinit_tls(rc_handle * rh)
511 tls_st *st = rh->so.ptr;
518 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
519 rc_log(LOG_ERR,
"rc_send_server: namespace %s set failed", ns);
523 if (st->ctx.init != 0)
524 deinit_session(&st->ctx);
526 gnutls_certificate_free_credentials(st->x509_cred);
528 gnutls_psk_free_client_credentials(st->psk_cred);
530 if(-1 == rc_reset_netns(&ns_def_hdl))
531 rc_log(LOG_ERR,
"rc_send_server: namespace %s reset failed", ns);
545int rc_init_tls(rc_handle * rh,
unsigned flags)
549 struct sockaddr_storage our_sockaddr;
550 const char *ca_file =
rc_conf_str(rh,
"tls-ca-file");
551 const char *cert_file =
rc_conf_str(rh,
"tls-cert-file");
552 const char *key_file =
rc_conf_str(rh,
"tls-key-file");
553 const char *pskkey = NULL;
560 memset(&rh->so, 0,
sizeof(rh->so));
564 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
565 rc_log(LOG_ERR,
"rc_send_server: namespace %s set failed", ns);
570 if (flags & SEC_FLAG_DTLS) {
572 rh->so.static_secret = DEFAULT_DTLS_SECRET;
575 rh->so.static_secret = DEFAULT_TLS_SECRET;
580 st = calloc(1,
sizeof(tls_st));
591 if (ca_file || (key_file && cert_file)) {
592 ret = gnutls_certificate_allocate_credentials(&st->x509_cred);
596 "%s: error in setting X.509 credentials: %s",
597 __func__, gnutls_strerror(ret));
603 gnutls_certificate_set_x509_trust_file(st->x509_cred,
605 GNUTLS_X509_FMT_PEM);
609 "%s: error in setting X.509 trust file: %s: %s",
610 __func__, gnutls_strerror(ret), ca_file);
615 if (cert_file && key_file) {
617 gnutls_certificate_set_x509_key_file(st->x509_cred,
620 GNUTLS_X509_FMT_PEM);
624 "%s: error in setting X.509 cert and key files: %s: %s - %s",
625 __func__, gnutls_strerror(ret), cert_file, key_file);
630 gnutls_certificate_set_verify_function(st->x509_cred,
631 cert_verify_callback);
636 if (authservers == NULL) {
638 "%s: cannot find authserver", __func__);
642 if (authservers->max > 1) {
645 "%s: too many auth servers for TLS/DTLS; only one is allowed",
649 strlcpy(hostname, authservers->name[0],
sizeof(hostname));
650 port = authservers->port[0];
651 if (authservers->secret[0])
652 pskkey = authservers->secret[0];
654 if (pskkey && pskkey[0] != 0) {
657 gnutls_datum_t hexkey;
660 if (strncmp(pskkey,
"psk@", 4) != 0) {
663 "%s: server secret is set but does not start with 'psk@'",
669 if ((p = strchr(pskkey,
'@')) == NULL) {
672 "%s: PSK key is not in 'username@hexkey' format",
677 username_len = p - pskkey;
678 if (username_len + 1 >
sizeof(username)) {
680 "%s: PSK username too big", __func__);
685 strlcpy(username, pskkey, username_len + 1);
688 hexkey.data = (uint8_t*)p;
689 hexkey.size = strlen(p);
691 ret = gnutls_psk_allocate_client_credentials(&st->psk_cred);
695 "%s: error in setting PSK credentials: %s",
696 __func__, gnutls_strerror(ret));
701 gnutls_psk_set_client_credentials(st->psk_cred,
707 "%s: error in setting PSK key: %s",
708 __func__, gnutls_strerror(ret));
713 ret = init_session(rh, &st->ctx, hostname, port, &our_sockaddr, 0, flags);
719 rh->so.get_fd = tls_get_fd;
720 rh->so.get_active_fd = tls_get_active_fd;
721 rh->so.sendto = tls_sendto;
722 rh->so.recvfrom = tls_recvfrom;
723 rh->so.lock = tls_lock;
724 rh->so.unlock = tls_unlock;
726 if(-1 == rc_reset_netns(&ns_def_hdl)) {
727 rc_log(LOG_ERR,
"rc_send_server: namespace %s reset failed", ns);
734 if (st->ctx.init != 0)
735 deinit_session(&st->ctx);
737 gnutls_certificate_free_credentials(st->x509_cred);
739 gnutls_psk_free_client_credentials(st->psk_cred);
743 if(-1 == rc_reset_netns(&ns_def_hdl))
744 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)