The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
session.h
Go to the documentation of this file.
1#pragma once
2/*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17#ifdef WITH_TLS
18/**
19 * $Id: 277a1ac71a28333148b59422ed7ab40b9dc3bc19 $
20 *
21 * @file lib/tls/session.h
22 * @brief Structures for session-resumption management.
23 *
24 * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25 */
26RCSIDH(session_h, "$Id: 277a1ac71a28333148b59422ed7ab40b9dc3bc19 $")
27
28#include "openssl_user_macros.h"
29
30#include <openssl/ssl.h>
31#include <openssl/err.h>
32
33typedef struct fr_tls_session_s fr_tls_session_t;
34
35#include <freeradius-devel/server/request.h>
36
37#include "cache.h"
38#include "conf.h"
39#include "index.h"
40#include "verify.h"
41
42#ifdef __cplusplus
43extern "C" {
44#endif
45
46/*
47 * A single TLS record may be up to 16384 octets in length, but a
48 * TLS message may span multiple TLS records, and a TLS
49 * certificate message may in principle be as long as 16MB.
50 *
51 * However, note that in order to protect against reassembly
52 * lockup and denial of service attacks, it may be desirable for
53 * an implementation to set a maximum size for one such group of
54 * TLS messages.
55 *
56 * The TLS Message Length field is four octets, and provides the
57 * total length of the TLS message or set of messages that is
58 * being fragmented; this simplifies buffer allocation.
59 */
60#define FR_TLS_MAX_RECORD_SIZE 16384
61
62/*
63 * FIXME: Dynamic allocation of buffer to overcome FR_TLS_MAX_RECORD_SIZE overflows.
64 * or configure TLS not to exceed FR_TLS_MAX_RECORD_SIZE.
65 */
66typedef struct {
67 uint8_t data[FR_TLS_MAX_RECORD_SIZE];
68 size_t used;
69} fr_tls_record_t;
70
71typedef enum {
72 TLS_INFO_ORIGIN_RECORD_RECEIVED,
73 TLS_INFO_ORIGIN_RECORD_SENT
74} fr_tls_info_origin_t;
75
76typedef struct {
77 int origin;
78 int content_type;
79 uint8_t handshake_type;
80 uint8_t alert_level;
81 uint8_t alert_description;
82 bool initialized;
83
84 char info_description[256];
85 size_t record_len;
86 int version;
87} fr_tls_info_t;
88
89/** Result of the last operation on the session
90 *
91 * This is needed to record the result of an asynchronous
92 */
93typedef enum {
94 FR_TLS_RESULT_IN_PROGRESS = 0x00, //!< Handshake round in progress.
95 FR_TLS_RESULT_ERROR = 0x01, //!< Handshake failed.
96 FR_TLS_RESULT_SUCCESS = 0x02 //!< Handshake round succeed.
97} fr_tls_result_t;
98
99/** Tracks the state of a TLS session
100 *
101 * Currently used for RADSEC and EAP-TLS + dependents (EAP-TTLS, EAP-PEAP etc...).
102 *
103 * In the case of EAP-TLS + dependents a #eap_tls_session_t struct is used to track
104 * the transfer of TLS records.
105 */
106struct fr_tls_session_s {
107 SSL_CTX *ctx; //!< TLS configuration context.
108 SSL *ssl; //!< This SSL session.
109 SSL_SESSION *session; //!< Session resumption data.
110 fr_tls_result_t result; //!< Result of the last handshake round.
111 fr_tls_info_t info; //!< Information about the state of the TLS session.
112
113 BIO *into_ssl; //!< Basic I/O input to OpenSSL.
114 BIO *from_ssl; //!< Basic I/O output from OpenSSL.
115 fr_tls_record_t clean_in; //!< Cleartext data that needs to be encrypted.
116 fr_tls_record_t clean_out; //!< Cleartext data that's been encrypted.
117 fr_tls_record_t dirty_in; //!< Encrypted data to decrypt.
118 fr_tls_record_t dirty_out; //!< Encrypted data that's been decrypted.
119 int last_ret; //!< Last result returned by SSL_read().
120
121 void (*record_init)(fr_tls_record_t *buf);
122 void (*record_close)(fr_tls_record_t *buf);
123 unsigned int (*record_from_buff)(fr_tls_record_t *buf, void const *ptr, unsigned int size);
124 unsigned int (*record_to_buff)(fr_tls_record_t *buf, void *ptr, unsigned int size);
125
126 size_t mtu; //!< Maximum record fragment size.
127
128 void *opaque; //!< Used to store module specific data.
129
130 fr_tls_cache_t *cache; //!< Current session resumption state.
131 bool allow_session_resumption; //!< Whether session resumption is allowed.
132 bool verify_client_cert; //!< Whether client cert verification has been requested.
133
134 fr_tls_verify_t validate; //!< Current session certificate validation state.
135
136 bool invalid; //!< Whether heartbleed attack was detected.
137
138 bool client_cert_ok; //!< whether or not the client certificate was validated
139 bool can_pause; //!< If true, it's ok to pause the request
140 ///< using the OpenSSL async API.
141
142 uint8_t alerts_sent;
143 bool pending_alert;
144 uint8_t pending_alert_level;
145 uint8_t pending_alert_description;
146
147 fr_pair_list_t extra_pairs; //!< Pairs to add to cache and certificate validation
148 ///< calls. These will be duplicated for every call.
149};
150
151/** Return the tls config associated with a tls_session
152 *
153 * @param[in] ssl to retrieve the configuration from.
154 * @return #fr_tls_conf_t associated with the session.
155 */
156static inline fr_tls_conf_t *fr_tls_session_conf(SSL *ssl)
157{
158 return talloc_get_type_abort(SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF), fr_tls_conf_t);
159}
160
161/** Return the tls_session associated with a SSL *
162 *
163 * @param[in] ssl to retrieve the configuration from.
164 * @return #fr_tls_conf_t associated with the session.
165 */
166static inline fr_tls_session_t *fr_tls_session(SSL *ssl)
167{
168 return talloc_get_type_abort(SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TLS_SESSION), fr_tls_session_t);
169}
170
171/** Check to see if a request is bound to a session
172 *
173 * @param[in] ssl session to check for requests.
174 * @return
175 * - true if a request is bound to this session.
176 * - false if a request is not bound to this session.
177 */
178static inline CC_HINT(nonnull) bool fr_tls_session_request_bound(SSL *ssl)
179{
180 return (SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST) != NULL);
181}
182
183/** Return the request associated with a ssl session
184 *
185 * @param[in] ssl session to retrieve the configuration from.
186 * @return #request associated with the session.
187 */
188static inline request_t *fr_tls_session_request(SSL const *ssl)
189{
190 return talloc_get_type_abort(SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST), request_t);
191}
192
193static inline CC_HINT(nonnull) void _fr_tls_session_request_bind(char const *file, int line,
194 SSL *ssl, request_t *request)
195{
196 int ret;
197
198 RDEBUG3("%s[%d] - Binding SSL * (%p) to request (%p)", file, line, ssl, request);
199
200#ifndef NDEBUG
201 {
202 request_t *old;
203 old = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST);
204 if (old) {
205 (void)talloc_get_type_abort(ssl, request_t);
206 fr_assert(0);
207 }
208 }
209#endif
210 ret = SSL_set_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST, request);
211 if (unlikely(ret == 0)) {
212 fr_assert(0);
213 return;
214 }
215}
216/** Place a request pointer in the SSL * for retrieval by callbacks
217 *
218 * @note A request must not already be bound to the SSL *
219 *
220 * @param[in] ssl to be bound.
221 * @param[in] request to bind to the tls_session.
222 */
223 #define fr_tls_session_request_bind(_ssl, _request) _fr_tls_session_request_bind(__FILE__, __LINE__, _ssl, _request)
224
225static inline CC_HINT(nonnull) void _fr_tls_session_request_unbind(char const *file, int line, SSL *ssl)
226{
227 request_t *request = fr_tls_session_request(ssl);
228 int ret;
229
230#ifndef NDEBUG
231 (void)talloc_get_type_abort(request, request_t);
232#endif
233
234 RDEBUG3("%s[%d] - Unbinding SSL * (%p) from request (%p)", file, line, ssl, request);
235 ret = SSL_set_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST, NULL);
236 if (unlikely(ret == 0)) {
237 fr_assert(0);
238 return;
239 }
240}
241/** Remove a request pointer from the tls_session
242 *
243 * @note A request must be bound to the tls_session
244 *
245 * @param[in] ssl session containing the request pointer.
246 */
247#define fr_tls_session_request_unbind(_ssl) _fr_tls_session_request_unbind(__FILE__, __LINE__, _ssl)
248
249/** Add extra pairs to the temporary subrequests
250 *
251 * @param[in] child to add extra pairs to.
252 * @param[in] tls_session to add extra pairs from.
253 */
254static inline CC_HINT(nonnull)
255void fr_tls_session_extra_pairs_copy_to_child(request_t *child, fr_tls_session_t *tls_session)
256{
257 if (!fr_pair_list_empty(&tls_session->extra_pairs)) {
258 MEM(fr_pair_list_copy(child->request_ctx, &child->request_pairs, &tls_session->extra_pairs) >= 0);
259 }
260}
261
262/** Add an additional pair (copying it) to the list of extra pairs
263 *
264 * @param[in] tls_session to add extra pairs to.
265 * @param[in] vp to add to tls_session.
266 */
267static inline CC_HINT(nonnull)
268void fr_tls_session_extra_pair_add(fr_tls_session_t *tls_session, fr_pair_t *vp)
269{
270 fr_pair_t *copy;
271
272 MEM(copy = fr_pair_copy(tls_session, vp));
273 fr_pair_append(&tls_session->extra_pairs, copy);
274}
275
276/** Add an additional pair to the list of extra pairs
277 *
278 * @param[in] tls_session to add extra pairs to.
279 * @param[in] vp to add to tls_session.
280 */
281static inline CC_HINT(nonnull)
282void fr_tls_session_extra_pair_add_shallow(fr_tls_session_t *tls_session, fr_pair_t *vp)
283{
284 fr_assert(talloc_parent(vp) == tls_session);
285 fr_pair_append(&tls_session->extra_pairs, vp);
286}
287
288
289int fr_tls_session_password_cb(char *buf, int num, int rwflag, void *userdata);
290
291unsigned int fr_tls_session_psk_client_cb(SSL *ssl, UNUSED char const *hint,
292 char *identity, unsigned int max_identity_len,
293 unsigned char *psk, unsigned int max_psk_len);
294
295unsigned int fr_tls_session_psk_server_cb(SSL *ssl, const char *identity,
296 unsigned char *psk, unsigned int max_psk_len);
297
298void fr_tls_session_info_cb(SSL const *s, int where, int ret);
299
300void fr_tls_session_msg_cb(int write_p, int msg_version, int content_type,
301 void const *buf, size_t len, SSL *ssl, void *arg);
302
303void fr_tls_session_keylog_cb(const SSL *ssl, const char *line);
304
305int fr_tls_session_pairs_from_x509_cert(fr_pair_list_t *pair_list, TALLOC_CTX *ctx,
306 request_t *request, X509 *cert) CC_HINT(nonnull);
307
308int fr_tls_session_recv(request_t *request, fr_tls_session_t *tls_session);
309
310int fr_tls_session_send(request_t *request, fr_tls_session_t *tls_session);
311
312int fr_tls_session_alert(request_t *request, fr_tls_session_t *tls_session, uint8_t level, uint8_t description);
313
314unlang_action_t fr_tls_session_async_handshake_push(request_t *request, fr_tls_session_t *tls_session);
315
316fr_tls_session_t *fr_tls_session_alloc_client(TALLOC_CTX *ctx, SSL_CTX *ssl_ctx);
317
318fr_tls_session_t *fr_tls_session_alloc_server(TALLOC_CTX *ctx, SSL_CTX *ssl_ctx, request_t *request, size_t dynamic_mtu, bool client_cert);
319
320unlang_action_t fr_tls_new_session_push(request_t *request, fr_tls_conf_t const *tls_conf);
321
322#ifdef __cplusplus
323}
324#endif
325#endif /* WITH_TLS */
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
int const char * file
Definition acutest.h:702
int const char int line
Definition acutest.h:702
#define RCSIDH(h, id)
Definition build.h:484
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
#define MEM(x)
Definition debug.h:36
#define RDEBUG3(fmt,...)
Definition log.h:343
unsigned char uint8_t
static size_t used
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition pair.c:2319
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1345
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:489
#define fr_assert(_expr)
Definition rad_assert.h:38
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
static fr_slen_t data
Definition value.h:1265
int nonnull(2, 5))