2 * rlm_eap_ttls.c contains the interfaces that are called from eap
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.
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.
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
20 * Copyright 2003 Alan DeKok <aland@freeradius.org>
21 * Copyright 2006 The FreeRADIUS server project
25 USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
29 typedef struct rlm_eap_ttls_t {
33 char const *tls_conf_name;
34 fr_tls_server_conf_t *tls_conf;
37 * Default tunneled EAP type
39 char const *default_method_name;
43 * Use the reply attributes from the tunneled session in
44 * the non-tunneled reply to the client.
46 bool use_tunneled_reply;
49 * Use SOME of the request attributes from outside of the
50 * tunneled session in the tunneled request
52 bool copy_request_to_tunnel;
55 * RFC 5281 (TTLS) says that the length field MUST NOT be
56 * in fragments after the first one. However, we've done
57 * it that way for years, and no one has complained.
59 * In the interests of allowing the server to follow the
60 * RFC, we add the option here. If set to "no", it sends
61 * the length field in ONLY the first fragment.
66 * Virtual server for inner tunnel session.
68 char const *virtual_server;
71 * Do we do require a client cert?
77 static CONF_PARSER module_config[] = {
78 { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, tls_conf_name), NULL },
79 { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, default_method_name), "md5" },
80 { "copy_request_to_tunnel", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, copy_request_to_tunnel), "no" },
81 { "use_tunneled_reply", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, use_tunneled_reply), "no" },
82 { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, virtual_server), NULL },
83 { "include_length", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, include_length), "yes" },
84 { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, req_client_cert), "no" },
86 { NULL, -1, 0, NULL, NULL } /* end the list */
93 static int eapttls_attach(CONF_SECTION *cs, void **instance)
97 *instance = inst = talloc_zero(cs, rlm_eap_ttls_t);
101 * Parse the configuration attributes.
103 if (cf_section_parse(cs, inst, module_config) < 0) {
108 * Convert the name to an integer, to make it easier to
111 inst->default_method = eap_name2type(inst->default_method_name);
112 if (inst->default_method < 0) {
113 ERROR("rlm_eap_ttls: Unknown EAP type %s",
114 inst->default_method_name);
119 * Read tls configuration, either from group given by 'tls'
120 * option, or from the eap-tls configuration.
122 inst->tls_conf = eaptls_conf_parse(cs, "tls");
124 if (!inst->tls_conf) {
125 ERROR("rlm_eap_ttls: Failed initializing SSL context");
134 * Free the TTLS per-session data
136 static void ttls_free(void *p)
138 ttls_tunnel_t *t = (ttls_tunnel_t *) p;
142 rad_assert(talloc_get_type_abort(t, ttls_tunnel_t) != NULL);
145 DEBUG2("rlm_eap_ttls: Freeing handler for user %s",
146 t->username->vp_strvalue);
149 pairfree(&t->username);
151 pairfree(&t->accept_vps);
157 * Allocate the TTLS per-session data
159 static ttls_tunnel_t *ttls_alloc(rlm_eap_ttls_t *inst, eap_handler_t *handler)
163 t = talloc_zero(handler, ttls_tunnel_t);
165 t->default_method = inst->default_method;
166 t->copy_request_to_tunnel = inst->copy_request_to_tunnel;
167 t->use_tunneled_reply = inst->use_tunneled_reply;
168 t->virtual_server = inst->virtual_server;
174 * Send an initial eap-tls request to the peer, using the libeap functions.
176 static int eapttls_initiate(void *type_arg, eap_handler_t *handler)
180 rlm_eap_ttls_t *inst;
183 REQUEST *request = handler->request;
188 handler->finished = false;
191 * Check if we need a client certificate.
195 * EAP-TLS-Require-Client-Cert attribute will override
196 * the require_client_cert configuration option.
198 vp = pairfind(handler->request->config_items, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
200 client_cert = vp->vp_integer ? true : false;
202 client_cert = inst->req_client_cert;
205 ssn = eaptls_session(handler, inst->tls_conf, client_cert);
210 handler->opaque = ((void *)ssn);
213 * Set up type-specific information.
215 ssn->prf_label = "ttls keying material";
218 * TLS session initialization is over. Now handle TLS
219 * related handshaking or application data.
221 status = eaptls_start(handler->eap_ds, ssn->peap_flag);
222 RDEBUG2("Start returned %d", status);
228 * The next stage to process the packet.
230 handler->stage = AUTHENTICATE;
237 * Do authentication, by letting EAP-TLS do most of the work.
239 static int mod_authenticate(void *arg, eap_handler_t *handler)
242 fr_tls_status_t status;
243 rlm_eap_ttls_t *inst = (rlm_eap_ttls_t *) arg;
244 tls_session_t *tls_session = (tls_session_t *) handler->opaque;
245 ttls_tunnel_t *t = (ttls_tunnel_t *) tls_session->opaque;
246 REQUEST *request = handler->request;
248 RDEBUG2("Authenticate");
250 tls_session->length_flag = inst->include_length;
253 * Process TLS layer until done.
255 status = eaptls_process(handler);
256 RDEBUG2("eaptls_process returned %d\n", status);
259 * EAP-TLS handshake was successful, tell the
260 * client to keep talking.
262 * If this was EAP-TLS, we would just return
263 * an EAP-TLS-Success packet here.
266 if (SSL_session_reused(tls_session->ssl)) {
267 RDEBUG("Skipping Phase2 due to session resumption");
271 if (t && t->authenticated) {
272 RDEBUG2("Using saved attributes from the original Access-Accept");
273 debug_pair_list(t->accept_vps);
274 pairfilter(handler->request->reply,
275 &handler->request->reply->vps,
276 &t->accept_vps, 0, 0, TAG_ANY);
279 * Success: Automatically return MPPE keys.
281 return eaptls_success(handler, 0);
283 eaptls_request(handler->eap_ds, tls_session);
288 * The TLS code is still working on the TLS
289 * exchange, and it's a valid TLS request.
296 * Handshake is done, proceed with decoding tunneled
303 * Anything else: fail.
310 * Session is established, proceed with decoding
313 RDEBUG2("Session established. Proceeding to decode tunneled attributes");
316 * We may need TTLS data associated with the session, so
317 * allocate it here, if it wasn't already alloacted.
319 if (!tls_session->opaque) {
320 tls_session->opaque = ttls_alloc(inst, handler);
321 tls_session->free_opaque = ttls_free;
325 * Process the TTLS portion of the request.
327 rcode = eapttls_process(handler, tls_session);
329 case PW_CODE_ACCESS_REJECT:
330 eaptls_fail(handler, 0);
334 * Access-Challenge, continue tunneled conversation.
336 case PW_CODE_ACCESS_CHALLENGE:
337 eaptls_request(handler->eap_ds, tls_session);
341 * Success: Automatically return MPPE keys.
343 case PW_CODE_ACCESS_ACCEPT:
344 return eaptls_success(handler, 0);
347 * No response packet, MUST be proxying it.
348 * The main EAP module will take care of discovering
349 * that the request now has a "proxy" packet, and
350 * will proxy it, rather than returning an EAP packet.
352 case PW_CODE_STATUS_CLIENT:
354 rad_assert(handler->request->proxy != NULL);
364 * Something we don't understand: Reject it.
366 eaptls_fail(handler, 0);
371 * The module name should be the only globally exported symbol.
372 * That is, everything else should be 'static'.
374 rlm_eap_module_t rlm_eap_ttls = {
376 eapttls_attach, /* attach */
377 eapttls_initiate, /* Start the initial request */
378 NULL, /* authorization */
379 mod_authenticate, /* authentication */