The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
connection.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 06701a05862f2032eec753b61222c5955b91a9c8 $
19 *
20 * @file tls/connection.c
21 * @brief Run one TLS connection from the first policy section to the last
22 *
23 * The state machine runs under one connection frame, which fr_tls_connection_push()
24 * pushes. Each state sets up frame->repeat as the next state, and which then
25 * lets the current state push children.
26 *
27 * @copyright 2026 The FreeRADIUS server project
28 */
29#ifdef WITH_TLS
30#define LOG_PREFIX "tls"
31#define _TLS_PRIVATE 1
32
33#include <freeradius-devel/unlang/function.h>
34#include <freeradius-devel/unlang/interpret.h>
35
36#include "base.h"
37#include "cache.h"
38#include "connection.h"
39#include "log.h"
40
41/** Wake the connection's request, if the request is waiting for a record
42 *
43 * The request yields in two places: the connection frame waiting for
44 * a record, and a policy section which pushed under the connection
45 * frame. Only a request which is yielded in the connection frame can
46 * be woken from outside.
47 *
48 * The request may push a subrequest, which runs policies to establish
49 * sessions, load / save session cache entries, etc. The parent
50 * request must wait until the subrequest is finished before it can
51 * continue. Erroneously waking a request while the subrequest is
52 * running will strand the subrequest on the runnable heap.
53 */
54static void tls_connection_request_wake(fr_tls_connection_t *conn)
55{
56 if (!conn->idle) return;
57
58 conn->idle = false;
59 unlang_interpret_mark_runnable(conn->request);
60}
61
62/** Decide whether the handshake is over, and whether the handshake succeeded
63 *
64 * The handshake is complete only when fr_tls_session_is_init_finished()
65 * returns true and every record produced by OpenSSL has reached the peer.
66 * That is not the same as OpenSSL's own SSL_is_init_finished(): with a
67 * TLS 1.3 stateless ticket there is a `load session` still to run.
68 */
69static void tls_connection_check(fr_tls_connection_t *conn)
70{
71 fr_tls_session_t *tls_session = conn->tls_session;
72
73 /*
74 * The cache load / save operations can wake the parent
75 * request, and change the state of the parents
76 * connection.
77 */
78 if (conn->state != TLS_CONNECTION_HANDSHAKE) return;
79
80 if (tls_session->result == FR_TLS_RESULT_ERROR) {
81 fr_tls_log(conn->request, "TLS handshake failed");
82 conn->failed = true;
83 goto finish;
84 }
85
86 /*
87 * The TLS handshake is continuing, OR it's done but
88 * there's still data to push to the peer.
89 */
90 if (!fr_tls_session_is_init_finished(tls_session)) return;
91 if (fr_dbuff_remaining(tls_session->dirty_out) > 0) return;
92
93 INFO("TLS handshake completed");
94 INFO(" version : %s", SSL_get_version(tls_session->ssl));
95 INFO(" cipher : %s", SSL_get_cipher(tls_session->ssl));
96 INFO(" resumed : %s", SSL_session_reused(tls_session->ssl) ? "yes" : "no");
97
98finish:
99 /*
100 * The cache callbacks push work onto the request stack,
101 * and the request is idle. We need to wake up the
102 * request.
103 *
104 * We're running in a callback, and not as part of a
105 * frame process function. We therefore change the state
106 * (not the process function), and then wake up the
107 * request. The frame process function will see that
108 * state change, and switch to the new function.
109 */
110 conn->state = TLS_CONNECTION_COMPLETE;
111 tls_connection_request_wake(conn);
112}
113
114static unlang_action_t tls_connection_application_data(request_t *request, void *uctx);
115
116/** Tell the application that the connection is over
117 *
118 * Only for a caller which has already run whatever policy the failure
119 * needs. A caller which has not should use tls_connection_failed(), which
120 * hands the failure to the connection frame instead.
121 *
122 * @param[in] conn which failed.
123 */
124static void tls_connection_finished(fr_tls_connection_t *conn)
125{
126 conn->failed = true;
127 conn->idle = false;
128
129 conn->finished(conn->uctx, conn);
130}
131
132/** Record a fatal error found outside of the interpreter
133 *
134 * The IO callbacks run outside of the interpreter, and so have no stack
135 * frame of their own. They cannot run policy. So they do what
136 * tls_connection_check() does for a failed handshake: record the failure,
137 * change the state, and wake the request. The connection frame then runs
138 * `fail session { ... }`, discards the session, and tells the application.
139 *
140 * The wake is not always possible, and does not have to be. A request
141 * which is running a policy subrequest is deliberately not woken, see
142 * tls_connection_request_wake(). The state change still stands, and the
143 * connection frame acts on the state change when the subrequest finishes.
144 *
145 * @param[in] conn which failed.
146 */
147static void tls_connection_failed(fr_tls_connection_t *conn)
148{
149 conn->failed = true;
150
151 /*
152 * The connection frame has already run the last of its
153 * states, so there is no policy left for it to run, and
154 * nothing would act on a state change. Say so directly.
155 */
156 if (conn->state != TLS_CONNECTION_HANDSHAKE) {
157 tls_connection_finished(conn);
158 return;
159 }
160
161 conn->state = TLS_CONNECTION_COMPLETE;
162 tls_connection_request_wake(conn);
163}
164
165/** There is a fatal connection error.
166 *
167 * The state functions have no way to report a failure to the
168 * interpreter, because we're pushing functions onto the stack with
169 * unlang_function_push(), instead of unlang_function_push_with_result().
170 *
171 * We therefore record the failure, discard the session, and return yield.
172 *
173 * @param[in] request running the connection frame.
174 * @param[in] conn which failed.
175 * @return
176 * - UNLANG_ACTION_PUSHED_CHILD - `clear session { ... }` is running.
177 * - UNLANG_ACTION_YIELD - the application has been told.
178 */
179static unlang_action_t tls_connection_error(request_t *request, fr_tls_connection_t *conn)
180{
182
183 conn->failed = true;
184 conn->idle = false;
185
186 /*
187 * Clear any pending repeat, so that the TLS state machine functions aren't used.
188 */
189 IGNORE(unlang_function_clear(request), int);
190
191 /*
192 * Set our own repeat, which closes the connection, as is
193 * done in tls_connection_init_finished(). We have to
194 * set a repeat function to a "connection done" function,
195 * as fr_tls_session_fail_session() may push a child. That runs
196 * `fail session { ... }`, and then the `clear session`
197 * code.
198 */
199 if (unlang_function_repeat_set(request, tls_connection_application_data) < 0) goto finished;
200
201 ua = fr_tls_session_fail_session(request, conn->tls_session);
202 if (ua == UNLANG_ACTION_PUSHED_CHILD) return ua;
203
204 /*
205 * Nothing was pushed, so we clear our repeat and return
206 * that the TLS connection failed.
207 *
208 * If the push failed, then nothing should have been
209 * pushed onto the stack. The cache operations are
210 * marked as "need to be run", but we can't do anything
211 * else. So we just return, and potentially leave any
212 * cache entries behind.
213 */
214 IGNORE(unlang_function_clear(request), int);
215
216finished:
217 tls_connection_finished(conn);
218 return UNLANG_ACTION_YIELD;
219}
220
221#define TLS_CONNECTION_ERROR_RETURN \
222 do { \
223 if (ua == UNLANG_ACTION_PUSHED_CHILD) return ua; \
224 if (ua == UNLANG_ACTION_FAIL) return tls_connection_error(request, conn); \
225 } while (0)
226
227#define TLS_CONNECTION_REPEAT(_func) \
228 do { \
229 if (unlang_function_repeat_set(request, _func) < 0) { \
230 return tls_connection_error(request, conn); \
231 } \
232 } while (0)
233
234/** Tell the application that the application data is ready
235 *
236 */
237static unlang_action_t tls_connection_application_data(UNUSED request_t *request, void *uctx)
238{
239 fr_tls_connection_t *conn = talloc_get_type_abort(uctx, fr_tls_connection_t);
240
241 conn->idle = false;
242
243 /*
244 * fr_tls_cache_store_session() and fr_tls_cache_clear_session()
245 * run every queued cache operation before either function
246 * returns. An operation still queued here would never run at
247 * all, and the session would silently not be cached, or would
248 * silently not be cleared.
249 */
250 fr_assert(!fr_tls_cache_pending(conn->tls_session->cache));
251
252 conn->finished(conn->uctx, conn);
253 return UNLANG_ACTION_YIELD;
254}
255
256/** Decide whether to keep the session once the handshake has stopped
257 *
258 * The handshakes are done, either due to success or failure. On
259 * failure, we discard any cached session. On success, we store the
260 * session before processing application data.
261 */
262static unlang_action_t tls_connection_init_finished(request_t *request, void *uctx)
263{
264 fr_tls_connection_t *conn = talloc_get_type_abort(uctx, fr_tls_connection_t);
266
267 conn->idle = false;
268
269 /*
270 * Arm the repeat before any push.
271 */
272 TLS_CONNECTION_REPEAT(tls_connection_application_data);
273
274 if (conn->failed) {
275 ua = fr_tls_session_fail_session(request, conn->tls_session);
276 } else {
277 ua = fr_tls_cache_store_session(request, conn->tls_session);
278 }
279 TLS_CONNECTION_ERROR_RETURN;
280
281 return tls_connection_application_data(request, conn);
282}
283
284/** Run handshake rounds until the handshakes finish.
285 *
286 * This function is largely a place-holder so that there is a stack
287 * frame which holds the current state. The request is woken up to
288 * process data, most of which happens in the async IO callback. But
289 * the frame is still processed. So we check the connection status
290 * here, and then either yield (if there's more handshaking to do), or
291 * go to the next state (on success or error).
292 */
293static unlang_action_t tls_connection_handshake(request_t *request, void *uctx)
294{
295 fr_tls_connection_t *conn = talloc_get_type_abort(uctx, fr_tls_connection_t);
297
298 conn->idle = false;
299
300 /*
301 * tls_connection_check() runs asynchronously in the IO
302 * callback, and changes the state we _want_ to be in.
303 * Check that here, and move to the next state if
304 * necessary.
305 */
306 if (conn->state == TLS_CONNECTION_COMPLETE) return tls_connection_init_finished(request, conn);
307
308 /*
309 * Arm the repeat function before pushing anything else.
310 */
311 TLS_CONNECTION_REPEAT(tls_connection_handshake);
312
313 /*
314 * No record is waiting for OpenSSL, yield until the next
315 * record arrives.
316 */
317 if (!conn->pending) {
318 conn->idle = true;
319 return UNLANG_ACTION_YIELD;
320 }
321
322 conn->pending = false;
323
324 /*
325 * fr_tls_session_async_handshake_push() pushes a new
326 * child frame onto the stack in order to process the
327 * SSL*. If that happens, we just tell the interpreter
328 * that we have a new child on the stack.
329 */
330 ua = fr_tls_session_async_handshake_push(request, conn->tls_session);
331 if (ua == UNLANG_ACTION_PUSHED_CHILD) return ua;
332
333 fr_tls_log(conn->request, "Failed pushing a TLS handshake round");
334 return tls_connection_error(request, conn);
335}
336
337/** Run `new session { ... }`, the first state of a connection
338 *
339 */
340static unlang_action_t tls_connection_new_session(request_t *request, void *uctx)
341{
342 fr_tls_connection_t *conn = talloc_get_type_abort(uctx, fr_tls_connection_t);
344
345 /*
346 * A state is running, so the request is not idle. The
347 * idle flag is set again during a handshake, if the
348 * request needs to wait for more OpenSSL negotiation to
349 * finish.
350 */
351 conn->idle = false;
352 conn->state = TLS_CONNECTION_HANDSHAKE;
353
354 if (conn->tls_conf->new_session) {
355 fr_assert(conn->tls_conf->virtual_server);
356
357 TLS_CONNECTION_REPEAT(tls_connection_handshake);
358
359 ua = fr_tls_new_session_push(request, conn->tls_conf);
360 TLS_CONNECTION_ERROR_RETURN;
361 }
362
363 return tls_connection_handshake(request, conn);
364}
365
366/** Push the connection frame onto the request's stack
367 *
368 * Run the interpreter once after fr_tls_connection_push() returns, so that
369 * the connection frame yields. unlang_interpret_mark_runnable() acts only on
370 * a yielded frame, and so fr_tls_connection_wake() does nothing until the
371 * connection frame has yielded at least once.
372 *
373 * @param[in] conn to run. `conn->request` must be set.
374 * @return
375 * - 0 on success.
376 * - -1 on failure.
377 */
378int fr_tls_connection_push(fr_tls_connection_t *conn)
379{
380 return unlang_function_push(conn->request,
381 tls_connection_new_session,
382 tls_connection_new_session,
383 NULL, 0, UNLANG_TOP_FRAME, conn);
384}
385
386/** A TLS record is available, so wake up the connection to process it.
387 *
388 * The connection frame yields between rounds, so we need to mark the
389 * request as runnable in order to process the data through the
390 * interpreter. We can't run the interpreter from an asynchronous IO
391 * callback!
392 *
393 * @param[in] conn to wake.
394 */
395void fr_tls_connection_wake(fr_tls_connection_t *conn)
396{
397 conn->pending = true;
398
399 tls_connection_request_wake(conn);
400}
401
402/** Hand octets which arrived on the connection to OpenSSL.
403 *
404 * The caller reads from whatever transport the caller uses, and
405 * passes the data to OpenSSL. Nothing else in the TLS library
406 * (currentl) reads a socket, so the transport stays entirely with the
407 * caller. EAP does the same thing, except the contents are taken
408 * from the EAP packets.
409 *
410 * The data doesn't have to be an entire record, and can be more than
411 * one record. The application doesn't parse TLS, it just reads raw
412 * data and hands it to OpenSSL. OpenSSL reads some or all of it.
413 * Any unread data is left in the buffer, as it generally means we
414 * read an incomplete TLS record from the wire.
415 *
416 * We therefore append the received data to the buffer. The
417 * "into_openssl" buffer size is capped at FR_TLS_MAX_PACKET_SIZE, so
418 * if a caller tries to overfill the buffer, this function marks the
419 * connection as failed.
420 *
421 * @todo - perhaps make the "into_ssl" dbuff extensable, but with
422 * limits. See tls_session_alloc() for caveats.
423 *
424 * @param[in] conn the octets arrived on.
425 * @param[in] data which arrived.
426 * @param[in] data_len how many octets arrived. Must be greater than zero.
427 */
428void fr_tls_connection_recv(fr_tls_connection_t *conn, uint8_t const *data, size_t data_len)
429{
430 fr_tls_session_t *tls_session = conn->tls_session;
431 request_t *request = conn->request;
432
433 RDEBUG3("Read %zu bytes from the connection", data_len);
434
435 if (fr_dbuff_in_memcpy_partial(tls_session->dirty_in, data, data_len) != data_len) {
436 RERROR("Failed buffering %zu bytes of TLS record data", data_len);
437 error:
438 tls_connection_failed(conn);
439 return;
440 }
441
442 /*
443 * Pushing a handshake round after the handshake has finished is
444 * a logic error. See src/lib/tls/session.c. Application data
445 * is not handled yet, so a record arriving now is an error.
446 */
447 if (fr_tls_session_is_init_finished(tls_session)) {
448 RERROR("Received %zu bytes of application data, which is not supported", data_len);
449 goto error;
450 }
451
452 /*
453 * Hand the round over to the connection frame, which is sitting
454 * yielded, waiting for exactly that record.
455 */
456 fr_tls_connection_wake(conn);
457}
458
459/** Write out any pending records, then re-check the handshake state
460 *
461 * Write the data to the IO layer, then check if the connection is
462 * errored, OK, finished, etc. We gave to write the data to the IO
463 * layer so that any TLS alerts, close-notify, etc. will reach the
464 * peer.
465 *
466 * @param[in] conn to process.
467 */
468void fr_tls_connection_process(fr_tls_connection_t *conn)
469{
470 if (conn->write(conn->uctx, conn) < 0) {
471 tls_connection_failed(conn);
472 return;
473 }
474
475 tls_connection_check(conn);
476}
477#endif /* WITH_TLS */
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition action.h:41
#define IGNORE(_expr, _type)
Definition build.h:584
#define UNUSED
Definition build.h:384
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
Definition dbuff.h:786
#define fr_dbuff_in_memcpy_partial(_out, _in, _inlen)
Copy at most _inlen bytes into the dbuff.
Definition dbuff.h:1478
int unlang_function_clear(request_t *request)
Clear pending repeat function calls, and remove the signal handler.
Definition function.c:279
#define unlang_function_repeat_set(_request, _repeat)
Set a new repeat function for an existing function frame.
Definition function.h:108
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
Definition function.h:179
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:2008
#define UNLANG_TOP_FRAME
Definition interpret.h:36
#define RDEBUG3(fmt,...)
Definition log.h:360
#define RERROR(fmt,...)
Definition log.h:315
unsigned char uint8_t
#define fr_assert(_expr)
Definition rad_assert.h:37
#define INFO(fmt,...)
Definition radict.c:63
static fr_slen_t data
Definition value.h:1367