From: Martin Willi Date: Wed, 12 Dec 2007 14:29:10 +0000 (-0000) Subject: merged EAP-MD5 into trunk X-Git-Tag: 4.1.10~20 X-Git-Url: https://git.strongswan.org/?p=strongswan.git;a=commitdiff_plain;h=4b403e7672a152c547492b6986bb2e52f10af9ec merged EAP-MD5 into trunk --- diff --git a/configure.in b/configure.in index 9de9386..308d6c6 100644 --- a/configure.in +++ b/configure.in @@ -244,6 +244,15 @@ AC_ARG_ENABLE( AM_CONDITIONAL(USE_EAP_IDENTITY, test x$eap_identity = xtrue) AC_ARG_ENABLE( + [eap-md5], + AS_HELP_STRING([--enable-eap-md5],[build MD5 (CHAP) authenication module for EAP (default is NO).]), + [if test x$enableval = xyes; then + eap_md5=true + fi] +) +AM_CONDITIONAL(BUILD_EAP_MD5, test x$eap_md5 = xtrue) + +AC_ARG_ENABLE( [nat-transport], AS_HELP_STRING([--enable-nat-transport],[enable NAT traversal with IPsec transport mode (default is NO).]), [if test x$enableval = xyes; then diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index ab8a42b..2a6bc20 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -128,6 +128,12 @@ if USE_EAP_SIM libcharon_eapsim_la_LDFLAGS = -module endif +if BUILD_EAP_MD5 + eap_LTLIBRARIES += libeapmd5.la + libeapmd5_la_SOURCES = sa/authenticators/eap/eap_md5.h sa/authenticators/eap/eap_md5.c + libeapmd5_la_LDFLAGS = -module +endif + # build backends ################ backend_LTLIBRARIES = diff --git a/src/charon/sa/authenticators/eap/eap_md5.c b/src/charon/sa/authenticators/eap/eap_md5.c new file mode 100644 index 0000000..8fe74ed --- /dev/null +++ b/src/charon/sa/authenticators/eap/eap_md5.c @@ -0,0 +1,280 @@ +/** + * @file eap_md5.c + * + * @brief Implementation of eap_md5_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See . + * + * 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. + */ + +#include "eap_md5.h" + +#include +#include + +typedef struct private_eap_md5_t private_eap_md5_t; + +/** + * Private data of an eap_md5_t object. + */ +struct private_eap_md5_t { + + /** + * Public authenticator_t interface. + */ + eap_md5_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + + /** + * challenge sent by the server + */ + chunk_t challenge; + + /** + * EAP message identififier + */ + u_int8_t identifier; +}; + +typedef struct eap_md5_header_t eap_md5_header_t; + +/** + * packed eap MD5 header struct + */ +struct eap_md5_header_t { + /** EAP code (REQUEST/RESPONSE) */ + u_int8_t code; + /** unique message identifier */ + u_int8_t identifier; + /** length of whole message */ + u_int16_t length; + /** EAP type */ + u_int8_t type; + /** length of value (challenge) */ + u_int8_t value_size; + /** actual value */ + u_int8_t value[]; +} __attribute__((__packed__)); + +#define CHALLENGE_LEN 16 +#define PAYLOAD_LEN (CHALLENGE_LEN + sizeof(eap_md5_header_t)) + +/** + * Hash the challenge string, create response + */ +static status_t hash_challenge(private_eap_md5_t *this, chunk_t *response) +{ + chunk_t concat, secret; + hasher_t *hasher; + + if (charon->credentials->get_eap_key(charon->credentials, this->server, + this->peer, &secret) != SUCCESS) + { + DBG1(DBG_IKE, "no EAP key found for hosts '%D' - '%D'", + this->server, this->peer); + return NOT_FOUND; + } + concat = chunk_cata("cmc", chunk_from_thing(this->identifier), + secret, this->challenge); + hasher = hasher_create(HASH_MD5); + hasher->allocate_hash(hasher, concat, response); + hasher->destroy(hasher); + return SUCCESS; +} + +/** + * Implementation of eap_method_t.initiate for the peer + */ +static status_t initiate_peer(private_eap_md5_t *this, eap_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +/** + * Implementation of eap_method_t.initiate for the server + */ +static status_t initiate_server(private_eap_md5_t *this, eap_payload_t **out) +{ + randomizer_t *randomizer; + status_t status; + eap_md5_header_t *req; + + randomizer = randomizer_create(); + status = randomizer->allocate_pseudo_random_bytes(randomizer, CHALLENGE_LEN, + &this->challenge); + randomizer->destroy(randomizer); + if (status != SUCCESS) + { + return FAILED; + } + + req = alloca(PAYLOAD_LEN); + req->length = htons(PAYLOAD_LEN); + req->code = EAP_REQUEST; + req->identifier = this->identifier; + req->type = EAP_MD5; + req->value_size = this->challenge.len; + memcpy(req->value, this->challenge.ptr, this->challenge.len); + + *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN)); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.process for the peer + */ +static status_t process_peer(private_eap_md5_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t response; + chunk_t data; + eap_md5_header_t *req; + + this->identifier = in->get_identifier(in); + data = in->get_data(in); + this->challenge = chunk_clone(chunk_skip(data, 6)); + if (data.len < 6 || this->challenge.len < *(data.ptr + 5)) + { + DBG1(DBG_IKE, "received invalid EAP-MD5 message"); + return FAILED; + } + if (hash_challenge(this, &response) != SUCCESS) + { + return FAILED; + } + req = alloca(PAYLOAD_LEN); + req->length = htons(PAYLOAD_LEN); + req->code = EAP_RESPONSE; + req->identifier = this->identifier; + req->type = EAP_MD5; + req->value_size = response.len; + memcpy(req->value, response.ptr, response.len); + chunk_free(&response); + + *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN)); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.process for the server + */ +static status_t process_server(private_eap_md5_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t response, expected; + chunk_t data; + + if (this->identifier != in->get_identifier(in)) + { + DBG1(DBG_IKE, "received invalid EAP-MD5 message"); + return FAILED; + } + if (hash_challenge(this, &expected) != SUCCESS) + { + return FAILED; + } + data = in->get_data(in); + response = chunk_skip(data, 6); + + if (!chunk_equals(response, expected)) + { + chunk_free(&expected); + DBG1(DBG_IKE, "EAP-MD5 verification failed"); + return FAILED; + } + chunk_free(&expected); + return SUCCESS; +} + +/** + * Implementation of eap_method_t.get_type. + */ +static eap_type_t get_type(private_eap_md5_t *this) +{ + return EAP_MD5; +} + +/** + * Implementation of eap_method_t.get_msk. + */ +static status_t get_msk(private_eap_md5_t *this, chunk_t *msk) +{ + return FAILED; +} + +/** + * Implementation of eap_method_t.is_mutual. + */ +static bool is_mutual(private_eap_md5_t *this) +{ + return FALSE; +} + +/** + * Implementation of eap_method_t.destroy. + */ +static void destroy(private_eap_md5_t *this) +{ + chunk_free(&this->challenge); + free(this); +} + +/* + * Described in header. + */ +eap_md5_t *eap_create(eap_role_t role, + identification_t *server, identification_t *peer) +{ + private_eap_md5_t *this = malloc_thing(private_eap_md5_t); + + /* public functions */ + switch (role) + { + case EAP_SERVER: + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_server; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_server; + break; + case EAP_PEER: + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_peer; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_peer; + break; + default: + free(this); + return NULL; + } + this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*))get_type; + this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; + this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; + this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; + + /* private data */ + this->peer = peer; + this->server = server; + this->challenge = chunk_empty; + this->identifier = random(); + + return &this->public; +} diff --git a/src/charon/sa/authenticators/eap/eap_md5.h b/src/charon/sa/authenticators/eap/eap_md5.h new file mode 100644 index 0000000..260210b --- /dev/null +++ b/src/charon/sa/authenticators/eap/eap_md5.h @@ -0,0 +1,59 @@ +/** + * @file eap_md5.h + * + * @brief Interface of eap_md5_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See . + * + * 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. + */ + +#ifndef EAP_MD5_H_ +#define EAP_MD5_H_ + +typedef struct eap_md5_t eap_md5_t; + +#include + +/** + * @brief Implementation of the eap_method_t interface using EAP-MD5 (CHAP). + * + * @b Constructors: + * - eap_md5_create() + * - eap_client_create() using eap_method EAP_MD5 + * + * @ingroup eap + */ +struct eap_md5_t { + + /** + * Implemented eap_method_t interface. + */ + eap_method_t eap_method_interface; +}; + +/** + * @brief Creates the EAP method EAP-MD5. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_md5_t object + * + * @ingroup eap + */ +eap_md5_t *eap_create(eap_role_t role, + identification_t *server, identification_t *peer); + +#endif /* EAP_MD5_H_ */ diff --git a/src/starter/confread.c b/src/starter/confread.c index cd18593..b758ffd 100644 --- a/src/starter/confread.c +++ b/src/starter/confread.c @@ -518,6 +518,10 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg) { conn->eap = 18; } + else if (streq(kw->value, "md5")) + { + conn->eap = 4; + } else { conn->eap = atoi(kw->value);