diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 14:11:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 14:11:00 +0000 |
commit | af754e596a8dbb05ed8580c342e7fe02e08b28e0 (patch) | |
tree | b2f334c2b55ede42081aa6710a72da784547d8ea /src/modules/rlm_eap/types/rlm_eap_tls | |
parent | Initial commit. (diff) | |
download | freeradius-af754e596a8dbb05ed8580c342e7fe02e08b28e0.tar.xz freeradius-af754e596a8dbb05ed8580c342e7fe02e08b28e0.zip |
Adding upstream version 3.2.3+dfsg.upstream/3.2.3+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/modules/rlm_eap/types/rlm_eap_tls')
-rw-r--r-- | src/modules/rlm_eap/types/rlm_eap_tls/README.md | 9 | ||||
-rw-r--r-- | src/modules/rlm_eap/types/rlm_eap_tls/all.mk | 10 | ||||
-rw-r--r-- | src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c | 303 | ||||
-rw-r--r-- | src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h | 52 |
4 files changed, 374 insertions, 0 deletions
diff --git a/src/modules/rlm_eap/types/rlm_eap_tls/README.md b/src/modules/rlm_eap/types/rlm_eap_tls/README.md new file mode 100644 index 0000000..afb80f2 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_tls/README.md @@ -0,0 +1,9 @@ +# rlm_eap_tls +## Metadata +<dl> + <dt>category</dt><dd>authentication</dd> +</dl> + +## Summary +Implements [RFC 5216](https://tools.ietf.org/html/rfc5216) EAP-TLS authentication. EAP-TLS provides mutual +authentication and session keying material for 802.11i (WPA/2 Enterprise) using certificates. diff --git a/src/modules/rlm_eap/types/rlm_eap_tls/all.mk b/src/modules/rlm_eap/types/rlm_eap_tls/all.mk new file mode 100644 index 0000000..fdb7c4b --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_tls/all.mk @@ -0,0 +1,10 @@ +TARGETNAME := rlm_eap_tls + +ifneq "$(OPENSSL_LIBS)" "" +TARGET := $(TARGETNAME).a +endif + +SOURCES := $(TARGETNAME).c + +SRC_INCDIRS := ../../ ../../libeap/ +TGT_PREREQS := libfreeradius-eap.a diff --git a/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c new file mode 100644 index 0000000..d327c57 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c @@ -0,0 +1,303 @@ +/* + * rlm_eap_tls.c contains the interfaces that are called from eap + * + * Version: $Id$ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> + * Copyright 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2006 The FreeRADIUS server project + * + */ + +RCSID("$Id$") +USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ + +#ifdef HAVE_OPENSSL_RAND_H +#include <openssl/rand.h> +#endif + +#ifdef HAVE_OPENSSL_EVP_H +#include <openssl/evp.h> +#endif + +#include "rlm_eap_tls.h" + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +static CONF_PARSER module_config[] = { + { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_tls_t, tls_conf_name), NULL }, + { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_tls_t, virtual_server), NULL }, + { "configurable_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_tls_t, configurable_client_cert), NULL }, + CONF_PARSER_TERMINATOR +}; + + +/* + * Attach the EAP-TLS module. + */ +static int mod_instantiate(CONF_SECTION *cs, void **instance) +{ + rlm_eap_tls_t *inst; + + /* + * Parse the config file & get all the configured values + */ + *instance = inst = talloc_zero(cs, rlm_eap_tls_t); + if (!inst) return -1; + + if (cf_section_parse(cs, inst, module_config) < 0) { + return -1; + } + + inst->tls_conf = eaptls_conf_parse(cs, "tls"); + + if (!inst->tls_conf) { + ERROR("rlm_eap_tls: Failed initializing SSL context"); + return -1; + } + +#ifdef TLS1_3_VERSION + if ((inst->tls_conf->max_version == TLS1_3_VERSION) || + (inst->tls_conf->min_version == TLS1_3_VERSION)) { + WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + WARN("!! Most supplicants do not support EAP-TLS with TLS 1.3"); + WARN("!! Please set tls_max_version = \"1.2\""); + WARN("!! FreeRADIUS only supports TLS 1.3 for special builds of wpa_supplicant and Windows"); + WARN("!! This limitation is likely to change in late 2021."); + WARN("!! If you are using this version of FreeRADIUS after 2021, you will probably need to upgrade"); + WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } +#endif + + return 0; +} + + +/* + * Send an initial eap-tls request to the peer, using the libeap functions. + */ +static int mod_session_init(void *type_arg, eap_handler_t *handler) +{ + int status; + tls_session_t *ssn; + rlm_eap_tls_t *inst; + REQUEST *request = handler->request; + bool require_client_cert = true; + + inst = type_arg; + + handler->tls = true; + + /* + * Respect EAP-TLS-Require-Client-Cert, but only if + * enabled in the module configuration. + * + * We can't change behavior of existing systems, so this + * change has to be enabled via a new configuration + * option. + */ + if (inst->configurable_client_cert) { + VALUE_PAIR *vp; + + vp = fr_pair_find_by_num(handler->request->config, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY); + if (vp && !vp->vp_integer) require_client_cert = false; + } + + /* + * EAP-TLS always requires a client certificate, and + * allows for TLS 1.3 if permitted. + */ + ssn = eaptls_session(handler, inst->tls_conf, require_client_cert, true); + if (!ssn) { + return 0; + } + + handler->opaque = ((void *)ssn); + ssn->quick_session_tickets = true; /* send as soon as we've seen the client cert */ + + /* + * TLS session initialization is over. Now handle TLS + * related handshaking or application data. + */ + status = eaptls_start(handler->eap_ds, ssn->peap_flag); + if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) { + REDEBUG("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } else { + RDEBUG3("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } + if (status == 0) return 0; + + /* + * The next stage to process the packet. + */ + handler->stage = PROCESS; + + return 1; +} + +/* + * Do authentication, by letting EAP-TLS do most of the work. + */ +static int CC_HINT(nonnull) mod_process(void *type_arg, eap_handler_t *handler) +{ + fr_tls_status_t status; + int ret; + tls_session_t *tls_session = (tls_session_t *) handler->opaque; + REQUEST *request = handler->request; + rlm_eap_tls_t *inst; + + inst = type_arg; + + status = eaptls_process(handler); + if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) { + REDEBUG("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } else { + RDEBUG3("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>")); + } + + + /* + * Make request available to any SSL callbacks + */ + SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request); + switch (status) { + /* + * EAP-TLS handshake was successful, return an + * EAP-TLS-Success packet here. + * + * If a virtual server was configured, check that + * it accepts the certificates, too. + */ + case FR_TLS_SUCCESS: + if (inst->virtual_server) { + VALUE_PAIR *vp; + REQUEST *fake; + + /* create a fake request */ + fake = request_alloc_fake(request); + rad_assert(!fake->packet->vps); + + fake->packet->vps = fr_pair_list_copy(fake->packet, request->packet->vps); + + /* set the virtual server to use */ + if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) { + fake->server = vp->vp_strvalue; + } else { + fake->server = inst->virtual_server; + } + + RDEBUG2("Validating certificate"); + rad_virtual_server(fake); + + /* copy the reply vps back to our reply */ + fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps, + &fake->reply->vps, 0, 0, TAG_ANY); + + /* reject if virtual server didn't return accept */ + if (fake->reply->code != PW_CODE_ACCESS_ACCEPT) { + RDEBUG2("Certificate rejected by the virtual server"); + talloc_free(fake); + eaptls_fail(handler, 0); + ret = 0; + goto done; + } + + talloc_free(fake); + /* success */ + } + + /* + * Set the label to a fixed string. For TLS 1.3, + * the label is the same for all TLS-based EAP + * methods. + */ + tls_session->label = "client EAP encryption"; + + /* + * Success: Automatically return MPPE keys. + */ + ret = eaptls_success(handler, 0); + break; + + /* + * The TLS code is still working on the TLS + * exchange, and it's a valid TLS request. + * do nothing. + */ + case FR_TLS_HANDLED: + ret = 1; + break; + + /* + * Handshake is done, proceed with decoding tunneled + * data. + */ + case FR_TLS_OK: + RDEBUG2("Received unexpected tunneled data after successful handshake"); +#ifndef NDEBUG + if ((rad_debug_lvl > 2) && fr_log_fp) { + unsigned int i; + unsigned int data_len; + unsigned char buffer[1024]; + + data_len = (tls_session->record_minus)(&tls_session->dirty_in, + buffer, sizeof(buffer)); + DEBUG(" Tunneled data (%u bytes)", data_len); + for (i = 0; i < data_len; i++) { + if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, " %x: ", i); + if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n"); + + fprintf(fr_log_fp, "%02x ", buffer[i]); + } + fprintf(fr_log_fp, "\n"); + } +#endif + + eaptls_fail(handler, 0); + ret = 0; + break; + + /* + * Anything else: fail. + * + * Also, remove the session from the cache so that + * the client can't re-use it. + */ + default: + tls_fail(tls_session); + ret = 0; + } + +done: + SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL); + + return ret; +} + +/* + * The module name should be the only globally exported symbol. + * That is, everything else should be 'static'. + */ +extern rlm_eap_module_t rlm_eap_tls; +rlm_eap_module_t rlm_eap_tls = { + .name = "eap_tls", + .instantiate = mod_instantiate, /* Create new submodule instance */ + .session_init = mod_session_init, /* Initialise a new EAP session */ + .process = mod_process /* Process next round of EAP method */ +}; diff --git a/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h new file mode 100644 index 0000000..550cbbd --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h @@ -0,0 +1,52 @@ +/* + * rlm_eap_tls.h + * + * Version: $Id$ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> + * Copyright 2003 Alan DeKok <aland@freeradius.org> + * Copyright 2006 The FreeRADIUS server project + */ +#ifndef _RLM_EAP_TLS_H +#define _RLM_EAP_TLS_H + +RCSIDH(rlm_eap_tls_h, "$Id$") + +#include <freeradius-devel/radiusd.h> +#include <freeradius-devel/modules.h> + +#include "eap_tls.h" + +typedef struct rlm_eap_tls_t { + /* + * TLS configuration + */ + char const *tls_conf_name; + fr_tls_server_conf_t *tls_conf; + + /* + * Virtual server for checking certificates + */ + char const *virtual_server; + + /* + * Configurable EAP-TLS-Require-Client-Cert + */ + bool configurable_client_cert; +} rlm_eap_tls_t; + +#endif /* _RLM_EAP_TLS_H */ |