The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_eap_tls.c
Go to the documentation of this file.
1/*
2 * rlm_eap_tls.c contains the interfaces that are called from eap
3 *
4 * Version: $Id: 5911d55f799188718fea8723e8fbd1967786e55f $
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 * @copyright 2001 hereUare Communications, Inc. (raghud@hereuare.com)
21 * @copyright 2003 Alan DeKok (aland@freeradius.org)
22 * @copyright 2006 The FreeRADIUS server project
23 *
24 */
25RCSID("$Id: 5911d55f799188718fea8723e8fbd1967786e55f $")
26USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
27
28#include <freeradius-devel/tls/openssl_user_macros.h>
29#ifdef HAVE_OPENSSL_RAND_H
30# include <openssl/rand.h>
31#endif
32#ifdef HAVE_OPENSSL_EVP_H
33# include <openssl/evp.h>
34#endif
35#ifdef HAVE_SYS_STAT_H
36# include <sys/stat.h>
37#endif
38
39#include "rlm_eap_tls.h"
40
41typedef struct {
42 SSL_CTX *ssl_ctx; //!< Thread local SSL_CTX.
44
46 { FR_CONF_OFFSET("tls", rlm_eap_tls_t, tls_conf_name) },
47
48 { FR_CONF_OFFSET("require_client_cert", rlm_eap_tls_t, req_client_cert), .dflt = "yes" },
49 { FR_CONF_OFFSET("include_length", rlm_eap_tls_t, include_length), .dflt = "yes" },
51};
52
54
57 { .out = &dict_freeradius, .proto = "freeradius" },
58 { NULL }
59};
60
62
65 { .out = &attr_eap_tls_require_client_cert, .name = "EAP-TLS-Require-Client-Cert", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
66 { NULL }
67};
68
70 UNUSED request_t *request)
71{
73}
74
76{
77 eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
78 eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
79 fr_tls_session_t *tls_session = eap_tls_session->tls_session;
80
81 if ((eap_tls_session->state == EAP_TLS_INVALID) || (eap_tls_session->state == EAP_TLS_FAIL)) {
82 REDEBUG("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
83 } else {
84 RDEBUG2("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
85 }
86
87 switch (eap_tls_session->state) {
88 /*
89 * EAP-TLS handshake was successful, return an
90 * EAP-TLS-Success packet here.
91 *
92 * If a virtual server was configured, check that
93 * it accepts the certificates, too.
94 */
96 {
97 eap_tls_prf_label_t prf_label;
98
99 eap_crypto_prf_label_init(&prf_label, eap_session,
100 "client EAP encryption",
101 sizeof("client EAP encryption") - 1);
102
103 if (eap_tls_success(request, eap_session, &prf_label) < 0) RETURN_MODULE_FAIL;
104
105 /*
106 * Result is always OK, even if we fail to persist the
107 * session data.
108 */
109 unlang_module_yield(request, mod_handshake_done, NULL, 0, mctx->rctx);
110 /*
111 * Write the session to the session cache
112 *
113 * We do this here (instead of relying on OpenSSL to call the
114 * session caching callback), because we only want to write
115 * session data to the cache if all phases were successful.
116 *
117 * If we wrote out the cache data earlier, and the server
118 * exited whilst the session was in progress, the supplicant
119 * could resume the session (and get access) even if phase2
120 * never completed.
121 */
122 return fr_tls_cache_pending_push(request, tls_session);
123 }
124
125 /*
126 * The TLS code is still working on the TLS
127 * exchange, and it's a valid TLS request.
128 * do nothing.
129 */
130 case EAP_TLS_HANDLED:
132
133 /*
134 * Handshake is done, proceed with decoding tunneled
135 * data.
136 */
138 REDEBUG("Received unexpected tunneled data after successful handshake");
139 eap_tls_fail(request, eap_session);
140
142
143 /*
144 * Anything else: fail.
145 *
146 * Also, remove the session from the cache so that
147 * the client can't reuse it.
148 */
149 default:
150 fr_tls_cache_deny(request, tls_session);
151 *p_result = RLM_MODULE_REJECT;
152
153 /*
154 * We'll jump back to the caller
155 * in the unlang stack if this
156 * fails.
157 */
158 return fr_tls_cache_pending_push(request, tls_session); /* Run any pending cache clear operations */
159 }
160}
161
162/*
163 * Do authentication, by letting EAP-TLS do most of the work.
164 */
166 request_t *request)
167{
168 eap_session_t *eap_session = eap_session_get(request->parent);
169
170 /*
171 * Setup the resumption frame to process the result
172 */
173 (void)unlang_module_yield(request, mod_handshake_resume, NULL, 0, eap_session);
174
175 /*
176 * Process TLS layer until done.
177 */
178 return eap_tls_process(request, eap_session);
179}
180
182{
183 rlm_eap_tls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_tls_t);
184 rlm_eap_tls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_tls_thread_t);
185 eap_session_t *eap_session = eap_session_get(request->parent);
186 eap_tls_session_t *eap_tls_session;
187
188 fr_pair_t *vp;
189 bool client_cert;
190
191 /*
192 * EAP-TLS-Require-Client-Cert attribute will override
193 * the require_client_cert configuration option.
194 */
195 vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_tls_require_client_cert);
196 if (vp) {
197 client_cert = vp->vp_uint32 ? true : false;
198 } else {
199 client_cert = inst->req_client_cert;
200 }
201
202 /*
203 * EAP-TLS always requires a client certificate.
204 */
205 eap_session->opaque = eap_tls_session = eap_tls_session_init(request, eap_session, t->ssl_ctx, client_cert);
206 if (!eap_tls_session) RETURN_MODULE_FAIL;
207
208 eap_tls_session->include_length = inst->include_length;
209
210 /*
211 * TLS session initialization is over. Now handle TLS
212 * related handshaking or application data.
213 */
214 if (eap_tls_start(request, eap_session) < 0) {
215 talloc_free(eap_tls_session);
217 }
218
219 eap_session->process = mod_handshake_process;
220
222}
223
224/*
225 * Send an initial eap-tls request to the peer, using the libeap functions.
226 */
228{
229 rlm_eap_tls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_tls_t);
230 eap_session_t *eap_session = eap_session_get(request->parent);
231
232 eap_session->tls = true;
233
234 (void) unlang_module_yield(request, mod_session_init_resume, NULL, 0, NULL);
235
236 if (inst->tls_conf->new_session) return fr_tls_new_session_push(request, inst->tls_conf);
237
239}
240
242{
243 rlm_eap_tls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_tls_t);
244 rlm_eap_tls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_tls_thread_t);
245
246 t->ssl_ctx = fr_tls_ctx_alloc(inst->tls_conf, false);
247 if (!t->ssl_ctx) return -1;
248
249 return 0;
250}
251
253{
254 rlm_eap_tls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_tls_thread_t);
255
256 if (likely(t->ssl_ctx != NULL)) SSL_CTX_free(t->ssl_ctx);
257 t->ssl_ctx = NULL;
258
259 return 0;
260}
261
262/*
263 * Attach the EAP-TLS module.
264 */
265static int mod_instantiate(module_inst_ctx_t const *mctx)
266{
267 rlm_eap_tls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_tls_t);
268 CONF_SECTION *conf = mctx->mi->conf;
269
270 inst->tls_conf = eap_tls_conf_parse(conf, "tls");
271 if (!inst->tls_conf) {
272 cf_log_err(conf, "Failed initializing SSL context");
273 return -1;
274 }
275
276 return 0;
277}
278
279/*
280 * The module name should be the only globally exported symbol.
281 * That is, everything else should be 'static'.
282 */
285 .common = {
286 .magic = MODULE_MAGIC_INIT,
287 .name = "eap_tls",
288 .inst_size = sizeof(rlm_eap_tls_t),
290 .instantiate = mod_instantiate, /* Create new submodule instance */
291
292 .thread_inst_size = sizeof(rlm_eap_tls_thread_t),
293 .thread_instantiate = mod_thread_instantiate,
294 .thread_detach = mod_thread_detach,
295 },
296 .provides = { FR_EAP_METHOD_TLS },
297 .session_init = mod_session_init, /* Initialise a new EAP session */
298};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
#define USES_APPLE_DEPRECATED_API
Definition build.h:470
#define RCSID(id)
Definition build.h:483
#define UNUSED
Definition build.h:315
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:658
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:284
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:595
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:268
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:281
Specifies an attribute which must be present for the module to function.
Definition dict.h:267
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:280
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
void eap_crypto_prf_label_init(eap_tls_prf_label_t *prf_label, eap_session_t *eap_session, char const *keying_prf_label, size_t keying_prf_label_len)
Initialize the PRF label fields.
Definition crypto.c:48
@ FR_EAP_METHOD_TLS
Definition types.h:58
static eap_session_t * eap_session_get(request_t *request)
Definition session.h:82
void * opaque
Opaque data used by EAP methods.
Definition session.h:62
bool tls
Whether EAP method uses TLS.
Definition session.h:70
module_method_t process
Callback that should be used to process the next round.
Definition session.h:64
Tracks the progress of a single session of any EAP method.
Definition session.h:40
talloc_free(reap)
@ FR_TYPE_UINT32
32 Bit unsigned integer.
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * thread
Thread specific instance data.
Definition module_ctx.h:43
void * rctx
Resume ctx that a module previously set.
Definition module_ctx.h:45
void * thread
Thread instance data.
Definition module_ctx.h:67
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:64
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
Temporary structure to hold arguments for thread_instantiation calls.
Definition module_ctx.h:63
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:693
static const conf_parser_t config[]
Definition base.c:183
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG2(fmt,...)
Definition radclient.h:54
static rs_t * conf
Definition radsniff.c:53
#define RETURN_MODULE_HANDLED
Definition rcode.h:58
#define RETURN_MODULE_INVALID
Definition rcode.h:59
#define RETURN_MODULE_OK
Definition rcode.h:57
#define RETURN_MODULE_FAIL
Definition rcode.h:56
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:41
static unlang_action_t mod_handshake_resume(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_eap_tls.c:75
static unlang_action_t mod_handshake_process(UNUSED rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
static fr_dict_t const * dict_freeradius
Definition rlm_eap_tls.c:53
static unlang_action_t mod_session_init(UNUSED rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
static fr_dict_attr_t const * attr_eap_tls_require_client_cert
Definition rlm_eap_tls.c:61
fr_dict_attr_autoload_t rlm_eap_tls_dict_attr[]
Definition rlm_eap_tls.c:64
static unlang_action_t mod_handshake_done(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, UNUSED request_t *request)
Definition rlm_eap_tls.c:69
fr_dict_autoload_t rlm_eap_tls_dict[]
Definition rlm_eap_tls.c:56
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
static unlang_action_t mod_session_init_resume(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
static conf_parser_t submodule_config[]
Definition rlm_eap_tls.c:45
rlm_eap_submodule_t rlm_eap_tls
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static int mod_instantiate(module_inst_ctx_t const *mctx)
SSL_CTX * ssl_ctx
Thread local SSL_CTX.
Definition rlm_eap_tls.c:42
static int instantiate(module_inst_ctx_t const *mctx)
Definition rlm_rest.c:1310
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:329
size_t inst_size
Size of the module's instance data.
Definition module.h:203
void * data
Module's instance data.
Definition module.h:271
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition module.c:419
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
module_t common
Common fields provided by all modules.
Definition submodule.h:50
Interface exported by EAP submodules.
Definition submodule.h:49
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
int eap_tls_success(request_t *request, eap_session_t *eap_session, eap_tls_prf_label_t *prf_label)
Send an EAP-TLS success.
Definition tls.c:264
eap_tls_session_t * eap_tls_session_init(request_t *request, eap_session_t *eap_session, SSL_CTX *ssl_ctx, bool client_cert)
Create a new fr_tls_session_t associated with an eap_session_t.
Definition tls.c:1131
int eap_tls_start(request_t *request, eap_session_t *eap_session)
Send an initial EAP-TLS request to the peer.
Definition tls.c:239
int eap_tls_fail(request_t *request, eap_session_t *eap_session)
Send an EAP-TLS failure.
Definition tls.c:322
USES_APPLE_DEPRECATED_API fr_table_num_ordered_t const eap_tls_status_table[]
Definition tls.c:80
fr_tls_conf_t * eap_tls_conf_parse(CONF_SECTION *cs, char const *attr)
Parse TLS configuration.
Definition tls.c:1264
unlang_action_t eap_tls_process(request_t *request, eap_session_t *eap_session)
Process an EAP TLS request.
Definition tls.c:963
eap_tls_status_t state
The state of the EAP-TLS session.
Definition tls.h:127
@ EAP_TLS_INVALID
Invalid, don't reply.
Definition tls.h:91
@ EAP_TLS_HANDLED
TLS code has handled it.
Definition tls.h:94
@ EAP_TLS_RECORD_RECV_COMPLETE
Received final fragment of a record.
Definition tls.h:111
@ EAP_TLS_FAIL
Fail, send fail.
Definition tls.h:93
@ EAP_TLS_ESTABLISHED
Session established, send success (or start phase2).
Definition tls.h:92
fr_tls_session_t * tls_session
TLS session used to authenticate peer or tunnel sensitive data.
Definition tls.h:129
bool include_length
A flag to include length in every TLS Data/Alert packet.
Definition tls.h:138
Tracks the state of an EAP-TLS session.
Definition tls.h:126