The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 4b1802f45a969e61cfb2497a33906139f27a79cd $
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  */
26 RCSIDH(session_h, "$Id: 4b1802f45a969e61cfb2497a33906139f27a79cd $")
27 
28 #include "openssl_user_macros.h"
29 
30 #include <openssl/ssl.h>
31 #include <openssl/err.h>
32 
33 typedef 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
43 extern "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  */
66 typedef struct {
67  uint8_t data[FR_TLS_MAX_RECORD_SIZE];
68  size_t used;
69 } fr_tls_record_t;
70 
71 typedef enum {
72  TLS_INFO_ORIGIN_RECORD_RECEIVED,
73  TLS_INFO_ORIGIN_RECORD_SENT
74 } fr_tls_info_origin_t;
75 
76 typedef 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  */
93 typedef 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  */
106 struct 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  */
156 static 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  */
166 static 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  */
178 static 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  */
188 static 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 
193 static 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[%u] - 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 
225 static 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[%u] - 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  */
254 static inline CC_HINT(nonnull)
255 void 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  */
267 static inline CC_HINT(nonnull)
268 void 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  */
281 static inline CC_HINT(nonnull)
282 void 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 
289 int fr_tls_session_password_cb(char *buf, int num, int rwflag, void *userdata);
290 
291 unsigned 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 
295 unsigned int fr_tls_session_psk_server_cb(SSL *ssl, const char *identity,
296  unsigned char *psk, unsigned int max_psk_len);
297 
298 void fr_tls_session_info_cb(SSL const *s, int where, int ret);
299 
300 void 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 
303 void fr_tls_session_keylog_cb(const SSL *ssl, const char *line);
304 
305 int 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 
308 int fr_tls_session_recv(request_t *request, fr_tls_session_t *tls_session);
309 
310 int fr_tls_session_send(request_t *request, fr_tls_session_t *tls_session);
311 
312 int fr_tls_session_alert(request_t *request, fr_tls_session_t *tls_session, uint8_t level, uint8_t description);
313 
314 unlang_action_t fr_tls_session_async_handshake_push(request_t *request, fr_tls_session_t *tls_session);
315 
316 fr_tls_session_t *fr_tls_session_alloc_client(TALLOC_CTX *ctx, SSL_CTX *ssl_ctx);
317 
318 fr_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 
320 #ifdef __cplusplus
321 }
322 #endif
323 #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:482
#define unlikely(_x)
Definition: build.h:379
#define UNUSED
Definition: build.h:313
#define RDEBUG3(fmt,...)
Definition: log.h:343
unsigned char uint8_t
Definition: merged_model.c:30
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
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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.
Definition: pair_inline.c:125
static fr_slen_t data
Definition: value.h:1265
int nonnull(2, 5))