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_md5 | |
parent | Initial commit. (diff) | |
download | freeradius-b95e0cd7685e6bbc2465b1f4efe1884df2f4ef01.tar.xz freeradius-b95e0cd7685e6bbc2465b1f4efe1884df2f4ef01.zip |
Adding upstream version 3.2.3+dfsg.upstream/3.2.3+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/modules/rlm_eap/types/rlm_eap_md5/README.md | 12 | ||||
-rw-r--r-- | src/modules/rlm_eap/types/rlm_eap_md5/all.mk | 12 | ||||
-rw-r--r-- | src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.c | 229 | ||||
-rw-r--r-- | src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.h | 52 | ||||
-rw-r--r-- | src/modules/rlm_eap/types/rlm_eap_md5/rlm_eap_md5.c | 168 |
5 files changed, 473 insertions, 0 deletions
diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/README.md b/src/modules/rlm_eap/types/rlm_eap_md5/README.md new file mode 100644 index 0000000..dba25cc --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_md5/README.md @@ -0,0 +1,12 @@ +# rlm_eap_md5 +## Metadata +<dl> + <dt>category</dt><dd>authentication</dd> +</dl> + +## Summary +Implements [RFC 3748](https://tools.ietf.org/html/rfc3748) EAP-MD5 authentication. EAP-MD5 allows EAP authentication +using a plaintext password. + +Does not provide keying material for 802.11i, so cannot be used for WPA/2-Enterprise authentication unless wrapped +in another method such as EAP-TTLS. diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/all.mk b/src/modules/rlm_eap/types/rlm_eap_md5/all.mk new file mode 100644 index 0000000..528ee82 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_md5/all.mk @@ -0,0 +1,12 @@ +TARGETNAME := rlm_eap_md5 + +ifneq "$(TARGETNAME)" "" +TARGET := $(TARGETNAME).a +endif + +SOURCES := $(TARGETNAME).c eap_md5.c + +SRC_CFLAGS := +TGT_LDLIBS := +SRC_INCDIRS := ../../ ../../libeap/ +TGT_PREREQS := libfreeradius-eap.a diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.c b/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.c new file mode 100644 index 0000000..e8acb5c --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.c @@ -0,0 +1,229 @@ +/* + * eap_md5.c EAP MD5 functionality. + * + * 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 2000,2001,2006 The FreeRADIUS server project + * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> + */ + +/* + * + * MD5 Packet Format in EAP Type-Data + * --- ------ ------ -- --- --------- + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Value-Size | Value ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Name ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +RCSID("$Id$") + +#include <stdio.h> +#include <stdlib.h> +#include "eap.h" + +#include "eap_md5.h" +#include <freeradius-devel/md5.h> + +/* + * We expect only RESPONSE for which SUCCESS or FAILURE is sent back + */ +MD5_PACKET *eapmd5_extract(EAP_DS *eap_ds) +{ + md5_packet_t *data; + MD5_PACKET *packet; + unsigned short name_len; + + /* + * We need a response, of type EAP-MD5, with at least + * one byte of type data (EAP-MD5) following the 4-byte + * EAP-Packet header. + */ + if (!eap_ds || + !eap_ds->response || + (eap_ds->response->code != PW_MD5_RESPONSE) || + eap_ds->response->type.num != PW_EAP_MD5 || + !eap_ds->response->type.data || + (eap_ds->response->length <= MD5_HEADER_LEN) || + (eap_ds->response->type.data[0] <= 0)) { + ERROR("rlm_eap_md5: corrupted data"); + return NULL; + } + + packet = talloc_zero(eap_ds, MD5_PACKET); + if (!packet) return NULL; + + /* + * Code & id for MD5 & EAP are same + * + * but md5_length = length of the EAP-MD5 data, which + * doesn't include the EAP header, or the octet saying + * EAP-MD5. + */ + packet->code = eap_ds->response->code; + packet->id = eap_ds->response->id; + packet->length = eap_ds->response->length - (MD5_HEADER_LEN + 1); + + /* + * Sanity check the EAP-MD5 packet sent to us + * by the client. + */ + data = (md5_packet_t *)eap_ds->response->type.data; + + /* + * Already checked the size above. + */ + packet->value_size = data->value_size; + + /* + * Allocate room for the data, and copy over the data. + */ + packet->value = talloc_array(packet, uint8_t, packet->value_size); + if (!packet->value) { + talloc_free(packet); + return NULL; + } + memcpy(packet->value, data->value_name, packet->value_size); + + /* + * Name is optional and is present after Value, but we + * need to check for it, as eapmd5_compose() + */ + name_len = packet->length - (packet->value_size + 1); + if (name_len) { + packet->name = talloc_array(packet, char, name_len + 1); + if (!packet->name) { + talloc_free(packet); + return NULL; + } + memcpy(packet->name, data->value_name + packet->value_size, + name_len); + packet->name[name_len] = 0; + } + + return packet; +} + + +/* + * verify = MD5(id+password+challenge_sent) + */ +int eapmd5_verify(MD5_PACKET *packet, VALUE_PAIR* password, + uint8_t *challenge) +{ + char *ptr; + char string[1 + MAX_STRING_LEN*2]; + uint8_t digest[16]; + unsigned short len; + + /* + * Sanity check it. + */ + if (packet->value_size != 16) { + ERROR("rlm_eap_md5: Expected 16 bytes of response to challenge, got %d", packet->value_size); + return 0; + } + + len = 0; + ptr = string; + + /* + * This is really rad_chap_pwencode()... + */ + *ptr++ = packet->id; + len++; + memcpy(ptr, password->vp_strvalue, password->vp_length); + ptr += password->vp_length; + len += password->vp_length; + + /* + * The challenge size is hard-coded. + */ + memcpy(ptr, challenge, MD5_CHALLENGE_LEN); + len += MD5_CHALLENGE_LEN; + + fr_md5_calc(digest, (u_char *)string, len); + + /* + * The length of the response is always 16 for MD5. + */ + if (rad_digest_cmp(digest, packet->value, 16) != 0) { + DEBUG("EAP-MD5 digests do not match."); + return 0; + } + + return 1; +} + +/* + * Compose the portions of the reply packet specific to the + * EAP-MD5 protocol, in the EAP reply typedata + */ +int eapmd5_compose(EAP_DS *eap_ds, MD5_PACKET *reply) +{ + uint8_t *ptr; + unsigned short name_len; + + /* + * We really only send Challenge (EAP-Identity), + * and EAP-Success, and EAP-Failure. + */ + if (reply->code < 3) { + eap_ds->request->type.num = PW_EAP_MD5; + + rad_assert(reply->length > 0); + + eap_ds->request->type.data = talloc_array(eap_ds->request, + uint8_t, + reply->length); + if (!eap_ds->request->type.data) { + talloc_free(reply); + return 0; + } + ptr = eap_ds->request->type.data; + *ptr++ = (uint8_t)(reply->value_size & 0xFF); + memcpy(ptr, reply->value, reply->value_size); + + /* Just the Challenge length */ + eap_ds->request->type.length = reply->value_size + 1; + + /* + * Return the name, if necessary. + * + * Don't see why this is *ever* necessary... + */ + name_len = reply->length - (reply->value_size + 1); + if (name_len && reply->name) { + ptr += reply->value_size; + memcpy(ptr, reply->name, name_len); + /* Challenge length + Name length */ + eap_ds->request->type.length += name_len; + } + } else { + eap_ds->request->type.length = 0; + /* TODO: In future we might add message here wrt rfc1994 */ + } + eap_ds->request->code = reply->code; + talloc_free(reply); + + return 1; +} diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.h b/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.h new file mode 100644 index 0000000..aafa407 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.h @@ -0,0 +1,52 @@ +#ifndef _EAP_MD5_H +#define _EAP_MD5_H + +RCSIDH(eap_md5_h, "$Id$") + +#include "eap.h" + +#define PW_MD5_CHALLENGE 1 +#define PW_MD5_RESPONSE 2 +#define PW_MD5_SUCCESS 3 +#define PW_MD5_FAILURE 4 +#define PW_MD5_MAX_CODES 4 + +#define MD5_HEADER_LEN 4 +#define MD5_CHALLENGE_LEN 16 + +/* + **** + * EAP - MD5 does not specify code, id & length but chap specifies them, + * for generalization purpose, complete header should be sent + * and not just value_size, value and name. + * future implementation. + * + * Huh? What does that mean? + */ + +/* eap packet structure */ +typedef struct md5_packet_t { +/* + uint8_t code; + uint8_t id; + uint16_t length; +*/ + uint8_t value_size; + uint8_t value_name[1]; +} md5_packet_t; + +typedef struct md5_packet { + unsigned char code; + unsigned char id; + unsigned short length; + unsigned char value_size; + unsigned char *value; + char *name; +} MD5_PACKET; + +/* function declarations here */ + +int eapmd5_compose(EAP_DS *auth, MD5_PACKET *reply); +MD5_PACKET *eapmd5_extract(EAP_DS *auth); +int eapmd5_verify(MD5_PACKET *pkt, VALUE_PAIR* pwd, uint8_t *ch); +#endif /*_EAP_MD5_H*/ diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/rlm_eap_md5.c b/src/modules/rlm_eap/types/rlm_eap_md5/rlm_eap_md5.c new file mode 100644 index 0000000..2fa0077 --- /dev/null +++ b/src/modules/rlm_eap/types/rlm_eap_md5/rlm_eap_md5.c @@ -0,0 +1,168 @@ +/* + * rlm_eap_md5.c Handles 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 2000,2001,2006 The FreeRADIUS server project + * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> + */ + +RCSID("$Id$") + +#include <stdio.h> +#include <stdlib.h> + +#include "eap_md5.h" + +#include <freeradius-devel/rad_assert.h> +#include <freeradius-devel/md5.h> + +/* + * Initiate the EAP-MD5 session by sending a challenge to the peer. + */ +static int mod_session_init(UNUSED void *instance, eap_handler_t *handler) +{ + int i; + MD5_PACKET *reply; + REQUEST *request = handler->request; + + /* + * Allocate an EAP-MD5 packet. + */ + reply = talloc(handler, MD5_PACKET); + if (!reply) { + return 0; + } + + /* + * Fill it with data. + */ + reply->code = PW_MD5_CHALLENGE; + reply->length = 1 + MD5_CHALLENGE_LEN; /* one byte of value size */ + reply->value_size = MD5_CHALLENGE_LEN; + + /* + * Allocate user data. + */ + reply->value = talloc_array(reply, uint8_t, reply->value_size); + if (!reply->value) { + talloc_free(reply); + return 0; + } + + /* + * Get a random challenge. + */ + for (i = 0; i < reply->value_size; i++) { + reply->value[i] = fr_rand(); + } + RDEBUG2("Issuing MD5 Challenge"); + + /* + * Keep track of the challenge. + */ + handler->opaque = talloc_array(handler, uint8_t, reply->value_size); + rad_assert(handler->opaque != NULL); + memcpy(handler->opaque, reply->value, reply->value_size); + handler->free_opaque = NULL; + + /* + * Compose the EAP-MD5 packet out of the data structure, + * and free it. + */ + eapmd5_compose(handler->eap_ds, reply); + + /* + * We don't need to authorize the user at this point. + * + * We also don't need to keep the challenge, as it's + * stored in 'handler->eap_ds', which will be given back + * to us... + */ + handler->stage = PROCESS; + + return 1; +} + +/* + * Authenticate a previously sent challenge. + */ +static int mod_process(UNUSED void *arg, eap_handler_t *handler) +{ + MD5_PACKET *packet; + MD5_PACKET *reply; + VALUE_PAIR *password; + REQUEST *request = handler->request; + + /* + * Get the Cleartext-Password for this user. + */ + rad_assert(handler->request != NULL); + rad_assert(handler->stage == PROCESS); + + password = fr_pair_find_by_num(handler->request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY); + if (!password) { + REDEBUG2("Cleartext-Password is required for EAP-MD5 authentication"); + return 0; + } + + /* + * Extract the EAP-MD5 packet. + */ + if (!(packet = eapmd5_extract(handler->eap_ds))) + return 0; + + /* + * Create a reply, and initialize it. + */ + reply = talloc(packet, MD5_PACKET); + if (!reply) { + talloc_free(packet); + return 0; + } + reply->id = handler->eap_ds->request->id; + reply->length = 0; + + /* + * Verify the received packet against the previous packet + * (i.e. challenge) which we sent out. + */ + if (eapmd5_verify(packet, password, handler->opaque)) { + reply->code = PW_MD5_SUCCESS; + } else { + reply->code = PW_MD5_FAILURE; + } + + /* + * Compose the EAP-MD5 packet out of the data structure, + * and free it. + */ + eapmd5_compose(handler->eap_ds, reply); + talloc_free(packet); + return 1; +} + +/* + * The module name should be the only globally exported symbol. + * That is, everything else should be 'static'. + */ +extern rlm_eap_module_t rlm_eap_md5; +rlm_eap_module_t rlm_eap_md5 = { + .name = "eap_md5", + .session_init = mod_session_init, /* Initialise a new EAP session */ + .process = mod_process /* Process next round of EAP method */ +}; |