The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 1586c6e2229763b22d24fc8cc9b64da43f517e03 $
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  */
25 RCSID("$Id: 1586c6e2229763b22d24fc8cc9b64da43f517e03 $")
26 USES_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 
41 typedef 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" },
50  { FR_CONF_OFFSET("virtual_server", rlm_eap_tls_t, virtual_server) },
52 };
53 
54 static fr_dict_t const *dict_freeradius;
55 
58  { .out = &dict_freeradius, .proto = "freeradius" },
59  { NULL }
60 };
61 
63 
66  { .out = &attr_eap_tls_require_client_cert, .name = "EAP-TLS-Require-Client-Cert", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
67  { NULL }
68 };
69 
71  UNUSED request_t *request)
72 {
74 }
75 
76 static unlang_action_t mod_handshake_resume(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
77 {
78  eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
79  eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
80  fr_tls_session_t *tls_session = eap_tls_session->tls_session;
81 
82  if ((eap_tls_session->state == EAP_TLS_INVALID) || (eap_tls_session->state == EAP_TLS_FAIL)) {
83  REDEBUG("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
84  } else {
85  RDEBUG2("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
86  }
87 
88  switch (eap_tls_session->state) {
89  /*
90  * EAP-TLS handshake was successful, return an
91  * EAP-TLS-Success packet here.
92  *
93  * If a virtual server was configured, check that
94  * it accepts the certificates, too.
95  */
97  {
98  eap_tls_prf_label_t prf_label;
99 
100  eap_crypto_prf_label_init(&prf_label, eap_session,
101  "client EAP encryption",
102  sizeof("client EAP encryption") - 1);
103 
104  if (eap_tls_success(request, eap_session, &prf_label) < 0) RETURN_MODULE_FAIL;
105 
106  /*
107  * Result is always OK, even if we fail to persist the
108  * session data.
109  */
110  unlang_module_yield(request, mod_handshake_done, NULL, 0, mctx->rctx);
111  /*
112  * Write the session to the session cache
113  *
114  * We do this here (instead of relying on OpenSSL to call the
115  * session caching callback), because we only want to write
116  * session data to the cache if all phases were successful.
117  *
118  * If we wrote out the cache data earlier, and the server
119  * exited whilst the session was in progress, the supplicant
120  * could resume the session (and get access) even if phase2
121  * never completed.
122  */
123  return fr_tls_cache_pending_push(request, tls_session);
124  }
125 
126  /*
127  * The TLS code is still working on the TLS
128  * exchange, and it's a valid TLS request.
129  * do nothing.
130  */
131  case EAP_TLS_HANDLED:
133 
134  /*
135  * Handshake is done, proceed with decoding tunneled
136  * data.
137  */
139  REDEBUG("Received unexpected tunneled data after successful handshake");
140  eap_tls_fail(request, eap_session);
141 
143 
144  /*
145  * Anything else: fail.
146  *
147  * Also, remove the session from the cache so that
148  * the client can't reuse it.
149  */
150  default:
151  fr_tls_cache_deny(request, tls_session);
152  *p_result = RLM_MODULE_REJECT;
153 
154  /*
155  * We'll jump back to the caller
156  * in the unlang stack if this
157  * fails.
158  */
159  return fr_tls_cache_pending_push(request, tls_session); /* Run any pending cache clear operations */
160  }
161 }
162 
163 /*
164  * Do authentication, by letting EAP-TLS do most of the work.
165  */
167  request_t *request)
168 {
169  eap_session_t *eap_session = eap_session_get(request->parent);
170 
171  /*
172  * Setup the resumption frame to process the result
173  */
174  (void)unlang_module_yield(request, mod_handshake_resume, NULL, 0, eap_session);
175 
176  /*
177  * Process TLS layer until done.
178  */
179  return eap_tls_process(request, eap_session);
180 }
181 
182 /*
183  * Send an initial eap-tls request to the peer, using the libeap functions.
184  */
185 static unlang_action_t mod_session_init(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
186 {
187  rlm_eap_tls_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_eap_tls_t);
188  rlm_eap_tls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_tls_thread_t);
189  eap_session_t *eap_session = eap_session_get(request->parent);
190  eap_tls_session_t *eap_tls_session;
191 
192  fr_pair_t *vp;
193  bool client_cert;
194 
195  eap_session->tls = true;
196 
197  /*
198  * EAP-TLS-Require-Client-Cert attribute will override
199  * the require_client_cert configuration option.
200  */
201  vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_tls_require_client_cert);
202  if (vp) {
203  client_cert = vp->vp_uint32 ? true : false;
204  } else {
205  client_cert = inst->req_client_cert;
206  }
207 
208  /*
209  * EAP-TLS always requires a client certificate.
210  */
211  eap_session->opaque = eap_tls_session = eap_tls_session_init(request, eap_session, t->ssl_ctx, client_cert);
212  if (!eap_tls_session) RETURN_MODULE_FAIL;
213 
214  eap_tls_session->include_length = inst->include_length;
215 
216  /*
217  * TLS session initialization is over. Now handle TLS
218  * related handshaking or application data.
219  */
220  if (eap_tls_start(request, eap_session) < 0) {
221  talloc_free(eap_tls_session);
223  }
224 
225  eap_session->process = mod_handshake_process;
226 
228 }
229 
231 {
232  rlm_eap_tls_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_eap_tls_t);
233  rlm_eap_tls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_tls_thread_t);
234 
235  t->ssl_ctx = fr_tls_ctx_alloc(inst->tls_conf, false);
236  if (!t->ssl_ctx) return -1;
237 
238  return 0;
239 }
240 
242 {
243  rlm_eap_tls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_tls_thread_t);
244 
245  if (likely(t->ssl_ctx != NULL)) SSL_CTX_free(t->ssl_ctx);
246  t->ssl_ctx = NULL;
247 
248  return 0;
249 }
250 
251 /*
252  * Attach the EAP-TLS module.
253  */
254 static int mod_instantiate(module_inst_ctx_t const *mctx)
255 {
256  rlm_eap_tls_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_eap_tls_t);
257  CONF_SECTION *conf = mctx->inst->conf;
258 
259  inst->tls_conf = eap_tls_conf_parse(conf, "tls");
260  if (!inst->tls_conf) {
261  cf_log_err(conf, "Failed initializing SSL context");
262  return -1;
263  }
264 
265  if (inst->virtual_server && !virtual_server_find(inst->virtual_server)) {
266  cf_log_err_by_child(conf, "virtual_server", "Unknown virtual server '%s'", inst->virtual_server);
267  return -1;
268  }
269 
270  return 0;
271 }
272 
273 /*
274  * The module name should be the only globally exported symbol.
275  * That is, everything else should be 'static'.
276  */
279  .common = {
280  .magic = MODULE_MAGIC_INIT,
281  .name = "eap_tls",
282  .inst_size = sizeof(rlm_eap_tls_t),
284  .instantiate = mod_instantiate, /* Create new submodule instance */
285 
286  .thread_inst_size = sizeof(rlm_eap_tls_thread_t),
287  .thread_instantiate = mod_thread_instantiate,
288  .thread_detach = mod_thread_detach,
289  },
290  .provides = { FR_EAP_METHOD_TLS },
291  .session_init = mod_session_init, /* Initialise a new EAP session */
292 };
#define true
Definition: abinary.c:57
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
#define USES_APPLE_DEPRECATED_API
Definition: build.h:431
#define RCSID(id)
Definition: build.h:444
#define UNUSED
Definition: build.h:313
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:626
#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:268
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:265
#define cf_log_err_by_child(_parent, _child, _fmt,...)
Log an error message against a specified child.
Definition: cf_util.h:292
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:250
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:263
Specifies an attribute which must be present for the module to function.
Definition: dict.h:249
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:262
void *_CONST data
Module instance's parsed configuration.
Definition: dl_module.h:165
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:65
CONF_SECTION *_CONST conf
Module's instance configuration.
Definition: dl_module.h:166
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
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
static eap_session_t * eap_session_get(request_t *request)
Definition: session.h:82
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.
Definition: merged_model.c:99
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
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:52
void * thread
Thread instance data.
Definition: module_ctx.h:62
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:42
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:59
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:51
Temporary structure to hold arguments for thread_instantiation calls.
Definition: module_ctx.h:58
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:688
static const conf_parser_t config[]
Definition: base.c:188
#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
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:76
static unlang_action_t mod_handshake_process(UNUSED rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
Definition: rlm_eap_tls.c:166
static fr_dict_t const * dict_freeradius
Definition: rlm_eap_tls.c:54
static fr_dict_attr_t const * attr_eap_tls_require_client_cert
Definition: rlm_eap_tls.c:62
fr_dict_attr_autoload_t rlm_eap_tls_dict_attr[]
Definition: rlm_eap_tls.c:65
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:70
fr_dict_autoload_t rlm_eap_tls_dict[]
Definition: rlm_eap_tls.c:57
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Definition: rlm_eap_tls.c:230
static conf_parser_t submodule_config[]
Definition: rlm_eap_tls.c:45
rlm_eap_submodule_t rlm_eap_tls
Definition: rlm_eap_tls.c:278
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Definition: rlm_eap_tls.c:241
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_eap_tls.c:254
SSL_CTX * ssl_ctx
Thread local SSL_CTX.
Definition: rlm_eap_tls.c:42
static unlang_action_t mod_session_init(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_eap_tls.c:185
static int instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_rest.c:1312
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:575
RETURN_MODULE_FAIL
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:253
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:262
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:1125
int eap_tls_start(request_t *request, eap_session_t *eap_session)
Send an initial EAP-TLS request to the peer.
Definition: tls.c:237
int eap_tls_fail(request_t *request, eap_session_t *eap_session)
Send an EAP-TLS failure.
Definition: tls.c:320
USES_APPLE_DEPRECATED_API fr_table_num_ordered_t const eap_tls_status_table[]
Definition: tls.c:78
fr_tls_conf_t * eap_tls_conf_parse(CONF_SECTION *cs, char const *attr)
Parse TLS configuration.
Definition: tls.c:1210
unlang_action_t eap_tls_process(request_t *request, eap_session_t *eap_session)
Process an EAP TLS request.
Definition: tls.c:957
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
CONF_SECTION * virtual_server_find(char const *name)
Return virtual server matching the specified name.