From 078755d0992801a9bc884303e8f9d9dc19627991 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 21 Aug 2012 16:48:47 +0200 Subject: [PATCH 01/18] Added a method to enumerate registered EAP methods --- src/libcharon/sa/eap/eap_manager.c | 34 ++++++++++++++++++++++++++++++ src/libcharon/sa/eap/eap_manager.h | 9 ++++++++ 2 files changed, 43 insertions(+) diff --git a/src/libcharon/sa/eap/eap_manager.c b/src/libcharon/sa/eap/eap_manager.c index d38754e01..ad2628393 100644 --- a/src/libcharon/sa/eap/eap_manager.c +++ b/src/libcharon/sa/eap/eap_manager.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -104,6 +105,38 @@ METHOD(eap_manager_t, remove_method, void, this->lock->unlock(this->lock); } +/** + * filter the registered methods + */ +static bool filter_methods(uintptr_t role, eap_entry_t **entry, + eap_type_t *type, void *in, u_int32_t *vendor) +{ + if ((*entry)->role != (eap_role_t)role) + { + return FALSE; + } + if (type) + { + *type = (*entry)->type; + } + if (vendor) + { + *vendor = (*entry)->vendor; + } + return TRUE; +} + +METHOD(eap_manager_t, create_enumerator, enumerator_t*, + private_eap_manager_t *this, eap_role_t role) +{ + this->lock->read_lock(this->lock); + return enumerator_create_cleaner( + enumerator_create_filter( + this->methods->create_enumerator(this->methods), + (void*)filter_methods, (void*)(uintptr_t)role, NULL), + (void*)this->lock->unlock, this->lock); +} + METHOD(eap_manager_t, create_instance, eap_method_t*, private_eap_manager_t *this, eap_type_t type, u_int32_t vendor, eap_role_t role, identification_t *server, identification_t *peer) @@ -150,6 +183,7 @@ eap_manager_t *eap_manager_create() .public = { .add_method = _add_method, .remove_method = _remove_method, + .create_enumerator = _create_enumerator, .create_instance = _create_instance, .destroy = _destroy, }, diff --git a/src/libcharon/sa/eap/eap_manager.h b/src/libcharon/sa/eap/eap_manager.h index 868eaef06..ff548f6db 100644 --- a/src/libcharon/sa/eap/eap_manager.h +++ b/src/libcharon/sa/eap/eap_manager.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -53,6 +54,14 @@ struct eap_manager_t { */ void (*remove_method)(eap_manager_t *this, eap_constructor_t constructor); + /** + * Enumerate the registered EAP methods for the given role. + * + * @param role EAP role of methods to enumerate + * @return enumerator over (eap_type_t type, u_int32_t vendor) + */ + enumerator_t* (*create_enumerator)(eap_manager_t *this, eap_role_t role); + /** * Create a new EAP method instance. * From eae5616ae69a3c289bc20d1e50ad90a2789a348b Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 31 Aug 2012 11:31:48 +0200 Subject: [PATCH 02/18] Move our pseudo EAP types out of the range of valid EAP methods --- src/libstrongswan/eap/eap.c | 20 ++++++++++---------- src/libstrongswan/eap/eap.h | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libstrongswan/eap/eap.c b/src/libstrongswan/eap/eap.c index efd3ee981..05e8da2a7 100644 --- a/src/libstrongswan/eap/eap.c +++ b/src/libstrongswan/eap/eap.c @@ -51,12 +51,12 @@ ENUM_NEXT(eap_type_names, EAP_MSTLV, EAP_MSTLV, EAP_MSCHAPV2, "EAP_MSTLV"); ENUM_NEXT(eap_type_names, EAP_TNC, EAP_TNC, EAP_MSTLV, "EAP_TNC"); -ENUM_NEXT(eap_type_names, EAP_DYNAMIC, EAP_EXPERIMENTAL, EAP_TNC, - "EAP_DYNAMIC", - "EAP_RADIUS", +ENUM_NEXT(eap_type_names, EAP_EXPANDED, EAP_DYNAMIC, EAP_TNC, "EAP_EXPANDED", - "EAP_EXPERIMENTAL"); -ENUM_END(eap_type_names, EAP_EXPERIMENTAL); + "EAP_EXPERIMENTAL", + "EAP_RADIUS", + "EAP_DYNAMIC"); +ENUM_END(eap_type_names, EAP_DYNAMIC); ENUM_BEGIN(eap_type_short_names, EAP_IDENTITY, EAP_GTC, "ID", @@ -80,12 +80,12 @@ ENUM_NEXT(eap_type_short_names, EAP_MSTLV, EAP_MSTLV, EAP_MSCHAPV2, "MSTLV"); ENUM_NEXT(eap_type_short_names, EAP_TNC, EAP_TNC, EAP_MSTLV, "TNC"); -ENUM_NEXT(eap_type_short_names, EAP_DYNAMIC, EAP_EXPERIMENTAL, EAP_TNC, - "DYN", - "RAD", +ENUM_NEXT(eap_type_short_names, EAP_EXPANDED, EAP_DYNAMIC, EAP_TNC, "EXP", - "XP"); -ENUM_END(eap_type_short_names, EAP_EXPERIMENTAL); + "XP", + "RAD", + "DYN"); +ENUM_END(eap_type_short_names, EAP_DYNAMIC); /* * See header diff --git a/src/libstrongswan/eap/eap.h b/src/libstrongswan/eap/eap.h index 143232e4b..936ae1190 100644 --- a/src/libstrongswan/eap/eap.h +++ b/src/libstrongswan/eap/eap.h @@ -64,12 +64,12 @@ enum eap_type_t { EAP_MSCHAPV2 = 26, EAP_MSTLV = 33, EAP_TNC = 38, - /** select EAP method dynamically based on i.e. EAP-Identity */ - EAP_DYNAMIC = 252, - /** not a method, but an implementation providing different methods */ - EAP_RADIUS = 253, EAP_EXPANDED = 254, EAP_EXPERIMENTAL = 255, + /** not a method, but an implementation providing different methods */ + EAP_RADIUS = 256, + /** not a method, select actual method dynamically based on e.g. the ID */ + EAP_DYNAMIC = 257, }; /** From 7cad171da8a67a61cce493d90206723dfc47d510 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 22 Aug 2012 17:01:13 +0200 Subject: [PATCH 03/18] Filter invalid EAP authentication types when enumerating them Valid authentication types defined by the IETF are 4-253 and 255. --- src/libcharon/sa/eap/eap_manager.c | 6 ++++++ src/libcharon/sa/eap/eap_manager.h | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/eap/eap_manager.c b/src/libcharon/sa/eap/eap_manager.c index ad2628393..520c0ce56 100644 --- a/src/libcharon/sa/eap/eap_manager.c +++ b/src/libcharon/sa/eap/eap_manager.c @@ -115,6 +115,12 @@ static bool filter_methods(uintptr_t role, eap_entry_t **entry, { return FALSE; } + if ((*entry)->vendor == 0 && + ((*entry)->type < 4 || (*entry)->type == EAP_EXPANDED || + (*entry)->type > EAP_EXPERIMENTAL)) + { /* filter invalid types */ + return FALSE; + } if (type) { *type = (*entry)->type; diff --git a/src/libcharon/sa/eap/eap_manager.h b/src/libcharon/sa/eap/eap_manager.h index ff548f6db..e318ef57a 100644 --- a/src/libcharon/sa/eap/eap_manager.h +++ b/src/libcharon/sa/eap/eap_manager.h @@ -55,7 +55,10 @@ struct eap_manager_t { void (*remove_method)(eap_manager_t *this, eap_constructor_t constructor); /** - * Enumerate the registered EAP methods for the given role. + * Enumerate the registered EAP authentication methods for the given role. + * + * @note Only authentication types are enumerated (e.g. EAP-Identity is not + * even though it is registered as method with this manager). * * @param role EAP role of methods to enumerate * @return enumerator over (eap_type_t type, u_int32_t vendor) From af04233e1451c02dcda2582cd369481b03f21974 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 21 Aug 2012 16:54:21 +0200 Subject: [PATCH 04/18] Send EAP-Nak with supported types if requested type is unsupported --- src/libcharon/encoding/payloads/eap_payload.c | 72 +++++++++++++++++-- src/libcharon/encoding/payloads/eap_payload.h | 5 +- .../plugins/eap_peap/eap_peap_peer.c | 5 +- .../plugins/eap_ttls/eap_ttls_peer.c | 5 +- .../ikev2/authenticators/eap_authenticator.c | 6 +- 5 files changed, 81 insertions(+), 12 deletions(-) diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c index 1b9a5c802..4420f281b 100644 --- a/src/libcharon/encoding/payloads/eap_payload.c +++ b/src/libcharon/encoding/payloads/eap_payload.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -20,6 +21,7 @@ #include #include +#include typedef struct private_eap_payload_t private_eap_payload_t; @@ -313,15 +315,75 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier) return eap_payload_create_data(data); } +/** + * Write the given type either expanded or not + */ +static void write_type(bio_writer_t *writer, eap_type_t type, u_int32_t vendor, + bool expanded) +{ + if (expanded) + { + writer->write_uint8(writer, EAP_EXPANDED); + writer->write_uint24(writer, vendor); + writer->write_uint32(writer, type); + } + else + { + writer->write_uint8(writer, type); + } +} + /* * Described in header */ -eap_payload_t *eap_payload_create_nak(u_int8_t identifier) +eap_payload_t *eap_payload_create_nak(u_int8_t identifier, bool expanded) { - chunk_t data; + enumerator_t *enumerator; + eap_type_t reg_type; + u_int32_t reg_vendor; + bio_writer_t *writer; + chunk_t length, data; + bool added_any = FALSE, found_vendor = FALSE; + eap_payload_t *payload; - data = chunk_from_chars(EAP_RESPONSE, identifier, 0, 0, EAP_NAK); - htoun16(data.ptr + 2, data.len); - return eap_payload_create_data(data); + writer = bio_writer_create(12); + writer->write_uint8(writer, EAP_RESPONSE); + writer->write_uint8(writer, identifier); + length = writer->skip(writer, 2); + + write_type(writer, EAP_NAK, 0, expanded); + + enumerator = charon->eap->create_enumerator(charon->eap, EAP_PEER); + while (enumerator->enumerate(enumerator, ®_type, ®_vendor)) + { + if (!reg_vendor || expanded) + { + write_type(writer, reg_type, reg_vendor, expanded); + added_any = TRUE; + } + else if (reg_vendor) + { /* found vendor specifc method, but this is not an expanded Nak */ + found_vendor = TRUE; + } + } + enumerator->destroy(enumerator); + + if (found_vendor) + { /* request an expanded authentication type */ + write_type(writer, EAP_EXPANDED, 0, expanded); + added_any = TRUE; + } + if (!added_any) + { /* no methods added */ + write_type(writer, 0, 0, expanded); + } + + /* set length */ + data = writer->get_buf(writer); + htoun16(length.ptr, data.len); + + payload = eap_payload_create_data(data); + writer->destroy(writer); + return payload; } diff --git a/src/libcharon/encoding/payloads/eap_payload.h b/src/libcharon/encoding/payloads/eap_payload.h index 52bc7ac5e..ad8c57de1 100644 --- a/src/libcharon/encoding/payloads/eap_payload.h +++ b/src/libcharon/encoding/payloads/eap_payload.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -126,8 +127,10 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier); * Creates an eap_payload_t EAP_RESPONSE containing an EAP_NAK. * * @param identifier EAP identifier to use in payload + * @param expanded TRUE to send an expanded Nak (as response to an expanded + * request, i.e. one with vendor specific type) * @return eap_payload_t object */ -eap_payload_t *eap_payload_create_nak(u_int8_t identifier); +eap_payload_t *eap_payload_create_nak(u_int8_t identifier, bool expanded); #endif /** EAP_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/plugins/eap_peap/eap_peap_peer.c b/src/libcharon/plugins/eap_peap/eap_peap_peer.c index 72e201fb6..96d4d0f30 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap_peer.c +++ b/src/libcharon/plugins/eap_peap/eap_peap_peer.c @@ -85,7 +85,7 @@ METHOD(tls_application_t, process, status_t, default: return FAILED; } - + in = eap_payload_create_data(data); DBG3(DBG_IKE, "%B", &data); chunk_free(&data); @@ -151,7 +151,8 @@ METHOD(tls_application_t, process, status_t, if (!this->ph2_method) { DBG1(DBG_IKE, "EAP method not supported"); - this->out = eap_payload_create_nak(in->get_identifier(in)); + this->out = eap_payload_create_nak(in->get_identifier(in), + received_vendor != 0); in->destroy(in); return NEED_MORE; } diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c index 767111b3e..59366b490 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c @@ -138,7 +138,7 @@ METHOD(tls_application_t, process, status_t, chunk_free(&avp_data); } while (eap_pos < eap_data.len); - + in = eap_payload_create_data(eap_data); chunk_free(&eap_data); payload = (payload_t*)in; @@ -192,7 +192,8 @@ METHOD(tls_application_t, process, status_t, if (!this->method) { DBG1(DBG_IKE, "EAP method not supported"); - this->out = eap_payload_create_nak(in->get_identifier(in)); + this->out = eap_payload_create_nak(in->get_identifier(in), + received_vendor != 0); in->destroy(in); return NEED_MORE; } diff --git a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c index 2c282dc06..46913a7e0 100644 --- a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c @@ -357,9 +357,11 @@ static eap_payload_t* client_process_eap(private_eap_authenticator_t *this, this->method->destroy(this->method); this->method = NULL; } + /* FIXME: sending a Nak is not correct here as EAP_IDENTITY (1) is no + * EAP method (types 3-253, 255) */ DBG1(DBG_IKE, "%N not supported, sending EAP_NAK", eap_type_names, type); - return eap_payload_create_nak(in->get_identifier(in)); + return eap_payload_create_nak(in->get_identifier(in), FALSE); } if (this->method == NULL) { @@ -377,7 +379,7 @@ static eap_payload_t* client_process_eap(private_eap_authenticator_t *this, if (!this->method) { DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK"); - return eap_payload_create_nak(in->get_identifier(in)); + return eap_payload_create_nak(in->get_identifier(in), vendor != 0); } } From 34742f1bf89d1ea734655baf86bf0b18447abcd3 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 21 Aug 2012 16:57:34 +0200 Subject: [PATCH 05/18] Virtual EAP methods handle EAP-Naks themselves --- .../ikev2/authenticators/eap_authenticator.c | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c index 46913a7e0..7cc862538 100644 --- a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2006-2009 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -233,9 +234,10 @@ static void replace_eap_identity(private_eap_authenticator_t *this) static eap_payload_t* server_process_eap(private_eap_authenticator_t *this, eap_payload_t *in) { - eap_type_t type, received_type; - u_int32_t vendor, received_vendor; + eap_type_t type, received_type, conf_type; + u_int32_t vendor, received_vendor, conf_vendor; eap_payload_t *out; + auth_cfg_t *auth; if (in->get_code(in) != EAP_RESPONSE) { @@ -250,15 +252,25 @@ static eap_payload_t* server_process_eap(private_eap_authenticator_t *this, { if (received_vendor == 0 && received_type == EAP_NAK) { - DBG1(DBG_IKE, "received %N, sending %N", - eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE); + conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR); + if ((type == EAP_IDENTITY && !vendor) || + (type == conf_type && vendor == conf_vendor)) + { + DBG1(DBG_IKE, "received %N, sending %N", + eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE); + return eap_payload_create_code(EAP_FAILURE, + in->get_identifier(in)); + } + /* virtual methods handle NAKs in process() */ } else { DBG1(DBG_IKE, "received invalid EAP response, sending %N", eap_code_names, EAP_FAILURE); + return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); } - return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); } switch (this->method->process(this->method, in, &out)) From 78e8dca94f86b97b7df649c1c96a7fe532019a5f Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 21 Aug 2012 17:11:14 +0200 Subject: [PATCH 06/18] Allow clients to request a configured EAP method via EAP-Nak --- src/libcharon/encoding/payloads/eap_payload.c | 8 +++++- src/libcharon/encoding/payloads/eap_payload.h | 5 +++- .../plugins/eap_peap/eap_peap_peer.c | 2 +- .../plugins/eap_ttls/eap_ttls_peer.c | 2 +- .../ikev2/authenticators/eap_authenticator.c | 28 ++++++++++++++++--- 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c index 4420f281b..15a9972f2 100644 --- a/src/libcharon/encoding/payloads/eap_payload.c +++ b/src/libcharon/encoding/payloads/eap_payload.c @@ -336,7 +336,8 @@ static void write_type(bio_writer_t *writer, eap_type_t type, u_int32_t vendor, /* * Described in header */ -eap_payload_t *eap_payload_create_nak(u_int8_t identifier, bool expanded) +eap_payload_t *eap_payload_create_nak(u_int8_t identifier, eap_type_t type, + u_int32_t vendor, bool expanded) { enumerator_t *enumerator; eap_type_t reg_type; @@ -356,6 +357,11 @@ eap_payload_t *eap_payload_create_nak(u_int8_t identifier, bool expanded) enumerator = charon->eap->create_enumerator(charon->eap, EAP_PEER); while (enumerator->enumerate(enumerator, ®_type, ®_vendor)) { + if ((type && type != reg_type) || + (type && vendor && vendor != reg_vendor)) + { /* the preferred type is only sent if we actually find it */ + continue; + } if (!reg_vendor || expanded) { write_type(writer, reg_type, reg_vendor, expanded); diff --git a/src/libcharon/encoding/payloads/eap_payload.h b/src/libcharon/encoding/payloads/eap_payload.h index ad8c57de1..d3c3fae28 100644 --- a/src/libcharon/encoding/payloads/eap_payload.h +++ b/src/libcharon/encoding/payloads/eap_payload.h @@ -127,10 +127,13 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier); * Creates an eap_payload_t EAP_RESPONSE containing an EAP_NAK. * * @param identifier EAP identifier to use in payload + * @param type preferred auth type, 0 to send all supported types + * @param vendor vendor identifier for auth type, 0 for default * @param expanded TRUE to send an expanded Nak (as response to an expanded * request, i.e. one with vendor specific type) * @return eap_payload_t object */ -eap_payload_t *eap_payload_create_nak(u_int8_t identifier, bool expanded); +eap_payload_t *eap_payload_create_nak(u_int8_t identifier, eap_type_t type, + u_int32_t vendor, bool expanded); #endif /** EAP_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/plugins/eap_peap/eap_peap_peer.c b/src/libcharon/plugins/eap_peap/eap_peap_peer.c index 96d4d0f30..5e1972672 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap_peer.c +++ b/src/libcharon/plugins/eap_peap/eap_peap_peer.c @@ -151,7 +151,7 @@ METHOD(tls_application_t, process, status_t, if (!this->ph2_method) { DBG1(DBG_IKE, "EAP method not supported"); - this->out = eap_payload_create_nak(in->get_identifier(in), + this->out = eap_payload_create_nak(in->get_identifier(in), 0, 0, received_vendor != 0); in->destroy(in); return NEED_MORE; diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c index 59366b490..811fe051b 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c @@ -192,7 +192,7 @@ METHOD(tls_application_t, process, status_t, if (!this->method) { DBG1(DBG_IKE, "EAP method not supported"); - this->out = eap_payload_create_nak(in->get_identifier(in), + this->out = eap_payload_create_nak(in->get_identifier(in), 0, 0, received_vendor != 0); in->destroy(in); return NEED_MORE; diff --git a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c index 7cc862538..c9178d061 100644 --- a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c @@ -336,8 +336,8 @@ static eap_payload_t* server_process_eap(private_eap_authenticator_t *this, static eap_payload_t* client_process_eap(private_eap_authenticator_t *this, eap_payload_t *in) { - eap_type_t type; - u_int32_t vendor; + eap_type_t type, conf_type; + u_int32_t vendor, conf_vendor; auth_cfg_t *auth; eap_payload_t *out; identification_t *id; @@ -373,7 +373,7 @@ static eap_payload_t* client_process_eap(private_eap_authenticator_t *this, * EAP method (types 3-253, 255) */ DBG1(DBG_IKE, "%N not supported, sending EAP_NAK", eap_type_names, type); - return eap_payload_create_nak(in->get_identifier(in), FALSE); + return eap_payload_create_nak(in->get_identifier(in), 0, 0, FALSE); } if (this->method == NULL) { @@ -387,11 +387,31 @@ static eap_payload_t* client_process_eap(private_eap_authenticator_t *this, DBG1(DBG_IKE, "server requested %N authentication (id 0x%02X)", eap_type_names, type, in->get_identifier(in)); } + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE); + conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR); + if (conf_type != EAP_NAK && + (conf_type != type || conf_vendor != vendor)) + { + if (conf_vendor) + { + DBG1(DBG_IKE, "requesting EAP method %d-%d, sending EAP_NAK", + conf_type, conf_vendor); + } + else + { + DBG1(DBG_IKE, "requesting %N authentication, sending EAP_NAK", + eap_type_names, conf_type); + } + return eap_payload_create_nak(in->get_identifier(in), conf_type, + conf_vendor, vendor != 0); + } this->method = load_method(this, type, vendor, EAP_PEER); if (!this->method) { DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK"); - return eap_payload_create_nak(in->get_identifier(in), vendor != 0); + return eap_payload_create_nak(in->get_identifier(in), 0, 0, + vendor != 0); } } From cc4eec56f73ef54386badc8732b1867cbe05b47f Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 23 Aug 2012 08:36:24 +0200 Subject: [PATCH 07/18] Encode EAP-Naks in expanded format if we got an expanded type request Since methods defined by the IETF (vendor ID 0) could also be encoded in expanded type format the previous check was insufficient. --- src/libcharon/encoding/payloads/eap_payload.c | 7 +++++++ src/libcharon/encoding/payloads/eap_payload.h | 10 ++++++++-- src/libcharon/plugins/eap_peap/eap_peap_peer.c | 2 +- src/libcharon/plugins/eap_ttls/eap_ttls_peer.c | 2 +- .../sa/ikev2/authenticators/eap_authenticator.c | 4 ++-- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c index 15a9972f2..855504fe0 100644 --- a/src/libcharon/encoding/payloads/eap_payload.c +++ b/src/libcharon/encoding/payloads/eap_payload.c @@ -241,6 +241,12 @@ METHOD(eap_payload_t, get_type, eap_type_t, return 0; } +METHOD(eap_payload_t, is_expanded, bool, + private_eap_payload_t *this) +{ + return this->data.len > 4 ? this->data.ptr[4] == EAP_EXPANDED : FALSE; +} + METHOD2(payload_t, eap_payload_t, destroy, void, private_eap_payload_t *this) { @@ -272,6 +278,7 @@ eap_payload_t *eap_payload_create() .get_code = _get_code, .get_identifier = _get_identifier, .get_type = _get_type, + .is_expanded = _is_expanded, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, diff --git a/src/libcharon/encoding/payloads/eap_payload.h b/src/libcharon/encoding/payloads/eap_payload.h index d3c3fae28..934983282 100644 --- a/src/libcharon/encoding/payloads/eap_payload.h +++ b/src/libcharon/encoding/payloads/eap_payload.h @@ -82,6 +82,13 @@ struct eap_payload_t { */ eap_type_t (*get_type) (eap_payload_t *this, u_int32_t *vendor); + /** + * Check if the EAP method type is encoded in the Expanded Type format. + * + * @return TRUE if in Expanded Type format + */ + bool (*is_expanded) (eap_payload_t *this); + /** * Destroys an eap_payload_t object. */ @@ -129,8 +136,7 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier); * @param identifier EAP identifier to use in payload * @param type preferred auth type, 0 to send all supported types * @param vendor vendor identifier for auth type, 0 for default - * @param expanded TRUE to send an expanded Nak (as response to an expanded - * request, i.e. one with vendor specific type) + * @param expanded TRUE to send an expanded Nak * @return eap_payload_t object */ eap_payload_t *eap_payload_create_nak(u_int8_t identifier, eap_type_t type, diff --git a/src/libcharon/plugins/eap_peap/eap_peap_peer.c b/src/libcharon/plugins/eap_peap/eap_peap_peer.c index 5e1972672..79fd667cb 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap_peer.c +++ b/src/libcharon/plugins/eap_peap/eap_peap_peer.c @@ -152,7 +152,7 @@ METHOD(tls_application_t, process, status_t, { DBG1(DBG_IKE, "EAP method not supported"); this->out = eap_payload_create_nak(in->get_identifier(in), 0, 0, - received_vendor != 0); + in->is_expanded(in)); in->destroy(in); return NEED_MORE; } diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c index 811fe051b..00a4da3f8 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c @@ -193,7 +193,7 @@ METHOD(tls_application_t, process, status_t, { DBG1(DBG_IKE, "EAP method not supported"); this->out = eap_payload_create_nak(in->get_identifier(in), 0, 0, - received_vendor != 0); + in->is_expanded(in)); in->destroy(in); return NEED_MORE; } diff --git a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c index c9178d061..a340c04d7 100644 --- a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c @@ -404,14 +404,14 @@ static eap_payload_t* client_process_eap(private_eap_authenticator_t *this, eap_type_names, conf_type); } return eap_payload_create_nak(in->get_identifier(in), conf_type, - conf_vendor, vendor != 0); + conf_vendor, in->is_expanded(in)); } this->method = load_method(this, type, vendor, EAP_PEER); if (!this->method) { DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK"); return eap_payload_create_nak(in->get_identifier(in), 0, 0, - vendor != 0); + in->is_expanded(in)); } } From 576490ab099bbbfa1bd90969b1d68c37d33eedeb Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 23 Aug 2012 09:06:47 +0200 Subject: [PATCH 08/18] Added method to enumerate EAP types contained in an EAP-Nak --- src/libcharon/encoding/payloads/eap_payload.c | 82 ++++++++++++++++--- src/libcharon/encoding/payloads/eap_payload.h | 8 ++ 2 files changed, 79 insertions(+), 11 deletions(-) diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c index 855504fe0..dd2e25795 100644 --- a/src/libcharon/encoding/payloads/eap_payload.c +++ b/src/libcharon/encoding/payloads/eap_payload.c @@ -219,28 +219,87 @@ METHOD(eap_payload_t, get_identifier, u_int8_t, return 0; } +/** + * Get the current type at the given offset into this->data. + * @return the new offset or 0 if failed + */ +static size_t extract_type(private_eap_payload_t *this, size_t offset, + eap_type_t *type, u_int32_t *vendor) +{ + if (this->data.len > offset) + { + *vendor = 0; + *type = this->data.ptr[offset]; + if (*type != EAP_EXPANDED) + { + return offset + 1; + } + if (this->data.len >= offset + 8) + { + *vendor = untoh32(this->data.ptr + offset) & 0x00FFFFFF; + *type = untoh32(this->data.ptr + offset + 4); + return offset + 8; + } + } + return 0; +} + METHOD(eap_payload_t, get_type, eap_type_t, private_eap_payload_t *this, u_int32_t *vendor) { eap_type_t type; *vendor = 0; - if (this->data.len > 4) + if (extract_type(this, 4, &type, vendor)) { - type = this->data.ptr[4]; - if (type != EAP_EXPANDED) - { - return type; - } - if (this->data.len >= 12) - { - *vendor = untoh32(this->data.ptr + 4) & 0x00FFFFFF; - return untoh32(this->data.ptr + 8); - } + return type; } return 0; } +/** + * Type enumerator + */ +typedef struct { + /** public interface */ + enumerator_t public; + /** payload */ + private_eap_payload_t *payload; + /** current offset in the data */ + size_t offset; +} type_enumerator_t; + +METHOD(enumerator_t, enumerate_types, bool, + type_enumerator_t *this, eap_type_t *type, u_int32_t *vendor) +{ + this->offset = extract_type(this->payload, this->offset, type, vendor); + return this->offset; +} + +METHOD(eap_payload_t, get_types, enumerator_t*, + private_eap_payload_t *this) +{ + type_enumerator_t *enumerator; + eap_type_t type; + u_int32_t vendor; + size_t offset; + + offset = extract_type(this, 4, &type, &vendor); + if (offset && type == EAP_NAK) + { + INIT(enumerator, + .public = { + .enumerate = (void*)_enumerate_types, + .destroy = (void*)free, + }, + .payload = this, + .offset = offset, + ); + return &enumerator->public; + } + return enumerator_create_empty(); +} + METHOD(eap_payload_t, is_expanded, bool, private_eap_payload_t *this) { @@ -278,6 +337,7 @@ eap_payload_t *eap_payload_create() .get_code = _get_code, .get_identifier = _get_identifier, .get_type = _get_type, + .get_types = _get_types, .is_expanded = _is_expanded, .destroy = _destroy, }, diff --git a/src/libcharon/encoding/payloads/eap_payload.h b/src/libcharon/encoding/payloads/eap_payload.h index 934983282..e8ed1c5e7 100644 --- a/src/libcharon/encoding/payloads/eap_payload.h +++ b/src/libcharon/encoding/payloads/eap_payload.h @@ -82,6 +82,14 @@ struct eap_payload_t { */ eap_type_t (*get_type) (eap_payload_t *this, u_int32_t *vendor); + /** + * Enumerate the EAP method types contained in an EAP-Nak (i.e. get_type() + * returns EAP_NAK). + * + * @return enumerator over (eap_type_t type, u_int32_t vendor) + */ + enumerator_t* (*get_types) (eap_payload_t *this); + /** * Check if the EAP method type is encoded in the Expanded Type format. * From db409006e4ddc5da4fee700993481edd8b4d7adf Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 23 Aug 2012 10:00:11 +0200 Subject: [PATCH 09/18] Function added that parses EAP method strings ([eap-]type[-vendor]) --- src/libstrongswan/eap/eap.c | 59 +++++++++++++++++++++++++++++++++++++ src/libstrongswan/eap/eap.h | 27 +++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/src/libstrongswan/eap/eap.c b/src/libstrongswan/eap/eap.c index 05e8da2a7..2cc488388 100644 --- a/src/libstrongswan/eap/eap.c +++ b/src/libstrongswan/eap/eap.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -13,8 +14,13 @@ * for more details. */ +#include +#include + #include "eap.h" +#include + ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE, "EAP_REQUEST", "EAP_RESPONSE", @@ -120,3 +126,56 @@ eap_type_t eap_type_from_string(char *name) } return 0; } + +/* + * See header + */ +eap_vendor_type_t *eap_vendor_type_from_string(char *str) +{ + enumerator_t *enumerator; + eap_vendor_type_t *result = NULL; + eap_type_t type = 0; + u_int32_t vendor = 0; + char *part, *end; + + /* parse EAP method string of the form: [eap-]type[-vendor] */ + enumerator = enumerator_create_token(str, "-", " "); + while (enumerator->enumerate(enumerator, &part)) + { + if (!type) + { + if (streq(part, "eap")) + { /* skip 'eap' at the beginning */ + continue; + } + type = eap_type_from_string(part); + if (!type) + { + type = strtoul(part, &end, 0); + if (*end != '\0' || errno) + { + DBG1(DBG_LIB, "unknown or invalid EAP method: %s", part); + break; + } + } + continue; + } + vendor = strtoul(part, &end, 0); + if (*end != '\0' || errno) + { + DBG1(DBG_LIB, "invalid EAP vendor: %s", part); + type = 0; + } + break; + } + enumerator->destroy(enumerator); + + if (type) + { + INIT(result, + .type = type, + .vendor = vendor, + ); + } + return result; +} diff --git a/src/libstrongswan/eap/eap.h b/src/libstrongswan/eap/eap.h index 936ae1190..d824783e5 100644 --- a/src/libstrongswan/eap/eap.h +++ b/src/libstrongswan/eap/eap.h @@ -1,6 +1,8 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG + * 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 @@ -23,6 +25,7 @@ typedef enum eap_code_t eap_code_t; typedef enum eap_type_t eap_type_t; +typedef struct eap_vendor_type_t eap_vendor_type_t; #include @@ -82,6 +85,22 @@ extern enum_name_t *eap_type_names; */ extern enum_name_t *eap_type_short_names; +/** + * Struct that stores EAP type and vendor ID + */ +struct eap_vendor_type_t { + + /** + * EAP type + */ + eap_type_t type; + + /** + * Vendor Id + */ + u_int32_t vendor; +}; + /** * EAP packet format */ @@ -101,4 +120,12 @@ typedef struct __attribute__((packed)) { */ eap_type_t eap_type_from_string(char *name); +/** + * Parse a string of the form [eap-]type[-vendor]. + * + * @param str EAP method string + * @return parsed type (gets allocated), NULL if unknown or failed + */ +eap_vendor_type_t *eap_vendor_type_from_string(char *str); + #endif /** EAP_H_ @}*/ From 7240914955546229bcb4249c83ecd741524b2430 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 23 Aug 2012 10:16:37 +0200 Subject: [PATCH 10/18] Use eap_vendor_type_from_string() in stroke --- src/libcharon/plugins/stroke/stroke_config.c | 45 +++----------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index bf93f2c34..9dcb9ba0c 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -563,51 +563,20 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, } else if (strneq(auth, "eap", 3)) { - enumerator_t *enumerator; - char *str; - int i = 0, type = 0, vendor; + eap_vendor_type_t *type; cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); - /* parse EAP string, format: eap[-type[-vendor]] */ - enumerator = enumerator_create_token(auth, "-", " "); - while (enumerator->enumerate(enumerator, &str)) + type = eap_vendor_type_from_string(auth); + if (type) { - switch (i) + cfg->add(cfg, AUTH_RULE_EAP_TYPE, type->type); + if (type->vendor) { - case 1: - type = eap_type_from_string(str); - if (!type) - { - type = atoi(str); - if (!type) - { - DBG1(DBG_CFG, "unknown EAP method: %s", str); - break; - } - } - cfg->add(cfg, AUTH_RULE_EAP_TYPE, type); - break; - case 2: - if (type) - { - vendor = atoi(str); - if (vendor) - { - cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor); - } - else - { - DBG1(DBG_CFG, "unknown EAP vendor: %s", str); - } - } - break; - default: - break; + cfg->add(cfg, AUTH_RULE_EAP_VENDOR, type->vendor); } - i++; + free(type); } - enumerator->destroy(enumerator); if (msg->add_conn.eap_identity) { From 700ff5def983947e7790c6c77831484e3a9e2bc2 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 23 Aug 2012 14:42:23 +0200 Subject: [PATCH 11/18] Added eap-dynamic plugin which can proxy any other EAP method --- configure.in | 4 + src/libcharon/Makefile.am | 7 + src/libcharon/plugins/eap_dynamic/Makefile.am | 16 ++ .../plugins/eap_dynamic/eap_dynamic.c | 146 ++++++++++++++++++ .../plugins/eap_dynamic/eap_dynamic.h | 52 +++++++ .../plugins/eap_dynamic/eap_dynamic_plugin.c | 62 ++++++++ .../plugins/eap_dynamic/eap_dynamic_plugin.h | 43 ++++++ src/libstrongswan/eap/eap.c | 1 + src/libstrongswan/eap/eap.h | 2 +- 9 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 src/libcharon/plugins/eap_dynamic/Makefile.am create mode 100644 src/libcharon/plugins/eap_dynamic/eap_dynamic.c create mode 100644 src/libcharon/plugins/eap_dynamic/eap_dynamic.h create mode 100644 src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.c create mode 100644 src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.h diff --git a/configure.in b/configure.in index 2ab96e078..a1c777aac 100644 --- a/configure.in +++ b/configure.in @@ -154,6 +154,7 @@ ARG_ENABL_SET([eap-tls], [enable EAP TLS authentication module.]) ARG_ENABL_SET([eap-ttls], [enable EAP TTLS authentication module.]) ARG_ENABL_SET([eap-peap], [enable EAP PEAP authentication module.]) ARG_ENABL_SET([eap-tnc], [enable EAP TNC trusted network connect module.]) +ARG_ENABL_SET([eap-dynamic], [enable dynamic EAP proxy module.]) ARG_ENABL_SET([eap-radius], [enable RADIUS proxy authentication module.]) ARG_DISBL_SET([xauth-generic], [disable generic XAuth backend.]) ARG_ENABL_SET([xauth-eap], [enable XAuth backend using EAP methods to verify passwords.]) @@ -922,6 +923,7 @@ ADD_PLUGIN([eap-simaka-reauth], [c charon]) ADD_PLUGIN([eap-md5], [c charon nm]) ADD_PLUGIN([eap-gtc], [c charon nm]) ADD_PLUGIN([eap-mschapv2], [c charon nm]) +ADD_PLUGIN([eap-dynamic], [c charon]) ADD_PLUGIN([eap-radius], [c charon]) ADD_PLUGIN([eap-tls], [c charon nm]) ADD_PLUGIN([eap-ttls], [c charon nm]) @@ -1055,6 +1057,7 @@ AM_CONDITIONAL(USE_EAP_TLS, test x$eap_tls = xtrue) AM_CONDITIONAL(USE_EAP_TTLS, test x$eap_ttls = xtrue) AM_CONDITIONAL(USE_EAP_PEAP, test x$eap_peap = xtrue) AM_CONDITIONAL(USE_EAP_TNC, test x$eap_tnc = xtrue) +AM_CONDITIONAL(USE_EAP_DYNAMIC, test x$eap_dynamic = xtrue) AM_CONDITIONAL(USE_EAP_RADIUS, test x$eap_radius = xtrue) AM_CONDITIONAL(USE_XAUTH_GENERIC, test x$xauth_generic = xtrue) AM_CONDITIONAL(USE_XAUTH_EAP, test x$xauth_eap = xtrue) @@ -1222,6 +1225,7 @@ AC_OUTPUT( src/libcharon/Makefile src/libcharon/plugins/eap_aka/Makefile src/libcharon/plugins/eap_aka_3gpp2/Makefile + src/libcharon/plugins/eap_dynamic/Makefile src/libcharon/plugins/eap_identity/Makefile src/libcharon/plugins/eap_md5/Makefile src/libcharon/plugins/eap_gtc/Makefile diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index eada68bf5..3869066a8 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -316,6 +316,13 @@ if MONOLITHIC endif endif +if USE_EAP_DYNAMIC + SUBDIRS += plugins/eap_dynamic +if MONOLITHIC + libcharon_la_LIBADD += plugins/eap_dynamic/libstrongswan-eap-dynamic.la +endif +endif + if USE_EAP_RADIUS SUBDIRS += plugins/eap_radius if MONOLITHIC diff --git a/src/libcharon/plugins/eap_dynamic/Makefile.am b/src/libcharon/plugins/eap_dynamic/Makefile.am new file mode 100644 index 000000000..0d07fbf35 --- /dev/null +++ b/src/libcharon/plugins/eap_dynamic/Makefile.am @@ -0,0 +1,16 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-eap-dynamic.la +else +plugin_LTLIBRARIES = libstrongswan-eap-dynamic.la +endif + +libstrongswan_eap_dynamic_la_SOURCES = \ + eap_dynamic_plugin.h eap_dynamic_plugin.c eap_dynamic.h eap_dynamic.c + +libstrongswan_eap_dynamic_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c new file mode 100644 index 000000000..a75f458bc --- /dev/null +++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * 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_dynamic.h" + +#include +#include + +typedef struct private_eap_dynamic_t private_eap_dynamic_t; + +/** + * Private data of an eap_dynamic_t object. + */ +struct private_eap_dynamic_t { + + /** + * Public authenticator_t interface. + */ + eap_dynamic_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + + /** + * The proxied EAP method + */ + eap_method_t *method; +}; + +METHOD(eap_method_t, initiate, status_t, + private_eap_dynamic_t *this, eap_payload_t **out) +{ + return FAILED; +} + +METHOD(eap_method_t, process, status_t, + private_eap_dynamic_t *this, eap_payload_t *in, eap_payload_t **out) +{ + return FAILED; +} + +METHOD(eap_method_t, get_type, eap_type_t, + private_eap_dynamic_t *this, u_int32_t *vendor) +{ + if (this->method) + { + return this->method->get_type(this->method, vendor); + } + *vendor = 0; + return EAP_DYNAMIC; +} + +METHOD(eap_method_t, get_msk, status_t, + private_eap_dynamic_t *this, chunk_t *msk) +{ + if (this->method) + { + return this->method->get_msk(this->method, msk); + } + return FAILED; +} + +METHOD(eap_method_t, get_identifier, u_int8_t, + private_eap_dynamic_t *this) +{ + if (this->method) + { + return this->method->get_identifier(this->method); + } + return 0; +} + +METHOD(eap_method_t, set_identifier, void, + private_eap_dynamic_t *this, u_int8_t identifier) +{ + if (this->method) + { + this->method->set_identifier(this->method, identifier); + } +} + +METHOD(eap_method_t, is_mutual, bool, + private_eap_dynamic_t *this) +{ + if (this->method) + { + return this->method->is_mutual(this->method); + } + return FALSE; +} + +METHOD(eap_method_t, destroy, void, + private_eap_dynamic_t *this) +{ + DESTROY_IF(this->method); + this->server->destroy(this->server); + this->peer->destroy(this->peer); + free(this); +} + +/* + * Defined in header + */ +eap_dynamic_t *eap_dynamic_create(identification_t *server, + identification_t *peer) +{ + private_eap_dynamic_t *this; + + INIT(this, + .public = { + .interface = { + .initiate = _initiate, + .process = _process, + .get_type = _get_type, + .is_mutual = _is_mutual, + .get_msk = _get_msk, + .get_identifier = _get_identifier, + .set_identifier = _set_identifier, + .destroy = _destroy, + }, + }, + .peer = peer->clone(peer), + .server = server->clone(server), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic.h b/src/libcharon/plugins/eap_dynamic/eap_dynamic.h new file mode 100644 index 000000000..35db4fa26 --- /dev/null +++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * 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. + */ + +/** + * @defgroup eap_dynamic_i eap_dynamic + * @{ @ingroup eap_dynamic + */ + +#ifndef EAP_DYNAMIC_H_ +#define EAP_DYNAMIC_H_ + +typedef struct eap_dynamic_t eap_dynamic_t; + +#include + +/** + * Implementation of the eap_method_t interface for a virtual EAP method that + * proxies other EAP methods and supports the selection of the actual method + * by the client. + */ +struct eap_dynamic_t { + + /** + * Implemented eap_method_t interface + */ + eap_method_t interface; +}; + +/** + * Create a dynamic EAP proxy serving any supported real method which is also + * supported (or selected) by the client. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_dynamic_t object + */ +eap_dynamic_t *eap_dynamic_create(identification_t *server, + identification_t *peer); + +#endif /** EAP_DYNAMIC_H_ @}*/ diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.c b/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.c new file mode 100644 index 000000000..d6f38b666 --- /dev/null +++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * 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_dynamic_plugin.h" + +#include "eap_dynamic.h" + +#include + +METHOD(plugin_t, get_name, char*, + eap_dynamic_plugin_t *this) +{ + return "eap-dynamic"; +} + +METHOD(plugin_t, get_features, int, + eap_dynamic_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK(eap_method_register, eap_dynamic_create), + PLUGIN_PROVIDE(EAP_SERVER, EAP_DYNAMIC), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + eap_dynamic_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *eap_dynamic_plugin_create() +{ + eap_dynamic_plugin_t *this; + + INIT(this, + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + ); + + return &this->plugin; +} + diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.h b/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.h new file mode 100644 index 000000000..9b124d8d2 --- /dev/null +++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * 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. + */ + +/** + * @defgroup eap_dynamic eap_dynamic + * @ingroup cplugins + * + * @defgroup eap_dynamic_plugin eap_dynamic_plugin + * @{ @ingroup eap_dynamic + */ + +#ifndef EAP_DYNAMIC_PLUGIN_H_ +#define EAP_DYNAMIC_PLUGIN_H_ + +#include + +typedef struct eap_dynamic_plugin_t eap_dynamic_plugin_t; + +/** + * EAP plugin that can use any supported EAP method the client supports or + * prefers to use. + */ +struct eap_dynamic_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** EAP_DYNAMIC_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/eap/eap.c b/src/libstrongswan/eap/eap.c index 2cc488388..1e4cf11bf 100644 --- a/src/libstrongswan/eap/eap.c +++ b/src/libstrongswan/eap/eap.c @@ -114,6 +114,7 @@ eap_type_t eap_type_from_string(char *name) {"peap", EAP_PEAP}, {"mschapv2", EAP_MSCHAPV2}, {"tnc", EAP_TNC}, + {"dynamic", EAP_DYNAMIC}, {"radius", EAP_RADIUS}, }; diff --git a/src/libstrongswan/eap/eap.h b/src/libstrongswan/eap/eap.h index d824783e5..0e144b123 100644 --- a/src/libstrongswan/eap/eap.h +++ b/src/libstrongswan/eap/eap.h @@ -71,7 +71,7 @@ enum eap_type_t { EAP_EXPERIMENTAL = 255, /** not a method, but an implementation providing different methods */ EAP_RADIUS = 256, - /** not a method, select actual method dynamically based on e.g. the ID */ + /** not a method, select method dynamically based on client selection */ EAP_DYNAMIC = 257, }; From a2a61ec2e238260f89992517be299da1a9533caf Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 23 Aug 2012 14:47:27 +0200 Subject: [PATCH 12/18] The eap-dynamic plugin uses the first supported method as default --- .../plugins/eap_dynamic/eap_dynamic.c | 92 ++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c index a75f458bc..afc29389a 100644 --- a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c +++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c @@ -40,21 +40,83 @@ struct private_eap_dynamic_t { */ identification_t *peer; + /** + * Our supported EAP types (as eap_vendor_type_t*) + */ + linked_list_t *types; + /** * The proxied EAP method */ eap_method_t *method; }; +/** + * Load the given EAP method + */ +static eap_method_t *load_method(private_eap_dynamic_t *this, + eap_type_t type, u_int32_t vendor) +{ + eap_method_t *method; + + method = charon->eap->create_instance(charon->eap, type, vendor, EAP_SERVER, + this->server, this->peer); + if (!method) + { + if (vendor) + { + DBG1(DBG_IKE, "loading vendor specific EAP method %d-%d failed", + type, vendor); + } + else + { + DBG1(DBG_IKE, "loading %N method failed", eap_type_names, type); + } + } + return method; +} + +/** + * Select the first method we can instantiate + */ +static void select_method(private_eap_dynamic_t *this) +{ + eap_vendor_type_t *entry; + + while (this->types->remove_first(this->types, (void*)&entry) == SUCCESS) + { + this->method = load_method(this, entry->type, entry->vendor); + free(entry); + + if (this->method) + { + break; + } + } +} + METHOD(eap_method_t, initiate, status_t, private_eap_dynamic_t *this, eap_payload_t **out) { - return FAILED; + if (!this->method) + { + select_method(this); + if (!this->method) + { + DBG1(DBG_IKE, "no supported EAP method found"); + return FAILED; + } + } + return this->method->initiate(this->method, out); } METHOD(eap_method_t, process, status_t, private_eap_dynamic_t *this, eap_payload_t *in, eap_payload_t **out) { + if (this->method) + { + return this->method->process(this->method, in, out); + } return FAILED; } @@ -112,11 +174,35 @@ METHOD(eap_method_t, destroy, void, private_eap_dynamic_t *this) { DESTROY_IF(this->method); + this->types->destroy_function(this->types, (void*)free); this->server->destroy(this->server); this->peer->destroy(this->peer); free(this); } +/** + * Get all supported EAP methods + */ +static void get_supported_eap_types(private_eap_dynamic_t *this) +{ + enumerator_t *enumerator; + eap_type_t type; + u_int32_t vendor; + + enumerator = charon->eap->create_enumerator(charon->eap, EAP_SERVER); + while (enumerator->enumerate(enumerator, &type, &vendor)) + { + eap_vendor_type_t *entry; + + INIT(entry, + .type = type, + .vendor = vendor, + ); + this->types->insert_last(this->types, entry); + } + enumerator->destroy(enumerator); +} + /* * Defined in header */ @@ -140,7 +226,11 @@ eap_dynamic_t *eap_dynamic_create(identification_t *server, }, .peer = peer->clone(peer), .server = server->clone(server), + .types = linked_list_create(), ); + /* get all supported EAP methods */ + get_supported_eap_types(this); + return &this->public; } From a2f1d75eaec862e168b2e1e69f795de3a929b395 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 23 Aug 2012 14:55:33 +0200 Subject: [PATCH 13/18] Preferred EAP methods for eap-dynamic can be configured --- .../plugins/eap_dynamic/eap_dynamic.c | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c index afc29389a..e6705cc39 100644 --- a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c +++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c @@ -51,6 +51,14 @@ struct private_eap_dynamic_t { eap_method_t *method; }; +/** + * Compare two eap_vendor_type_t objects + */ +static bool entry_matches(eap_vendor_type_t *item, eap_vendor_type_t *other) +{ + return item->type == other->type && item->vendor == other->vendor; +} + /** * Load the given EAP method */ @@ -180,6 +188,49 @@ METHOD(eap_method_t, destroy, void, free(this); } +/** + * Parse preferred EAP types + */ +static void handle_preferred_eap_types(private_eap_dynamic_t *this, + char *methods) +{ + enumerator_t *enumerator; + eap_vendor_type_t *type, *entry; + linked_list_t *preferred; + char *method; + + /* parse preferred EAP methods, format: type[-vendor], ... */ + preferred = linked_list_create(); + enumerator = enumerator_create_token(methods, ",", " "); + while (enumerator->enumerate(enumerator, &method)) + { + type = eap_vendor_type_from_string(method); + if (type) + { + preferred->insert_last(preferred, type); + } + } + enumerator->destroy(enumerator); + + enumerator = this->types->create_enumerator(this->types); + while (preferred->remove_last(preferred, (void**)&type) == SUCCESS) + { /* move (supported) types to the front, maintain the preferred order */ + this->types->reset_enumerator(this->types, enumerator); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry_matches(entry, type)) + { + this->types->remove_at(this->types, enumerator); + this->types->insert_first(this->types, entry); + break; + } + } + free(type); + } + enumerator->destroy(enumerator); + preferred->destroy(preferred); +} + /** * Get all supported EAP methods */ @@ -210,6 +261,7 @@ eap_dynamic_t *eap_dynamic_create(identification_t *server, identification_t *peer) { private_eap_dynamic_t *this; + char *preferred; INIT(this, .public = { @@ -231,6 +283,12 @@ eap_dynamic_t *eap_dynamic_create(identification_t *server, /* get all supported EAP methods */ get_supported_eap_types(this); - + /* move preferred methods to the front */ + preferred = lib->settings->get_str(lib->settings, + "%s.plugins.eap-dynamic.preferred", NULL, charon->name); + if (preferred) + { + handle_preferred_eap_types(this, preferred); + } return &this->public; } From 3dde55e67b7c58969dc70e3b682bfb467d9a5edc Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 23 Aug 2012 15:00:20 +0200 Subject: [PATCH 14/18] eap-dynamic plugin handles EAP-Nak messages and selects a method supported by the peer --- .../plugins/eap_dynamic/eap_dynamic.c | 73 ++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c index e6705cc39..d4ffe637a 100644 --- a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c +++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c @@ -45,6 +45,11 @@ struct private_eap_dynamic_t { */ linked_list_t *types; + /** + * EAP types supported by peer, if any + */ + linked_list_t *other_types; + /** * The proxied EAP method */ @@ -85,7 +90,8 @@ static eap_method_t *load_method(private_eap_dynamic_t *this, } /** - * Select the first method we can instantiate + * Select the first method we can instantiate and is (optionally) supported + * by the client. */ static void select_method(private_eap_dynamic_t *this) { @@ -93,6 +99,25 @@ static void select_method(private_eap_dynamic_t *this) while (this->types->remove_first(this->types, (void*)&entry) == SUCCESS) { + if (this->other_types) + { + if (this->other_types->find_first(this->other_types, + (void*)entry_matches, NULL, entry) != SUCCESS) + { + if (entry->vendor) + { + DBG2(DBG_IKE, "skip vendor specific EAP method %d-%d not " + "supported by peer", entry->type, entry->vendor); + } + else + { + DBG2(DBG_IKE, "skip %N method not supported by peer", + eap_type_names, entry->type); + } + free(entry); + continue; + } + } this->method = load_method(this, entry->type, entry->vendor); free(entry); @@ -121,6 +146,51 @@ METHOD(eap_method_t, initiate, status_t, METHOD(eap_method_t, process, status_t, private_eap_dynamic_t *this, eap_payload_t *in, eap_payload_t **out) { + eap_type_t received_type, type; + u_int32_t received_vendor, vendor; + + received_type = in->get_type(in, &received_vendor); + if (received_vendor == 0 && received_type == EAP_NAK) + { + enumerator_t *enumerator; + + DBG1(DBG_IKE, "received %N", eap_type_names, EAP_NAK); + if (this->other_types) + { /* we already received a Nak or a proper response before */ + DBG1(DBG_IKE, "%N is not supported in this state", eap_type_names, + EAP_NAK); + return FAILED; + } + + this->other_types = linked_list_create(); + enumerator = in->get_types(in); + while (enumerator->enumerate(enumerator, &type, &vendor)) + { + eap_vendor_type_t *entry; + + if (!type) + { + DBG1(DBG_IKE, "peer does not support any other EAP methods"); + enumerator->destroy(enumerator); + return FAILED; + } + INIT(entry, + .type = type, + .vendor = vendor, + ); + this->other_types->insert_last(this->other_types, entry); + } + enumerator->destroy(enumerator); + + /* restart with a different method */ + this->method->destroy(this->method); + this->method = NULL; + return initiate(this, out); + } + if (!this->other_types) + { /* so we don't handle EAP-Naks later */ + this->other_types = linked_list_create(); + } if (this->method) { return this->method->process(this->method, in, out); @@ -183,6 +253,7 @@ METHOD(eap_method_t, destroy, void, { DESTROY_IF(this->method); this->types->destroy_function(this->types, (void*)free); + DESTROY_FUNCTION_IF(this->other_types, (void*)free); this->server->destroy(this->server); this->peer->destroy(this->peer); free(this); From 333c3b62285d9a9861845843f8ec0f4492012fc9 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 23 Aug 2012 16:02:51 +0200 Subject: [PATCH 15/18] Added an option to prefer types sent by peer in eap-dynamic plugin --- .../plugins/eap_dynamic/eap_dynamic.c | 56 ++++++++++++++----- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c index d4ffe637a..d24cbd128 100644 --- a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c +++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c @@ -50,6 +50,11 @@ struct private_eap_dynamic_t { */ linked_list_t *other_types; + /** + * Prefer types sent by peer + */ + bool prefer_peer; + /** * The proxied EAP method */ @@ -90,41 +95,60 @@ static eap_method_t *load_method(private_eap_dynamic_t *this, } /** - * Select the first method we can instantiate and is (optionally) supported - * by the client. + * Select the first method we can instantiate and is supported by both peers. */ static void select_method(private_eap_dynamic_t *this) { eap_vendor_type_t *entry; + linked_list_t *outer = this->types, *inner = this->other_types; + char *who = "peer"; - while (this->types->remove_first(this->types, (void*)&entry) == SUCCESS) + if (this->other_types && this->prefer_peer) { - if (this->other_types) + outer = this->other_types; + inner = this->types; + who = "us"; + } + + while (outer->remove_first(outer, (void*)&entry) == SUCCESS) + { + if (inner) { - if (this->other_types->find_first(this->other_types, - (void*)entry_matches, NULL, entry) != SUCCESS) + if (inner->find_first(inner, (void*)entry_matches, + NULL, entry) != SUCCESS) { if (entry->vendor) { - DBG2(DBG_IKE, "skip vendor specific EAP method %d-%d not " - "supported by peer", entry->type, entry->vendor); + DBG2(DBG_IKE, "proposed vendor specific EAP method %d-%d " + "not supported by %s, skipped", entry->type, + entry->vendor, who); } else { - DBG2(DBG_IKE, "skip %N method not supported by peer", - eap_type_names, entry->type); + DBG2(DBG_IKE, "proposed %N method not supported by %s, " + "skipped", eap_type_names, entry->type, who); } free(entry); continue; } } this->method = load_method(this, entry->type, entry->vendor); - free(entry); - if (this->method) { + if (entry->vendor) + { + DBG1(DBG_IKE, "vendor specific EAP method %d-%d selected", + entry->type, entry->vendor); + } + else + { + DBG1(DBG_IKE, "%N method selected", eap_type_names, + entry->type); + } + free(entry); break; } + free(entry); } } @@ -154,7 +178,9 @@ METHOD(eap_method_t, process, status_t, { enumerator_t *enumerator; - DBG1(DBG_IKE, "received %N", eap_type_names, EAP_NAK); + DBG1(DBG_IKE, "received %N, selecting a different EAP method", + eap_type_names, EAP_NAK); + if (this->other_types) { /* we already received a Nak or a proper response before */ DBG1(DBG_IKE, "%N is not supported in this state", eap_type_names, @@ -350,13 +376,15 @@ eap_dynamic_t *eap_dynamic_create(identification_t *server, .peer = peer->clone(peer), .server = server->clone(server), .types = linked_list_create(), + .prefer_peer = lib->settings->get_bool(lib->settings, + "%s.plugins.eap-dynamic.prefer_peer", FALSE, charon->name), ); /* get all supported EAP methods */ get_supported_eap_types(this); /* move preferred methods to the front */ preferred = lib->settings->get_str(lib->settings, - "%s.plugins.eap-dynamic.preferred", NULL, charon->name); + "%s.plugins.eap-dynamic.preferred", NULL, charon->name); if (preferred) { handle_preferred_eap_types(this, preferred); From 7f2e3091ee2593b59119dccbb8c41e6fed7cabb4 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 23 Aug 2012 16:10:47 +0200 Subject: [PATCH 16/18] Log the proper type for virtual EAP methods --- src/libcharon/sa/ikev2/authenticators/eap_authenticator.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c index a340c04d7..aa0644033 100644 --- a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c @@ -187,9 +187,9 @@ static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this, if (this->method) { action = "initiating"; - type = this->method->get_type(this->method, &vendor); if (this->method->initiate(this->method, &out) == NEED_MORE) { + type = this->method->get_type(this->method, &vendor); if (vendor) { DBG1(DBG_IKE, "initiating EAP vendor type %d-%d method (id 0x%02X)", @@ -202,6 +202,8 @@ static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this, } return out; } + /* type might have changed for virtual methods */ + type = this->method->get_type(this->method, &vendor); } if (vendor) { @@ -314,6 +316,8 @@ static eap_payload_t* server_process_eap(private_eap_authenticator_t *this, return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in)); case FAILED: default: + /* type might have changed for virtual methods */ + type = this->method->get_type(this->method, &vendor); if (vendor) { DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for " From 5f6ef5d5ce794976b23d799b3f36242a5737e096 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 23 Aug 2012 16:21:22 +0200 Subject: [PATCH 17/18] Documentation for eap-dynamic added --- man/ipsec.conf.5.in | 1 + man/strongswan.conf.5.in | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/man/ipsec.conf.5.in b/man/ipsec.conf.5.in index ca77ee7de..837a2055a 100644 --- a/man/ipsec.conf.5.in +++ b/man/ipsec.conf.5.in @@ -523,6 +523,7 @@ an optional EAP method can be appended. Currently defined methods are .BR eap-sim , .BR eap-tls , .BR eap-ttls , +.BR eap-dynamic , and .BR eap-radius . Alternatively, IANA assigned EAP method numbers are accepted. Vendor specific diff --git a/man/strongswan.conf.5.in b/man/strongswan.conf.5.in index 4fba2344b..8df6cf1fa 100644 --- a/man/strongswan.conf.5.in +++ b/man/strongswan.conf.5.in @@ -302,6 +302,16 @@ enable loaded duplicheck plugin .TP .BR charon.plugins.eap-aka-3ggp2.seq_check +.TP +.BR charon.plugins.eap-dynamic.preferred +The preferred EAP method(s) to be used. If it is not given the first +registered method will be used initially. If a comma separated list is given +the methods are tried in the given order before trying the rest of the +registered methods. +.TP +.BR charon.plugins.eap-dynamic.prefer_user " [no]" +If enabled the EAP methods proposed in an EAP-Nak message sent by the peer are +preferred over the methods registered locally. .TP .BR charon.plugins.eap-gtc.backend " [pam]" XAuth backend to be used for credential verification From cbe244a5fe81268a1aba30f871d57d81ee6e5e6e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 31 Aug 2012 12:16:43 +0200 Subject: [PATCH 18/18] NEWS about eap-dynamic plugin added --- NEWS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/NEWS b/NEWS index 3a308178b..fb963fce7 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,15 @@ strongswan-5.0.1 PAM directly anymore, but can use any XAuth backend to verify credentials, including xauth-pam. +- An EAP-Nak payload is returned by clients if the gateway requests an EAP + method that the client does not support. Clients can also request a specific + EAP method by configuring that method with leftauth. + +- The eap-dynamic plugin handles EAP-Nak payloads returned by clients and uses + these to select a different EAP method supported/requested by the client. + The plugin initially requests the first registered method or the first method + configured with charon.plugins.eap-dynamic.preferred. + - The autotools build has been migrated to use a config.h header. strongSwan development headers will get installed during "make install" if --with-dev-headers has been passed to ./configure.