2 * rlm_eap_tls.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 2001 hereUare Communications, Inc. <raghud@hereuare.com>
21 * Copyright 2003 Alan DeKok <aland@freeradius.org>
22 * Copyright 2006 The FreeRADIUS server project
26 #include <freeradius-devel/ident.h>
29 #include <freeradius-devel/autoconf.h>
31 #ifdef HAVE_OPENSSL_RAND_H
32 #include <openssl/rand.h>
35 #ifdef HAVE_OPENSSL_EVP_H
36 #include <openssl/evp.h>
39 #include "rlm_eap_tls.h"
42 #ifdef HAVE_SYS_STAT_H
47 * Detach the EAP-TLS module.
49 static int eaptls_detach(void *arg)
51 rlm_eap_tls_t *inst = (rlm_eap_tls_t *) arg;
60 * Attach the EAP-TLS module.
62 static int eaptls_attach(CONF_SECTION *cs, void **instance)
67 * Parse the config file & get all the configured values
69 inst = rad_malloc(sizeof(*inst));
71 radlog(L_ERR, "rlm_eap_tls: out of memory");
74 memset(inst, 0, sizeof(*inst));
76 if (cf_section_parse(cs, inst, module_config) < 0) {
81 inst->tls_conf = eaptls_conf_parse(cs, "tls");
83 if (!inst->tls_conf) {
84 radlog(L_ERR, "rlm_eap_tls: Failed initializing SSL context");
96 * Send an initial eap-tls request to the peer, using the libeap functions.
98 static int eaptls_initiate(void *type_arg, EAP_HANDLER *handler)
103 REQUEST *request = handler->request;
108 handler->finished = FALSE;
111 * EAP-TLS always requires a client certificate.
113 ssn = eaptls_session(inst->tls_conf, handler, TRUE);
118 handler->opaque = ((void *)ssn);
119 handler->free_opaque = session_free;
122 * Set up type-specific information.
124 ssn->prf_label = "client EAP encryption";
127 * TLS session initialization is over. Now handle TLS
128 * related handshaking or application data.
130 status = eaptls_start(handler->eap_ds, ssn->peap_flag);
131 RDEBUG2("Start returned %d", status);
137 * The next stage to process the packet.
139 handler->stage = AUTHENTICATE;
145 * Do authentication, by letting EAP-TLS do most of the work.
147 static int eaptls_authenticate(void *type_arg, EAP_HANDLER *handler)
149 fr_tls_status_t status;
150 tls_session_t *tls_session = (tls_session_t *) handler->opaque;
151 REQUEST *request = handler->request;
156 RDEBUG2("Authenticate");
158 status = eaptls_process(handler);
159 RDEBUG2("eaptls_process returned %d\n", status);
162 * EAP-TLS handshake was successful, return an
163 * EAP-TLS-Success packet here.
165 * If a virtual server was configured, check that
166 * it accepts the certificates, too.
169 if (inst->virtual_server) {
173 /* create a fake request */
174 fake = request_alloc_fake(request);
175 rad_assert(fake->packet->vps == NULL);
177 fake->packet->vps = paircopy(request->packet->vps);
179 /* set the virtual server to use */
180 if ((vp = pairfind(request->config_items,
181 PW_VIRTUAL_SERVER, 0)) != NULL) {
182 fake->server = vp->vp_strvalue;
184 fake->server = inst->virtual_server;
187 RDEBUG("Processing EAP-TLS Certificate check:");
188 debug_pair_list(fake->packet->vps);
190 RDEBUG("server %s {", fake->server);
192 rad_authenticate(fake);
194 RDEBUG("} # server %s", fake->server);
196 /* copy the reply vps back to our reply */
197 pairadd(&request->reply->vps, fake->reply->vps);
198 fake->reply->vps = NULL;
200 /* reject if virtual server didn't return accept */
201 if (fake->reply->code != PW_AUTHENTICATION_ACK) {
202 RDEBUG2("Certifictes were rejected by the virtual server");
204 eaptls_fail(handler, 0);
214 * The TLS code is still working on the TLS
215 * exchange, and it's a valid TLS request.
222 * Handshake is done, proceed with decoding tunneled
226 RDEBUG2("Received unexpected tunneled data after successful handshake.");
228 if ((debug_flag > 2) && fr_log_fp) {
230 unsigned int data_len;
231 unsigned char buffer[1024];
233 data_len = (tls_session->record_minus)(&tls_session->dirty_in,
234 buffer, sizeof(buffer));
235 log_debug(" Tunneled data (%u bytes)\n", data_len);
236 for (i = 0; i < data_len; i++) {
237 if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, " %x: ", i);
238 if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
240 fprintf(fr_log_fp, "%02x ", buffer[i]);
242 fprintf(fr_log_fp, "\n");
246 eaptls_fail(handler, 0);
251 * Anything else: fail.
253 * Also, remove the session from the cache so that
254 * the client can't re-use it.
257 tls_fail(tls_session);
263 * Success: Automatically return MPPE keys.
265 return eaptls_success(handler, 0);
269 * The module name should be the only globally exported symbol.
270 * That is, everything else should be 'static'.
272 EAP_TYPE rlm_eap_tls = {
274 eaptls_attach, /* attach */
275 eaptls_initiate, /* Start the initial request */
276 NULL, /* authorization */
277 eaptls_authenticate, /* authentication */
278 eaptls_detach /* detach */