The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
cache.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: 7218cbc7a0721b8c91762c90ec1f45e8256d7fe1 $
19 *
20 * @file tls/cache.c
21 * @brief Functions to support TLS session resumption
22 *
23 * @copyright 2015-2016 The FreeRADIUS server project
24 * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25 */
26RCSID("$Id: 7218cbc7a0721b8c91762c90ec1f45e8256d7fe1 $")
27USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
28
29#ifdef WITH_TLS
30#define LOG_PREFIX "tls"
31
32#include <freeradius-devel/internal/internal.h>
33#include <freeradius-devel/server/pair.h>
34#include <freeradius-devel/server/module_rlm.h>
35#include <freeradius-devel/unlang/function.h>
36#include <freeradius-devel/unlang/subrequest.h>
37#include <freeradius-devel/unlang/interpret.h>
38#include <freeradius-devel/util/debug.h>
39
40#include "attrs.h"
41#include "base.h"
42#include "cache.h"
43#include "log.h"
44#include "strerror.h"
45#include "verify.h"
46
47#include <openssl/ssl.h>
48#include <openssl/kdf.h>
49
50/** Retrieve session ID (in binary form) from the session
51 *
52 * @param[in] ctx Where to allocate the array to hold the session id.
53 * @param[in] sess to retrieve the ID for.
54 * @return A copy of the session id.
55 */
56uint8_t *fr_tls_cache_id(TALLOC_CTX *ctx, SSL_SESSION *sess)
57{
58 unsigned int len;
59 uint8_t const *id;
60
61 id = SSL_SESSION_get_id(sess, &len);
62 if (unlikely(!id)) return NULL;
63
64 return talloc_typed_memdup(ctx, id, len);
65}
66
67/** Retrieve session ID (in binary form), and assign it to a box
68 *
69 * @note Box will be reinitialised
70 *
71 * @param[out] out Where to write the session ID.
72 * @param[in] sess to retrieve the ID for.
73 */
74static inline CC_HINT(always_inline, nonnull)
75int fr_tls_cache_id_to_box_shallow(fr_value_box_t *out, SSL_SESSION *sess)
76{
77 unsigned int len;
78 uint8_t const *id;
79
80 id = SSL_SESSION_get_id(sess, &len);
81 if (unlikely(!id)) return -1;
82
83 fr_value_box_memdup_shallow(out, NULL, id, len, true);
84
85 return 0;
86}
87
88/** Create a temporary boxed version of the session ID
89 *
90 * @param[out] _box to place on the stack.
91 * @param[in] _sess to write to box.
92 */
93#define SESSION_ID(_box, _sess) \
94fr_value_box_t _box; \
95if (unlikely(fr_tls_cache_id_to_box_shallow(&_box, _sess) < 0)) fr_value_box_init_null(&_box)
96
97
98/** Add an attribute specifying the session id for the operation to be performed with.
99 *
100 * Adds the following attributes to the request:
101 *
102 * - &request.Session-Id
103 *
104 * Session identity will contain the binary session key used to create, retrieve
105 * and delete cache entries related to the SSL session.
106 *
107 * @param[in] request The current request.
108 * @param[in] session_id Identifier for the session.
109 */
110static inline CC_HINT(always_inline, nonnull(2))
111void tls_cache_session_id_to_vp(request_t *request, uint8_t const *session_id)
112{
113 fr_pair_t *vp;
115 fr_pair_value_memdup_buffer(vp, session_id, true);
116}
117
118static inline CC_HINT(always_inline, nonnull(2))
119void _tls_cache_load_state_reset(request_t *request, fr_tls_cache_t *cache, char const *func)
120{
121 if (cache->load.sess) {
123 SESSION_ID(sess_id, cache->load.sess);
124 ROPTIONAL(RDEBUG3, DEBUG3, "Session ID %pV - Freeing loaded session in %s", &sess_id, func);
125 }
126
127 SSL_SESSION_free(cache->load.sess);
128 cache->load.sess = NULL;
129 }
130 cache->load.state = FR_TLS_CACHE_LOAD_INIT;
131}
132#define tls_cache_load_state_reset(_request, _cache) _tls_cache_load_state_reset(_request, _cache, __FUNCTION__)
133
134static inline CC_HINT(always_inline, nonnull(2))
135void _tls_cache_store_state_reset(request_t *request, fr_tls_cache_t *cache, char const *func)
136{
137 if (cache->store.sess) {
139 SESSION_ID(sess_id, cache->store.sess);
140 ROPTIONAL(RDEBUG3, DEBUG3, "Session ID %pV - Freeing session to store in %s", &sess_id, func);
141 }
142 SSL_SESSION_free(cache->store.sess);
143 cache->store.sess = NULL;
144 }
145 cache->store.state = FR_TLS_CACHE_STORE_INIT;
146}
147#define tls_cache_store_state_reset(_request, _cache) _tls_cache_store_state_reset(_request, _cache, __FUNCTION__)
148
149static inline CC_HINT(always_inline)
150void _tls_cache_clear_state_reset(request_t *request, fr_tls_cache_t *cache, char const *func)
151{
152 if (cache->clear.id) {
154 ROPTIONAL(RDEBUG3, DEBUG3, "Session ID %pV - Freeing session ID to clear in %s",
155 fr_box_octets_buffer(cache->clear.id), func);
156 }
157 TALLOC_FREE(cache->clear.id);
158 }
159 cache->clear.state = FR_TLS_CACHE_CLEAR_INIT;
160}
161#define tls_cache_clear_state_reset(_request, _cache) _tls_cache_clear_state_reset(_request, _cache, __FUNCTION__)
162
163/** Serialize the session-state list and store it in the SSL_SESSION *
164 *
165 */
166static int tls_cache_app_data_set(request_t *request, SSL_SESSION *sess, uint32_t resumption_type)
167{
168 fr_dbuff_t dbuff;
169 fr_dbuff_uctx_talloc_t tctx;
170 fr_dcursor_t dcursor;
171 fr_pair_t *vp, *type_vp;
172 ssize_t slen;
173 int ret;
174
175 /*
176 * Add a temporary pair for the type of session resumption
177 */
179 type_vp->vp_uint32 = resumption_type;
180
181 if (RDEBUG_ENABLED2) {
182 SESSION_ID(sess_id, sess);
183
184 RDEBUG2("Session ID %pV - Adding session-state[*] to data", &sess_id);
185 RINDENT();
186 log_request_pair_list(L_DBG_LVL_2, request, NULL, &request->session_state_pairs, NULL);
187 REXDENT();
188 }
189
190 /*
191 * Absolute maximum is `0..2^16-1`.
192 *
193 * We leave OpenSSL 2k to add anything else
194 */
195 MEM(fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 1024, 1024 * 62));
196
197 /*
198 * Encode the session-state contents and
199 * add it to the ticket.
200 */
201 for (vp = fr_pair_dcursor_init(&dcursor, &request->session_state_pairs);
202 vp;
203 vp = fr_dcursor_current(&dcursor)) {
204 slen = fr_internal_encode_pair(&dbuff, &dcursor, NULL);
205 if (slen < 0) {
206 SESSION_ID(sess_id, sess);
207
208 RPERROR("Session ID %pV - Failed serialising session-state list", &sess_id);
209 fr_dbuff_free_talloc(&dbuff);
210 fr_pair_delete(&request->session_state_pairs, type_vp);
211 return 0; /* didn't store data */
212 }
213 }
214
215 fr_pair_remove(&request->session_state_pairs, type_vp);
216
217 RHEXDUMP4(fr_dbuff_start(&dbuff), fr_dbuff_used(&dbuff), "session-ticket application data");
218
219 /*
220 * Pass the serialized session-state list
221 * over to OpenSSL.
222 */
223 ret = SSL_SESSION_set1_ticket_appdata(sess, fr_dbuff_start(&dbuff), fr_dbuff_used(&dbuff));
224 fr_dbuff_free_talloc(&dbuff); /* OpenSSL memdups the data */
225 if (ret != 1) {
226 SESSION_ID(sess_id, sess);
227
228 fr_tls_log(request, "Session ID %pV - Failed setting application data", &sess_id);
229 return -1;
230 }
231
232 return 1; /* successfully stored data */
233}
234
235static int tls_cache_app_data_get(request_t *request, SSL_SESSION *sess)
236{
237 uint8_t *data;
238 size_t data_len;
239 fr_dbuff_t dbuff;
240 fr_pair_list_t tmp;
241
242 /*
243 * Extract the session-state list from the ticket.
244 */
245 if (SSL_SESSION_get0_ticket_appdata(sess, (void **)&data, &data_len) != 1) {
246 SESSION_ID(sess_id, sess);
247
248 fr_tls_log(request, "Session ID %pV - Failed retrieving application data", &sess_id);
249 return -1;
250 }
251
252 fr_pair_list_init(&tmp);
253 fr_dbuff_init(&dbuff, data, data_len);
254
255 RHEXDUMP4(fr_dbuff_start(&dbuff), fr_dbuff_len(&dbuff), "session application data");
256
257 /*
258 * Decode the session-state data into a temporary list.
259 *
260 * It's very important that we decode _all_ attributes,
261 * or disallow session resumption.
262 */
263 while (fr_dbuff_remaining(&dbuff) > 0) {
264 if (fr_internal_decode_pair_dbuff(request->session_state_ctx, &tmp,
265 fr_dict_root(request->proto_dict), &dbuff, NULL) < 0) {
266 SESSION_ID(sess_id, sess);
267
268 fr_pair_list_free(&tmp);
269 RPEDEBUG("Session-ID %pV - Failed decoding session-state", &sess_id);
270 return -1;
271 }
272 }
273
274 if (RDEBUG_ENABLED2) {
275 SESSION_ID(sess_id, sess);
276
277 RDEBUG2("Session-ID %pV - Restoring session-state[*]", &sess_id);
278 RINDENT();
279 log_request_pair_list(L_DBG_LVL_2, request, NULL, &tmp, "session-state.");
280 REXDENT();
281 }
282
283 fr_pair_list_append(&request->session_state_pairs, &tmp);
284
285 return 0;
286}
287
288/** Delete session data be deleted from the cache
289 *
290 * @param[in] sess to be deleted.
291 */
292static void tls_cache_delete_request(SSL_SESSION *sess)
293{
294 fr_tls_session_t *tls_session;
295 fr_tls_cache_t *tls_cache;
296 request_t *request;
297
298 tls_session = talloc_get_type_abort(SSL_SESSION_get_ex_data(sess, FR_TLS_EX_INDEX_TLS_SESSION), fr_tls_session_t);
299
300 if (!tls_session->cache) return;
301
302 request = fr_tls_session_request(tls_session->ssl);
303 tls_cache = tls_session->cache;
304
305 /*
306 * Request was cancelled just return without doing any work.
307 */
308 if (unlang_request_is_cancelled(request)) return;
309
310 fr_assert(tls_cache->clear.state == FR_TLS_CACHE_CLEAR_INIT);
311
312 /*
313 * Record the session to delete
314 */
315 tls_cache->clear.id = fr_tls_cache_id(tls_cache, sess);
316 if (!tls_cache->clear.id) {
317 RWDEBUG("Error retrieving Session ID");
318 return;
319 }
320
321 RDEBUG3("Session ID %pV - Requested session clear", fr_box_octets_buffer(tls_cache->clear.id));
322
323 tls_cache->clear.state = FR_TLS_CACHE_CLEAR_REQUESTED;
324
325 /*
326 * We store a copy of the pointer for the session
327 * in tls_session->session. If the session is
328 * being freed then this pointer must be invalid
329 * so clear it to prevent crashes in other areas
330 * of the code.
331 */
332 if (tls_session->session == sess) tls_session->session = NULL;
333
334 /*
335 * Previously the code called ASYNC_pause_job();
336 * assuming this callback would always be called
337 * from SSL_read() or another SSL function.
338 *
339 * Unfortunately it appears that the call path
340 * can also be triggered with SSL_CTX_remove_session
341 * if the reference count on the SSL_SESSION
342 * drops to zero.
343 *
344 * We now check the 'can_pause' flag to determine
345 * if we're inside a yieldable SSL_read call.
346 */
347 if (tls_session->can_pause) ASYNC_pause_job();
348}
349
350/** Process the result of `load session { ... }`
351 */
352static unlang_action_t tls_cache_load_result(request_t *request, void *uctx)
353{
354 fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
355 fr_tls_cache_t *tls_cache = tls_session->cache;
356 fr_pair_t *vp;
357 uint8_t const *q, **p;
358 SSL_SESSION *sess;
359
360 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_tls_packet_type);
361 if (!vp || (vp->vp_uint32 != enum_tls_packet_type_success->vb_uint32)) {
362 RWDEBUG("Failed acquiring session data");
363 error:
364 tls_cache->load.state = FR_TLS_CACHE_LOAD_FAILED;
366 }
367
368 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_tls_session_data);
369 if (!vp) {
370 RWDEBUG("No cached session found");
371 goto error;
372 }
373
374 q = vp->vp_octets; /* openssl will mutate q, so we can't use vp_octets directly */
375 p = (unsigned char const **)&q;
376
377 sess = d2i_SSL_SESSION(NULL, p, vp->vp_length);
378 if (!sess) {
379 fr_tls_log(request, "Failed loading persisted session");
380 goto error;
381 }
382
383 if (RDEBUG_ENABLED3) {
384 SESSION_ID(sess_id, sess);
385
386 RDEBUG3("Session ID %pV - Read %zu bytes of data. "
387 "Session de-serialized successfully", &sess_id, vp->vp_length);
388 SSL_SESSION_print(fr_tls_request_log_bio(request, L_DBG, L_DBG_LVL_3), sess);
389 }
390
391 /*
392 * OpenSSL's API is very inconsistent.
393 *
394 * We need to set external data here, so it can be
395 * retrieved in fr_tls_cache_delete.
396 *
397 * ex_data is not serialised in i2d_SSL_SESSION
398 * so we don't have to bother unsetting it.
399 */
400 SSL_SESSION_set_ex_data(sess, FR_TLS_EX_INDEX_TLS_SESSION, fr_tls_session(tls_session->ssl));
401
402 tls_cache->load.state = FR_TLS_CACHE_LOAD_RETRIEVED;
403 tls_cache->load.sess = sess; /* This is consumed in tls_cache_load_cb */
404
406}
407
408/** Push a `load session { ... }` call into the current request, using a subrequest
409 *
410 * @param[in] request The current request.
411 * @param[in] tls_session The current TLS session.
412 * @return
413 * - UNLANG_ACTION_CALCULATE_RESULT on noop.
414 * - UNLANG_ACTION_PUSHED_CHILD on success.
415 * - UNLANG_ACTION_FAIL on failure.
416 */
417static unlang_action_t tls_cache_load_push(request_t *request, fr_tls_session_t *tls_session)
418{
419 fr_tls_cache_t *tls_cache = tls_session->cache;
420 fr_tls_conf_t *conf = fr_tls_session_conf(tls_session->ssl);
421 request_t *child;
422 fr_pair_t *vp;
424
425 if (tls_cache->load.state != FR_TLS_CACHE_LOAD_REQUESTED) return UNLANG_ACTION_CALCULATE_RESULT;
426
427 fr_assert(tls_cache->load.id);
428
429 MEM(child = unlang_subrequest_alloc(request, dict_tls));
430 request = child;
431
432 /*
433 * Setup the child request for loading
434 * session resumption data.
435 */
437 vp->vp_uint32 = enum_tls_packet_type_load_session->vb_uint32;
438
439 /*
440 * Add the session identifier we're
441 * trying to load.
442 */
443 tls_cache_session_id_to_vp(child, tls_cache->load.id);
444
445 /*
446 * Allocate a child, and set it up to call
447 * the TLS virtual server.
448 */
449 ua = fr_tls_call_push(child, tls_cache_load_result, conf, tls_session, true);
450 if (ua < 0) {
451 talloc_free(child);
452 tls_cache_load_state_reset(request, tls_cache);
453 return UNLANG_ACTION_FAIL;
454 }
455
456 return ua;
457}
458
459/** Process the result of `store session { ... }`
460 */
461static unlang_action_t tls_cache_store_result(request_t *request, void *uctx)
462{
463 fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
464 fr_tls_cache_t *tls_cache = tls_session->cache;
465 fr_pair_t *vp;
466
467 tls_cache_store_state_reset(request, tls_cache);
468
469 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_tls_packet_type);
470 if (vp && (vp->vp_uint32 == enum_tls_packet_type_success->vb_uint32)) {
471 tls_cache->store.state = FR_TLS_CACHE_STORE_PERSISTED; /* Avoid spurious clear calls */
472 } else {
473 RWDEBUG("Failed storing session data");
474 tls_cache->store.state = FR_TLS_CACHE_STORE_INIT;
475 }
476
478}
479
480/** Push a `store session { ... }` call into the current request, using a subrequest
481 *
482 * @param[in] request The current request.
483 * @param[in] conf TLS configuration.
484 * @param[in] tls_session The current TLS session.
485 * @return
486 * - UNLANG_ACTION_CALCULATE_RESULT on noop.
487 * - UNLANG_ACTION_PUSHED_CHILD on success.
488 * - UNLANG_ACTION_FAIL on failure.
489 */
490static inline CC_HINT(always_inline)
491unlang_action_t tls_cache_store_push(request_t *request, fr_tls_conf_t *conf, fr_tls_session_t *tls_session)
492{
493 fr_tls_cache_t *tls_cache = tls_session->cache;
494 size_t len, ret;
495 int rcode;
496
497 uint8_t *p, *data = NULL;
498
499 request_t *child;
500 fr_pair_t *vp;
501 SSL_SESSION *sess = tls_session->cache->store.sess;
503#if OPENSSL_VERSION_NUMBER >= 0x30400000L
504 fr_time_t expires = fr_time_from_sec((time_t)(SSL_SESSION_get_time_ex(sess) + SSL_get_timeout(sess)));
505#else
506 fr_time_t expires = fr_time_from_sec((time_t)(SSL_SESSION_get_time(sess) + SSL_get_timeout(sess)));
507#endif
508 fr_time_t now = fr_time();
509
510 fr_assert(tls_cache->store.sess);
511 fr_assert(tls_cache->store.state == FR_TLS_CACHE_STORE_REQUESTED);
512
513 if (fr_time_lteq(expires, now)) {
515 fr_tls_cache_id_to_box_shallow(&id, sess);
516
517 RWDEBUG("Session ID %pV - Session has already expired, not storing", &id);
519 }
520
521 /*
522 * Add the current session-state list
523 * contents to the ssl-data
524 */
525 rcode = tls_cache_app_data_set(request, sess, enum_tls_session_resumed_stateful->vb_uint32);
526 if (rcode < 0) {
527 tls_cache_store_state_reset(request, tls_cache);
528 return UNLANG_ACTION_FAIL;
529 }
530
531 if (rcode == 0) return UNLANG_ACTION_CALCULATE_RESULT;
532
533 MEM(child = unlang_subrequest_alloc(request, dict_tls));
534 request = child;
535
536 /*
537 * Setup the child request for storing
538 * session resumption data.
539 */
541 vp->vp_uint32 = enum_tls_packet_type_store_session->vb_uint32;
542
543 /*
544 * Add the session identifier we're trying
545 * to store.
546 */
548 fr_pair_value_memdup_buffer_shallow(vp, fr_tls_cache_id(vp, sess), true);
549
550 /*
551 * How long the session has to live
552 */
554 vp->vp_time_delta = fr_time_sub(expires, now);
555
556 /*
557 * Serialize the session
558 */
559 ret = i2d_SSL_SESSION(sess, NULL); /* find out what length data we need */
560 if (ret < 1) {
562 fr_tls_cache_id_to_box_shallow(&id, sess);
563
564 /* something went wrong */
565 fr_tls_strerror_printf(NULL); /* Drain the OpenSSL error stack */
566 RPWDEBUG("Session ID %pV - Serialisation failed, couldn't determine "
567 "required buffer length", &id);
568 error:
569 tls_cache_store_state_reset(request, tls_cache);
570 talloc_free(child);
571 return UNLANG_ACTION_FAIL;
572 }
573 len = ret;
574
576 MEM(data = talloc_array(vp, uint8_t, len));
577
578 /* openssl mutates &p */
579 p = data;
580 ret = i2d_SSL_SESSION(sess, &p); /* Serialize as ASN.1 */
581 if (ret != len) {
583 fr_tls_cache_id_to_box_shallow(&id, sess);
584
585 fr_tls_strerror_printf(NULL); /* Drain the OpenSSL error stack */
586 RPWDEBUG("Session ID %pV - Serialisation failed", &id);
588 goto error;
589 }
591
592 /*
593 * Allocate a child, and set it up to call
594 * the TLS virtual server.
595 */
596 ua = fr_tls_call_push(child, tls_cache_store_result, conf, tls_session, true);
597 if (ua < 0) goto error;
598
599 return ua;
600}
601
602/** Process the result of `clear session { ... }`
603 */
604static unlang_action_t tls_cache_clear_result(request_t *request, void *uctx)
605{
606 fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
607 fr_tls_cache_t *tls_cache = tls_session->cache;
608 fr_pair_t *vp;
609
610 tls_cache_clear_state_reset(request, tls_cache);
611
612 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_tls_packet_type);
613 if (vp &&
614 ((vp->vp_uint32 == enum_tls_packet_type_success->vb_uint32) ||
615 (vp->vp_uint32 == enum_tls_packet_type_notfound->vb_uint32))) {
617 }
618
619 RWDEBUG("Failed deleting session data - security may be compromised");
621}
622
623/** Push a `clear session { ... }` call into the current request, using a subrequest
624 *
625 * @param[in] request The current request.
626 * @param[in] conf TLS configuration.
627 * @param[in] tls_session The current TLS session.
628 * @return
629 * - UNLANG_ACTION_CALCULATE_RESULT on noop.
630 * - UNLANG_ACTION_PUSHED_CHILD on success.
631 * - UNLANG_ACTION_FAIL on failure.
632 */
633static inline CC_HINT(always_inline)
634unlang_action_t tls_cache_clear_push(request_t *request, fr_tls_conf_t *conf, fr_tls_session_t *tls_session)
635{
636 request_t *child;
637 fr_pair_t *vp;
638 fr_tls_cache_t *tls_cache = tls_session->cache;
640
641 fr_assert(tls_cache->clear.state == FR_TLS_CACHE_CLEAR_REQUESTED);
642 fr_assert(tls_cache->clear.id);
643
644 MEM(child = unlang_subrequest_alloc(request, dict_tls));
645
646 /*
647 * Setup the child request for loading
648 * session resumption data.
649 */
651 vp->vp_uint32 = enum_tls_packet_type_clear_session->vb_uint32;
652
653 /*
654 * Add the session identifier we're
655 * trying to load.
656 */
657 tls_cache_session_id_to_vp(child, tls_cache->clear.id);
658
659 /*
660 * Allocate a child, and set it up to call
661 * the TLS virtual server.
662 */
663 ua = fr_tls_call_push(child, tls_cache_clear_result, conf, tls_session, true);
664 if (ua < 0) {
665 talloc_free(child);
666 tls_cache_clear_state_reset(request, tls_cache);
667 return UNLANG_ACTION_FAIL;
668 }
669
670 return ua;
671}
672
673/** Push a `store session { ... }` or `clear session { ... }` or `load session { ... }` depending on what operations are pending
674 *
675 * @param[in] request The current request.
676 * @param[in] tls_session The current TLS session.
677 * @return
678 * - UNLANG_ACTION_CALCULATE_RESULT - No pending actions
679 * - UNLANG_ACTION_PUSHED_CHILD - Pending operations to evaluate.
680 */
681unlang_action_t fr_tls_cache_pending_push(request_t *request, fr_tls_session_t *tls_session)
682{
683 fr_tls_cache_t *tls_cache = tls_session->cache;
684 fr_tls_conf_t *conf = fr_tls_session_conf(tls_session->ssl);
685
686 if (!tls_cache) return UNLANG_ACTION_CALCULATE_RESULT; /* No caching allowed */
687
688 /*
689 * Load stateful session data
690 */
691 if (tls_cache->load.state == FR_TLS_CACHE_LOAD_REQUESTED) {
692 return tls_cache_load_push(request, tls_session);
693 }
694
695 /*
696 * We only support a single session
697 * ticket currently...
698 */
699 if (tls_cache->clear.state == FR_TLS_CACHE_CLEAR_REQUESTED) {
700 /*
701 * Abort any pending store operations
702 * if they were for the same ID as
703 * we're now trying to clear.
704 */
705 if (tls_cache->store.state == FR_TLS_CACHE_STORE_REQUESTED) {
706 unsigned int len;
707 uint8_t const *id;
708
709 id = SSL_SESSION_get_id(tls_cache->store.sess, &len);
710 if ((len == talloc_array_length(tls_cache->clear.id)) &&
711 (memcmp(tls_cache->clear.id, id, len) == 0)) {
712 tls_cache_store_state_reset(request, tls_cache);
713 }
714 }
715
716 return tls_cache_clear_push(request, conf, tls_session);
717 }
718
719 if (tls_cache->store.state == FR_TLS_CACHE_STORE_REQUESTED) {
720 return tls_cache_store_push(request, conf, tls_session);
721 }
722
724}
725
726/** Write a newly created session data to the tls_session->cache structure
727 *
728 * @note If you hit an assert in this function, it was likely called twice, which shouldn't happen
729 * so blame OpenSSL.
730 *
731 * @param[in] ssl session state.
732 * @param[in] sess to serialise and write to the cache.
733 * @return
734 * - 1. What we return is not used by OpenSSL to indicate success
735 * or failure, but to indicate whether it should free its copy of
736 * the session data.
737 * In this case we tell it not to free the session data, as we
738 */
739static int tls_cache_store_cb(SSL *ssl, SSL_SESSION *sess)
740{
741 request_t *request;
742 fr_tls_session_t *tls_session;
743 fr_tls_cache_t *tls_cache;
744 unsigned int id_len;
745 uint8_t const *id;
746
747 /*
748 * This functions should only be called once during the lifetime
749 * of the tls_session, as the fields aren't re-populated on
750 * resumption.
751 */
752 tls_session = fr_tls_session(ssl);
753
754 /*
755 * If the session is TLS 1.3, then resumption will be handled by a
756 * session ticket. However, if this callback is defined, it still
757 * gets called.
758 * To avoid unnecessary entries in the stateful cache just return.
759 */
760 if (tls_session->info.version == TLS1_3_VERSION) return 0;
761
762 request = fr_tls_session_request(tls_session->ssl);
763 tls_cache = tls_session->cache;
764
765 /*
766 * Request was cancelled, just get OpenSSL to
767 * free the session data, and don't do any work.
768 */
769 if (unlang_request_is_cancelled(request)) return 0;
770
771 id = SSL_SESSION_get_id(sess, &id_len);
772 RDEBUG3("Session ID %pV - Requested store", fr_box_octets(id, id_len));
773 /*
774 * Store the session blob and session id for writing
775 * later, once all the authentication phases have completed.
776 */
777 tls_cache->store.sess = sess;
778 tls_cache->store.state = FR_TLS_CACHE_STORE_REQUESTED;
779
780 return 1;
781}
782
783/** Read session data from the cache
784 *
785 * @param[in] ssl session state.
786 * @param[in] key to retrieve session data for.
787 * @param[in] key_len The length of the key.
788 * @param[out] copy Indicates whether OpenSSL should increment the reference
789 * count on SSL_SESSION to prevent it being automatically freed. We always
790 * set this to 0.
791 * @return
792 * - Deserialised session data on success.
793 * - NULL on error.
794 */
795static SSL_SESSION *tls_cache_load_cb(SSL *ssl,
796 unsigned char const *key,
797 int key_len, int *copy)
798{
799 fr_tls_session_t *tls_session;
800 fr_tls_cache_t *tls_cache;
801 request_t *request;
802
803 tls_session = fr_tls_session(ssl);
804 request = fr_tls_session_request(tls_session->ssl);
805 tls_cache = tls_session->cache;
806
807 /*
808 * Request was cancelled, don't return any session and hopefully
809 * OpenSSL will return back to SSL_read() soon.
810 */
811 if (unlang_request_is_cancelled(request)) return NULL;
812
813 /*
814 * Ensure if session resumption is disallowed this callback
815 * will never return session data.
816 */
817 if (!tls_cache || !tls_session->allow_session_resumption) return NULL;
818
819 /*
820 * 1. On the first call we return SSL_magic_pending_session_ptr.
821 * This causes the current SSL_read() call to error out and
822 * for SSL_get_error() to return SSL_ERROR_PENDING_SESSION.
823 * 2. On receiving SSL_ERROR_PENDING_SESSION we asynchronously
824 * load session information from a datastore and associated
825 * it with the SSL session.
826 * 3. We asynchronously validate the certificate information
827 * retrieved during the session session load.
828 * 3. We call SSL_read() again, which in turn calls this callback
829 * again.
830 */
831again:
832 switch (tls_cache->load.state) {
833 case FR_TLS_CACHE_LOAD_INIT:
834 fr_assert(!tls_cache->load.id);
835
836 tls_cache->load.state = FR_TLS_CACHE_LOAD_REQUESTED;
837 MEM(tls_cache->load.id = talloc_typed_memdup(tls_cache, (uint8_t const *)key, key_len));
838
839 RDEBUG3("Requested session load - ID %pV", fr_box_octets_buffer(tls_cache->load.id));
840
841 /*
842 * Cache functions are only allowed during the handshake
843 * FIXME: With TLS 1.3 session tickets can be sent
844 * later... Technically every point where we call
845 * SSL_read() may need to be a yield point.
846 */
847 if (unlikely(!tls_session->can_pause)) {
848 cant_pause:
849 fr_assert_msg("Unexpected call to %s. "
850 "tls_session_async_handshake_cont must be in call stack", __FUNCTION__);
851 return NULL;
852 }
853 /*
854 * Jumps back to SSL_read() in session.c
855 *
856 * Be aware that if the request is cancelled
857 * whatever was meant to be done during the
858 * time we yielded may not have been completed.
859 */
860 ASYNC_pause_job();
861
862 /*
863 * load cache { ... } returned, but the parent
864 * request was cancelled, try and get everything
865 * back into a consistent state and tell OpenSSL
866 * we failed to load the session.
867 */
868 if (unlang_request_is_cancelled(request)) {
869 tls_cache_load_state_reset(request, tls_cache); /* Clears any loaded session data */
870 return NULL;
871
872 }
873 goto again;
874
875 case FR_TLS_CACHE_LOAD_REQUESTED:
876 fr_assert(0); /* Called twice without attempting the load?! */
877 tls_cache->load.state = FR_TLS_CACHE_LOAD_FAILED;
878 break;
879
880 case FR_TLS_CACHE_LOAD_RETRIEVED:
881 {
882 SSL_SESSION *sess;
883
884 TALLOC_FREE(tls_cache->load.id);
885
886 RDEBUG3("Setting session data");
887
888 /*
889 * This restores the contents of &session-state[*]
890 * which hopefully still contains all the certificate
891 * pairs.
892 *
893 * Although the SSL_SESSION does contain a copy of
894 * the peer's certificate, it does not contain the
895 * peer's certificate chain, and so isn't reliable
896 * for performing re-validation.
897 */
898 if (tls_cache_app_data_get(request, tls_cache->load.sess) < 0) {
899 REDEBUG("Denying session resumption via session-id");
900 verify_error:
901 /*
902 * Request the session be deleted the next
903 * time something calls cache action pending.
904 */
905 tls_cache_delete_request(tls_cache->load.sess);
906 tls_cache_load_state_reset(request, tls_session->cache); /* Free the session */
907 return NULL;
908 }
909
910 /*
911 * This sets the validation state of the tls_session
912 * so that when we call ASYNC_pause_job(), and execution
913 * jumps back to tls_session_async_handshake_cont
914 * (just under SSL_read())
915 * the code there knows what job it needs to push onto
916 * the unlang stack.
917 */
918 fr_tls_verify_cert_request(tls_session, true);
919
920 if (unlikely(!tls_session->can_pause)) goto cant_pause;
921 /*
922 * Jumps back to SSL_read() in session.c
923 *
924 * Be aware that if the request is cancelled
925 * whatever was meant to be done during the
926 * time we yielded may not have been completed.
927 */
928 ASYNC_pause_job();
929
930 /*
931 * Certificate validation returned but the request
932 * was cancelled. Free any data we have so far
933 * and reset the states, then let OpenSSL know
934 * we failed to load the session.
935 */
936 if (unlang_request_is_cancelled(request)) {
937 tls_cache_load_state_reset(request, tls_cache); /* Clears any loaded session data */
938 fr_tls_verify_cert_reset(tls_session);
939 return NULL;
940
941 }
942
943 /*
944 * If we couldn't validate the client certificate
945 * then validation overall fails.
946 */
947 if (!fr_tls_verify_cert_result(tls_session)) {
948 RDEBUG2("Certificate re-validation failed, denying session resumption via session-id");
949 goto verify_error;
950 }
951 sess = tls_cache->load.sess;
952
953 /*
954 * After we return it's OpenSSL's responsibility
955 * to free the session data, so set our copy of
956 * the pointer to NULL, to prevent a double free
957 * on cleanup.
958 */
959 {
960 SESSION_ID(sess_id, tls_cache->load.sess);
961
962 RDEBUG3("Session ID %pV - Session ownership transferred to libssl", &sess_id);
963 *copy = 0;
964 tls_cache->load.sess = NULL;
965 }
966 return sess;
967 }
968
969
970 case FR_TLS_CACHE_LOAD_FAILED:
971 RDEBUG3("Session data load failed");
972 break;
973 }
974
975 TALLOC_FREE(tls_cache->load.id);
976 fr_assert(!tls_cache->load.sess);
977
978 return NULL;
979}
980
981/** Delete session data from the cache
982 *
983 * @param[in] ctx Current ssl context.
984 * @param[in] sess to be deleted.
985 */
986static void tls_cache_delete_cb(UNUSED SSL_CTX *ctx, SSL_SESSION *sess)
987{
988 /*
989 * Not sure why this happens, but sometimes SSL_SESSION *s
990 * make it here without the correct ex data.
991 *
992 * Maybe it's one OpenSSL created internally?
993 */
994 if (!SSL_SESSION_get_ex_data(sess, FR_TLS_EX_INDEX_TLS_SESSION)) return;
995 tls_cache_delete_request(sess);
996}
997
998/** Prevent a TLS session from being resumed in future
999 *
1000 * @note In OpenSSL > 1.1.0 this should not be called directly, but passed as a callback to
1001 * SSL_CTX_set_not_resumable_session_callback.
1002 *
1003 * @param ssl The current OpenSSL session.
1004 * @param is_forward_secure Whether the cipher is forward secure, pass -1 if unknown.
1005 * @return
1006 * - 0 if session-resumption is allowed.
1007 * - 1 if enabling session-resumption was disabled for this session.
1008 */
1009int fr_tls_cache_disable_cb(SSL *ssl, int is_forward_secure)
1010{
1011 request_t *request;
1012
1013 fr_tls_session_t *tls_session;
1014 fr_pair_t *vp;
1015
1016 tls_session = fr_tls_session(ssl);
1017 request = fr_tls_session_request(tls_session->ssl);
1018
1019 /*
1020 * Request was cancelled, try and get OpenSSL to
1021 * do as little work as possible.
1022 */
1023 if (unlang_request_is_cancelled(request)) return 1;
1024
1025 {
1026 fr_tls_conf_t *conf;
1027
1028 conf = talloc_get_type_abort(SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF), fr_tls_conf_t);
1029 if (conf->cache.require_extms && (SSL_get_extms_support(tls_session->ssl) == 0)) {
1030 RDEBUG2("Client does not support the Extended Master Secret extension, "
1031 "denying session resumption");
1032 goto disable;
1033 }
1034
1035 if (conf->cache.require_pfs && !is_forward_secure) {
1036 RDEBUG2("Cipher suite is not forward secure, denying session resumption");
1037 goto disable;
1038 }
1039 }
1040
1041 /*
1042 * If there's no session resumption, delete the entry
1043 * from the cache. This means either it's disabled
1044 * globally for this SSL context, OR we were told to
1045 * disable it for this user.
1046 *
1047 * This also means you can't turn it on just for one
1048 * user.
1049 */
1050 if (!tls_session->allow_session_resumption) {
1051 RDEBUG2("Session resumption not enabled for this TLS session, denying session resumption");
1052 goto disable;
1053 }
1054
1055 vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_allow_session_resumption);
1056 if (vp && (vp->vp_uint32 == 0)) {
1057 RDEBUG2("control.Allow-Session-Resumption == no, denying session resumption");
1058 disable:
1059 SSL_CTX_remove_session(tls_session->ctx, tls_session->session);
1060 tls_session->allow_session_resumption = false;
1061 return 1;
1062 }
1063
1064 RDEBUG2("Allowing future session-resumption");
1065
1066 return 0;
1067}
1068
1069/** Prevent a pending TLS session being persisted, and clear any resumed sessions
1070 *
1071 * Usually called if authentication has failed for some reason.
1072 *
1073 * Will clear any serialized data out of the tls_session structure
1074 * and should result in tls_cache_delete_cb being called.
1075 *
1076 * @note Calling this function will immediately free the memory used
1077 * by the session, but not the external persisted copy of the
1078 * session. To clear the persisted copy #fr_tls_cache_pending_push
1079 * must be called in a place where the caller is prepared to yield.
1080 * In most cases this means whether the handshake is a success or
1081 * failure, the last thing the caller of the TLS code should do
1082 * is set the result, and call #fr_tls_cache_pending_push.
1083 *
1084 * @param[in] request to use for running any async cache actions.
1085 * @param[in] tls_session on which to prevent resumption.
1086 */
1087void fr_tls_cache_deny(request_t *request, fr_tls_session_t *tls_session)
1088{
1089 fr_tls_cache_t *tls_cache = tls_session->cache;
1090 bool tmp_bind = !fr_tls_session_request_bound(tls_session->ssl);
1091
1092 /*
1093 * This is necessary to allow this function to
1094 * be called inside and outside of OpenSSL handshake
1095 * code.
1096 */
1097 if (tmp_bind) {
1098 fr_tls_session_request_bind(tls_session->ssl, request);
1099 /*
1100 * If there's already a request bound, it better be
1101 * the one passed to this function.
1102 */
1103 } else {
1104 fr_assert(fr_tls_session_request(tls_session->ssl) == request);
1105 }
1106
1107 /*
1108 * SSL_CTX_remove_session frees the previously loaded
1109 * session in tls_session. If the reference count reaches zero
1110 * the SSL_CTX_sess_remove_cb is called, which in our code is
1111 * tls_cache_delete_cb.
1112 *
1113 * tls_cache_delete_cb calls tls_cache_delete_request
1114 * to record the ID of tls_session->session
1115 * in our pending cache state structure.
1116 *
1117 * tls_cache_delete_request does NOT immediately call the
1118 * `cache clear {}` section as that must be done in a code area
1119 * which is prepared to yield.
1120 *
1121 * #fr_tls_cache_pending_push MUST be called to actually
1122 * clear external data.
1123 */
1124 if (tls_session->session) SSL_CTX_remove_session(tls_session->ctx, tls_session->session);
1125 tls_session->allow_session_resumption = false;
1126
1127 /*
1128 * Clear any pending store requests.
1129 */
1130 tls_cache_store_state_reset(fr_tls_session_request(tls_session->ssl), tls_cache);
1131
1132 /*
1133 * Unbind the request last...
1134 */
1135 if (tmp_bind) fr_tls_session_request_unbind(tls_session->ssl);
1136}
1137
1138/** Cleanup any memory allocated by OpenSSL
1139 */
1140static int _tls_cache_free(fr_tls_cache_t *tls_cache)
1141{
1142 tls_cache_load_state_reset(NULL, tls_cache);
1143 tls_cache_store_state_reset(NULL, tls_cache);
1144
1145 return 0;
1146}
1147
1148/** Allocate a session cache state structure, and assign it to a tls_session
1149 *
1150 * @note This must be called if session caching is enabled for a tls session.
1151 *
1152 * @param[in] tls_session to assign cache structure to.
1153 */
1154void fr_tls_cache_session_alloc(fr_tls_session_t *tls_session)
1155{
1156 fr_assert(!tls_session->cache);
1157
1158 MEM(tls_session->cache = talloc_zero(tls_session, fr_tls_cache_t));
1159 talloc_set_destructor(tls_session->cache, _tls_cache_free);
1160}
1161
1162/** Disable stateless session tickets for a given TLS ctx
1163 *
1164 * @param[in] ctx to disable session tickets for.
1165 */
1166static inline CC_HINT(always_inline)
1167void tls_cache_disable_stateless_resumption(SSL_CTX *ctx)
1168{
1169 long ctx_options = SSL_CTX_get_options(ctx);
1170
1171 /*
1172 * Disable session tickets for older TLS versions
1173 */
1174 ctx_options |= SSL_OP_NO_TICKET;
1175 SSL_CTX_set_options(ctx, ctx_options);
1176
1177 /*
1178 * This controls the number of stateful or stateless
1179 * tickets generated with TLS 1.3. In OpenSSL 1.1.0
1180 * it's also required to disable sending session tickets,
1181 * SSL_SESS_CACHE_OFF is not good enough.
1182 */
1183 SSL_CTX_set_num_tickets(ctx, 0);
1184}
1185
1186/** Disable stateful session resumption for a given TLS ctx
1187 *
1188 * @param[in] ctx to disable stateful session resumption for.
1189 */
1190static inline CC_HINT(always_inline)
1191void tls_cache_disable_statefull_resumption(SSL_CTX *ctx)
1192{
1193 /*
1194 * Only disables stateful session-resumption.
1195 *
1196 * As per Matt Caswell:
1197 *
1198 * SSL_SESS_CACHE_OFF, when called on the server,
1199 * disables caching of server side sessions.
1200 * It does not switch off resumption. Resumption can
1201 * still occur if a stateless session ticket is used
1202 * (even in TLSv1.2).
1203 */
1204 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
1205}
1206
1207/** Called when new tickets are being generated
1208 *
1209 * This adds additional application data to the session ticket to
1210 * allow us to perform validation checks when the session is
1211 * resumed.
1212 */
1213static int tls_cache_session_ticket_app_data_set(SSL *ssl, void *arg)
1214{
1215 fr_tls_session_t *tls_session = fr_tls_session(ssl);
1216 fr_tls_cache_conf_t *tls_cache_conf = arg; /* Not talloced */
1217 SSL_SESSION *sess;
1218 request_t *request;
1219
1220 /*
1221 * Check to see if we have a request bound
1222 * to the session. If we don't have a
1223 * request there's no application data to
1224 * add.
1225 */
1226 if (!fr_tls_session_request_bound(ssl)) return 1;
1227
1228 /*
1229 * Encode the complete session state list
1230 * as app data. Then, when the session is
1231 * resumed, the session-state list is
1232 * repopulated.
1233 */
1234 request = fr_tls_session_request(ssl);
1235
1236 /*
1237 * Request was cancelled, don't do anything.
1238 */
1239 if (unlang_request_is_cancelled(request)) return 0;
1240
1241 /*
1242 * Fatal error - We definitely should be
1243 * attempting to generate session tickets
1244 * if it's not permitted.
1245 */
1246 if (!tls_session->allow_session_resumption ||
1247 (!(tls_cache_conf->mode & FR_TLS_CACHE_STATELESS))) {
1248 REDEBUG("Generating session-tickets is not allowed");
1249 return 0;
1250 }
1251
1252 sess = SSL_get_session(ssl);
1253 if (!sess) {
1254 REDEBUG("Failed retrieving session in session generation callback");
1255 return 0;
1256 }
1257
1258 if (tls_cache_app_data_set(request, sess, enum_tls_session_resumed_stateless->vb_uint32) < 0) return 0;
1259
1260 return 1;
1261}
1262
1263/** Called when new tickets are being decoded
1264 *
1265 * This adds the session-state attributes back to the current request.
1266 */
1267static SSL_TICKET_RETURN tls_cache_session_ticket_app_data_get(SSL *ssl, SSL_SESSION *sess,
1268 UNUSED unsigned char const *keyname,
1269 UNUSED size_t keyname_len,
1270 SSL_TICKET_STATUS status,
1271 void *arg)
1272{
1273 fr_tls_session_t *tls_session = fr_tls_session(ssl);
1274 fr_tls_conf_t *conf = fr_tls_session_conf(tls_session->ssl);
1275 fr_tls_cache_conf_t *tls_cache_conf = arg; /* Not talloced */
1276 request_t *request = NULL;
1277
1278 if (fr_tls_session_request_bound(ssl)) {
1279 request = fr_tls_session_request(ssl);
1280 if (unlang_request_is_cancelled(request)) return SSL_TICKET_RETURN_ABORT;
1281 }
1282
1283 if (!tls_session->allow_session_resumption ||
1284 (!(tls_cache_conf->mode & FR_TLS_CACHE_STATELESS))) {
1285 ROPTIONAL(RDEBUG2, DEBUG2, "Session resumption not enabled for this TLS session, "
1286 "denying session resumption via session-ticket");
1287 return SSL_TICKET_RETURN_IGNORE;
1288 }
1289
1290 switch (status) {
1291 case SSL_TICKET_EMPTY:
1292 case SSL_TICKET_NO_DECRYPT:
1293 case SSL_TICKET_FATAL_ERR_MALLOC:
1294 case SSL_TICKET_FATAL_ERR_OTHER:
1295 case SSL_TICKET_NONE:
1296#ifdef STATIC_ANALYZER
1297 default:
1298#endif
1299 return SSL_TICKET_RETURN_IGNORE_RENEW; /* Send a new ticket */
1300
1301 case SSL_TICKET_SUCCESS:
1302 if (!request) return SSL_TICKET_RETURN_USE;
1303 break;
1304
1305 case SSL_TICKET_SUCCESS_RENEW:
1306 if (!request) return SSL_TICKET_RETURN_USE_RENEW;
1307 break;
1308 }
1309
1310 /*
1311 * This restores the contents of &session-state[*]
1312 * which hopefully still contains all the certificate
1313 * pairs.
1314 *
1315 * Although the SSL_SESSION does contain a copy of
1316 * the peer's certificate, it does not contain the
1317 * peer's certificate chain, and so isn't reliable
1318 * for performing re-validation.
1319 */
1320 if (tls_cache_app_data_get(request, sess) < 0) {
1321 REDEBUG("Denying session resumption via session-ticket");
1322 return SSL_TICKET_RETURN_IGNORE_RENEW;
1323 }
1324
1325 if (conf->virtual_server && tls_session->verify_client_cert) {
1326 RDEBUG2("Requesting certificate re-validation for session-ticket");
1327 /*
1328 * This sets the validation state of the tls_session
1329 * so that when we call ASYNC_pause_job(), and execution
1330 * jumps back to tls_session_async_handshake_cont
1331 * (just under SSL_read())
1332 * the code there knows what job it needs to push onto
1333 * the unlang stack.
1334 */
1335 fr_tls_verify_cert_request(tls_session, true);
1336
1337 /*
1338 * Cache functions are only allowed during the handshake
1339 * FIXME: With TLS 1.3 session tickets can be sent
1340 * later... Technically every point where we call
1341 * SSL_read() may need to be a yield point.
1342 */
1343 if (unlikely(!tls_session->can_pause)) {
1344 fr_assert_msg("Unexpected call to %s. "
1345 "tls_session_async_handshake_cont must be in call stack", __FUNCTION__);
1346 return SSL_TICKET_RETURN_IGNORE_RENEW;
1347 }
1348
1349 /*
1350 * Jumps back to SSL_read() in session.c
1351 *
1352 * Be aware that if the request is cancelled
1353 * whatever was meant to be done during the
1354 * time we yielded may not have been completed.
1355 */
1356 ASYNC_pause_job();
1357
1358 /*
1359 * If the request was cancelled get everything back into
1360 * a known state.
1361 */
1362 if (unlang_request_is_cancelled(request)) {
1363 fr_tls_verify_cert_reset(tls_session);
1364 return SSL_TICKET_RETURN_ABORT;
1365 }
1366
1367 /*
1368 * If we couldn't validate the client certificate
1369 * give the client the opportunity to send a new
1370 * one, but _don't_ allow session resumption.
1371 */
1372 if (!fr_tls_verify_cert_result(tls_session)) {
1373 RDEBUG2("Certificate re-validation failed, denying session resumption via session-ticket");
1374 return SSL_TICKET_RETURN_IGNORE_RENEW;
1375 }
1376 }
1377
1378 return (status == SSL_TICKET_SUCCESS_RENEW) ? SSL_TICKET_RETURN_USE_RENEW : SSL_TICKET_RETURN_USE;
1379}
1380
1381/** Sets callbacks and flags on a SSL_CTX to enable/disable session resumption
1382 *
1383 * @param[in] ctx to modify.
1384 * @param[in] cache_conf Session caching configuration.
1385 * @return
1386 * - 0 on success.
1387 * - -1 on failure.
1388 */
1389int fr_tls_cache_ctx_init(SSL_CTX *ctx, fr_tls_cache_conf_t const *cache_conf)
1390{
1391 switch (cache_conf->mode) {
1392 case FR_TLS_CACHE_DISABLED:
1393 tls_cache_disable_stateless_resumption(ctx);
1394 tls_cache_disable_statefull_resumption(ctx);
1395 return 0;
1396
1397 case FR_TLS_CACHE_AUTO:
1398 case FR_TLS_CACHE_STATEFUL:
1399 /*
1400 * Setup the callbacks for stateful session-resumption
1401 * i.e. where the server stores session information.
1402 */
1403 SSL_CTX_sess_set_new_cb(ctx, tls_cache_store_cb);
1404 SSL_CTX_sess_set_get_cb(ctx, tls_cache_load_cb);
1405 SSL_CTX_sess_set_remove_cb(ctx, tls_cache_delete_cb);
1406
1407 /*
1408 * Controls the stateful cache mode
1409 *
1410 * Here we disable internal lookups, and rely on the
1411 * callbacks above.
1412 */
1413 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL);
1414
1415 /*
1416 * Controls the validity period of the stateful cache.
1417 */
1418 SSL_CTX_set_timeout(ctx, fr_time_delta_to_sec(cache_conf->lifetime));
1419
1420 /*
1421 * Disables stateless session tickets for TLS 1.3.
1422 */
1423 if (!(cache_conf->mode & FR_TLS_CACHE_STATELESS)) {
1424 tls_cache_disable_stateless_resumption(ctx);
1425 break;
1426 }
1428
1429 case FR_TLS_CACHE_STATELESS:
1430 {
1431 size_t key_len;
1432 uint8_t *key_buff;
1433 EVP_PKEY_CTX *pkey_ctx = NULL;
1434
1435 if (!(cache_conf->mode & FR_TLS_CACHE_STATEFUL)) tls_cache_disable_statefull_resumption(ctx);
1436
1437 /*
1438 * If keys is NULL, then OpenSSL returns the expected
1439 * key length, which may be different across different
1440 * flavours/versions of OpenSSL.
1441 *
1442 * We could calculate this in conf.c, but, if in future
1443 * OpenSSL decides to use different key lengths based
1444 * on other parameters in the ctx, that'd break.
1445 */
1446 key_len = SSL_CTX_set_tlsext_ticket_keys(ctx, NULL, 0);
1447
1448 if (unlikely((pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL)) == NULL)) {
1449 fr_tls_strerror_printf(NULL);
1450 PERROR("Failed initialising KDF");
1451 kdf_error:
1452 if (pkey_ctx) EVP_PKEY_CTX_free(pkey_ctx);
1453 return -1;
1454 }
1455 if (unlikely(EVP_PKEY_derive_init(pkey_ctx) != 1)) {
1456 fr_tls_strerror_printf(NULL);
1457 PERROR("Failed initialising KDF derivation ctx");
1458 goto kdf_error;
1459 }
1460 if (unlikely(EVP_PKEY_CTX_set_hkdf_md(pkey_ctx, UNCONST(struct evp_md_st *, EVP_sha256())) != 1)) {
1461 fr_tls_strerror_printf(NULL);
1462 PERROR("Failed setting KDF MD");
1463 goto kdf_error;
1464 }
1465 if (unlikely(EVP_PKEY_CTX_set1_hkdf_key(pkey_ctx,
1466 UNCONST(unsigned char *, cache_conf->session_ticket_key),
1467 talloc_array_length(cache_conf->session_ticket_key)) != 1)) {
1468 fr_tls_strerror_printf(NULL);
1469 PERROR("Failed setting KDF key");
1470 goto kdf_error;
1471 }
1472 if (unlikely(EVP_PKEY_CTX_add1_hkdf_info(pkey_ctx,
1473 UNCONST(unsigned char *, "freeradius-session-ticket"),
1474 sizeof("freeradius-session-ticket") - 1) != 1)) {
1475 fr_tls_strerror_printf(NULL);
1476 PERROR("Failed setting KDF label");
1477 goto kdf_error;
1478 }
1479
1480 /*
1481 * SSL_CTX_set_tlsext_ticket_keys memcpys its
1482 * inputs so this is just a temporary buffer.
1483 */
1484 MEM(key_buff = talloc_array(NULL, uint8_t, key_len));
1485 if (EVP_PKEY_derive(pkey_ctx, key_buff, &key_len) != 1) {
1486 fr_tls_strerror_printf(NULL);
1487 PERROR("Failed deriving session ticket key");
1488
1489 key_buff_error:
1490 talloc_free(key_buff);
1491 goto kdf_error;
1492 }
1493 EVP_PKEY_CTX_free(pkey_ctx);
1494
1495 fr_assert(talloc_array_length(key_buff) == key_len);
1496
1497 /*
1498 * Ensure the same keys are used across all threads
1499 */
1500 if (SSL_CTX_set_tlsext_ticket_keys(ctx,
1501 key_buff, key_len) != 1) {
1502 fr_tls_strerror_printf(NULL);
1503 PERROR("Failed setting session ticket keys");
1504 goto key_buff_error;
1505 }
1506
1507 DEBUG3("Derived session-ticket-key:");
1508 HEXDUMP3(key_buff, key_len, NULL);
1509 talloc_free(key_buff);
1510
1511 /*
1512 * These callbacks embed and extract the
1513 * session-state list from the session-ticket.
1514 */
1515 if (unlikely(SSL_CTX_set_session_ticket_cb(ctx,
1516 tls_cache_session_ticket_app_data_set,
1517 tls_cache_session_ticket_app_data_get,
1518 UNCONST(fr_tls_cache_conf_t *, cache_conf)) != 1)) {
1519 fr_tls_strerror_printf(NULL);
1520 PERROR("Failed setting session ticket callbacks");
1521 goto key_buff_error;
1522 }
1523
1524 /*
1525 * Stateless resumption is enabled by default when
1526 * the TLS ctx is created, but OpenSSL sends too
1527 * many session tickets by default (2), and we only
1528 * need one.
1529 */
1530 SSL_CTX_set_num_tickets(ctx, 1);
1531 }
1532 break;
1533 }
1534
1535 SSL_CTX_set_not_resumable_session_callback(ctx, fr_tls_cache_disable_cb);
1536 SSL_CTX_set_quiet_shutdown(ctx, 1);
1537
1538 return 0;
1539}
1540#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_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define USES_APPLE_DEPRECATED_API
Definition build.h:474
#define RCSID(id)
Definition build.h:487
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition dbuff.h:777
static void fr_dbuff_free_talloc(fr_dbuff_t *dbuff)
Free the talloc buffer associated with a dbuff.
Definition dbuff.h:463
#define fr_dbuff_len(_dbuff_or_marker)
The length of the underlying buffer.
Definition dbuff.h:786
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
Definition dbuff.h:364
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:908
#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:753
static fr_dbuff_t * fr_dbuff_init_talloc(TALLOC_CTX *ctx, fr_dbuff_t *dbuff, fr_dbuff_uctx_talloc_t *tctx, size_t init, size_t max)
Initialise a special dbuff which automatically extends as additional data is written.
Definition dbuff.h:421
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:339
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:202
#define MEM(x)
Definition debug.h:36
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2672
talloc_free(hp)
bool unlang_request_is_cancelled(request_t const *request)
Return whether a request has been cancelled.
Definition interpret.c:1591
static fr_dict_t const * dict_tls
Definition base.c:79
void log_request_pair_list(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_list_t const *vps, char const *prefix)
Print a fr_pair_list_t.
Definition log.c:820
#define PERROR(_fmt,...)
Definition log.h:228
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:455
#define DEBUG3(_fmt,...)
Definition log.h:266
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition log.h:540
#define RWDEBUG(fmt,...)
Definition log.h:373
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition log.h:347
#define RDEBUG3(fmt,...)
Definition log.h:355
#define RHEXDUMP4(_data, _len, _fmt,...)
Definition log.h:718
#define ROPTIONAL_ENABLED(_e_request, _e_global)
Check if a debug level is set by the request (if !NULL) or by the global log.
Definition log.h:554
#define RPERROR(fmt,...)
Definition log.h:314
#define RPEDEBUG(fmt,...)
Definition log.h:388
#define HEXDUMP3(_data, _len, _fmt,...)
Definition log.h:735
#define RPWDEBUG(fmt,...)
Definition log.h:378
#define DEBUG_ENABLED3
True if global debug level 1-3 messages are enabled.
Definition log.h:259
#define RINDENT()
Indent R* messages by one level.
Definition log.h:442
fr_value_box_t const * enum_tls_packet_type_store_session
HIDDEN fr_dict_attr_t const * attr_tls_packet_type
fr_value_box_t const * enum_tls_packet_type_success
HIDDEN fr_dict_attr_t const * attr_tls_session_ttl
fr_value_box_t const * enum_tls_session_resumed_stateful
HIDDEN fr_dict_attr_t const * attr_tls_session_data
fr_value_box_t const * enum_tls_packet_type_load_session
HIDDEN fr_dict_attr_t const * attr_tls_session_id
fr_value_box_t const * enum_tls_packet_type_clear_session
fr_value_box_t const * enum_tls_session_resumed_stateless
fr_value_box_t const * enum_tls_packet_type_notfound
HIDDEN fr_dict_attr_t const * attr_tls_session_resume_type
HIDDEN fr_dict_attr_t const * attr_allow_session_resumption
@ L_DBG_LVL_3
3rd highest priority debug messages (-xxx | -Xx).
Definition log.h:72
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
Definition log.h:71
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:59
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
int fr_pair_value_memdup_buffer(fr_pair_t *vp, uint8_t const *src, bool tainted)
Copy data from a talloced buffer into an "octets" data type.
Definition pair.c:2975
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:704
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
int fr_pair_delete(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list and free.
Definition pair.c:1830
int fr_pair_value_memdup_buffer_shallow(fr_pair_t *vp, uint8_t const *src, bool tainted)
Assign a talloced buffer to a "octets" type value pair.
Definition pair.c:3020
ssize_t fr_internal_decode_pair_dbuff(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, fr_dbuff_t *dbuff, void *decode_ctx)
Definition decode.c:286
ssize_t fr_internal_encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx)
Encode a data structure into an internal attribute.
Definition encode.c:281
#define fr_assert(_expr)
Definition rad_assert.h:38
#define pair_update_request(_attr, _da)
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG_ENABLED2()
Definition radclient.h:50
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define DEBUG2(fmt,...)
Definition radclient.h:43
static rs_t * conf
Definition radsniff.c:53
#define pair_append_session_state(_attr, _da)
Allocate and append a fr_pair_t to session-state list.
Definition pair.h:67
#define pair_prepend_request(_attr, _da)
Allocate and prepend a fr_pair_t to the request list.
Definition pair.h:77
fr_pair_t * vp
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
request_t * unlang_subrequest_alloc(request_t *parent, fr_dict_t const *namespace)
Allocate a subrequest to run through a virtual server at some point in the future.
Definition subrequest.c:305
uint8_t * talloc_typed_memdup(TALLOC_CTX *ctx, uint8_t const *in, size_t inlen)
Call talloc_memdup, setting the type on the new chunk correctly.
Definition talloc.c:443
#define fr_time_lteq(_a, _b)
Definition time.h:240
static int64_t fr_time_delta_to_sec(fr_time_delta_t delta)
Definition time.h:647
static fr_time_t fr_time_from_sec(time_t when)
Convert a time_t (wallclock time) to a fr_time_t (internal time)
Definition time.h:858
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition time.h:229
"server local" time.
Definition time.h:69
fr_pair_t * fr_pair_remove(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list without freeing.
Definition pair_inline.c:93
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition pair.h:604
void fr_value_box_memdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Assign a buffer to a box, but don't copy it.
Definition value.c:5178
static fr_slen_t data
Definition value.h:1334
#define fr_box_octets_buffer(_val)
Definition value.h:313
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1024
#define fr_box_octets(_val, _len)
Definition value.h:311