30#define LOG_PREFIX "tls"
33#include <freeradius-devel/unlang/function.h>
34#include <freeradius-devel/unlang/interpret.h>
36#include <freeradius-devel/protocol/tls/freeradius.h>
40#include "connection.h"
45 [TLS_CONNECTION_NEW_SESSION] = {
L(
"new_session"), TLS_CONNECTION_NEW_SESSION },
46 [TLS_CONNECTION_HANDSHAKE] = {
L(
"handshake"), TLS_CONNECTION_HANDSHAKE },
47 [TLS_CONNECTION_TICKET] = {
L(
"ticket"), TLS_CONNECTION_TICKET },
48 [TLS_CONNECTION_CONNECTED] = {
L(
"connected"), TLS_CONNECTION_CONNECTED }
50size_t fr_tls_connection_state_table_len =
NUM_ELEMENTS(fr_tls_connection_state_table);
53 [TLS_CONNECTION_FAIL_NONE] = {
L(
"none"), TLS_CONNECTION_FAIL_NONE },
54 [TLS_CONNECTION_FAIL_TLS] = {
L(
"tls"), TLS_CONNECTION_FAIL_TLS },
55 [TLS_CONNECTION_FAIL_SYSCALL] = {
L(
"syscall"), TLS_CONNECTION_FAIL_SYSCALL },
56 [TLS_CONNECTION_FAIL_APPLICATION] = {
L(
"application"), TLS_CONNECTION_FAIL_APPLICATION }
58size_t fr_tls_connection_fail_table_len =
NUM_ELEMENTS(fr_tls_connection_fail_table);
61 [FR_TLS_CONNECTION_IO_OK] = {
L(
"ok"), FR_TLS_CONNECTION_IO_OK },
62 [FR_TLS_CONNECTION_IO_RETRY] = {
L(
"retry"), FR_TLS_CONNECTION_IO_RETRY },
63 [FR_TLS_CONNECTION_IO_BLOCKED] = {
L(
"blocked"), FR_TLS_CONNECTION_IO_BLOCKED },
64 [FR_TLS_CONNECTION_IO_EOF] = {
L(
"eof"), FR_TLS_CONNECTION_IO_EOF },
65 [FR_TLS_CONNECTION_IO_FATAL] = {
L(
"fatal"), FR_TLS_CONNECTION_IO_FATAL }
67size_t fr_tls_connection_io_state_table_len =
NUM_ELEMENTS(fr_tls_connection_io_state_table);
82static void tls_connection_request_wake(fr_tls_connection_t *conn)
84 if (!conn->idle)
return;
94 conn->wake_pending =
true;
106#define TLS_POST_HANDSHAKE_TIMEOUT fr_time_delta_from_sec(2)
113 fr_tls_connection_t *conn = talloc_get_type_abort(uctx, fr_tls_connection_t);
116 REDEBUG(
"(TLS) %s - Timed out waiting for data after the handshake completed", conn->name);
118 fr_tls_session_error_add(
request, FR_ERROR_VALUE_POST_HANDSHAKE_TIMEOUT);
119 fr_tls_connection_failed(conn, TLS_CONNECTION_FAIL_TLS);
129static void tls_connection_check(fr_tls_connection_t *conn)
131 fr_tls_session_t *tls_session = conn->tls_session;
139 if (conn->state != TLS_CONNECTION_HANDSHAKE)
return;
147 if (conn->fail_pending) {
148 if (!conn->idle)
return;
150 conn->fail_pending =
false;
163 if (conn->eof && conn->idle && !fr_tls_session_is_init_finished(tls_session)) {
164 REDEBUG(
"(TLS) Peer closed the connection before the handshake completed");
166 fr_tls_connection_failed(conn, TLS_CONNECTION_FAIL_SYSCALL);
170 if (tls_session->result == FR_TLS_RESULT_ERROR) {
171 fr_tls_log_perror(conn->request,
"TLS handshake failed");
178 fr_tls_connection_failed(conn, TLS_CONNECTION_FAIL_TLS);
186 if (!fr_tls_session_is_init_finished(tls_session)) {
194 if (SSL_is_init_finished(tls_session->ssl) && !conn->post_handshake_ev &&
195 fr_timer_in(conn, conn->tl, &conn->post_handshake_ev,
196 TLS_POST_HANDSHAKE_TIMEOUT,
false,
197 _tls_connection_post_handshake_timeout, conn) < 0) {
198 fr_tls_log_error(
"Failed arming the post-handshake timer");
199 fr_tls_connection_failed(conn, TLS_CONNECTION_FAIL_APPLICATION);
209 INFO(
"%s - TLS handshake completed", conn->name);
210 INFO(
" version : %s", SSL_get_version(tls_session->ssl));
211 INFO(
" cipher : %s", SSL_get_cipher(tls_session->ssl));
212 INFO(
" resumed : %s", SSL_session_reused(tls_session->ssl) ?
"yes" :
"no");
226 conn->state = TLS_CONNECTION_TICKET;
227 tls_connection_request_wake(conn);
237static void tls_connection_close(fr_tls_connection_t *conn)
246 fr_assert(conn->failed != TLS_CONNECTION_FAIL_NONE);
251 TALLOC_FREE(conn->tl);
253 RDEBUG2(
"(TLS) %s - closing connection", conn->name);
264 fr_tls_connection_t *conn = talloc_get_type_abort(uctx, fr_tls_connection_t);
275 fr_assert(!fr_tls_ticket_stateful_pending(conn->tls_session->cache));
282 tls_connection_close(conn);
291 conn->state = TLS_CONNECTION_CONNECTED;
294 RDEBUG2(
"(TLS) %s - connection state is now %s", conn->name,
300 conn->connected(conn);
330void fr_tls_connection_failed(fr_tls_connection_t *conn, fr_tls_connection_fail_t reason)
334 fr_assert(reason != TLS_CONNECTION_FAIL_NONE);
336 if (conn->failed)
return;
338 conn->failed = reason;
339 if (conn->failed == TLS_CONNECTION_FAIL_SYSCALL) conn->error = errno;
341 RDEBUG2(
"(TLS) %s - connection failed: %s", conn->name,
355 case TLS_CONNECTION_FAIL_SYSCALL:
356 fr_tls_session_error_add(conn->request, FR_ERROR_VALUE_SYSTEM_CALL_FAILED);
359 case TLS_CONNECTION_FAIL_APPLICATION:
360 fr_tls_session_error_add(conn->request, FR_ERROR_VALUE_APPLICATION_FAILED);
371 if (conn->state != TLS_CONNECTION_HANDSHAKE) {
372 tls_connection_close(conn);
386 conn->fail_pending =
true;
387 tls_connection_request_wake(conn);
395 conn->state = TLS_CONNECTION_TICKET;
396 tls_connection_request_wake(conn);
412void fr_tls_connection_eof(fr_tls_connection_t *conn)
417 fr_tls_session_error_add(
request, FR_ERROR_VALUE_PEER_CLOSED_CONNECTION);
420 tls_connection_request_wake(conn);
424 REDEBUG(
"(TLS) Peer closed the connection before the handshake completed");
426 fr_tls_connection_failed(conn, TLS_CONNECTION_FAIL_SYSCALL);
446fr_tls_connection_io_state_t fr_tls_connection_io_error(fr_tls_connection_t *conn,
ssize_t slen)
455 conn->io_state = FR_TLS_CONNECTION_IO_OK;
457 return conn->io_state;
467 if (conn->tls_session && (conn->tls_session->socket_type == SOCK_DGRAM)) {
468 conn->io_state = FR_TLS_CONNECTION_IO_OK;
472 conn->io_state = FR_TLS_CONNECTION_IO_EOF;
478 conn->io_state = FR_TLS_CONNECTION_IO_RETRY;
481#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
485 conn->io_state = FR_TLS_CONNECTION_IO_BLOCKED;
495 conn->io_state = FR_TLS_CONNECTION_IO_EOF;
499 conn->io_state = FR_TLS_CONNECTION_IO_FATAL;
504 switch (conn->io_state) {
509 case FR_TLS_CONNECTION_IO_OK:
510 case FR_TLS_CONNECTION_IO_RETRY:
511 case FR_TLS_CONNECTION_IO_BLOCKED:
519 case FR_TLS_CONNECTION_IO_EOF:
520 fr_tls_connection_eof(conn);
523 case FR_TLS_CONNECTION_IO_FATAL:
524 fr_tls_session_error_add(
request, FR_ERROR_VALUE_SYSTEM_CALL_FAILED);
525 fr_tls_connection_failed(conn, TLS_CONNECTION_FAIL_SYSCALL);
537 RDEBUG3(
"(TLS) %s - IO state is now %s", conn->name,
540 return conn->io_state;
548#define TLS_CONNECTION_FUNC_SET(_conn, _func) (_conn)->process = (_func)
549#define TLS_CONNECTION_FUNC_CLEAR(_conn) (_conn)->process = NULL
581 conn->failed = TLS_CONNECTION_FAIL_TLS;
587 TLS_CONNECTION_FUNC_CLEAR(conn);
597 TLS_CONNECTION_FUNC_SET(conn, tls_connection_connected);
599 ua = fr_tls_session_fail_session(
request, conn->tls_session);
612 TLS_CONNECTION_FUNC_CLEAR(conn);
614 tls_connection_close(conn);
618#define TLS_CONNECTION_ERROR_RETURN \
620 if (ua == UNLANG_ACTION_PUSHED_CHILD) return ua; \
621 if (ua == UNLANG_ACTION_FAIL) return tls_connection_error(request, conn); \
632 fr_tls_connection_t *conn = talloc_get_type_abort(uctx, fr_tls_connection_t);
640 TLS_CONNECTION_FUNC_SET(conn, tls_connection_connected);
643 ua = fr_tls_session_fail_session(
request, conn->tls_session);
645 ua = fr_tls_ticket_stateful_store_session(
request, conn->tls_session);
647 TLS_CONNECTION_ERROR_RETURN;
649 return tls_connection_connected(
request, conn);
663 fr_tls_connection_t *conn = talloc_get_type_abort(uctx, fr_tls_connection_t);
674 if (conn->state == TLS_CONNECTION_TICKET)
return tls_connection_ticket(
request, conn);
679 TLS_CONNECTION_FUNC_SET(conn, tls_connection_handshake);
685 if (!conn->pending) {
690 conn->pending =
false;
698 ua = fr_tls_session_async_handshake_push(
request, conn->tls_session);
701 REDEBUG(
"(TLS) Failed pushing a TLS handshake round");
702 return tls_connection_error(
request, conn);
710 fr_tls_connection_t *conn = talloc_get_type_abort(uctx, fr_tls_connection_t);
720 conn->state = TLS_CONNECTION_HANDSHAKE;
722 if (conn->tls_session->conf->new_session) {
723 fr_assert(conn->tls_session->conf->virtual_server);
725 TLS_CONNECTION_FUNC_SET(conn, tls_connection_handshake);
727 ua = fr_tls_new_session_push(
request, conn->tls_session->conf);
728 TLS_CONNECTION_ERROR_RETURN;
731 return tls_connection_handshake(
request, conn);
743static size_t tls_connection_write_len(fr_tls_connection_t *conn)
745 fr_tls_session_t *tls_session = conn->tls_session;
747 if (tls_session->socket_type == SOCK_DGRAM)
return fr_tls_session_datagram_len(tls_session);
772fr_tls_connection_t *fr_tls_connection_alloc(TALLOC_CTX *ctx,
fr_timer_list_t *tl,
773 ssize_t (*write)(fr_tls_connection_t *conn,
775 void (*connected)(fr_tls_connection_t *conn),
776 void (*close)(fr_tls_connection_t *conn))
778 fr_tls_connection_t *conn;
780 conn = talloc_zero(ctx, fr_tls_connection_t);
781 if (!conn)
return NULL;
790 conn->connected = connected;
817 fr_tls_connection_t *conn = talloc_get_type_abort(uctx, fr_tls_connection_t);
832 conn->in_frame =
true;
835 conn->wake_pending =
false;
837 ua = conn->process(
request, conn);
845 conn->in_frame =
false;
853 fr_tls_connection_process(conn);
861 if (conn->wake_pending)
goto again;
863 conn->in_frame =
false;
867 conn->in_frame =
false;
885int fr_tls_connection_push(fr_tls_connection_t *conn)
904 TLS_CONNECTION_FUNC_SET(conn, tls_connection_new_session);
907 tls_connection_frame_process,
908 tls_connection_frame_process,
921void fr_tls_connection_wake(fr_tls_connection_t *conn)
923 conn->pending =
true;
925 tls_connection_request_wake(conn);
954void fr_tls_connection_recv(fr_tls_connection_t *conn,
uint8_t const *
data,
size_t data_len)
956 fr_tls_session_t *tls_session = conn->tls_session;
959 RDEBUG3(
"(TLS) Read %zu bytes from the connection", data_len);
962 REDEBUG(
"(TLS) Failed buffering %zu bytes of TLS record data", data_len);
963 fr_tls_session_error_alert(
request, tls_session,
964 FR_ERROR_VALUE_RECORD_TOO_LARGE, SSL_AD_RECORD_OVERFLOW);
966 fr_tls_connection_failed(conn, TLS_CONNECTION_FAIL_TLS);
975 if (fr_tls_session_is_init_finished(tls_session)) {
976 REDEBUG(
"(TLS) Received %zu bytes of application data, which is not supported", data_len);
977 fr_tls_session_error_alert(
request, tls_session,
978 FR_ERROR_VALUE_RECORD_AFTER_HANDSHAKE, SSL_AD_UNEXPECTED_MESSAGE);
986 fr_tls_connection_wake(conn);
1002int fr_tls_connection_write(fr_tls_connection_t *conn)
1006 while ((size = tls_connection_write_len(conn)) > 0) {
1010 slen = conn->write(conn,
data, size);
1011 if (slen < 0)
return -1;
1016 if (slen == 0)
break;
1023 fr_assert((conn->tls_session->socket_type != SOCK_DGRAM) || ((
size_t) slen == size));
1031 if (conn->tls_session->socket_type == SOCK_DGRAM) fr_tls_session_datagram_sent(conn->tls_session);
1046void fr_tls_connection_process(fr_tls_connection_t *conn)
1060 if (conn->failed == TLS_CONNECTION_FAIL_TLS) fr_tls_session_close_send(conn->request, conn->tls_session);
1066 if (fr_tls_connection_write(conn) < 0) fr_tls_connection_failed(conn, TLS_CONNECTION_FAIL_APPLICATION);
1075 fr_dtls_timer_update(conn);
1077 tls_connection_check(conn);
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
static uint8_t request[4]
#define L(_str)
Helper for initialising arrays of string literals.
#define fr_dbuff_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
#define fr_dbuff_in_memcpy_partial(_out, _in, _inlen)
Copy at most _inlen bytes into the dbuff.
#define unlang_function_repeat_set(_request, _repeat)
Set a new repeat function for an existing function frame.
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
@ FR_SIGNAL_NONE
No signals.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
An element in a table indexed by numeric value.
#define talloc_strdup(_ctx, _str)
fr_timer_list_t * fr_timer_list_lst_alloc(TALLOC_CTX *ctx, fr_timer_list_t *parent)
Allocate a new lst based timer list.
#define FR_TIMER_DELETE(_ev_p)