The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_eap_ttls.c
Go to the documentation of this file.
1 /*
2  * This program is 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 (at
5  * 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: 38951a61642261902a8148b916367b648fe5fcf9 $
19  * @file rlm_eap_ttls.c
20  * @brief EAP-TTLS as defined by RFC 5281
21  *
22  * @copyright 2003 Alan DeKok (aland@freeradius.org)
23  * @copyright 2006 The FreeRADIUS server project
24  */
25 
26 RCSID("$Id: 38951a61642261902a8148b916367b648fe5fcf9 $")
27 USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
28 
29 #include <freeradius-devel/eap/tls.h>
30 #include "eap_ttls.h"
31 
32 typedef struct {
33  SSL_CTX *ssl_ctx; //!< Thread local SSL_CTX.
35 
36 typedef struct {
37  /*
38  * TLS configuration
39  */
40  char const *tls_conf_name;
41  fr_tls_conf_t *tls_conf;
42 
43  /*
44  * RFC 5281 (TTLS) says that the length field MUST NOT be
45  * in fragments after the first one. However, we've done
46  * it that way for years, and no one has complained.
47  *
48  * In the interests of allowing the server to follow the
49  * RFC, we add the option here. If set to "no", it sends
50  * the length field in ONLY the first fragment.
51  */
53 
54  /*
55  * Virtual server for inner tunnel session.
56  */
57  char const *virtual_server;
59 
60  /*
61  * Do we do require a client cert?
62  */
65 
66 
68  { FR_CONF_OFFSET("tls", rlm_eap_ttls_t, tls_conf_name) },
69  { FR_CONF_DEPRECATED("copy_request_to_tunnel", rlm_eap_ttls_t, NULL), .dflt = "no" },
70  { FR_CONF_DEPRECATED("use_tunneled_reply", rlm_eap_ttls_t, NULL), .dflt = "no" },
71  { FR_CONF_OFFSET_FLAGS("virtual_server", CONF_FLAG_REQUIRED | CONF_FLAG_NOT_EMPTY, rlm_eap_ttls_t, virtual_server) },
72  { FR_CONF_OFFSET("include_length", rlm_eap_ttls_t, include_length), .dflt = "yes" },
73  { FR_CONF_OFFSET("require_client_cert", rlm_eap_ttls_t, req_client_cert), .dflt = "no" },
75 };
76 
77 static fr_dict_t const *dict_freeradius;
78 static fr_dict_t const *dict_radius;
79 
82  { .out = &dict_freeradius, .proto = "freeradius" },
83  { .out = &dict_radius, .proto = "radius" },
84  { NULL }
85 };
86 
88 
98 
101  { .out = &attr_eap_tls_require_client_cert, .name = "EAP-TLS-Require-Client-Cert", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
102 
103  { .out = &attr_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
104  { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
105  { .out = &attr_ms_chap_challenge, .name = "Vendor-Specific.Microsoft.CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
106  { .out = &attr_ms_chap2_success, .name = "Vendor-Specific.Microsoft.CHAP2-Success", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
107  { .out = &attr_reply_message, .name = "Reply-Message", .type = FR_TYPE_STRING, .dict = &dict_radius },
108  { .out = &attr_eap_channel_binding_message, .name = "Vendor-Specific.UKERNA.EAP-Channel-Binding-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
109  { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
110  { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
111  { .out = &attr_vendor_specific, .name = "Vendor-Specific", .type = FR_TYPE_VSA, .dict = &dict_radius },
112  { NULL }
113 };
114 
115 /*
116  * Allocate the TTLS per-session data
117  */
118 static ttls_tunnel_t *ttls_alloc(TALLOC_CTX *ctx, rlm_eap_ttls_t *inst)
119 {
120  ttls_tunnel_t *t;
121 
122  t = talloc_zero(ctx, ttls_tunnel_t);
123  t->server_cs = inst->server_cs;
124 
125  return t;
126 }
127 
129 {
130  eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
131  eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
132  fr_tls_session_t *tls_session = eap_tls_session->tls_session;
133 
134  ttls_tunnel_t *tunnel = talloc_get_type_abort(tls_session->opaque, ttls_tunnel_t);
135 
136  if ((eap_tls_session->state == EAP_TLS_INVALID) || (eap_tls_session->state == EAP_TLS_FAIL)) {
137  REDEBUG("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
138  } else {
139  RDEBUG2("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
140  }
141 
142  switch (eap_tls_session->state) {
143  /*
144  * EAP-TLS handshake was successful, tell the
145  * client to keep talking.
146  *
147  * If this was EAP-TLS, we would just return
148  * an EAP-TLS-Success packet here.
149  */
150  case EAP_TLS_ESTABLISHED:
151  if (SSL_session_reused(tls_session->ssl)) {
152  RDEBUG2("Skipping Phase2 due to session resumption");
153  return eap_ttls_success(p_result, request, eap_session);
154  }
155 
156  if (tunnel && tunnel->authenticated) return eap_ttls_success(p_result, request, eap_session);
157 
158  eap_tls_request(request, eap_session);
160 
161  /*
162  * The TLS code is still working on the TLS
163  * exchange, and it's a valid TLS request.
164  * do nothing.
165  */
166  case EAP_TLS_HANDLED:
168 
169  /*
170  * Handshake is done, proceed with decoding tunneled
171  * data.
172  */
174  break;
175 
176  /*
177  * Anything else: fail.
178  */
179  default:
181  }
182 
183  /*
184  * Session is established, proceed with decoding
185  * tunneled data.
186  */
187  RDEBUG2("Session established. Decoding Diameter attributes");
188 
189  /*
190  * Process the TTLS portion of the request.
191  */
192  return eap_ttls_process(request, eap_session, tls_session);
193 }
194 
195 /*
196  * Do authentication, by letting EAP-TLS do most of the work.
197  */
199  request_t *request)
200 {
201  eap_session_t *eap_session = eap_session_get(request->parent);
202 
203  /*
204  * Setup the resumption frame to process the result
205  */
206  (void)unlang_module_yield(request, mod_handshake_resume, NULL, 0, eap_session);
207 
208  /*
209  * Process TLS layer until done.
210  */
211  return eap_tls_process(request, eap_session);
212 }
213 
214 /*
215  * Send an initial eap-tls request to the peer, using the libeap functions.
216  */
217 static unlang_action_t mod_session_init(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
218 {
219  rlm_eap_ttls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_ttls_t);
220  rlm_eap_ttls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_ttls_thread_t);
221  eap_session_t *eap_session = eap_session_get(request->parent);
222 
223  eap_tls_session_t *eap_tls_session;
224  fr_tls_session_t *tls_session;
225  fr_pair_t *vp;
226  bool client_cert;
227 
228  eap_session->tls = true;
229 
230  /*
231  * EAP-TLS-Require-Client-Cert attribute will override
232  * the require_client_cert configuration option.
233  */
234  vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_tls_require_client_cert);
235  if (vp) {
236  client_cert = vp->vp_uint32 ? true : false;
237  } else {
238  client_cert = inst->req_client_cert;
239  }
240 
241  eap_session->opaque = eap_tls_session = eap_tls_session_init(request, eap_session, t->ssl_ctx, client_cert);
242  if (!eap_tls_session) RETURN_MODULE_FAIL;
243  tls_session = eap_tls_session->tls_session;
244 
245  eap_tls_session->include_length = inst->include_length;
246 
247  /*
248  * TLS session initialization is over. Now handle TLS
249  * related handshaking or application data.
250  */
251  if (eap_tls_start(request, eap_session) < 0) {
252  talloc_free(eap_tls_session);
254  }
255 
256  tls_session->opaque = ttls_alloc(tls_session, inst);
257 
258  eap_session->process = mod_handshake_process;
259 
261 }
262 
264 {
265  rlm_eap_ttls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_ttls_t);
266  rlm_eap_ttls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_ttls_thread_t);
267 
268  t->ssl_ctx = fr_tls_ctx_alloc(inst->tls_conf, false);
269  if (!t->ssl_ctx) return -1;
270 
271  return 0;
272 }
273 
275 {
276  rlm_eap_ttls_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_ttls_thread_t);
277 
278  if (likely(t->ssl_ctx != NULL)) SSL_CTX_free(t->ssl_ctx);
279  t->ssl_ctx = NULL;
280 
281  return 0;
282 }
283 
284 /*
285  * Attach the module.
286  */
287 static int mod_instantiate(module_inst_ctx_t const *mctx)
288 {
289  rlm_eap_ttls_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_ttls_t);
290  CONF_SECTION *conf = mctx->mi->conf;
291  virtual_server_t const *virtual_server = virtual_server_find(inst->virtual_server);
292 
293  if (!virtual_server) {
294  cf_log_err_by_child(conf, "virtual_server", "Unknown virtual server '%s'", inst->virtual_server);
295  return -1;
296  }
297 
298  inst->server_cs = virtual_server_cs(virtual_server);
299  if (!inst->server_cs) {
300  cf_log_err_by_child(conf, "virtual_server", "Virtual server \"%s\" missing", inst->virtual_server);
301  return -1;
302  }
303 
304  /*
305  * Read tls configuration, either from group given by 'tls'
306  * option, or from the eap-tls configuration.
307  */
308  inst->tls_conf = eap_tls_conf_parse(conf, "tls");
309  if (!inst->tls_conf) {
310  cf_log_err(conf, "Failed initializing SSL context");
311  return -1;
312  }
313 
314  return 0;
315 }
316 
317 /*
318  * The module name should be the only globally exported symbol.
319  * That is, everything else should be 'static'.
320  */
323  .common = {
324  .magic = MODULE_MAGIC_INIT,
325  .name = "eap_ttls",
326 
327  .inst_size = sizeof(rlm_eap_ttls_t),
329  .instantiate = mod_instantiate, /* Create new submodule instance */
330 
331  .thread_inst_size = sizeof(rlm_eap_ttls_thread_t),
332  .thread_instantiate = mod_thread_instantiate,
333  .thread_detach = mod_thread_detach,
334  },
335  .provides = { FR_EAP_METHOD_TTLS },
336  .session_init = mod_session_init, /* Initialise a new EAP session */
337 };
#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:468
#define RCSID(id)
Definition: build.h:481
#define UNUSED
Definition: build.h:313
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
#define FR_CONF_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a matching CONF_PAIR is found
Definition: cf_parse.h:385
#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
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:256
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition: cf_parse.h:405
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition: cf_parse.h:420
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:564
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:101
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:289
#define cf_log_err_by_child(_parent, _child, _fmt,...)
Log an error message against a specified child.
Definition: cf_util.h:316
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:267
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:280
Specifies an attribute which must be present for the module to function.
Definition: dict.h:266
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:279
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
@ FR_EAP_METHOD_TTLS
Definition: types.h:66
Declarations for EAP-TTLS as defined by RFC 5281.
unlang_action_t eap_ttls_process(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
Definition: ttls.c:634
CONF_SECTION * server_cs
Definition: eap_ttls.h:46
bool authenticated
Definition: eap_ttls.h:45
unlang_action_t eap_ttls_success(rlm_rcode_t *p_result, request_t *request, eap_session_t *eap_session)
Definition: ttls.c:595
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_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
Definition: merged_model.c:121
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
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_OK
Definition: rcode.h:57
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
fr_dict_attr_t const * attr_user_password
Definition: rlm_eap_ttls.c:96
static unlang_action_t mod_handshake_resume(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_eap_ttls.c:128
char const * tls_conf_name
Definition: rlm_eap_ttls.c:40
bool req_client_cert
Definition: rlm_eap_ttls.c:63
fr_dict_attr_t const * attr_eap_message
Definition: rlm_eap_ttls.c:91
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_ttls.c:198
fr_dict_attr_t const * attr_eap_channel_binding_message
Definition: rlm_eap_ttls.c:94
static fr_dict_t const * dict_freeradius
Definition: rlm_eap_ttls.c:77
fr_dict_attr_t const * attr_eap_tls_require_client_cert
Definition: rlm_eap_ttls.c:87
SSL_CTX * ssl_ctx
Thread local SSL_CTX.
Definition: rlm_eap_ttls.c:33
fr_dict_attr_t const * attr_ms_chap2_success
Definition: rlm_eap_ttls.c:90
static fr_dict_t const * dict_radius
Definition: rlm_eap_ttls.c:78
fr_dict_attr_t const * attr_ms_chap_challenge
Definition: rlm_eap_ttls.c:92
fr_dict_attr_t const * attr_chap_challenge
Definition: rlm_eap_ttls.c:89
fr_dict_attr_t const * attr_vendor_specific
Definition: rlm_eap_ttls.c:97
fr_dict_attr_t const * attr_reply_message
Definition: rlm_eap_ttls.c:93
char const * virtual_server
Definition: rlm_eap_ttls.c:57
static ttls_tunnel_t * ttls_alloc(TALLOC_CTX *ctx, rlm_eap_ttls_t *inst)
Definition: rlm_eap_ttls.c:118
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Definition: rlm_eap_ttls.c:263
fr_tls_conf_t * tls_conf
Definition: rlm_eap_ttls.c:41
CONF_SECTION * server_cs
Definition: rlm_eap_ttls.c:58
fr_dict_attr_t const * attr_user_name
Definition: rlm_eap_ttls.c:95
static conf_parser_t submodule_config[]
Definition: rlm_eap_ttls.c:67
fr_dict_attr_autoload_t rlm_eap_ttls_dict_attr[]
Definition: rlm_eap_ttls.c:100
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Definition: rlm_eap_ttls.c:274
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_eap_ttls.c:287
fr_dict_autoload_t rlm_eap_ttls_dict[]
Definition: rlm_eap_ttls.c:81
rlm_eap_submodule_t rlm_eap_ttls
Definition: rlm_eap_ttls.c:322
static unlang_action_t mod_session_init(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_eap_ttls.c:217
static int instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_rest.c:1302
CONF_SECTION * conf
Module's instance configuration.
Definition: module.h:329
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
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:772
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_request(request_t *request, eap_session_t *eap_session)
Frames the OpenSSL data that needs to be sent to the client in an EAP-Request.
Definition: tls.c:372
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:1231
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
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.
virtual_server_t const * virtual_server_find(char const *name)
Return virtual server matching the specified name.