diff options
64 files changed, 8517 insertions, 460 deletions
diff --git a/configure.in b/configure.in index ffc142f8b..89ab54fff 100644 --- a/configure.in +++ b/configure.in @@ -19,9 +19,7 @@ dnl =========================== AC_INIT(strongSwan,4.0.8) AM_INIT_AUTOMAKE(tar-ustar) AC_C_BIGENDIAN -AC_SUBST(ipsecdir, '${libexecdir}/ipsec') AC_SUBST(confdir, '${sysconfdir}') -AC_SUBST(piddir, '/var/run') dnl ================================= dnl check --enable-xxx & --with-xxx @@ -30,7 +28,7 @@ dnl ================================= AC_ARG_WITH( [default-pkcs11], - AS_HELP_STRING([--with-default-pkcs11=lib],[set the default PKCS11 library other than /usr/lib/opensc-pkcs11.so]), + AS_HELP_STRING([--with-default-pkcs11=lib],[set the default PKCS11 library other than "/usr/lib/opensc-pkcs11.so"]), [AC_DEFINE_UNQUOTED(PKCS11_DEFAULT_LIB, "$withval")], [AC_DEFINE_UNQUOTED(PKCS11_DEFAULT_LIB, "/usr/lib/opensc-pkcs11.so")] ) @@ -43,18 +41,39 @@ AC_ARG_WITH( AC_ARG_WITH( [random-device], - AS_HELP_STRING([--with-random-device=dev],[set the device for real random data other than /dev/random]), + AS_HELP_STRING([--with-random-device=dev],[set the device for real random data other than "/dev/random"]), [AC_DEFINE_UNQUOTED(DEV_RANDOM, "$withval")], [AC_DEFINE_UNQUOTED(DEV_RANDOM, "/dev/random")] ) AC_ARG_WITH( [urandom-device], - AS_HELP_STRING([--with-urandom-device=dev],[set the device for pseudo random data other than /dev/urandom]), + AS_HELP_STRING([--with-urandom-device=dev],[set the device for pseudo random data other than "/dev/urandom"]), [AC_DEFINE_UNQUOTED(DEV_URANDOM, "$withval")], [AC_DEFINE_UNQUOTED(DEV_URANDOM, "/dev/urandom")] ) +AC_ARG_WITH( + [ipsecdir], + AS_HELP_STRING([--with-ipsecdir=dir],[installation path for ipsec tools other than "libexecdir/ipsec"]), + [AC_SUBST(ipsecdir, "$withval")], + [AC_SUBST(ipsecdir, "${libexecdir}/ipsec")] +) + +AC_ARG_WITH( + [piddir], + AS_HELP_STRING([--with-piddir=dir],[path for PID and UNIX socket files other than "/var/run"]), + [AC_SUBST(piddir, "$withval")], + [AC_SUBST(piddir, "/var/run")] +) + +AC_ARG_WITH( + [eapdir], + AS_HELP_STRING([--with-eapdir=dir],[path for pluggable EAP modules other than "ipsecdir/eap"]), + [AC_SUBST(eapdir, "$withval")], + [AC_SUBST(eapdir, "${ipsecdir}/eap")] +) + AC_ARG_ENABLE( [http], AS_HELP_STRING([--enable-http],[enable OCSP and fetching of Certificates and CRLs over HTTP (default is NO). Requires libcurl.]), diff --git a/scripts/cfg-leak b/scripts/cfg-leak index 00623a141..44c3ec8b6 100755 --- a/scripts/cfg-leak +++ b/scripts/cfg-leak @@ -1,2 +1,4 @@ #!/bin/bash -CFLAGS="-Wall -Wno-format -Wno-pointer-sign -Wno-strict-aliasing -g -O2" ./configure --sysconfdir=/etc --with-random-device=/dev/urandom --enable-ldap --enable-http --enable-leak-detective +CFLAGS="-Wall -Wno-format -Wno-pointer-sign -Wno-strict-aliasing -g -O2" ./configure \ +--sysconfdir=/etc --with-random-device=/dev/urandom --enable-ldap --enable-http \ +--enable-leak-detective diff --git a/scripts/cfg-nodebug b/scripts/cfg-nodebug index 7f5e58102..319f51283 100755 --- a/scripts/cfg-nodebug +++ b/scripts/cfg-nodebug @@ -1,2 +1,3 @@ #!/bin/bash -CFLAGS="-Wall -Wno-format -Wno-pointer-sign -Wno-strict-aliasing -O2 -DDEBUG_LEVEL=0" ./configure --sysconfdir=/etc --with-random-device=/dev/urandom --enable-ldap --enable-http +CFLAGS="-Wall -Wno-format -Wno-pointer-sign -Wno-strict-aliasing -O2 -DDEBUG_LEVEL=0" ./configure \ +--sysconfdir=/etc --with-random-device=/dev/urandom --enable-ldap --enable-http diff --git a/scripts/cfg-norm b/scripts/cfg-norm index 164f9a6c4..54faf7355 100755 --- a/scripts/cfg-norm +++ b/scripts/cfg-norm @@ -1,2 +1,3 @@ #!/bin/bash -CFLAGS="-Wall -Wno-format -Wno-pointer-sign -Wno-strict-aliasing -g -O2" ./configure --sysconfdir=/etc --with-random-device=/dev/urandom --enable-ldap --enable-http +CFLAGS="-Wall -Wno-format -Wno-pointer-sign -Wno-strict-aliasing -g -O2" ./configure \ +--sysconfdir=/etc --with-random-device=/dev/urandom --enable-ldap --enable-http diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index 913556fc9..c4a6afa5f 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -1,5 +1,9 @@ # SUBDIRS = . testing +eap_LTLIBRARIES = + +# build optional EAP modules + ipsec_PROGRAMS = charon charon_SOURCES = \ @@ -24,6 +28,8 @@ sa/transactions/rekey_ike_sa.h sa/transactions/rekey_ike_sa.c \ sa/authenticators/authenticator.h sa/authenticators/authenticator.c \ sa/authenticators/rsa_authenticator.h sa/authenticators/rsa_authenticator.c \ sa/authenticators/psk_authenticator.h sa/authenticators/psk_authenticator.c \ +sa/authenticators/eap_authenticator.h sa/authenticators/eap_authenticator.c \ +sa/authenticators/eap/eap_method.h sa/authenticators/eap/eap_method.c \ sa/child_sa.c sa/child_sa.h sa/ike_sa.c sa/ike_sa.h sa/ike_sa_manager.c sa/ike_sa_manager.h \ sa/ike_sa_id.c sa/ike_sa_id.h encoding/payloads/encryption_payload.c \ encoding/payloads/cert_payload.c encoding/payloads/payload.h encoding/payloads/traffic_selector_substructure.c \ @@ -59,5 +65,5 @@ threads/sender.h threads/kernel_interface.h threads/scheduler.h threads/receiver threads/thread_pool.h threads/receiver.h threads/stroke_interface.h INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon -I$(top_srcdir)/src/stroke -AM_CFLAGS = -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lgmp -lpthread -lm +AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_EAPDIR=\"${eapdir}\" +charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lgmp -lpthread -lm -ldl diff --git a/src/charon/config/policies/local_policy_store.c b/src/charon/config/policies/local_policy_store.c index 7d2fad110..7eef382f0 100644 --- a/src/charon/config/policies/local_policy_store.c +++ b/src/charon/config/policies/local_policy_store.c @@ -92,8 +92,7 @@ static bool contains_traffic_selectors(policy_t *policy, bool mine, static policy_t *get_policy(private_local_policy_store_t *this, identification_t *my_id, identification_t *other_id, linked_list_t *my_ts, linked_list_t *other_ts, - host_t *my_host, host_t *other_host, - linked_list_t *requested_ca_keyids) + host_t *my_host, host_t *other_host) { typedef enum { PRIO_UNDEFINED = 0x00, @@ -254,7 +253,7 @@ local_policy_store_t *local_policy_store_create(void) this->public.policy_store.add_policy = (void (*) (policy_store_t*,policy_t*))add_policy; this->public.policy_store.get_policy = (policy_t* (*) (policy_store_t*,identification_t*,identification_t*, - linked_list_t*,linked_list_t*,host_t*,host_t*,linked_list_t*))get_policy; + linked_list_t*,linked_list_t*,host_t*,host_t*))get_policy; this->public.policy_store.get_policy_by_name = (policy_t* (*) (policy_store_t*,char*))get_policy_by_name; this->public.policy_store.delete_policy = (status_t (*) (policy_store_t*,char*))delete_policy; this->public.policy_store.create_iterator = (iterator_t* (*) (policy_store_t*))create_iterator; diff --git a/src/charon/config/policies/policy.c b/src/charon/config/policies/policy.c index 34bd15131..e68a8ad2b 100644 --- a/src/charon/config/policies/policy.c +++ b/src/charon/config/policies/policy.c @@ -84,6 +84,11 @@ struct private_policy_t { auth_method_t auth_method; /** + * EAP type to use for peer authentication + */ + eap_type_t eap_type; + + /** * we have a cert issued by this CA */ identification_t *my_ca; @@ -194,6 +199,14 @@ static auth_method_t get_auth_method(private_policy_t *this) } /** + * Implementation of connection_t.get_eap_type. + */ +static eap_type_t get_eap_type(private_policy_t *this) +{ + return this->eap_type; +} + +/** * Get traffic selectors, with wildcard-address update */ static linked_list_t *get_traffic_selectors(private_policy_t *this, linked_list_t *list, host_t *host) @@ -492,7 +505,7 @@ static void destroy(private_policy_t *this) * Described in header-file */ policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id, - auth_method_t auth_method, + auth_method_t auth_method, eap_type_t eap_type, u_int32_t hard_lifetime, u_int32_t soft_lifetime, u_int32_t jitter, char *updown, bool hostaccess, mode_t mode, dpd_action_t dpd_action) @@ -506,6 +519,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o this->public.get_my_ca = (identification_t* (*) (policy_t*))get_my_ca; this->public.get_other_ca = (identification_t* (*) (policy_t*))get_other_ca; this->public.get_auth_method = (auth_method_t (*) (policy_t*)) get_auth_method; + this->public.get_eap_type = (eap_type_t (*) (policy_t*)) get_eap_type; this->public.get_my_traffic_selectors = (linked_list_t* (*) (policy_t*,host_t*))get_my_traffic_selectors; this->public.get_other_traffic_selectors = (linked_list_t* (*) (policy_t*,host_t*))get_other_traffic_selectors; this->public.select_my_traffic_selectors = (linked_list_t* (*) (policy_t*,linked_list_t*,host_t*))select_my_traffic_selectors; @@ -530,6 +544,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o this->my_id = my_id; this->other_id = other_id; this->auth_method = auth_method; + this->eap_type = eap_type; this->hard_lifetime = hard_lifetime; this->soft_lifetime = soft_lifetime; this->jitter = jitter; diff --git a/src/charon/config/policies/policy.h b/src/charon/config/policies/policy.h index 123383ca6..a2d9ae8d0 100644 --- a/src/charon/config/policies/policy.h +++ b/src/charon/config/policies/policy.h @@ -32,6 +32,7 @@ typedef struct policy_t policy_t; #include <config/traffic_selector.h> #include <config/proposal.h> #include <sa/authenticators/authenticator.h> +#include <sa/authenticators/eap/eap_method.h> /** @@ -148,6 +149,14 @@ struct policy_t { * @return authentication method */ auth_method_t (*get_auth_method) (policy_t *this); + + /** + * @brief Get the EAP type to use for peer authentication. + * + * @param this calling object + * @return authentication method + */ + eap_type_t (*get_eap_type) (policy_t *this); /** * @brief Get configured traffic selectors for our site. @@ -358,6 +367,7 @@ struct policy_t { * @param my_id identification_t for ourselves * @param other_id identification_t for the remote guy * @param auth_method Authentication method to use for our(!) auth data + * @param eap_type EAP type to use for peer authentication * @param hard_lifetime lifetime before deleting an SA * @param soft_lifetime lifetime before rekeying an SA * @param jitter range of randomization time @@ -371,7 +381,7 @@ struct policy_t { */ policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id, - auth_method_t auth_method, + auth_method_t auth_method, eap_type_t eap_type, u_int32_t hard_lifetime, u_int32_t soft_lifetime, u_int32_t jitter, char *updown, bool hostaccess, mode_t mode, dpd_action_t dpd_action); diff --git a/src/charon/config/policies/policy_store.h b/src/charon/config/policies/policy_store.h index 6b470055e..cd8870953 100755 --- a/src/charon/config/policies/policy_store.h +++ b/src/charon/config/policies/policy_store.h @@ -49,14 +49,13 @@ struct policy_store_t { * other_id must be fully qualified. my_id may be %any, as the * other peer may not include an IDr Request. * - * @param this calling object - * @param my_id own ID of the policy - * @param other_id others ID of the policy - * @param my_ts traffic selectors requested for local host - * @param other_ts traffic selectors requested for remote host - * @param my_host host to use for wilcards in TS compare - * @param other_host host to use for wildcards in TS compare - * @param requested_ca_keyids list of requested CA keyids + * @param this calling object + * @param my_id own ID of the policy + * @param other_id others ID of the policy + * @param my_ts traffic selectors requested for local host + * @param other_ts traffic selectors requested for remote host + * @param my_host host to use for wilcards in TS compare + * @param other_host host to use for wildcards in TS compare * @return * - matching policy_t, if found * - NULL otherwise @@ -64,8 +63,7 @@ struct policy_store_t { policy_t *(*get_policy) (policy_store_t *this, identification_t *my_id, identification_t *other_id, linked_list_t *my_ts, linked_list_t *other_ts, - host_t *my_host, host_t* other_host, - linked_list_t *requested_ca_keyids); + host_t *my_host, host_t* other_host); /** * @brief Returns a policy identified by a connection name. diff --git a/src/charon/daemon.c b/src/charon/daemon.c index 2d15b58d2..3bac57f7f 100644 --- a/src/charon/daemon.c +++ b/src/charon/daemon.c @@ -42,6 +42,7 @@ #include <config/credentials/local_credential_store.h> #include <config/connections/local_connection_store.h> #include <config/policies/local_policy_store.h> +#include <sa/authenticators/eap/eap_method.h> typedef struct private_daemon_t private_daemon_t; @@ -393,6 +394,7 @@ int main(int argc, char *argv[]) { bool strict_crl_policy = FALSE; bool use_syslog = FALSE; + char *eapdir = IPSEC_EAPDIR; private_daemon_t *private_charon; FILE *pid_file; @@ -416,6 +418,7 @@ int main(int argc, char *argv[]) { "version", no_argument, NULL, 'v' }, { "use-syslog", no_argument, NULL, 'l' }, { "strictcrlpolicy", no_argument, NULL, 'r' }, + { "eapdir", required_argument, NULL, 'e' }, /* TODO: handle "debug-all" */ { "debug-dmn", required_argument, &signal, DBG_DMN }, { "debug-mgr", required_argument, &signal, DBG_MGR }, @@ -447,6 +450,9 @@ int main(int argc, char *argv[]) case 'r': strict_crl_policy = TRUE; continue; + case 'e': + eapdir = optarg; + continue; case 0: /* option is in signal */ levels[signal] = atoi(optarg); @@ -463,6 +469,8 @@ int main(int argc, char *argv[]) /* initialize daemon */ initialize(private_charon, strict_crl_policy, use_syslog, levels); + /* load pluggable EAP modules */ + eap_method_load(eapdir); /* check/setup PID file */ if (stat(PID_FILE, &stb) == 0) @@ -477,6 +485,7 @@ int main(int argc, char *argv[]) fprintf(pid_file, "%d\n", getpid()); fclose(pid_file); } + /* log socket info */ list = charon->socket->create_local_address_list(charon->socket); DBG1(DBG_NET, "listening on %d addresses:", list->get_count(list)); @@ -490,6 +499,7 @@ int main(int argc, char *argv[]) /* run daemon */ run(private_charon); + eap_method_unload(); /* normal termination, cleanup and exit */ destroy(private_charon); unlink(PID_FILE); diff --git a/src/charon/daemon.h b/src/charon/daemon.h index afe880533..8296aead4 100644 --- a/src/charon/daemon.h +++ b/src/charon/daemon.h @@ -180,6 +180,14 @@ typedef struct daemon_t daemon_t; */ /** + * @defgroup eap eap + * + * EAP authentication module interface and it's implementations. + * + * @ingroup authenticators + */ + +/** * @defgroup threads threads * * Threaded classes, which will do their job alone. diff --git a/src/charon/doc/standards/rfc3748.txt b/src/charon/doc/standards/rfc3748.txt new file mode 100644 index 000000000..75600c1f2 --- /dev/null +++ b/src/charon/doc/standards/rfc3748.txt @@ -0,0 +1,3755 @@ + + + + + + +Network Working Group B. Aboba +Request for Comments: 3748 Microsoft +Obsoletes: 2284 L. Blunk +Category: Standards Track Merit Network, Inc + J. Vollbrecht + Vollbrecht Consulting LLC + J. Carlson + Sun + H. Levkowetz, Ed. + ipUnplugged + June 2004 + + + Extensible Authentication Protocol (EAP) + +Status of this Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2004). + +Abstract + + This document defines the Extensible Authentication Protocol (EAP), + an authentication framework which supports multiple authentication + methods. EAP typically runs directly over data link layers such as + Point-to-Point Protocol (PPP) or IEEE 802, without requiring IP. EAP + provides its own support for duplicate elimination and + retransmission, but is reliant on lower layer ordering guarantees. + Fragmentation is not supported within EAP itself; however, individual + EAP methods may support this. + + This document obsoletes RFC 2284. A summary of the changes between + this document and RFC 2284 is available in Appendix A. + + + + + + + + + + + +Aboba, et al. Standards Track [Page 1] + +RFC 3748 EAP June 2004 + + +Table of Contents + + 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . 3 + 1.1. Specification of Requirements . . . . . . . . . . . . . 4 + 1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . 4 + 1.3. Applicability . . . . . . . . . . . . . . . . . . . . . 6 + 2. Extensible Authentication Protocol (EAP). . . . . . . . . . . 7 + 2.1. Support for Sequences . . . . . . . . . . . . . . . . . 9 + 2.2. EAP Multiplexing Model. . . . . . . . . . . . . . . . . 10 + 2.3. Pass-Through Behavior . . . . . . . . . . . . . . . . . 12 + 2.4. Peer-to-Peer Operation. . . . . . . . . . . . . . . . . 14 + 3. Lower Layer Behavior. . . . . . . . . . . . . . . . . . . . . 15 + 3.1. Lower Layer Requirements. . . . . . . . . . . . . . . . 15 + 3.2. EAP Usage Within PPP. . . . . . . . . . . . . . . . . . 18 + 3.2.1. PPP Configuration Option Format. . . . . . . . . 18 + 3.3. EAP Usage Within IEEE 802 . . . . . . . . . . . . . . . 19 + 3.4. Lower Layer Indications . . . . . . . . . . . . . . . . 19 + 4. EAP Packet Format . . . . . . . . . . . . . . . . . . . . . . 20 + 4.1. Request and Response. . . . . . . . . . . . . . . . . . 21 + 4.2. Success and Failure . . . . . . . . . . . . . . . . . . 23 + 4.3. Retransmission Behavior . . . . . . . . . . . . . . . . 26 + 5. Initial EAP Request/Response Types. . . . . . . . . . . . . . 27 + 5.1. Identity. . . . . . . . . . . . . . . . . . . . . . . . 28 + 5.2. Notification. . . . . . . . . . . . . . . . . . . . . . 29 + 5.3. Nak . . . . . . . . . . . . . . . . . . . . . . . . . . 31 + 5.3.1. Legacy Nak . . . . . . . . . . . . . . . . . . . 31 + 5.3.2. Expanded Nak . . . . . . . . . . . . . . . . . . 32 + 5.4. MD5-Challenge . . . . . . . . . . . . . . . . . . . . . 35 + 5.5. One-Time Password (OTP) . . . . . . . . . . . . . . . . 36 + 5.6. Generic Token Card (GTC). . . . . . . . . . . . . . . . 37 + 5.7. Expanded Types. . . . . . . . . . . . . . . . . . . . . 38 + 5.8. Experimental. . . . . . . . . . . . . . . . . . . . . . 40 + 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 40 + 6.1. Packet Codes. . . . . . . . . . . . . . . . . . . . . . 41 + 6.2. Method Types. . . . . . . . . . . . . . . . . . . . . . 41 + 7. Security Considerations . . . . . . . . . . . . . . . . . . . 42 + 7.1. Threat Model. . . . . . . . . . . . . . . . . . . . . . 42 + 7.2. Security Claims . . . . . . . . . . . . . . . . . . . . 43 + 7.2.1. Security Claims Terminology for EAP Methods. . . 44 + 7.3. Identity Protection . . . . . . . . . . . . . . . . . . 46 + 7.4. Man-in-the-Middle Attacks . . . . . . . . . . . . . . . 47 + 7.5. Packet Modification Attacks . . . . . . . . . . . . . . 48 + 7.6. Dictionary Attacks. . . . . . . . . . . . . . . . . . . 49 + 7.7. Connection to an Untrusted Network. . . . . . . . . . . 49 + 7.8. Negotiation Attacks . . . . . . . . . . . . . . . . . . 50 + 7.9. Implementation Idiosyncrasies . . . . . . . . . . . . . 50 + 7.10. Key Derivation. . . . . . . . . . . . . . . . . . . . . 51 + 7.11. Weak Ciphersuites . . . . . . . . . . . . . . . . . . . 53 + + + +Aboba, et al. Standards Track [Page 2] + +RFC 3748 EAP June 2004 + + + 7.12. Link Layer. . . . . . . . . . . . . . . . . . . . . . . 53 + 7.13. Separation of Authenticator and Backend Authentication + Server. . . . . . . . . . . . . . . . . . . . . . . . . 54 + 7.14. Cleartext Passwords . . . . . . . . . . . . . . . . . . 55 + 7.15. Channel Binding . . . . . . . . . . . . . . . . . . . . 55 + 7.16. Protected Result Indications. . . . . . . . . . . . . . 56 + 8. Acknowledgements. . . . . . . . . . . . . . . . . . . . . . . 58 + 9. References. . . . . . . . . . . . . . . . . . . . . . . . . . 59 + 9.1. Normative References. . . . . . . . . . . . . . . . . . 59 + 9.2. Informative References. . . . . . . . . . . . . . . . . 60 + Appendix A. Changes from RFC 2284. . . . . . . . . . . . . . . . . 64 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 66 + Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 67 + +1. Introduction + + This document defines the Extensible Authentication Protocol (EAP), + an authentication framework which supports multiple authentication + methods. EAP typically runs directly over data link layers such as + Point-to-Point Protocol (PPP) or IEEE 802, without requiring IP. EAP + provides its own support for duplicate elimination and + retransmission, but is reliant on lower layer ordering guarantees. + Fragmentation is not supported within EAP itself; however, individual + EAP methods may support this. + + EAP may be used on dedicated links, as well as switched circuits, and + wired as well as wireless links. To date, EAP has been implemented + with hosts and routers that connect via switched circuits or dial-up + lines using PPP [RFC1661]. It has also been implemented with + switches and access points using IEEE 802 [IEEE-802]. EAP + encapsulation on IEEE 802 wired media is described in [IEEE-802.1X], + and encapsulation on IEEE wireless LANs in [IEEE-802.11i]. + + One of the advantages of the EAP architecture is its flexibility. + EAP is used to select a specific authentication mechanism, typically + after the authenticator requests more information in order to + determine the specific authentication method to be used. Rather than + requiring the authenticator to be updated to support each new + authentication method, EAP permits the use of a backend + authentication server, which may implement some or all authentication + methods, with the authenticator acting as a pass-through for some or + all methods and peers. + + Within this document, authenticator requirements apply regardless of + whether the authenticator is operating as a pass-through or not. + Where the requirement is meant to apply to either the authenticator + or backend authentication server, depending on where the EAP + authentication is terminated, the term "EAP server" will be used. + + + +Aboba, et al. Standards Track [Page 3] + +RFC 3748 EAP June 2004 + + +1.1. Specification of Requirements + + In this document, several words are used to signify the requirements + of the specification. The key words "MUST", "MUST NOT", "REQUIRED", + "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", + and "OPTIONAL" in this document are to be interpreted as described in + [RFC2119]. + +1.2. Terminology + + This document frequently uses the following terms: + + authenticator + The end of the link initiating EAP authentication. The term + authenticator is used in [IEEE-802.1X], and has the same meaning + in this document. + + peer + The end of the link that responds to the authenticator. In + [IEEE-802.1X], this end is known as the Supplicant. + + Supplicant + The end of the link that responds to the authenticator in [IEEE- + 802.1X]. In this document, this end of the link is called the + peer. + + backend authentication server + A backend authentication server is an entity that provides an + authentication service to an authenticator. When used, this + server typically executes EAP methods for the authenticator. This + terminology is also used in [IEEE-802.1X]. + + AAA + Authentication, Authorization, and Accounting. AAA protocols with + EAP support include RADIUS [RFC3579] and Diameter [DIAM-EAP]. In + this document, the terms "AAA server" and "backend authentication + server" are used interchangeably. + + Displayable Message + This is interpreted to be a human readable string of characters. + The message encoding MUST follow the UTF-8 transformation format + [RFC2279]. + + + + + + + + + +Aboba, et al. Standards Track [Page 4] + +RFC 3748 EAP June 2004 + + + EAP server + The entity that terminates the EAP authentication method with the + peer. In the case where no backend authentication server is used, + the EAP server is part of the authenticator. In the case where + the authenticator operates in pass-through mode, the EAP server is + located on the backend authentication server. + + Silently Discard + This means the implementation discards the packet without further + processing. The implementation SHOULD provide the capability of + logging the event, including the contents of the silently + discarded packet, and SHOULD record the event in a statistics + counter. + + Successful Authentication + In the context of this document, "successful authentication" is an + exchange of EAP messages, as a result of which the authenticator + decides to allow access by the peer, and the peer decides to use + this access. The authenticator's decision typically involves both + authentication and authorization aspects; the peer may + successfully authenticate to the authenticator, but access may be + denied by the authenticator due to policy reasons. + + Message Integrity Check (MIC) + A keyed hash function used for authentication and integrity + protection of data. This is usually called a Message + Authentication Code (MAC), but IEEE 802 specifications (and this + document) use the acronym MIC to avoid confusion with Medium + Access Control. + + Cryptographic Separation + Two keys (x and y) are "cryptographically separate" if an + adversary that knows all messages exchanged in the protocol cannot + compute x from y or y from x without "breaking" some cryptographic + assumption. In particular, this definition allows that the + adversary has the knowledge of all nonces sent in cleartext, as + well as all predictable counter values used in the protocol. + Breaking a cryptographic assumption would typically require + inverting a one-way function or predicting the outcome of a + cryptographic pseudo-random number generator without knowledge of + the secret state. In other words, if the keys are + cryptographically separate, there is no shortcut to compute x from + y or y from x, but the work an adversary must do to perform this + computation is equivalent to performing an exhaustive search for + the secret state value. + + + + + + +Aboba, et al. Standards Track [Page 5] + +RFC 3748 EAP June 2004 + + + Master Session Key (MSK) + Keying material that is derived between the EAP peer and server + and exported by the EAP method. The MSK is at least 64 octets in + length. In existing implementations, a AAA server acting as an + EAP server transports the MSK to the authenticator. + + Extended Master Session Key (EMSK) + Additional keying material derived between the EAP client and + server that is exported by the EAP method. The EMSK is at least + 64 octets in length. The EMSK is not shared with the + authenticator or any other third party. The EMSK is reserved for + future uses that are not defined yet. + + Result indications + A method provides result indications if after the method's last + message is sent and received: + + 1) The peer is aware of whether it has authenticated the server, + as well as whether the server has authenticated it. + + 2) The server is aware of whether it has authenticated the peer, + as well as whether the peer has authenticated it. + + In the case where successful authentication is sufficient to + authorize access, then the peer and authenticator will also know if + the other party is willing to provide or accept access. This may not + always be the case. An authenticated peer may be denied access due + to lack of authorization (e.g., session limit) or other reasons. + Since the EAP exchange is run between the peer and the server, other + nodes (such as AAA proxies) may also affect the authorization + decision. This is discussed in more detail in Section 7.16. + +1.3. Applicability + + EAP was designed for use in network access authentication, where IP + layer connectivity may not be available. Use of EAP for other + purposes, such as bulk data transport, is NOT RECOMMENDED. + + Since EAP does not require IP connectivity, it provides just enough + support for the reliable transport of authentication protocols, and + no more. + + EAP is a lock-step protocol which only supports a single packet in + flight. As a result, EAP cannot efficiently transport bulk data, + unlike transport protocols such as TCP [RFC793] or SCTP [RFC2960]. + + + + + + +Aboba, et al. Standards Track [Page 6] + +RFC 3748 EAP June 2004 + + + While EAP provides support for retransmission, it assumes ordering + guarantees provided by the lower layer, so out of order reception is + not supported. + + Since EAP does not support fragmentation and reassembly, EAP + authentication methods generating payloads larger than the minimum + EAP MTU need to provide fragmentation support. + + While authentication methods such as EAP-TLS [RFC2716] provide + support for fragmentation and reassembly, the EAP methods defined in + this document do not. As a result, if the EAP packet size exceeds + the EAP MTU of the link, these methods will encounter difficulties. + + EAP authentication is initiated by the server (authenticator), + whereas many authentication protocols are initiated by the client + (peer). As a result, it may be necessary for an authentication + algorithm to add one or two additional messages (at most one + roundtrip) in order to run over EAP. + + Where certificate-based authentication is supported, the number of + additional roundtrips may be much larger due to fragmentation of + certificate chains. In general, a fragmented EAP packet will require + as many round-trips to send as there are fragments. For example, a + certificate chain 14960 octets in size would require ten round-trips + to send with a 1496 octet EAP MTU. + + Where EAP runs over a lower layer in which significant packet loss is + experienced, or where the connection between the authenticator and + authentication server experiences significant packet loss, EAP + methods requiring many round-trips can experience difficulties. In + these situations, use of EAP methods with fewer roundtrips is + advisable. + +2. Extensible Authentication Protocol (EAP) + + The EAP authentication exchange proceeds as follows: + + [1] The authenticator sends a Request to authenticate the peer. The + Request has a Type field to indicate what is being requested. + Examples of Request Types include Identity, MD5-challenge, etc. + The MD5-challenge Type corresponds closely to the CHAP + authentication protocol [RFC1994]. Typically, the authenticator + will send an initial Identity Request; however, an initial + Identity Request is not required, and MAY be bypassed. For + example, the identity may not be required where it is determined + by the port to which the peer has connected (leased lines, + + + + + +Aboba, et al. Standards Track [Page 7] + +RFC 3748 EAP June 2004 + + + dedicated switch or dial-up ports), or where the identity is + obtained in another fashion (via calling station identity or MAC + address, in the Name field of the MD5-Challenge Response, etc.). + + [2] The peer sends a Response packet in reply to a valid Request. As + with the Request packet, the Response packet contains a Type + field, which corresponds to the Type field of the Request. + + [3] The authenticator sends an additional Request packet, and the + peer replies with a Response. The sequence of Requests and + Responses continues as long as needed. EAP is a 'lock step' + protocol, so that other than the initial Request, a new Request + cannot be sent prior to receiving a valid Response. The + authenticator is responsible for retransmitting requests as + described in Section 4.1. After a suitable number of + retransmissions, the authenticator SHOULD end the EAP + conversation. The authenticator MUST NOT send a Success or + Failure packet when retransmitting or when it fails to get a + response from the peer. + + [4] The conversation continues until the authenticator cannot + authenticate the peer (unacceptable Responses to one or more + Requests), in which case the authenticator implementation MUST + transmit an EAP Failure (Code 4). Alternatively, the + authentication conversation can continue until the authenticator + determines that successful authentication has occurred, in which + case the authenticator MUST transmit an EAP Success (Code 3). + + Advantages: + + o The EAP protocol can support multiple authentication mechanisms + without having to pre-negotiate a particular one. + + o Network Access Server (NAS) devices (e.g., a switch or access + point) do not have to understand each authentication method and + MAY act as a pass-through agent for a backend authentication + server. Support for pass-through is optional. An authenticator + MAY authenticate local peers, while at the same time acting as a + pass-through for non-local peers and authentication methods it + does not implement locally. + + o Separation of the authenticator from the backend authentication + server simplifies credentials management and policy decision + making. + + + + + + + +Aboba, et al. Standards Track [Page 8] + +RFC 3748 EAP June 2004 + + + Disadvantages: + + o For use in PPP, EAP requires the addition of a new authentication + Type to PPP LCP and thus PPP implementations will need to be + modified to use it. It also strays from the previous PPP + authentication model of negotiating a specific authentication + mechanism during LCP. Similarly, switch or access point + implementations need to support [IEEE-802.1X] in order to use EAP. + + o Where the authenticator is separate from the backend + authentication server, this complicates the security analysis and, + if needed, key distribution. + +2.1. Support for Sequences + + An EAP conversation MAY utilize a sequence of methods. A common + example of this is an Identity request followed by a single EAP + authentication method such as an MD5-Challenge. However, the peer + and authenticator MUST utilize only one authentication method (Type 4 + or greater) within an EAP conversation, after which the authenticator + MUST send a Success or Failure packet. + + Once a peer has sent a Response of the same Type as the initial + Request, an authenticator MUST NOT send a Request of a different Type + prior to completion of the final round of a given method (with the + exception of a Notification-Request) and MUST NOT send a Request for + an additional method of any Type after completion of the initial + authentication method; a peer receiving such Requests MUST treat them + as invalid, and silently discard them. As a result, Identity Requery + is not supported. + + A peer MUST NOT send a Nak (legacy or expanded) in reply to a Request + after an initial non-Nak Response has been sent. Since spoofed EAP + Request packets may be sent by an attacker, an authenticator + receiving an unexpected Nak SHOULD discard it and log the event. + + Multiple authentication methods within an EAP conversation are not + supported due to their vulnerability to man-in-the-middle attacks + (see Section 7.4) and incompatibility with existing implementations. + + Where a single EAP authentication method is utilized, but other + methods are run within it (a "tunneled" method), the prohibition + against multiple authentication methods does not apply. Such + "tunneled" methods appear as a single authentication method to EAP. + Backward compatibility can be provided, since a peer not supporting a + "tunneled" method can reply to the initial EAP-Request with a Nak + + + + + +Aboba, et al. Standards Track [Page 9] + +RFC 3748 EAP June 2004 + + + (legacy or expanded). To address security vulnerabilities, + "tunneled" methods MUST support protection against man-in-the-middle + attacks. + +2.2. EAP Multiplexing Model + + Conceptually, EAP implementations consist of the following + components: + + [a] Lower layer. The lower layer is responsible for transmitting and + receiving EAP frames between the peer and authenticator. EAP has + been run over a variety of lower layers including PPP, wired IEEE + 802 LANs [IEEE-802.1X], IEEE 802.11 wireless LANs [IEEE-802.11], + UDP (L2TP [RFC2661] and IKEv2 [IKEv2]), and TCP [PIC]. Lower + layer behavior is discussed in Section 3. + + [b] EAP layer. The EAP layer receives and transmits EAP packets via + the lower layer, implements duplicate detection and + retransmission, and delivers and receives EAP messages to and + from the EAP peer and authenticator layers. + + [c] EAP peer and authenticator layers. Based on the Code field, the + EAP layer demultiplexes incoming EAP packets to the EAP peer and + authenticator layers. Typically, an EAP implementation on a + given host will support either peer or authenticator + functionality, but it is possible for a host to act as both an + EAP peer and authenticator. In such an implementation both EAP + peer and authenticator layers will be present. + + [d] EAP method layers. EAP methods implement the authentication + algorithms and receive and transmit EAP messages via the EAP peer + and authenticator layers. Since fragmentation support is not + provided by EAP itself, this is the responsibility of EAP + methods, which are discussed in Section 5. + + The EAP multiplexing model is illustrated in Figure 1 below. Note + that there is no requirement that an implementation conform to this + model, as long as the on-the-wire behavior is consistent with it. + + + + + + + + + + + + + +Aboba, et al. Standards Track [Page 10] + +RFC 3748 EAP June 2004 + + + +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ + | | | | | | + | EAP method| EAP method| | EAP method| EAP method| + | Type = X | Type = Y | | Type = X | Type = Y | + | V | | | ^ | | + +-+-+-+-!-+-+-+-+-+-+-+-+ +-+-+-+-!-+-+-+-+-+-+-+-+ + | ! | | ! | + | EAP ! Peer layer | | EAP ! Auth. layer | + | ! | | ! | + +-+-+-+-!-+-+-+-+-+-+-+-+ +-+-+-+-!-+-+-+-+-+-+-+-+ + | ! | | ! | + | EAP ! layer | | EAP ! layer | + | ! | | ! | + +-+-+-+-!-+-+-+-+-+-+-+-+ +-+-+-+-!-+-+-+-+-+-+-+-+ + | ! | | ! | + | Lower ! layer | | Lower ! layer | + | ! | | ! | + +-+-+-+-!-+-+-+-+-+-+-+-+ +-+-+-+-!-+-+-+-+-+-+-+-+ + ! ! + ! Peer ! Authenticator + +------------>-------------+ + + Figure 1: EAP Multiplexing Model + + Within EAP, the Code field functions much like a protocol number in + IP. It is assumed that the EAP layer demultiplexes incoming EAP + packets according to the Code field. Received EAP packets with + Code=1 (Request), 3 (Success), and 4 (Failure) are delivered by the + EAP layer to the EAP peer layer, if implemented. EAP packets with + Code=2 (Response) are delivered to the EAP authenticator layer, if + implemented. + + Within EAP, the Type field functions much like a port number in UDP + or TCP. It is assumed that the EAP peer and authenticator layers + demultiplex incoming EAP packets according to their Type, and deliver + them only to the EAP method corresponding to that Type. An EAP + method implementation on a host may register to receive packets from + the peer or authenticator layers, or both, depending on which role(s) + it supports. + + Since EAP authentication methods may wish to access the Identity, + implementations SHOULD make the Identity Request and Response + accessible to authentication methods (Types 4 or greater), in + addition to the Identity method. The Identity Type is discussed in + Section 5.1. + + + + + + +Aboba, et al. Standards Track [Page 11] + +RFC 3748 EAP June 2004 + + + A Notification Response is only used as confirmation that the peer + received the Notification Request, not that it has processed it, or + displayed the message to the user. It cannot be assumed that the + contents of the Notification Request or Response are available to + another method. The Notification Type is discussed in Section 5.2. + + Nak (Type 3) or Expanded Nak (Type 254) are utilized for the purposes + of method negotiation. Peers respond to an initial EAP Request for + an unacceptable Type with a Nak Response (Type 3) or Expanded Nak + Response (Type 254). It cannot be assumed that the contents of the + Nak Response(s) are available to another method. The Nak Type(s) are + discussed in Section 5.3. + + EAP packets with Codes of Success or Failure do not include a Type + field, and are not delivered to an EAP method. Success and Failure + are discussed in Section 4.2. + + Given these considerations, the Success, Failure, Nak Response(s), + and Notification Request/Response messages MUST NOT be used to carry + data destined for delivery to other EAP methods. + +2.3. Pass-Through Behavior + + When operating as a "pass-through authenticator", an authenticator + performs checks on the Code, Identifier, and Length fields as + described in Section 4.1. It forwards EAP packets received from the + peer and destined to its authenticator layer to the backend + authentication server; packets received from the backend + authentication server destined to the peer are forwarded to it. + + A host receiving an EAP packet may only do one of three things with + it: act on it, drop it, or forward it. The forwarding decision is + typically based only on examination of the Code, Identifier, and + Length fields. A pass-through authenticator implementation MUST be + capable of forwarding EAP packets received from the peer with Code=2 + (Response) to the backend authentication server. It also MUST be + capable of receiving EAP packets from the backend authentication + server and forwarding EAP packets of Code=1 (Request), Code=3 + (Success), and Code=4 (Failure) to the peer. + + Unless the authenticator implements one or more authentication + methods locally which support the authenticator role, the EAP method + layer header fields (Type, Type-Data) are not examined as part of the + forwarding decision. Where the authenticator supports local + authentication methods, it MAY examine the Type field to determine + whether to act on the packet itself or forward it. Compliant pass- + through authenticator implementations MUST by default forward EAP + packets of any Type. + + + +Aboba, et al. Standards Track [Page 12] + +RFC 3748 EAP June 2004 + + + EAP packets received with Code=1 (Request), Code=3 (Success), and + Code=4 (Failure) are demultiplexed by the EAP layer and delivered to + the peer layer. Therefore, unless a host implements an EAP peer + layer, these packets will be silently discarded. Similarly, EAP + packets received with Code=2 (Response) are demultiplexed by the EAP + layer and delivered to the authenticator layer. Therefore, unless a + host implements an EAP authenticator layer, these packets will be + silently discarded. The behavior of a "pass-through peer" is + undefined within this specification, and is unsupported by AAA + protocols such as RADIUS [RFC3579] and Diameter [DIAM-EAP]. + + The forwarding model is illustrated in Figure 2. + + Peer Pass-through Authenticator Authentication + Server + + +-+-+-+-+-+-+ +-+-+-+-+-+-+ + | | | | + |EAP method | |EAP method | + | V | | ^ | + +-+-+-!-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-!-+-+-+ + | ! | |EAP | EAP | | | ! | + | ! | |Peer | Auth.| EAP Auth. | | ! | + |EAP ! peer| | | +-----------+ | |EAP !Auth.| + | ! | | | ! | ! | | ! | + +-+-+-!-+-+-+ +-+-+-+-!-+-+-+-+-+-!-+-+-+-+ +-+-+-!-+-+-+ + | ! | | ! | ! | | ! | + |EAP !layer| | EAP !layer| EAP !layer | |EAP !layer| + | ! | | ! | ! | | ! | + +-+-+-!-+-+-+ +-+-+-+-!-+-+-+-+-+-!-+-+-+-+ +-+-+-!-+-+-+ + | ! | | ! | ! | | ! | + |Lower!layer| | Lower!layer| AAA ! /IP | | AAA ! /IP | + | ! | | ! | ! | | ! | + +-+-+-!-+-+-+ +-+-+-+-!-+-+-+-+-+-!-+-+-+-+ +-+-+-!-+-+-+ + ! ! ! ! + ! ! ! ! + +-------->--------+ +--------->-------+ + + + Figure 2: Pass-through Authenticator + + For sessions in which the authenticator acts as a pass-through, it + MUST determine the outcome of the authentication solely based on the + Accept/Reject indication sent by the backend authentication server; + the outcome MUST NOT be determined by the contents of an EAP packet + sent along with the Accept/Reject indication, or the absence of such + an encapsulated EAP packet. + + + + +Aboba, et al. Standards Track [Page 13] + +RFC 3748 EAP June 2004 + + +2.4. Peer-to-Peer Operation + + Since EAP is a peer-to-peer protocol, an independent and simultaneous + authentication may take place in the reverse direction (depending on + the capabilities of the lower layer). Both ends of the link may act + as authenticators and peers at the same time. In this case, it is + necessary for both ends to implement EAP authenticator and peer + layers. In addition, the EAP method implementations on both peers + must support both authenticator and peer functionality. + + Although EAP supports peer-to-peer operation, some EAP + implementations, methods, AAA protocols, and link layers may not + support this. Some EAP methods may support asymmetric + authentication, with one type of credential being required for the + peer and another type for the authenticator. Hosts supporting peer- + to-peer operation with such a method would need to be provisioned + with both types of credentials. + + For example, EAP-TLS [RFC2716] is a client-server protocol in which + distinct certificate profiles are typically utilized for the client + and server. This implies that a host supporting peer-to-peer + authentication with EAP-TLS would need to implement both the EAP peer + and authenticator layers, support both peer and authenticator roles + in the EAP-TLS implementation, and provision certificates appropriate + for each role. + + AAA protocols such as RADIUS/EAP [RFC3579] and Diameter EAP [DIAM- + EAP] only support "pass-through authenticator" operation. As noted + in [RFC3579] Section 2.6.2, a RADIUS server responds to an Access- + Request encapsulating an EAP-Request, Success, or Failure packet with + an Access-Reject. There is therefore no support for "pass-through + peer" operation. + + Even where a method is used which supports mutual authentication and + result indications, several considerations may dictate that two EAP + authentications (one in each direction) are required. These include: + + [1] Support for bi-directional session key derivation in the lower + layer. Lower layers such as IEEE 802.11 may only support uni- + directional derivation and transport of transient session keys. + For example, the group-key handshake defined in [IEEE-802.11i] is + uni-directional, since in IEEE 802.11 infrastructure mode, only + the Access Point (AP) sends multicast/broadcast traffic. In IEEE + 802.11 ad hoc mode, where either peer may send + multicast/broadcast traffic, two uni-directional group-key + + + + + + +Aboba, et al. Standards Track [Page 14] + +RFC 3748 EAP June 2004 + + + exchanges are required. Due to limitations of the design, this + also implies the need for unicast key derivations and EAP method + exchanges to occur in each direction. + + [2] Support for tie-breaking in the lower layer. Lower layers such + as IEEE 802.11 ad hoc do not support "tie breaking" wherein two + hosts initiating authentication with each other will only go + forward with a single authentication. This implies that even if + 802.11 were to support a bi-directional group-key handshake, then + two authentications, one in each direction, might still occur. + + [3] Peer policy satisfaction. EAP methods may support result + indications, enabling the peer to indicate to the EAP server + within the method that it successfully authenticated the EAP + server, as well as for the server to indicate that it has + authenticated the peer. However, a pass-through authenticator + will not be aware that the peer has accepted the credentials + offered by the EAP server, unless this information is provided to + the authenticator via the AAA protocol. The authenticator SHOULD + interpret the receipt of a key attribute within an Accept packet + as an indication that the peer has successfully authenticated the + server. + + However, it is possible that the EAP peer's access policy was not + satisfied during the initial EAP exchange, even though mutual + authentication occurred. For example, the EAP authenticator may not + have demonstrated authorization to act in both peer and authenticator + roles. As a result, the peer may require an additional + authentication in the reverse direction, even if the peer provided an + indication that the EAP server had successfully authenticated to it. + +3. Lower Layer Behavior + +3.1. Lower Layer Requirements + + EAP makes the following assumptions about lower layers: + + [1] Unreliable transport. In EAP, the authenticator retransmits + Requests that have not yet received Responses so that EAP does + not assume that lower layers are reliable. Since EAP defines its + own retransmission behavior, it is possible (though undesirable) + for retransmission to occur both in the lower layer and the EAP + layer when EAP is run over a reliable lower layer. + + + + + + + + +Aboba, et al. Standards Track [Page 15] + +RFC 3748 EAP June 2004 + + + Note that EAP Success and Failure packets are not retransmitted. + Without a reliable lower layer, and with a non-negligible error rate, + these packets can be lost, resulting in timeouts. It is therefore + desirable for implementations to improve their resilience to loss of + EAP Success or Failure packets, as described in Section 4.2. + + [2] Lower layer error detection. While EAP does not assume that the + lower layer is reliable, it does rely on lower layer error + detection (e.g., CRC, Checksum, MIC, etc.). EAP methods may not + include a MIC, or if they do, it may not be computed over all the + fields in the EAP packet, such as the Code, Identifier, Length, + or Type fields. As a result, without lower layer error + detection, undetected errors could creep into the EAP layer or + EAP method layer header fields, resulting in authentication + failures. + + For example, EAP TLS [RFC2716], which computes its MIC over the + Type-Data field only, regards MIC validation failures as a fatal + error. Without lower layer error detection, this method, and + others like it, will not perform reliably. + + [3] Lower layer security. EAP does not require lower layers to + provide security services such as per-packet confidentiality, + authentication, integrity, and replay protection. However, where + these security services are available, EAP methods supporting Key + Derivation (see Section 7.2.1) can be used to provide dynamic + keying material. This makes it possible to bind the EAP + authentication to subsequent data and protect against data + modification, spoofing, or replay. See Section 7.1 for details. + + [4] Minimum MTU. EAP is capable of functioning on lower layers that + provide an EAP MTU size of 1020 octets or greater. + + EAP does not support path MTU discovery, and fragmentation and + reassembly is not supported by EAP, nor by the methods defined in + this specification: Identity (1), Notification (2), Nak Response + (3), MD5-Challenge (4), One Time Password (5), Generic Token Card + (6), and expanded Nak Response (254) Types. + + Typically, the EAP peer obtains information on the EAP MTU from + the lower layers and sets the EAP frame size to an appropriate + value. Where the authenticator operates in pass-through mode, + the authentication server does not have a direct way of + determining the EAP MTU, and therefore relies on the + authenticator to provide it with this information, such as via + the Framed-MTU attribute, as described in [RFC3579], Section 2.4. + + + + + +Aboba, et al. Standards Track [Page 16] + +RFC 3748 EAP June 2004 + + + While methods such as EAP-TLS [RFC2716] support fragmentation and + reassembly, EAP methods originally designed for use within PPP + where a 1500 octet MTU is guaranteed for control frames (see + [RFC1661], Section 6.1) may lack fragmentation and reassembly + features. + + EAP methods can assume a minimum EAP MTU of 1020 octets in the + absence of other information. EAP methods SHOULD include support + for fragmentation and reassembly if their payloads can be larger + than this minimum EAP MTU. + + EAP is a lock-step protocol, which implies a certain inefficiency + when handling fragmentation and reassembly. Therefore, if the + lower layer supports fragmentation and reassembly (such as where + EAP is transported over IP), it may be preferable for + fragmentation and reassembly to occur in the lower layer rather + than in EAP. This can be accomplished by providing an + artificially large EAP MTU to EAP, causing fragmentation and + reassembly to be handled within the lower layer. + + [5] Possible duplication. Where the lower layer is reliable, it will + provide the EAP layer with a non-duplicated stream of packets. + However, while it is desirable that lower layers provide for + non-duplication, this is not a requirement. The Identifier field + provides both the peer and authenticator with the ability to + detect duplicates. + + [6] Ordering guarantees. EAP does not require the Identifier to be + monotonically increasing, and so is reliant on lower layer + ordering guarantees for correct operation. EAP was originally + defined to run on PPP, and [RFC1661] Section 1 has an ordering + requirement: + + "The Point-to-Point Protocol is designed for simple links + which transport packets between two peers. These links + provide full-duplex simultaneous bi-directional operation, + and are assumed to deliver packets in order." + + Lower layer transports for EAP MUST preserve ordering between a + source and destination at a given priority level (the ordering + guarantee provided by [IEEE-802]). + + Reordering, if it occurs, will typically result in an EAP + authentication failure, causing EAP authentication to be re-run. + In an environment in which reordering is likely, it is therefore + expected that EAP authentication failures will be common. It is + RECOMMENDED that EAP only be run over lower layers that provide + ordering guarantees; running EAP over raw IP or UDP transport is + + + +Aboba, et al. Standards Track [Page 17] + +RFC 3748 EAP June 2004 + + + NOT RECOMMENDED. Encapsulation of EAP within RADIUS [RFC3579] + satisfies ordering requirements, since RADIUS is a "lockstep" + protocol that delivers packets in order. + +3.2. EAP Usage Within PPP + + In order to establish communications over a point-to-point link, each + end of the PPP link first sends LCP packets to configure the data + link during the Link Establishment phase. After the link has been + established, PPP provides for an optional Authentication phase before + proceeding to the Network-Layer Protocol phase. + + By default, authentication is not mandatory. If authentication of + the link is desired, an implementation MUST specify the + Authentication Protocol Configuration Option during the Link + Establishment phase. + + If the identity of the peer has been established in the + Authentication phase, the server can use that identity in the + selection of options for the following network layer negotiations. + + When implemented within PPP, EAP does not select a specific + authentication mechanism at the PPP Link Control Phase, but rather + postpones this until the Authentication Phase. This allows the + authenticator to request more information before determining the + specific authentication mechanism. This also permits the use of a + "backend" server which actually implements the various mechanisms + while the PPP authenticator merely passes through the authentication + exchange. The PPP Link Establishment and Authentication phases, and + the Authentication Protocol Configuration Option, are defined in The + Point-to-Point Protocol (PPP) [RFC1661]. + +3.2.1. PPP Configuration Option Format + + A summary of the PPP Authentication Protocol Configuration Option + format to negotiate EAP follows. The fields are transmitted from + left to right. + + Exactly one EAP packet is encapsulated in the Information field of a + PPP Data Link Layer frame where the protocol field indicates type hex + C227 (PPP EAP). + + + + + + + + + + +Aboba, et al. Standards Track [Page 18] + +RFC 3748 EAP June 2004 + + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Length | Authentication Protocol | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Type + + 3 + + Length + + 4 + + Authentication Protocol + + C227 (Hex) for Extensible Authentication Protocol (EAP) + +3.3. EAP Usage Within IEEE 802 + + The encapsulation of EAP over IEEE 802 is defined in [IEEE-802.1X]. + The IEEE 802 encapsulation of EAP does not involve PPP, and IEEE + 802.1X does not include support for link or network layer + negotiations. As a result, within IEEE 802.1X, it is not possible to + negotiate non-EAP authentication mechanisms, such as PAP or CHAP + [RFC1994]. + +3.4. Lower Layer Indications + + The reliability and security of lower layer indications is dependent + on the lower layer. Since EAP is media independent, the presence or + absence of lower layer security is not taken into account in the + processing of EAP messages. + + To improve reliability, if a peer receives a lower layer success + indication as defined in Section 7.2, it MAY conclude that a Success + packet has been lost, and behave as if it had actually received a + Success packet. This includes choosing to ignore the Success in some + circumstances as described in Section 4.2. + + A discussion of some reliability and security issues with lower layer + indications in PPP, IEEE 802 wired networks, and IEEE 802.11 wireless + LANs can be found in the Security Considerations, Section 7.12. + + After EAP authentication is complete, the peer will typically + transmit and receive data via the authenticator. It is desirable to + provide assurance that the entities transmitting data are the same + ones that successfully completed EAP authentication. To accomplish + + + +Aboba, et al. Standards Track [Page 19] + +RFC 3748 EAP June 2004 + + + this, it is necessary for the lower layer to provide per-packet + integrity, authentication and replay protection, and to bind these + per-packet services to the keys derived during EAP authentication. + Otherwise, it is possible for subsequent data traffic to be modified, + spoofed, or replayed. + + Where keying material for the lower layer ciphersuite is itself + provided by EAP, ciphersuite negotiation and key activation are + controlled by the lower layer. In PPP, ciphersuites are negotiated + within ECP so that it is not possible to use keys derived from EAP + authentication until the completion of ECP. Therefore, an initial + EAP exchange cannot be protected by a PPP ciphersuite, although EAP + re-authentication can be protected. + + In IEEE 802 media, initial key activation also typically occurs after + completion of EAP authentication. Therefore an initial EAP exchange + typically cannot be protected by the lower layer ciphersuite, + although an EAP re-authentication or pre-authentication exchange can + be protected. + +4. EAP Packet Format + + A summary of the EAP packet format is shown below. The fields are + transmitted from left to right. + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Code | Identifier | Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Data ... + +-+-+-+-+ + + Code + + The Code field is one octet and identifies the Type of EAP packet. + EAP Codes are assigned as follows: + + 1 Request + 2 Response + 3 Success + 4 Failure + + Since EAP only defines Codes 1-4, EAP packets with other codes + MUST be silently discarded by both authenticators and peers. + + + + + + +Aboba, et al. Standards Track [Page 20] + +RFC 3748 EAP June 2004 + + + Identifier + + The Identifier field is one octet and aids in matching Responses + with Requests. + + Length + + The Length field is two octets and indicates the length, in + octets, of the EAP packet including the Code, Identifier, Length, + and Data fields. Octets outside the range of the Length field + should be treated as Data Link Layer padding and MUST be ignored + upon reception. A message with the Length field set to a value + larger than the number of received octets MUST be silently + discarded. + + Data + + The Data field is zero or more octets. The format of the Data + field is determined by the Code field. + +4.1. Request and Response + + Description + + The Request packet (Code field set to 1) is sent by the + authenticator to the peer. Each Request has a Type field which + serves to indicate what is being requested. Additional Request + packets MUST be sent until a valid Response packet is received, an + optional retry counter expires, or a lower layer failure + indication is received. + + Retransmitted Requests MUST be sent with the same Identifier value + in order to distinguish them from new Requests. The content of + the data field is dependent on the Request Type. The peer MUST + send a Response packet in reply to a valid Request packet. + Responses MUST only be sent in reply to a valid Request and never + be retransmitted on a timer. + + If a peer receives a valid duplicate Request for which it has + already sent a Response, it MUST resend its original Response + without reprocessing the Request. Requests MUST be processed in + the order that they are received, and MUST be processed to their + completion before inspecting the next Request. + + A summary of the Request and Response packet format follows. The + fields are transmitted from left to right. + + + + + +Aboba, et al. Standards Track [Page 21] + +RFC 3748 EAP June 2004 + + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Code | Identifier | Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Type-Data ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- + + Code + + 1 for Request + 2 for Response + + Identifier + + The Identifier field is one octet. The Identifier field MUST be + the same if a Request packet is retransmitted due to a timeout + while waiting for a Response. Any new (non-retransmission) + Requests MUST modify the Identifier field. + + The Identifier field of the Response MUST match that of the + currently outstanding Request. An authenticator receiving a + Response whose Identifier value does not match that of the + currently outstanding Request MUST silently discard the Response. + + In order to avoid confusion between new Requests and + retransmissions, the Identifier value chosen for each new Request + need only be different from the previous Request, but need not be + unique within the conversation. One way to achieve this is to + start the Identifier at an initial value and increment it for each + new Request. Initializing the first Identifier with a random + number rather than starting from zero is recommended, since it + makes sequence attacks somewhat more difficult. + + Since the Identifier space is unique to each session, + authenticators are not restricted to only 256 simultaneous + authentication conversations. Similarly, with re-authentication, + an EAP conversation might continue over a long period of time, and + is not limited to only 256 roundtrips. + + Implementation Note: The authenticator is responsible for + retransmitting Request messages. If the Request message is obtained + from elsewhere (such as from a backend authentication server), then + the authenticator will need to save a copy of the Request in order to + accomplish this. The peer is responsible for detecting and handling + duplicate Request messages before processing them in any way, + including passing them on to an outside party. The authenticator is + also responsible for discarding Response messages with a non-matching + + + +Aboba, et al. Standards Track [Page 22] + +RFC 3748 EAP June 2004 + + + Identifier value before acting on them in any way, including passing + them on to the backend authentication server for verification. Since + the authenticator can retransmit before receiving a Response from the + peer, the authenticator can receive multiple Responses, each with a + matching Identifier. Until a new Request is received by the + authenticator, the Identifier value is not updated, so that the + authenticator forwards Responses to the backend authentication + server, one at a time. + + Length + + The Length field is two octets and indicates the length of the EAP + packet including the Code, Identifier, Length, Type, and Type-Data + fields. Octets outside the range of the Length field should be + treated as Data Link Layer padding and MUST be ignored upon + reception. A message with the Length field set to a value larger + than the number of received octets MUST be silently discarded. + + Type + + The Type field is one octet. This field indicates the Type of + Request or Response. A single Type MUST be specified for each EAP + Request or Response. An initial specification of Types follows in + Section 5 of this document. + + The Type field of a Response MUST either match that of the + Request, or correspond to a legacy or Expanded Nak (see Section + 5.3) indicating that a Request Type is unacceptable to the peer. + A peer MUST NOT send a Nak (legacy or expanded) in response to a + Request, after an initial non-Nak Response has been sent. An EAP + server receiving a Response not meeting these requirements MUST + silently discard it. + + Type-Data + + The Type-Data field varies with the Type of Request and the + associated Response. + +4.2. Success and Failure + + The Success packet is sent by the authenticator to the peer after + completion of an EAP authentication method (Type 4 or greater) to + indicate that the peer has authenticated successfully to the + authenticator. The authenticator MUST transmit an EAP packet with + the Code field set to 3 (Success). If the authenticator cannot + authenticate the peer (unacceptable Responses to one or more + Requests), then after unsuccessful completion of the EAP method in + progress, the implementation MUST transmit an EAP packet with the + + + +Aboba, et al. Standards Track [Page 23] + +RFC 3748 EAP June 2004 + + + Code field set to 4 (Failure). An authenticator MAY wish to issue + multiple Requests before sending a Failure response in order to allow + for human typing mistakes. Success and Failure packets MUST NOT + contain additional data. + + Success and Failure packets MUST NOT be sent by an EAP authenticator + if the specification of the given method does not explicitly permit + the method to finish at that point. A peer EAP implementation + receiving a Success or Failure packet where sending one is not + explicitly permitted MUST silently discard it. By default, an EAP + peer MUST silently discard a "canned" Success packet (a Success + packet sent immediately upon connection). This ensures that a rogue + authenticator will not be able to bypass mutual authentication by + sending a Success packet prior to conclusion of the EAP method + conversation. + + Implementation Note: Because the Success and Failure packets are not + acknowledged, they are not retransmitted by the authenticator, and + may be potentially lost. A peer MUST allow for this circumstance as + described in this note. See also Section 3.4 for guidance on the + processing of lower layer success and failure indications. + + As described in Section 2.1, only a single EAP authentication method + is allowed within an EAP conversation. EAP methods may implement + result indications. After the authenticator sends a failure result + indication to the peer, regardless of the response from the peer, it + MUST subsequently send a Failure packet. After the authenticator + sends a success result indication to the peer and receives a success + result indication from the peer, it MUST subsequently send a Success + packet. + + On the peer, once the method completes unsuccessfully (that is, + either the authenticator sends a failure result indication, or the + peer decides that it does not want to continue the conversation, + possibly after sending a failure result indication), the peer MUST + terminate the conversation and indicate failure to the lower layer. + The peer MUST silently discard Success packets and MAY silently + discard Failure packets. As a result, loss of a Failure packet need + not result in a timeout. + + On the peer, after success result indications have been exchanged by + both sides, a Failure packet MUST be silently discarded. The peer + MAY, in the event that an EAP Success is not received, conclude that + the EAP Success packet was lost and that authentication concluded + successfully. + + + + + + +Aboba, et al. Standards Track [Page 24] + +RFC 3748 EAP June 2004 + + + If the authenticator has not sent a result indication, and the peer + is willing to continue the conversation, the peer waits for a Success + or Failure packet once the method completes, and MUST NOT silently + discard either of them. In the event that neither a Success nor + Failure packet is received, the peer SHOULD terminate the + conversation to avoid lengthy timeouts in case the lost packet was an + EAP Failure. + + If the peer attempts to authenticate to the authenticator and fails + to do so, the authenticator MUST send a Failure packet and MUST NOT + grant access by sending a Success packet. However, an authenticator + MAY omit having the peer authenticate to it in situations where + limited access is offered (e.g., guest access). In this case, the + authenticator MUST send a Success packet. + + Where the peer authenticates successfully to the authenticator, but + the authenticator does not send a result indication, the + authenticator MAY deny access by sending a Failure packet where the + peer is not currently authorized for network access. + + A summary of the Success and Failure packet format is shown below. + The fields are transmitted from left to right. + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Code | Identifier | Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Code + + 3 for Success + 4 for Failure + + Identifier + + The Identifier field is one octet and aids in matching replies to + Responses. The Identifier field MUST match the Identifier field + of the Response packet that it is sent in response to. + + Length + + 4 + + + + + + + + +Aboba, et al. Standards Track [Page 25] + +RFC 3748 EAP June 2004 + + +4.3. Retransmission Behavior + + Because the authentication process will often involve user input, + some care must be taken when deciding upon retransmission strategies + and authentication timeouts. By default, where EAP is run over an + unreliable lower layer, the EAP retransmission timer SHOULD be + dynamically estimated. A maximum of 3-5 retransmissions is + suggested. + + When run over a reliable lower layer (e.g., EAP over ISAKMP/TCP, as + within [PIC]), the authenticator retransmission timer SHOULD be set + to an infinite value, so that retransmissions do not occur at the EAP + layer. The peer may still maintain a timeout value so as to avoid + waiting indefinitely for a Request. + + Where the authentication process requires user input, the measured + round trip times may be determined by user responsiveness rather than + network characteristics, so that dynamic RTO estimation may not be + helpful. Instead, the retransmission timer SHOULD be set so as to + provide sufficient time for the user to respond, with longer timeouts + required in certain cases, such as where Token Cards (see Section + 5.6) are involved. + + In order to provide the EAP authenticator with guidance as to the + appropriate timeout value, a hint can be communicated to the + authenticator by the backend authentication server (such as via the + RADIUS Session-Timeout attribute). + + In order to dynamically estimate the EAP retransmission timer, the + algorithms for the estimation of SRTT, RTTVAR, and RTO described in + [RFC2988] are RECOMMENDED, including use of Karn's algorithm, with + the following potential modifications: + + [a] In order to avoid synchronization behaviors that can occur with + fixed timers among distributed systems, the retransmission timer + is calculated with a jitter by using the RTO value and randomly + adding a value drawn between -RTOmin/2 and RTOmin/2. Alternative + calculations to create jitter MAY be used. These MUST be + pseudo-random. For a discussion of pseudo-random number + generation, see [RFC1750]. + + [b] When EAP is transported over a single link (as opposed to over + the Internet), smaller values of RTOinitial, RTOmin, and RTOmax + MAY be used. Recommended values are RTOinitial=1 second, + RTOmin=200ms, and RTOmax=20 seconds. + + + + + + +Aboba, et al. Standards Track [Page 26] + +RFC 3748 EAP June 2004 + + + [c] When EAP is transported over a single link (as opposed to over + the Internet), estimates MAY be done on a per-authenticator + basis, rather than a per-session basis. This enables the + retransmission estimate to make the most use of information on + link-layer behavior. + + [d] An EAP implementation MAY clear SRTT and RTTVAR after backing off + the timer multiple times, as it is likely that the current SRTT + and RTTVAR are bogus in this situation. Once SRTT and RTTVAR are + cleared, they should be initialized with the next RTT sample + taken as described in [RFC2988] equation 2.2. + +5. Initial EAP Request/Response Types + + This section defines the initial set of EAP Types used in Request/ + Response exchanges. More Types may be defined in future documents. + The Type field is one octet and identifies the structure of an EAP + Request or Response packet. The first 3 Types are considered special + case Types. + + The remaining Types define authentication exchanges. Nak (Type 3) or + Expanded Nak (Type 254) are valid only for Response packets, they + MUST NOT be sent in a Request. + + All EAP implementations MUST support Types 1-4, which are defined in + this document, and SHOULD support Type 254. Implementations MAY + support other Types defined here or in future RFCs. + + 1 Identity + 2 Notification + 3 Nak (Response only) + 4 MD5-Challenge + 5 One Time Password (OTP) + 6 Generic Token Card (GTC) + 254 Expanded Types + 255 Experimental use + + EAP methods MAY support authentication based on shared secrets. If + the shared secret is a passphrase entered by the user, + implementations MAY support entering passphrases with non-ASCII + characters. In this case, the input should be processed using an + appropriate stringprep [RFC3454] profile, and encoded in octets using + UTF-8 encoding [RFC2279]. A preliminary version of a possible + stringprep profile is described in [SASLPREP]. + + + + + + + +Aboba, et al. Standards Track [Page 27] + +RFC 3748 EAP June 2004 + + +5.1. Identity + + Description + + The Identity Type is used to query the identity of the peer. + Generally, the authenticator will issue this as the initial + Request. An optional displayable message MAY be included to + prompt the peer in the case where there is an expectation of + interaction with a user. A Response of Type 1 (Identity) SHOULD + be sent in Response to a Request with a Type of 1 (Identity). + + Some EAP implementations piggy-back various options into the + Identity Request after a NUL-character. By default, an EAP + implementation SHOULD NOT assume that an Identity Request or + Response can be larger than 1020 octets. + + It is RECOMMENDED that the Identity Response be used primarily for + routing purposes and selecting which EAP method to use. EAP + Methods SHOULD include a method-specific mechanism for obtaining + the identity, so that they do not have to rely on the Identity + Response. Identity Requests and Responses are sent in cleartext, + so an attacker may snoop on the identity, or even modify or spoof + identity exchanges. To address these threats, it is preferable + for an EAP method to include an identity exchange that supports + per-packet authentication, integrity and replay protection, and + confidentiality. The Identity Response may not be the appropriate + identity for the method; it may have been truncated or obfuscated + so as to provide privacy, or it may have been decorated for + routing purposes. Where the peer is configured to only accept + authentication methods supporting protected identity exchanges, + the peer MAY provide an abbreviated Identity Response (such as + omitting the peer-name portion of the NAI [RFC2486]). For further + discussion of identity protection, see Section 7.3. + + Implementation Note: The peer MAY obtain the Identity via user input. + It is suggested that the authenticator retry the Identity Request in + the case of an invalid Identity or authentication failure to allow + for potential typos on the part of the user. It is suggested that + the Identity Request be retried a minimum of 3 times before + terminating the authentication. The Notification Request MAY be used + to indicate an invalid authentication attempt prior to transmitting a + new Identity Request (optionally, the failure MAY be indicated within + the message of the new Identity Request itself). + + + + + + + + +Aboba, et al. Standards Track [Page 28] + +RFC 3748 EAP June 2004 + + + Type + + 1 + + Type-Data + + This field MAY contain a displayable message in the Request, + containing UTF-8 encoded ISO 10646 characters [RFC2279]. Where + the Request contains a null, only the portion of the field prior + to the null is displayed. If the Identity is unknown, the + Identity Response field should be zero bytes in length. The + Identity Response field MUST NOT be null terminated. In all + cases, the length of the Type-Data field is derived from the + Length field of the Request/Response packet. + + Security Claims (see Section 7.2): + + Auth. mechanism: None + Ciphersuite negotiation: No + Mutual authentication: No + Integrity protection: No + Replay protection: No + Confidentiality: No + Key derivation: No + Key strength: N/A + Dictionary attack prot.: N/A + Fast reconnect: No + Crypt. binding: N/A + Session independence: N/A + Fragmentation: No + Channel binding: No + +5.2. Notification + + Description + + The Notification Type is optionally used to convey a displayable + message from the authenticator to the peer. An authenticator MAY + send a Notification Request to the peer at any time when there is + no outstanding Request, prior to completion of an EAP + authentication method. The peer MUST respond to a Notification + Request with a Notification Response unless the EAP authentication + method specification prohibits the use of Notification messages. + In any case, a Nak Response MUST NOT be sent in response to a + Notification Request. Note that the default maximum length of a + Notification Request is 1020 octets. By default, this leaves at + most 1015 octets for the human readable message. + + + + +Aboba, et al. Standards Track [Page 29] + +RFC 3748 EAP June 2004 + + + An EAP method MAY indicate within its specification that + Notification messages must not be sent during that method. In + this case, the peer MUST silently discard Notification Requests + from the point where an initial Request for that Type is answered + with a Response of the same Type. + + The peer SHOULD display this message to the user or log it if it + cannot be displayed. The Notification Type is intended to provide + an acknowledged notification of some imperative nature, but it is + not an error indication, and therefore does not change the state + of the peer. Examples include a password with an expiration time + that is about to expire, an OTP sequence integer which is nearing + 0, an authentication failure warning, etc. In most circumstances, + Notification should not be required. + + Type + + 2 + + Type-Data + + The Type-Data field in the Request contains a displayable message + greater than zero octets in length, containing UTF-8 encoded ISO + 10646 characters [RFC2279]. The length of the message is + determined by the Length field of the Request packet. The message + MUST NOT be null terminated. A Response MUST be sent in reply to + the Request with a Type field of 2 (Notification). The Type-Data + field of the Response is zero octets in length. The Response + should be sent immediately (independent of how the message is + displayed or logged). + + Security Claims (see Section 7.2): + + Auth. mechanism: None + Ciphersuite negotiation: No + Mutual authentication: No + Integrity protection: No + Replay protection: No + Confidentiality: No + Key derivation: No + Key strength: N/A + Dictionary attack prot.: N/A + Fast reconnect: No + Crypt. binding: N/A + Session independence: N/A + Fragmentation: No + Channel binding: No + + + + +Aboba, et al. Standards Track [Page 30] + +RFC 3748 EAP June 2004 + + +5.3. Nak + +5.3.1. Legacy Nak + + Description + + The legacy Nak Type is valid only in Response messages. It is + sent in reply to a Request where the desired authentication Type + is unacceptable. Authentication Types are numbered 4 and above. + The Response contains one or more authentication Types desired by + the Peer. Type zero (0) is used to indicate that the sender has + no viable alternatives, and therefore the authenticator SHOULD NOT + send another Request after receiving a Nak Response containing a + zero value. + + Since the legacy Nak Type is valid only in Responses and has very + limited functionality, it MUST NOT be used as a general purpose + error indication, such as for communication of error messages, or + negotiation of parameters specific to a particular EAP method. + + Code + + 2 for Response. + + Identifier + + The Identifier field is one octet and aids in matching Responses + with Requests. The Identifier field of a legacy Nak Response MUST + match the Identifier field of the Request packet that it is sent + in response to. + + Length + + >=6 + + Type + + 3 + + Type-Data + + Where a peer receives a Request for an unacceptable authentication + Type (4-253,255), or a peer lacking support for Expanded Types + receives a Request for Type 254, a Nak Response (Type 3) MUST be + sent. The Type-Data field of the Nak Response (Type 3) MUST + contain one or more octets indicating the desired authentication + Type(s), one octet per Type, or the value zero (0) to indicate no + proposed alternative. A peer supporting Expanded Types that + + + +Aboba, et al. Standards Track [Page 31] + +RFC 3748 EAP June 2004 + + + receives a Request for an unacceptable authentication Type (4-253, + 255) MAY include the value 254 in the Nak Response (Type 3) to + indicate the desire for an Expanded authentication Type. If the + authenticator can accommodate this preference, it will respond + with an Expanded Type Request (Type 254). + + Security Claims (see Section 7.2): + + Auth. mechanism: None + Ciphersuite negotiation: No + Mutual authentication: No + Integrity protection: No + Replay protection: No + Confidentiality: No + Key derivation: No + Key strength: N/A + Dictionary attack prot.: N/A + Fast reconnect: No + Crypt. binding: N/A + Session independence: N/A + Fragmentation: No + Channel binding: No + + +5.3.2. Expanded Nak + + Description + + The Expanded Nak Type is valid only in Response messages. It MUST + be sent only in reply to a Request of Type 254 (Expanded Type) + where the authentication Type is unacceptable. The Expanded Nak + Type uses the Expanded Type format itself, and the Response + contains one or more authentication Types desired by the peer, all + in Expanded Type format. Type zero (0) is used to indicate that + the sender has no viable alternatives. The general format of the + Expanded Type is described in Section 5.7. + + Since the Expanded Nak Type is valid only in Responses and has + very limited functionality, it MUST NOT be used as a general + purpose error indication, such as for communication of error + messages, or negotiation of parameters specific to a particular + EAP method. + + Code + + 2 for Response. + + + + + +Aboba, et al. Standards Track [Page 32] + +RFC 3748 EAP June 2004 + + + Identifier + + The Identifier field is one octet and aids in matching Responses + with Requests. The Identifier field of an Expanded Nak Response + MUST match the Identifier field of the Request packet that it is + sent in response to. + + Length + + >=20 + + Type + + 254 + + Vendor-Id + + 0 (IETF) + + Vendor-Type + + 3 (Nak) + + Vendor-Data + + The Expanded Nak Type is only sent when the Request contains an + Expanded Type (254) as defined in Section 5.7. The Vendor-Data + field of the Nak Response MUST contain one or more authentication + Types (4 or greater), all in expanded format, 8 octets per Type, + or the value zero (0), also in Expanded Type format, to indicate + no proposed alternative. The desired authentication Types may + include a mixture of Vendor-Specific and IETF Types. For example, + an Expanded Nak Response indicating a preference for OTP (Type 5), + and an MIT (Vendor-Id=20) Expanded Type of 6 would appear as + follows: + + + + + + + + + + + + + + + + +Aboba, et al. Standards Track [Page 33] + +RFC 3748 EAP June 2004 + + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 2 | Identifier | Length=28 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type=254 | 0 (IETF) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 3 (Nak) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type=254 | 0 (IETF) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 5 (OTP) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type=254 | 20 (MIT) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 6 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + An Expanded Nak Response indicating a no desired alternative would + appear as follows: + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 2 | Identifier | Length=20 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type=254 | 0 (IETF) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 3 (Nak) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type=254 | 0 (IETF) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 0 (No alternative) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Security Claims (see Section 7.2): + + Auth. mechanism: None + Ciphersuite negotiation: No + Mutual authentication: No + Integrity protection: No + Replay protection: No + Confidentiality: No + Key derivation: No + Key strength: N/A + Dictionary attack prot.: N/A + Fast reconnect: No + Crypt. binding: N/A + + + +Aboba, et al. Standards Track [Page 34] + +RFC 3748 EAP June 2004 + + + Session independence: N/A + Fragmentation: No + Channel binding: No + + +5.4. MD5-Challenge + + Description + + The MD5-Challenge Type is analogous to the PPP CHAP protocol + [RFC1994] (with MD5 as the specified algorithm). The Request + contains a "challenge" message to the peer. A Response MUST be + sent in reply to the Request. The Response MAY be either of Type + 4 (MD5-Challenge), Nak (Type 3), or Expanded Nak (Type 254). The + Nak reply indicates the peer's desired authentication Type(s). + EAP peer and EAP server implementations MUST support the MD5- + Challenge mechanism. An authenticator that supports only pass- + through MUST allow communication with a backend authentication + server that is capable of supporting MD5-Challenge, although the + EAP authenticator implementation need not support MD5-Challenge + itself. However, if the EAP authenticator can be configured to + authenticate peers locally (e.g., not operate in pass-through), + then the requirement for support of the MD5-Challenge mechanism + applies. + + Note that the use of the Identifier field in the MD5-Challenge + Type is different from that described in [RFC1994]. EAP allows + for retransmission of MD5-Challenge Request packets, while + [RFC1994] states that both the Identifier and Challenge fields + MUST change each time a Challenge (the CHAP equivalent of the + MD5-Challenge Request packet) is sent. + + Note: [RFC1994] treats the shared secret as an octet string, and + does not specify how it is entered into the system (or if it is + handled by the user at all). EAP MD5-Challenge implementations + MAY support entering passphrases with non-ASCII characters. See + Section 5 for instructions how the input should be processed and + encoded into octets. + + Type + + 4 + + Type-Data + + The contents of the Type-Data field is summarized below. For + reference on the use of these fields, see the PPP Challenge + Handshake Authentication Protocol [RFC1994]. + + + +Aboba, et al. Standards Track [Page 35] + +RFC 3748 EAP June 2004 + + + 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 ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Security Claims (see Section 7.2): + + Auth. mechanism: Password or pre-shared key. + Ciphersuite negotiation: No + Mutual authentication: No + Integrity protection: No + Replay protection: No + Confidentiality: No + Key derivation: No + Key strength: N/A + Dictionary attack prot.: No + Fast reconnect: No + Crypt. binding: N/A + Session independence: N/A + Fragmentation: No + Channel binding: No + +5.5. One-Time Password (OTP) + + Description + + The One-Time Password system is defined in "A One-Time Password + System" [RFC2289] and "OTP Extended Responses" [RFC2243]. The + Request contains an OTP challenge in the format described in + [RFC2289]. A Response MUST be sent in reply to the Request. The + Response MUST be of Type 5 (OTP), Nak (Type 3), or Expanded Nak + (Type 254). The Nak Response indicates the peer's desired + authentication Type(s). The EAP OTP method is intended for use + with the One-Time Password system only, and MUST NOT be used to + provide support for cleartext passwords. + + Type + + 5 + + + + + + + + + +Aboba, et al. Standards Track [Page 36] + +RFC 3748 EAP June 2004 + + + Type-Data + + The Type-Data field contains the OTP "challenge" as a displayable + message in the Request. In the Response, this field is used for + the 6 words from the OTP dictionary [RFC2289]. The messages MUST + NOT be null terminated. The length of the field is derived from + the Length field of the Request/Reply packet. + + Note: [RFC2289] does not specify how the secret pass-phrase is + entered by the user, or how the pass-phrase is converted into + octets. EAP OTP implementations MAY support entering passphrases + with non-ASCII characters. See Section 5 for instructions on how + the input should be processed and encoded into octets. + + Security Claims (see Section 7.2): + + Auth. mechanism: One-Time Password + Ciphersuite negotiation: No + Mutual authentication: No + Integrity protection: No + Replay protection: Yes + Confidentiality: No + Key derivation: No + Key strength: N/A + Dictionary attack prot.: No + Fast reconnect: No + Crypt. binding: N/A + Session independence: N/A + Fragmentation: No + Channel binding: No + + +5.6. Generic Token Card (GTC) + + Description + + The Generic Token Card Type is defined for use with various Token + Card implementations which require user input. The Request + contains a displayable message and the Response contains the Token + Card information necessary for authentication. Typically, this + would be information read by a user from the Token card device and + entered as ASCII text. A Response MUST be sent in reply to the + Request. The Response MUST be of Type 6 (GTC), Nak (Type 3), or + Expanded Nak (Type 254). The Nak Response indicates the peer's + desired authentication Type(s). The EAP GTC method is intended + for use with the Token Cards supporting challenge/response + + + + + +Aboba, et al. Standards Track [Page 37] + +RFC 3748 EAP June 2004 + + + authentication and MUST NOT be used to provide support for + cleartext passwords in the absence of a protected tunnel with + server authentication. + + Type + + 6 + + Type-Data + + The Type-Data field in the Request contains a displayable message + greater than zero octets in length. The length of the message is + determined by the Length field of the Request packet. The message + MUST NOT be null terminated. A Response MUST be sent in reply to + the Request with a Type field of 6 (Generic Token Card). The + Response contains data from the Token Card required for + authentication. The length of the data is determined by the + Length field of the Response packet. + + EAP GTC implementations MAY support entering a response with non- + ASCII characters. See Section 5 for instructions how the input + should be processed and encoded into octets. + + Security Claims (see Section 7.2): + + Auth. mechanism: Hardware token. + Ciphersuite negotiation: No + Mutual authentication: No + Integrity protection: No + Replay protection: No + Confidentiality: No + Key derivation: No + Key strength: N/A + Dictionary attack prot.: No + Fast reconnect: No + Crypt. binding: N/A + Session independence: N/A + Fragmentation: No + Channel binding: No + + +5.7. Expanded Types + + Description + + Since many of the existing uses of EAP are vendor-specific, the + Expanded method Type is available to allow vendors to support + their own Expanded Types not suitable for general usage. + + + +Aboba, et al. Standards Track [Page 38] + +RFC 3748 EAP June 2004 + + + The Expanded Type is also used to expand the global Method Type + space beyond the original 255 values. A Vendor-Id of 0 maps the + original 255 possible Types onto a space of 2^32-1 possible Types. + (Type 0 is only used in a Nak Response to indicate no acceptable + alternative). + + An implementation that supports the Expanded attribute MUST treat + EAP Types that are less than 256 equivalently, whether they appear + as a single octet or as the 32-bit Vendor-Type within an Expanded + Type where Vendor-Id is 0. Peers not equipped to interpret the + Expanded Type MUST send a Nak as described in Section 5.3.1, and + negotiate a more suitable authentication method. + + A summary of the Expanded Type format is shown below. The fields + are transmitted from left to right. + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Vendor-Id | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Vendor-Type | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Vendor data... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Type + + 254 for Expanded Type + + Vendor-Id + + The Vendor-Id is 3 octets and represents the SMI Network + Management Private Enterprise Code of the Vendor in network byte + order, as allocated by IANA. A Vendor-Id of zero is reserved for + use by the IETF in providing an expanded global EAP Type space. + + Vendor-Type + + The Vendor-Type field is four octets and represents the vendor- + specific method Type. + + If the Vendor-Id is zero, the Vendor-Type field is an extension + and superset of the existing namespace for EAP Types. The first + 256 Types are reserved for compatibility with single-octet EAP + Types that have already been assigned or may be assigned in the + future. Thus, EAP Types from 0 through 255 are semantically + identical, whether they appear as single octet EAP Types or as + + + +Aboba, et al. Standards Track [Page 39] + +RFC 3748 EAP June 2004 + + + Vendor-Types when Vendor-Id is zero. There is one exception to + this rule: Expanded Nak and Legacy Nak packets share the same + Type, but must be treated differently because they have a + different format. + + Vendor-Data + + The Vendor-Data field is defined by the vendor. Where a Vendor-Id + of zero is present, the Vendor-Data field will be used for + transporting the contents of EAP methods of Types defined by the + IETF. + +5.8. Experimental + + Description + + The Experimental Type has no fixed format or content. It is + intended for use when experimenting with new EAP Types. This Type + is intended for experimental and testing purposes. No guarantee + is made for interoperability between peers using this Type, as + outlined in [RFC3692]. + + Type + + 255 + + Type-Data + + Undefined + +6. IANA Considerations + + This section provides guidance to the Internet Assigned Numbers + Authority (IANA) regarding registration of values related to the EAP + protocol, in accordance with BCP 26, [RFC2434]. + + There are two name spaces in EAP that require registration: Packet + Codes and method Types. + + EAP is not intended as a general-purpose protocol, and allocations + SHOULD NOT be made for purposes unrelated to authentication. + + The following terms are used here with the meanings defined in BCP + 26: "name space", "assigned value", "registration". + + The following policies are used here with the meanings defined in BCP + 26: "Private Use", "First Come First Served", "Expert Review", + "Specification Required", "IETF Consensus", "Standards Action". + + + +Aboba, et al. Standards Track [Page 40] + +RFC 3748 EAP June 2004 + + + For registration requests where a Designated Expert should be + consulted, the responsible IESG area director should appoint the + Designated Expert. The intention is that any allocation will be + accompanied by a published RFC. But in order to allow for the + allocation of values prior to the RFC being approved for publication, + the Designated Expert can approve allocations once it seems clear + that an RFC will be published. The Designated expert will post a + request to the EAP WG mailing list (or a successor designated by the + Area Director) for comment and review, including an Internet-Draft. + Before a period of 30 days has passed, the Designated Expert will + either approve or deny the registration request and publish a notice + of the decision to the EAP WG mailing list or its successor, as well + as informing IANA. A denial notice must be justified by an + explanation, and in the cases where it is possible, concrete + suggestions on how the request can be modified so as to become + acceptable should be provided. + +6.1. Packet Codes + + Packet Codes have a range from 1 to 255, of which 1-4 have been + allocated. Because a new Packet Code has considerable impact on + interoperability, a new Packet Code requires Standards Action, and + should be allocated starting at 5. + +6.2. Method Types + + The original EAP method Type space has a range from 1 to 255, and is + the scarcest resource in EAP, and thus must be allocated with care. + Method Types 1-45 have been allocated, with 20 available for re-use. + Method Types 20 and 46-191 may be allocated on the advice of a + Designated Expert, with Specification Required. + + Allocation of blocks of method Types (more than one for a given + purpose) should require IETF Consensus. EAP Type Values 192-253 are + reserved and allocation requires Standards Action. + + Method Type 254 is allocated for the Expanded Type. Where the + Vendor-Id field is non-zero, the Expanded Type is used for functions + specific only to one vendor's implementation of EAP, where no + interoperability is deemed useful. When used with a Vendor-Id of + zero, method Type 254 can also be used to provide for an expanded + IETF method Type space. Method Type values 256-4294967295 may be + allocated after Type values 1-191 have been allocated, on the advice + of a Designated Expert, with Specification Required. + + Method Type 255 is allocated for Experimental use, such as testing of + new EAP methods before a permanent Type is allocated. + + + + +Aboba, et al. Standards Track [Page 41] + +RFC 3748 EAP June 2004 + + +7. Security Considerations + + This section defines a generic threat model as well as the EAP method + security claims mitigating those threats. + + It is expected that the generic threat model and corresponding + security claims will used to define EAP method requirements for use + in specific environments. An example of such a requirements analysis + is provided in [IEEE-802.11i-req]. A security claims section is + required in EAP method specifications, so that EAP methods can be + evaluated against the requirements. + +7.1. Threat Model + + EAP was developed for use with PPP [RFC1661] and was later adapted + for use in wired IEEE 802 networks [IEEE-802] in [IEEE-802.1X]. + Subsequently, EAP has been proposed for use on wireless LAN networks + and over the Internet. In all these situations, it is possible for + an attacker to gain access to links over which EAP packets are + transmitted. For example, attacks on telephone infrastructure are + documented in [DECEPTION]. + + An attacker with access to the link may carry out a number of + attacks, including: + + [1] An attacker may try to discover user identities by snooping + authentication traffic. + + [2] An attacker may try to modify or spoof EAP packets. + + [3] An attacker may launch denial of service attacks by spoofing + lower layer indications or Success/Failure packets, by replaying + EAP packets, or by generating packets with overlapping + Identifiers. + + [4] An attacker may attempt to recover the pass-phrase by mounting + an offline dictionary attack. + + [5] An attacker may attempt to convince the peer to connect to an + untrusted network by mounting a man-in-the-middle attack. + + [6] An attacker may attempt to disrupt the EAP negotiation in order + cause a weak authentication method to be selected. + + [7] An attacker may attempt to recover keys by taking advantage of + weak key derivation techniques used within EAP methods. + + + + + +Aboba, et al. Standards Track [Page 42] + +RFC 3748 EAP June 2004 + + + [8] An attacker may attempt to take advantage of weak ciphersuites + subsequently used after the EAP conversation is complete. + + [9] An attacker may attempt to perform downgrading attacks on lower + layer ciphersuite negotiation in order to ensure that a weaker + ciphersuite is used subsequently to EAP authentication. + + [10] An attacker acting as an authenticator may provide incorrect + information to the EAP peer and/or server via out-of-band + mechanisms (such as via a AAA or lower layer protocol). This + includes impersonating another authenticator, or providing + inconsistent information to the peer and EAP server. + + Depending on the lower layer, these attacks may be carried out + without requiring physical proximity. Where EAP is used over + wireless networks, EAP packets may be forwarded by authenticators + (e.g., pre-authentication) so that the attacker need not be within + the coverage area of an authenticator in order to carry out an attack + on it or its peers. Where EAP is used over the Internet, attacks may + be carried out at an even greater distance. + +7.2. Security Claims + + In order to clearly articulate the security provided by an EAP + method, EAP method specifications MUST include a Security Claims + section, including the following declarations: + + [a] Mechanism. This is a statement of the authentication technology: + certificates, pre-shared keys, passwords, token cards, etc. + + [b] Security claims. This is a statement of the claimed security + properties of the method, using terms defined in Section 7.2.1: + mutual authentication, integrity protection, replay protection, + confidentiality, key derivation, dictionary attack resistance, + fast reconnect, cryptographic binding. The Security Claims + section of an EAP method specification SHOULD provide + justification for the claims that are made. This can be + accomplished by including a proof in an Appendix, or including a + reference to a proof. + + [c] Key strength. If the method derives keys, then the effective key + strength MUST be estimated. This estimate is meant for potential + users of the method to determine if the keys produced are strong + enough for the intended application. + + + + + + + +Aboba, et al. Standards Track [Page 43] + +RFC 3748 EAP June 2004 + + + The effective key strength SHOULD be stated as a number of bits, + defined as follows: If the effective key strength is N bits, the + best currently known methods to recover the key (with non- + negligible probability) require, on average, an effort comparable + to 2^(N-1) operations of a typical block cipher. The statement + SHOULD be accompanied by a short rationale, explaining how this + number was derived. This explanation SHOULD include the + parameters required to achieve the stated key strength based on + current knowledge of the algorithms. + + (Note: Although it is difficult to define what "comparable + effort" and "typical block cipher" exactly mean, reasonable + approximations are sufficient here. Refer to e.g. [SILVERMAN] + for more discussion.) + + The key strength depends on the methods used to derive the keys. + For instance, if keys are derived from a shared secret (such as a + password or a long-term secret), and possibly some public + information such as nonces, the effective key strength is limited + by the strength of the long-term secret (assuming that the + derivation procedure is computationally simple). To take another + example, when using public key algorithms, the strength of the + symmetric key depends on the strength of the public keys used. + + [d] Description of key hierarchy. EAP methods deriving keys MUST + either provide a reference to a key hierarchy specification, or + describe how Master Session Keys (MSKs) and Extended Master + Session Keys (EMSKs) are to be derived. + + [e] Indication of vulnerabilities. In addition to the security + claims that are made, the specification MUST indicate which of + the security claims detailed in Section 7.2.1 are NOT being made. + +7.2.1. Security Claims Terminology for EAP Methods + + These terms are used to describe the security properties of EAP + methods: + + Protected ciphersuite negotiation + This refers to the ability of an EAP method to negotiate the + ciphersuite used to protect the EAP conversation, as well as to + integrity protect the negotiation. It does not refer to the + ability to negotiate the ciphersuite used to protect data. + + + + + + + + +Aboba, et al. Standards Track [Page 44] + +RFC 3748 EAP June 2004 + + + Mutual authentication + This refers to an EAP method in which, within an interlocked + exchange, the authenticator authenticates the peer and the peer + authenticates the authenticator. Two independent one-way methods, + running in opposite directions do not provide mutual + authentication as defined here. + + Integrity protection + This refers to providing data origin authentication and protection + against unauthorized modification of information for EAP packets + (including EAP Requests and Responses). When making this claim, a + method specification MUST describe the EAP packets and fields + within the EAP packet that are protected. + + Replay protection + This refers to protection against replay of an EAP method or its + messages, including success and failure result indications. + + Confidentiality + This refers to encryption of EAP messages, including EAP Requests + and Responses, and success and failure result indications. A + method making this claim MUST support identity protection (see + Section 7.3). + + Key derivation + This refers to the ability of the EAP method to derive exportable + keying material, such as the Master Session Key (MSK), and + Extended Master Session Key (EMSK). The MSK is used only for + further key derivation, not directly for protection of the EAP + conversation or subsequent data. Use of the EMSK is reserved. + + Key strength + If the effective key strength is N bits, the best currently known + methods to recover the key (with non-negligible probability) + require, on average, an effort comparable to 2^(N-1) operations of + a typical block cipher. + + Dictionary attack resistance + Where password authentication is used, passwords are commonly + selected from a small set (as compared to a set of N-bit keys), + which raises a concern about dictionary attacks. A method may be + said to provide protection against dictionary attacks if, when it + uses a password as a secret, the method does not allow an offline + attack that has a work factor based on the number of passwords in + an attacker's dictionary. + + + + + + +Aboba, et al. Standards Track [Page 45] + +RFC 3748 EAP June 2004 + + + Fast reconnect + The ability, in the case where a security association has been + previously established, to create a new or refreshed security + association more efficiently or in a smaller number of round- + trips. + + Cryptographic binding + The demonstration of the EAP peer to the EAP server that a single + entity has acted as the EAP peer for all methods executed within a + tunnel method. Binding MAY also imply that the EAP server + demonstrates to the peer that a single entity has acted as the EAP + server for all methods executed within a tunnel method. If + executed correctly, binding serves to mitigate man-in-the-middle + vulnerabilities. + + Session independence + The demonstration that passive attacks (such as capture of the EAP + conversation) or active attacks (including compromise of the MSK + or EMSK) does not enable compromise of subsequent or prior MSKs or + EMSKs. + + Fragmentation + This refers to whether an EAP method supports fragmentation and + reassembly. As noted in Section 3.1, EAP methods should support + fragmentation and reassembly if EAP packets can exceed the minimum + MTU of 1020 octets. + + Channel binding + The communication within an EAP method of integrity-protected + channel properties such as endpoint identifiers which can be + compared to values communicated via out of band mechanisms (such + as via a AAA or lower layer protocol). + + Note: This list of security claims is not exhaustive. Additional + properties, such as additional denial-of-service protection, may be + relevant as well. + +7.3. Identity Protection + + An Identity exchange is optional within the EAP conversation. + Therefore, it is possible to omit the Identity exchange entirely, or + to use a method-specific identity exchange once a protected channel + has been established. + + However, where roaming is supported as described in [RFC2607], it may + be necessary to locate the appropriate backend authentication server + before the authentication conversation can proceed. The realm + portion of the Network Access Identifier (NAI) [RFC2486] is typically + + + +Aboba, et al. Standards Track [Page 46] + +RFC 3748 EAP June 2004 + + + included within the EAP-Response/Identity in order to enable the + authentication exchange to be routed to the appropriate backend + authentication server. Therefore, while the peer-name portion of the + NAI may be omitted in the EAP-Response/Identity where proxies or + relays are present, the realm portion may be required. + + It is possible for the identity in the identity response to be + different from the identity authenticated by the EAP method. This + may be intentional in the case of identity privacy. An EAP method + SHOULD use the authenticated identity when making access control + decisions. + +7.4. Man-in-the-Middle Attacks + + Where EAP is tunneled within another protocol that omits peer + authentication, there exists a potential vulnerability to a man-in- + the-middle attack. For details, see [BINDING] and [MITM]. + + As noted in Section 2.1, EAP does not permit untunneled sequences of + authentication methods. Were a sequence of EAP authentication + methods to be permitted, the peer might not have proof that a single + entity has acted as the authenticator for all EAP methods within the + sequence. For example, an authenticator might terminate one EAP + method, then forward the next method in the sequence to another party + without the peer's knowledge or consent. Similarly, the + authenticator might not have proof that a single entity has acted as + the peer for all EAP methods within the sequence. + + Tunneling EAP within another protocol enables an attack by a rogue + EAP authenticator tunneling EAP to a legitimate server. Where the + tunneling protocol is used for key establishment but does not require + peer authentication, an attacker convincing a legitimate peer to + connect to it will be able to tunnel EAP packets to a legitimate + server, successfully authenticating and obtaining the key. This + allows the attacker to successfully establish itself as a man-in- + the-middle, gaining access to the network, as well as the ability to + decrypt data traffic between the legitimate peer and server. + + This attack may be mitigated by the following measures: + + [a] Requiring mutual authentication within EAP tunneling mechanisms. + + [b] Requiring cryptographic binding between the EAP tunneling + protocol and the tunneled EAP methods. Where cryptographic + binding is supported, a mechanism is also needed to protect + against downgrade attacks that would bypass it. For further + details on cryptographic binding, see [BINDING]. + + + + +Aboba, et al. Standards Track [Page 47] + +RFC 3748 EAP June 2004 + + + [c] Limiting the EAP methods authorized for use without protection, + based on peer and authenticator policy. + + [d] Avoiding the use of tunnels when a single, strong method is + available. + +7.5. Packet Modification Attacks + + While EAP methods may support per-packet data origin authentication, + integrity, and replay protection, support is not provided within the + EAP layer. + + Since the Identifier is only a single octet, it is easy to guess, + allowing an attacker to successfully inject or replay EAP packets. + An attacker may also modify EAP headers (Code, Identifier, Length, + Type) within EAP packets where the header is unprotected. This could + cause packets to be inappropriately discarded or misinterpreted. + + To protect EAP packets against modification, spoofing, or replay, + methods supporting protected ciphersuite negotiation, mutual + authentication, and key derivation, as well as integrity and replay + protection, are recommended. See Section 7.2.1 for definitions of + these security claims. + + Method-specific MICs may be used to provide protection. If a per- + packet MIC is employed within an EAP method, then peers, + authentication servers, and authenticators not operating in pass- + through mode MUST validate the MIC. MIC validation failures SHOULD + be logged. Whether a MIC validation failure is considered a fatal + error or not is determined by the EAP method specification. + + It is RECOMMENDED that methods providing integrity protection of EAP + packets include coverage of all the EAP header fields, including the + Code, Identifier, Length, Type, and Type-Data fields. + + Since EAP messages of Types Identity, Notification, and Nak do not + include their own MIC, it may be desirable for the EAP method MIC to + cover information contained within these messages, as well as the + header of each EAP message. + + To provide protection, EAP also may be encapsulated within a + protected channel created by protocols such as ISAKMP [RFC2408], as + is done in [IKEv2] or within TLS [RFC2246]. However, as noted in + Section 7.4, EAP tunneling may result in a man-in-the-middle + vulnerability. + + + + + + +Aboba, et al. Standards Track [Page 48] + +RFC 3748 EAP June 2004 + + + Existing EAP methods define message integrity checks (MICs) that + cover more than one EAP packet. For example, EAP-TLS [RFC2716] + defines a MIC over a TLS record that could be split into multiple + fragments; within the FINISHED message, the MIC is computed over + previous messages. Where the MIC covers more than one EAP packet, a + MIC validation failure is typically considered a fatal error. + + Within EAP-TLS [RFC2716], a MIC validation failure is treated as a + fatal error, since that is what is specified in TLS [RFC2246]. + However, it is also possible to develop EAP methods that support + per-packet MICs, and respond to verification failures by silently + discarding the offending packet. + + In this document, descriptions of EAP message handling assume that + per-packet MIC validation, where it occurs, is effectively performed + as though it occurs before sending any responses or changing the + state of the host which received the packet. + +7.6. Dictionary Attacks + + Password authentication algorithms such as EAP-MD5, MS-CHAPv1 + [RFC2433], and Kerberos V [RFC1510] are known to be vulnerable to + dictionary attacks. MS-CHAPv1 vulnerabilities are documented in + [PPTPv1]; MS-CHAPv2 vulnerabilities are documented in [PPTPv2]; + Kerberos vulnerabilities are described in [KRBATTACK], [KRBLIM], and + [KERB4WEAK]. + + In order to protect against dictionary attacks, authentication + methods resistant to dictionary attacks (as defined in Section 7.2.1) + are recommended. + + If an authentication algorithm is used that is known to be vulnerable + to dictionary attacks, then the conversation may be tunneled within a + protected channel in order to provide additional protection. + However, as noted in Section 7.4, EAP tunneling may result in a man- + in-the-middle vulnerability, and therefore dictionary attack + resistant methods are preferred. + +7.7. Connection to an Untrusted Network + + With EAP methods supporting one-way authentication, such as EAP-MD5, + the peer does not authenticate the authenticator, making the peer + vulnerable to attack by a rogue authenticator. Methods supporting + mutual authentication (as defined in Section 7.2.1) address this + vulnerability. + + In EAP there is no requirement that authentication be full duplex or + that the same protocol be used in both directions. It is perfectly + + + +Aboba, et al. Standards Track [Page 49] + +RFC 3748 EAP June 2004 + + + acceptable for different protocols to be used in each direction. + This will, of course, depend on the specific protocols negotiated. + However, in general, completing a single unitary mutual + authentication is preferable to two one-way authentications, one in + each direction. This is because separate authentications that are + not bound cryptographically so as to demonstrate they are part of the + same session are subject to man-in-the-middle attacks, as discussed + in Section 7.4. + +7.8. Negotiation Attacks + + In a negotiation attack, the attacker attempts to convince the peer + and authenticator to negotiate a less secure EAP method. EAP does + not provide protection for Nak Response packets, although it is + possible for a method to include coverage of Nak Responses within a + method-specific MIC. + + Within or associated with each authenticator, it is not anticipated + that a particular named peer will support a choice of methods. This + would make the peer vulnerable to attacks that negotiate the least + secure method from among a set. Instead, for each named peer, there + SHOULD be an indication of exactly one method used to authenticate + that peer name. If a peer needs to make use of different + authentication methods under different circumstances, then distinct + identities SHOULD be employed, each of which identifies exactly one + authentication method. + +7.9. Implementation Idiosyncrasies + + The interaction of EAP with lower layers such as PPP and IEEE 802 are + highly implementation dependent. + + For example, upon failure of authentication, some PPP implementations + do not terminate the link, instead limiting traffic in Network-Layer + Protocols to a filtered subset, which in turn allows the peer the + opportunity to update secrets or send mail to the network + administrator indicating a problem. Similarly, while an + authentication failure will result in denied access to the controlled + port in [IEEE-802.1X], limited traffic may be permitted on the + uncontrolled port. + + In EAP there is no provision for retries of failed authentication. + However, in PPP the LCP state machine can renegotiate the + authentication protocol at any time, thus allowing a new attempt. + Similarly, in IEEE 802.1X the Supplicant or Authenticator can re- + authenticate at any time. It is recommended that any counters used + for authentication failure not be reset until after successful + authentication, or subsequent termination of the failed link. + + + +Aboba, et al. Standards Track [Page 50] + +RFC 3748 EAP June 2004 + + +7.10. Key Derivation + + It is possible for the peer and EAP server to mutually authenticate + and derive keys. In order to provide keying material for use in a + subsequently negotiated ciphersuite, an EAP method supporting key + derivation MUST export a Master Session Key (MSK) of at least 64 + octets, and an Extended Master Session Key (EMSK) of at least 64 + octets. EAP Methods deriving keys MUST provide for mutual + authentication between the EAP peer and the EAP Server. + + The MSK and EMSK MUST NOT be used directly to protect data; however, + they are of sufficient size to enable derivation of a AAA-Key + subsequently used to derive Transient Session Keys (TSKs) for use + with the selected ciphersuite. Each ciphersuite is responsible for + specifying how to derive the TSKs from the AAA-Key. + + The AAA-Key is derived from the keying material exported by the EAP + method (MSK and EMSK). This derivation occurs on the AAA server. In + many existing protocols that use EAP, the AAA-Key and MSK are + equivalent, but more complicated mechanisms are possible (see + [KEYFRAME] for details). + + EAP methods SHOULD ensure the freshness of the MSK and EMSK, even in + cases where one party may not have a high quality random number + generator. A RECOMMENDED method is for each party to provide a nonce + of at least 128 bits, used in the derivation of the MSK and EMSK. + + EAP methods export the MSK and EMSK, but not Transient Session Keys + so as to allow EAP methods to be ciphersuite and media independent. + Keying material exported by EAP methods MUST be independent of the + ciphersuite negotiated to protect data. + + Depending on the lower layer, EAP methods may run before or after + ciphersuite negotiation, so that the selected ciphersuite may not be + known to the EAP method. By providing keying material usable with + any ciphersuite, EAP methods can used with a wide range of + ciphersuites and media. + + In order to preserve algorithm independence, EAP methods deriving + keys SHOULD support (and document) the protected negotiation of the + ciphersuite used to protect the EAP conversation between the peer and + server. This is distinct from the ciphersuite negotiated between the + peer and authenticator, used to protect data. + + The strength of Transient Session Keys (TSKs) used to protect data is + ultimately dependent on the strength of keys generated by the EAP + method. If an EAP method cannot produce keying material of + sufficient strength, then the TSKs may be subject to a brute force + + + +Aboba, et al. Standards Track [Page 51] + +RFC 3748 EAP June 2004 + + + attack. In order to enable deployments requiring strong keys, EAP + methods supporting key derivation SHOULD be capable of generating an + MSK and EMSK, each with an effective key strength of at least 128 + bits. + + Methods supporting key derivation MUST demonstrate cryptographic + separation between the MSK and EMSK branches of the EAP key + hierarchy. Without violating a fundamental cryptographic assumption + (such as the non-invertibility of a one-way function), an attacker + recovering the MSK or EMSK MUST NOT be able to recover the other + quantity with a level of effort less than brute force. + + Non-overlapping substrings of the MSK MUST be cryptographically + separate from each other, as defined in Section 7.2.1. That is, + knowledge of one substring MUST NOT help in recovering some other + substring without breaking some hard cryptographic assumption. This + is required because some existing ciphersuites form TSKs by simply + splitting the AAA-Key to pieces of appropriate length. Likewise, + non-overlapping substrings of the EMSK MUST be cryptographically + separate from each other, and from substrings of the MSK. + + The EMSK is reserved for future use and MUST remain on the EAP peer + and EAP server where it is derived; it MUST NOT be transported to, or + shared with, additional parties, or used to derive any other keys. + (This restriction will be relaxed in a future document that specifies + how the EMSK can be used.) + + Since EAP does not provide for explicit key lifetime negotiation, EAP + peers, authenticators, and authentication servers MUST be prepared + for situations in which one of the parties discards the key state, + which remains valid on another party. + + This specification does not provide detailed guidance on how EAP + methods derive the MSK and EMSK, how the AAA-Key is derived from the + MSK and/or EMSK, or how the TSKs are derived from the AAA-Key. + + The development and validation of key derivation algorithms is + difficult, and as a result, EAP methods SHOULD re-use well + established and analyzed mechanisms for key derivation (such as those + specified in IKE [RFC2409] or TLS [RFC2246]), rather than inventing + new ones. EAP methods SHOULD also utilize well established and + analyzed mechanisms for MSK and EMSK derivation. Further details on + EAP Key Derivation are provided within [KEYFRAME]. + + + + + + + + +Aboba, et al. Standards Track [Page 52] + +RFC 3748 EAP June 2004 + + +7.11. Weak Ciphersuites + + If after the initial EAP authentication, data packets are sent + without per-packet authentication, integrity, and replay protection, + an attacker with access to the media can inject packets, "flip bits" + within existing packets, replay packets, or even hijack the session + completely. Without per-packet confidentiality, it is possible to + snoop data packets. + + To protect against data modification, spoofing, or snooping, it is + recommended that EAP methods supporting mutual authentication and key + derivation (as defined by Section 7.2.1) be used, along with lower + layers providing per-packet confidentiality, authentication, + integrity, and replay protection. + + Additionally, if the lower layer performs ciphersuite negotiation, it + should be understood that EAP does not provide by itself integrity + protection of that negotiation. Therefore, in order to avoid + downgrading attacks which would lead to weaker ciphersuites being + used, clients implementing lower layer ciphersuite negotiation SHOULD + protect against negotiation downgrading. + + This can be done by enabling users to configure which ciphersuites + are acceptable as a matter of security policy, or the ciphersuite + negotiation MAY be authenticated using keying material derived from + the EAP authentication and a MIC algorithm agreed upon in advance by + lower-layer peers. + +7.12. Link Layer + + There are reliability and security issues with link layer indications + in PPP, IEEE 802 LANs, and IEEE 802.11 wireless LANs: + + [a] PPP. In PPP, link layer indications such as LCP-Terminate (a + link failure indication) and NCP (a link success indication) are + not authenticated or integrity protected. They can therefore be + spoofed by an attacker with access to the link. + + [b] IEEE 802. IEEE 802.1X EAPOL-Start and EAPOL-Logoff frames are + not authenticated or integrity protected. They can therefore be + spoofed by an attacker with access to the link. + + [c] IEEE 802.11. In IEEE 802.11, link layer indications include + Disassociate and Deauthenticate frames (link failure + indications), and the first message of the 4-way handshake (link + success indication). These messages are not authenticated or + integrity protected, and although they are not forwardable, they + are spoofable by an attacker within range. + + + +Aboba, et al. Standards Track [Page 53] + +RFC 3748 EAP June 2004 + + + In IEEE 802.11, IEEE 802.1X data frames may be sent as Class 3 + unicast data frames, and are therefore forwardable. This implies + that while EAPOL-Start and EAPOL-Logoff messages may be authenticated + and integrity protected, they can be spoofed by an authenticated + attacker far from the target when "pre-authentication" is enabled. + + In IEEE 802.11, a "link down" indication is an unreliable indication + of link failure, since wireless signal strength can come and go and + may be influenced by radio frequency interference generated by an + attacker. To avoid unnecessary resets, it is advisable to damp these + indications, rather than passing them directly to the EAP. Since EAP + supports retransmission, it is robust against transient connectivity + losses. + +7.13. Separation of Authenticator and Backend Authentication Server + + It is possible for the EAP peer and EAP server to mutually + authenticate and derive a AAA-Key for a ciphersuite used to protect + subsequent data traffic. This does not present an issue on the peer, + since the peer and EAP client reside on the same machine; all that is + required is for the client to derive the AAA-Key from the MSK and + EMSK exported by the EAP method, and to subsequently pass a Transient + Session Key (TSK) to the ciphersuite module. + + However, in the case where the authenticator and authentication + server reside on different machines, there are several implications + for security. + + [a] Authentication will occur between the peer and the authentication + server, not between the peer and the authenticator. This means + that it is not possible for the peer to validate the identity of + the authenticator that it is speaking to, using EAP alone. + + [b] As discussed in [RFC3579], the authenticator is dependent on the + AAA protocol in order to know the outcome of an authentication + conversation, and does not look at the encapsulated EAP packet + (if one is present) to determine the outcome. In practice, this + implies that the AAA protocol spoken between the authenticator + and authentication server MUST support per-packet authentication, + integrity, and replay protection. + + [c] After completion of the EAP conversation, where lower layer + security services such as per-packet confidentiality, + authentication, integrity, and replay protection will be enabled, + a secure association protocol SHOULD be run between the peer and + authenticator in order to provide mutual authentication between + + + + + +Aboba, et al. Standards Track [Page 54] + +RFC 3748 EAP June 2004 + + + the peer and authenticator, guarantee liveness of transient + session keys, provide protected ciphersuite and capabilities + negotiation for subsequent data, and synchronize key usage. + + [d] A AAA-Key derived from the MSK and/or EMSK negotiated between the + peer and authentication server MAY be transmitted to the + authenticator. Therefore, a mechanism needs to be provided to + transmit the AAA-Key from the authentication server to the + authenticator that needs it. The specification of the AAA-key + derivation, transport, and wrapping mechanisms is outside the + scope of this document. Further details on AAA-Key Derivation + are provided within [KEYFRAME]. + +7.14. Cleartext Passwords + + This specification does not define a mechanism for cleartext password + authentication. The omission is intentional. Use of cleartext + passwords would allow the password to be captured by an attacker with + access to a link over which EAP packets are transmitted. + + Since protocols encapsulating EAP, such as RADIUS [RFC3579], may not + provide confidentiality, EAP packets may be subsequently encapsulated + for transport over the Internet where they may be captured by an + attacker. + + As a result, cleartext passwords cannot be securely used within EAP, + except where encapsulated within a protected tunnel with server + authentication. Some of the same risks apply to EAP methods without + dictionary attack resistance, as defined in Section 7.2.1. For + details, see Section 7.6. + +7.15. Channel Binding + + It is possible for a compromised or poorly implemented EAP + authenticator to communicate incorrect information to the EAP peer + and/or server. This may enable an authenticator to impersonate + another authenticator or communicate incorrect information via out- + of-band mechanisms (such as via a AAA or lower layer protocol). + + Where EAP is used in pass-through mode, the EAP peer typically does + not verify the identity of the pass-through authenticator, it only + verifies that the pass-through authenticator is trusted by the EAP + server. This creates a potential security vulnerability. + + Section 4.3.7 of [RFC3579] describes how an EAP pass-through + authenticator acting as a AAA client can be detected if it attempts + to impersonate another authenticator (such by sending incorrect NAS- + Identifier [RFC2865], NAS-IP-Address [RFC2865] or NAS-IPv6-Address + + + +Aboba, et al. Standards Track [Page 55] + +RFC 3748 EAP June 2004 + + + [RFC3162] attributes via the AAA protocol). However, it is possible + for a pass-through authenticator acting as a AAA client to provide + correct information to the AAA server while communicating misleading + information to the EAP peer via a lower layer protocol. + + For example, it is possible for a compromised authenticator to + utilize another authenticator's Called-Station-Id or NAS-Identifier + in communicating with the EAP peer via a lower layer protocol, or for + a pass-through authenticator acting as a AAA client to provide an + incorrect peer Calling-Station-Id [RFC2865][RFC3580] to the AAA + server via the AAA protocol. + + In order to address this vulnerability, EAP methods may support a + protected exchange of channel properties such as endpoint + identifiers, including (but not limited to): Called-Station-Id + [RFC2865][RFC3580], Calling-Station-Id [RFC2865][RFC3580], NAS- + Identifier [RFC2865], NAS-IP-Address [RFC2865], and NAS-IPv6-Address + [RFC3162]. + + Using such a protected exchange, it is possible to match the channel + properties provided by the authenticator via out-of-band mechanisms + against those exchanged within the EAP method. Where discrepancies + are found, these SHOULD be logged; additional actions MAY also be + taken, such as denying access. + +7.16. Protected Result Indications + + Within EAP, Success and Failure packets are neither acknowledged nor + integrity protected. Result indications improve resilience to loss + of Success and Failure packets when EAP is run over lower layers + which do not support retransmission or synchronization of the + authentication state. In media such as IEEE 802.11, which provides + for retransmission, as well as synchronization of authentication + state via the 4-way handshake defined in [IEEE-802.11i], additional + resilience is typically of marginal benefit. + + Depending on the method and circumstances, result indications can be + spoofable by an attacker. A method is said to provide protected + result indications if it supports result indications, as well as the + "integrity protection" and "replay protection" claims. A method + supporting protected result indications MUST indicate which result + indications are protected, and which are not. + + Protected result indications are not required to protect against + rogue authenticators. Within a mutually authenticating method, + requiring that the server authenticate to the peer before the peer + will accept a Success packet prevents an attacker from acting as a + rogue authenticator. + + + +Aboba, et al. Standards Track [Page 56] + +RFC 3748 EAP June 2004 + + + However, it is possible for an attacker to forge a Success packet + after the server has authenticated to the peer, but before the peer + has authenticated to the server. If the peer were to accept the + forged Success packet and attempt to access the network when it had + not yet successfully authenticated to the server, a denial of service + attack could be mounted against the peer. After such an attack, if + the lower layer supports failure indications, the authenticator can + synchronize state with the peer by providing a lower layer failure + indication. See Section 7.12 for details. + + If a server were to authenticate the peer and send a Success packet + prior to determining whether the peer has authenticated the + authenticator, an idle timeout can occur if the authenticator is not + authenticated by the peer. Where supported by the lower layer, an + authenticator sensing the absence of the peer can free resources. + + In a method supporting result indications, a peer that has + authenticated the server does not consider the authentication + successful until it receives an indication that the server + successfully authenticated it. Similarly, a server that has + successfully authenticated the peer does not consider the + authentication successful until it receives an indication that the + peer has authenticated the server. + + In order to avoid synchronization problems, prior to sending a + success result indication, it is desirable for the sender to verify + that sufficient authorization exists for granting access, though, as + discussed below, this is not always possible. + + While result indications may enable synchronization of the + authentication result between the peer and server, this does not + guarantee that the peer and authenticator will be synchronized in + terms of their authorization or that timeouts will not occur. For + example, the EAP server may not be aware of an authorization decision + made by a AAA proxy; the AAA server may check authorization only + after authentication has completed successfully, to discover that + authorization cannot be granted, or the AAA server may grant access + but the authenticator may be unable to provide it due to a temporary + lack of resources. In these situations, synchronization may only be + achieved via lower layer result indications. + + Success indications may be explicit or implicit. For example, where + a method supports error messages, an implicit success indication may + be defined as the reception of a specific message without a preceding + error message. Failures are typically indicated explicitly. As + described in Section 4.2, a peer silently discards a Failure packet + received at a point where the method does not explicitly permit this + + + + +Aboba, et al. Standards Track [Page 57] + +RFC 3748 EAP June 2004 + + + to be sent. For example, a method providing its own error messages + might require the peer to receive an error message prior to accepting + a Failure packet. + + Per-packet authentication, integrity, and replay protection of result + indications protects against spoofing. Since protected result + indications require use of a key for per-packet authentication and + integrity protection, methods supporting protected result indications + MUST also support the "key derivation", "mutual authentication", + "integrity protection", and "replay protection" claims. + + Protected result indications address some denial-of-service + vulnerabilities due to spoofing of Success and Failure packets, + though not all. EAP methods can typically provide protected result + indications only in some circumstances. For example, errors can + occur prior to key derivation, and so it may not be possible to + protect all failure indications. It is also possible that result + indications may not be supported in both directions or that + synchronization may not be achieved in all modes of operation. + + For example, within EAP-TLS [RFC2716], in the client authentication + handshake, the server authenticates the peer, but does not receive a + protected indication of whether the peer has authenticated it. In + contrast, the peer authenticates the server and is aware of whether + the server has authenticated it. In the session resumption + handshake, the peer authenticates the server, but does not receive a + protected indication of whether the server has authenticated it. In + this mode, the server authenticates the peer and is aware of whether + the peer has authenticated it. + +8. Acknowledgements + + This protocol derives much of its inspiration from Dave Carrel's AHA + document, as well as the PPP CHAP protocol [RFC1994]. Valuable + feedback was provided by Yoshihiro Ohba of Toshiba America Research, + Jari Arkko of Ericsson, Sachin Seth of Microsoft, Glen Zorn of Cisco + Systems, Jesse Walker of Intel, Bill Arbaugh, Nick Petroni and Bryan + Payne of the University of Maryland, Steve Bellovin of AT&T Research, + Paul Funk of Funk Software, Pasi Eronen of Nokia, Joseph Salowey of + Cisco, Paul Congdon of HP, and members of the EAP working group. + + The use of Security Claims sections for EAP methods, as required by + Section 7.2 and specified for each EAP method described in this + document, was inspired by Glen Zorn through [EAP-EVAL]. + + + + + + + +Aboba, et al. Standards Track [Page 58] + +RFC 3748 EAP June 2004 + + +9. References + +9.1. Normative References + + [RFC1661] Simpson, W., "The Point-to-Point Protocol (PPP)", + STD 51, RFC 1661, July 1994. + + [RFC1994] Simpson, W., "PPP Challenge Handshake + Authentication Protocol (CHAP)", RFC 1994, August + 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to + Indicate Requirement Levels", BCP 14, RFC 2119, + March 1997. + + [RFC2243] Metz, C., "OTP Extended Responses", RFC 2243, + November 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of + ISO 10646", RFC 2279, January 1998. + + [RFC2289] Haller, N., Metz, C., Nesser, P. and M. Straw, "A + One-Time Password System", RFC 2289, February + 1998. + + [RFC2434] Narten, T. and H. Alvestrand, "Guidelines for + Writing an IANA Considerations Section in RFCs", + BCP 26, RFC 2434, October 1998. + + [RFC2988] Paxson, V. and M. Allman, "Computing TCP's + Retransmission Timer", RFC 2988, November 2000. + + [IEEE-802] Institute of Electrical and Electronics Engineers, + "Local and Metropolitan Area Networks: Overview + and Architecture", IEEE Standard 802, 1990. + + [IEEE-802.1X] Institute of Electrical and Electronics Engineers, + "Local and Metropolitan Area Networks: Port-Based + Network Access Control", IEEE Standard 802.1X, + September 2001. + + + + + + + + + + + +Aboba, et al. Standards Track [Page 59] + +RFC 3748 EAP June 2004 + + +9.2. Informative References + + [RFC793] Postel, J., "Transmission Control Protocol", STD + 7, RFC 793, September 1981. + + [RFC1510] Kohl, J. and B. Neuman, "The Kerberos Network + Authentication Service (V5)", RFC 1510, September + 1993. + + [RFC1750] Eastlake, D., Crocker, S. and J. Schiller, + "Randomness Recommendations for Security", RFC + 1750, December 1994. + + [RFC2246] Dierks, T., Allen, C., Treese, W., Karlton, P., + Freier, A. and P. Kocher, "The TLS Protocol + Version 1.0", RFC 2246, January 1999. + + [RFC2284] Blunk, L. and J. Vollbrecht, "PPP Extensible + Authentication Protocol (EAP)", RFC 2284, March + 1998. + + [RFC2486] Aboba, B. and M. Beadles, "The Network Access + Identifier", RFC 2486, January 1999. + + [RFC2408] Maughan, D., Schneider, M. and M. Schertler, + "Internet Security Association and Key Management + Protocol (ISAKMP)", RFC 2408, November 1998. + + [RFC2409] Harkins, D. and D. Carrel, "The Internet Key + Exchange (IKE)", RFC 2409, November 1998. + + [RFC2433] Zorn, G. and S. Cobb, "Microsoft PPP CHAP + Extensions", RFC 2433, October 1998. + + [RFC2607] Aboba, B. and J. Vollbrecht, "Proxy Chaining and + Policy Implementation in Roaming", RFC 2607, June + 1999. + + [RFC2661] Townsley, W., Valencia, A., Rubens, A., Pall, G., + Zorn, G. and B. Palter, "Layer Two Tunneling + Protocol "L2TP"", RFC 2661, August 1999. + + [RFC2716] Aboba, B. and D. Simon, "PPP EAP TLS + Authentication Protocol", RFC 2716, October 1999. + + [RFC2865] Rigney, C., Willens, S., Rubens, A. and W. + Simpson, "Remote Authentication Dial In User + Service (RADIUS)", RFC 2865, June 2000. + + + +Aboba, et al. Standards Track [Page 60] + +RFC 3748 EAP June 2004 + + + [RFC2960] Stewart, R., Xie, Q., Morneault, K., Sharp, C., + Schwarzbauer, H., Taylor, T., Rytina, I., Kalla, + M., Zhang, L. and V. Paxson, "Stream Control + Transmission Protocol", RFC 2960, October 2000. + + [RFC3162] Aboba, B., Zorn, G. and D. Mitton, "RADIUS and + IPv6", RFC 3162, August 2001. + + [RFC3454] Hoffman, P. and M. Blanchet, "Preparation of + Internationalized Strings ("stringprep")", RFC + 3454, December 2002. + + [RFC3579] Aboba, B. and P. Calhoun, "RADIUS (Remote + Authentication Dial In User Service) Support For + Extensible Authentication Protocol (EAP)", RFC + 3579, September 2003. + + [RFC3580] Congdon, P., Aboba, B., Smith, A., Zorn, G. and J. + Roese, "IEEE 802.1X Remote Authentication Dial In + User Service (RADIUS) Usage Guidelines", RFC 3580, + September 2003. + + [RFC3692] Narten, T., "Assigning Experimental and Testing + Numbers Considered Useful", BCP 82, RFC 3692, + January 2004. + + [DECEPTION] Slatalla, M. and J. Quittner, "Masters of + Deception", Harper-Collins, New York, 1995. + + [KRBATTACK] Wu, T., "A Real-World Analysis of Kerberos + Password Security", Proceedings of the 1999 ISOC + Network and Distributed System Security Symposium, + http://www.isoc.org/isoc/conferences/ndss/99/ + proceedings/papers/wu.pdf. + + [KRBLIM] Bellovin, S. and M. Merrit, "Limitations of the + Kerberos authentication system", Proceedings of + the 1991 Winter USENIX Conference, pp. 253-267, + 1991. + + [KERB4WEAK] Dole, B., Lodin, S. and E. Spafford, "Misplaced + trust: Kerberos 4 session keys", Proceedings of + the Internet Society Network and Distributed + System Security Symposium, pp. 60-70, March 1997. + + + + + + + +Aboba, et al. Standards Track [Page 61] + +RFC 3748 EAP June 2004 + + + [PIC] Aboba, B., Krawczyk, H. and Y. Sheffer, "PIC, A + Pre-IKE Credential Provisioning Protocol", Work in + Progress, October 2002. + + [IKEv2] Kaufman, C., "Internet Key Exchange (IKEv2) + Protocol", Work in Progress, January 2004. + + [PPTPv1] Schneier, B. and Mudge, "Cryptanalysis of + Microsoft's Point-to- Point Tunneling Protocol", + Proceedings of the 5th ACM Conference on + Communications and Computer Security, ACM Press, + November 1998. + + [IEEE-802.11] Institute of Electrical and Electronics Engineers, + "Wireless LAN Medium Access Control (MAC) and + Physical Layer (PHY) Specifications", IEEE + Standard 802.11, 1999. + + [SILVERMAN] Silverman, Robert D., "A Cost-Based Security + Analysis of Symmetric and Asymmetric Key Lengths", + RSA Laboratories Bulletin 13, April 2000 (Revised + November 2001), + http://www.rsasecurity.com/rsalabs/bulletins/ + bulletin13.html. + + [KEYFRAME] Aboba, B., "EAP Key Management Framework", Work in + Progress, October 2003. + + [SASLPREP] Zeilenga, K., "SASLprep: Stringprep profile for + user names and passwords", Work in Progress, March + 2004. + + [IEEE-802.11i] Institute of Electrical and Electronics Engineers, + "Unapproved Draft Supplement to Standard for + Telecommunications and Information Exchange + Between Systems - LAN/MAN Specific Requirements - + Part 11: Wireless LAN Medium Access Control (MAC) + and Physical Layer (PHY) Specifications: + Specification for Enhanced Security", IEEE Draft + 802.11i (work in progress), 2003. + + [DIAM-EAP] Eronen, P., Hiller, T. and G. Zorn, "Diameter + Extensible Authentication Protocol (EAP) + Application", Work in Progress, February 2004. + + [EAP-EVAL] Zorn, G., "Specifying Security Claims for EAP + Authentication Types", Work in Progress, October + 2002. + + + +Aboba, et al. Standards Track [Page 62] + +RFC 3748 EAP June 2004 + + + [BINDING] Puthenkulam, J., "The Compound Authentication + Binding Problem", Work in Progress, October 2003. + + [MITM] Asokan, N., Niemi, V. and K. Nyberg, "Man-in-the- + Middle in Tunneled Authentication Protocols", IACR + ePrint Archive Report 2002/163, October 2002, + <http://eprint.iacr.org/2002/163>. + + [IEEE-802.11i-req] Stanley, D., "EAP Method Requirements for Wireless + LANs", Work in Progress, February 2004. + + [PPTPv2] Schneier, B. and Mudge, "Cryptanalysis of + Microsoft's PPTP Authentication Extensions (MS- + CHAPv2)", CQRE 99, Springer-Verlag, 1999, pp. + 192-203. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Aboba, et al. Standards Track [Page 63] + +RFC 3748 EAP June 2004 + + +Appendix A. Changes from RFC 2284 + + This section lists the major changes between [RFC2284] and this + document. Minor changes, including style, grammar, spelling, and + editorial changes are not mentioned here. + + o The Terminology section (Section 1.2) has been expanded, defining + more concepts and giving more exact definitions. + + o The concepts of Mutual Authentication, Key Derivation, and Result + Indications are introduced and discussed throughout the document + where appropriate. + + o In Section 2, it is explicitly specified that more than one + exchange of Request and Response packets may occur as part of the + EAP authentication exchange. How this may be used and how it may + not be used is specified in detail in Section 2.1. + + o Also in Section 2, some requirements have been made explicit for + the authenticator when acting in pass-through mode. + + o An EAP multiplexing model (Section 2.2) has been added to + illustrate a typical implementation of EAP. There is no + requirement that an implementation conform to this model, as long + as the on-the-wire behavior is consistent with it. + + o As EAP is now in use with a variety of lower layers, not just PPP + for which it was first designed, Section 3 on lower layer behavior + has been added. + + o In the description of the EAP Request and Response interaction + (Section 4.1), both the behavior on receiving duplicate requests, + and when packets should be silently discarded has been more + exactly specified. The implementation notes in this section have + been substantially expanded. + + o In Section 4.2, it has been clarified that Success and Failure + packets must not contain additional data, and the implementation + note has been expanded. A subsection giving requirements on + processing of success and failure packets has been added. + + o Section 5 on EAP Request/Response Types lists two new Type values: + the Expanded Type (Section 5.7), which is used to expand the Type + value number space, and the Experimental Type. In the Expanded + Type number space, the new Expanded Nak (Section 5.3.2) Type has + been added. Clarifications have been made in the description of + most of the existing Types. Security claims summaries have been + added for authentication methods. + + + +Aboba, et al. Standards Track [Page 64] + +RFC 3748 EAP June 2004 + + + o In Sections 5, 5.1, and 5.2, a requirement has been added such + that fields with displayable messages should contain UTF-8 encoded + ISO 10646 characters. + + o It is now required in Section 5.1 that if the Type-Data field of + an Identity Request contains a NUL-character, only the part before + the null is displayed. RFC 2284 prohibits the null termination of + the Type-Data field of Identity messages. This rule has been + relaxed for Identity Request messages and the Identity Request + Type-Data field may now be null terminated. + + o In Section 5.5, support for OTP Extended Responses [RFC2243] has + been added to EAP OTP. + + o An IANA Considerations section (Section 6) has been added, giving + registration policies for the numbering spaces defined for EAP. + + o The Security Considerations (Section 7) have been greatly + expanded, giving a much more comprehensive coverage of possible + threats and other security considerations. + + o In Section 7.5, text has been added on method-specific behavior, + providing guidance on how EAP method-specific integrity checks + should be processed. Where possible, it is desirable for a + method-specific MIC to be computed over the entire EAP packet, + including the EAP layer header (Code, Identifier, Length) and EAP + method layer header (Type, Type-Data). + + o In Section 7.14 the security risks involved in use of cleartext + passwords with EAP are described. + + o In Section 7.15 text has been added relating to detection of rogue + NAS behavior. + + + + + + + + + + + + + + + + + + +Aboba, et al. Standards Track [Page 65] + +RFC 3748 EAP June 2004 + + +Authors' Addresses + + Bernard Aboba + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + USA + + Phone: +1 425 706 6605 + Fax: +1 425 936 6605 + EMail: bernarda@microsoft.com + + Larry J. Blunk + Merit Network, Inc + 4251 Plymouth Rd., Suite 2000 + Ann Arbor, MI 48105-2785 + USA + + Phone: +1 734-647-9563 + Fax: +1 734-647-3185 + EMail: ljb@merit.edu + + John R. Vollbrecht + Vollbrecht Consulting LLC + 9682 Alice Hill Drive + Dexter, MI 48130 + USA + + EMail: jrv@umich.edu + + James Carlson + Sun Microsystems, Inc + 1 Network Drive + Burlington, MA 01803-2757 + USA + + Phone: +1 781 442 2084 + Fax: +1 781 442 1677 + EMail: james.d.carlson@sun.com + + Henrik Levkowetz + ipUnplugged AB + Arenavagen 33 + Stockholm S-121 28 + SWEDEN + + Phone: +46 708 32 16 08 + EMail: henrik@levkowetz.com + + + +Aboba, et al. Standards Track [Page 66] + +RFC 3748 EAP June 2004 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2004). This document is subject + to the rights, licenses and restrictions contained in BCP 78, and + except as set forth therein, the authors retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at ietf- + ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + +Aboba, et al. Standards Track [Page 67] + diff --git a/src/charon/doc/standards/rfc4739.txt b/src/charon/doc/standards/rfc4739.txt new file mode 100644 index 000000000..db5cf6acf --- /dev/null +++ b/src/charon/doc/standards/rfc4739.txt @@ -0,0 +1,619 @@ + + + + + + +Network Working Group P. Eronen +Request for Comments: 4739 Nokia +Category: Experimental J. Korhonen + TeliaSonera + November 2006 + + + Multiple Authentication Exchanges + in the Internet Key Exchange (IKEv2) Protocol + +Status of This Memo + + This memo defines an Experimental Protocol for the Internet + community. It does not specify an Internet standard of any kind. + Discussion and suggestions for improvement are requested. + Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The IETF Trust (2006). + +Abstract + + The Internet Key Exchange (IKEv2) protocol supports several + mechanisms for authenticating the parties, including signatures with + public-key certificates, shared secrets, and Extensible + Authentication Protocol (EAP) methods. Currently, each endpoint uses + only one of these mechanisms to authenticate itself. This document + specifies an extension to IKEv2 that allows the use of multiple + authentication exchanges, using either different mechanisms or the + same mechanism. This extension allows, for instance, performing + certificate-based authentication of the client host followed by an + EAP authentication of the user. When backend authentication servers + are used, they can belong to different administrative domains, such + as the network access provider and the service provider. + + + + + + + + + + + + + + + + +Eronen & Korhonen Experimental [Page 1] + +RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006 + + +Table of Contents + + 1. Introduction ....................................................3 + 1.1. Usage Scenarios ............................................4 + 1.2. Terminology ................................................5 + 2. Solution ........................................................5 + 2.1. Solution Overview ..........................................5 + 2.2. Example 1: Multiple EAP Authentications ....................6 + 2.3. Example 2: Mixed EAP and Certificate Authentications .......7 + 2.4. Example 3: Multiple Initiator Certificates .................8 + 2.5. Example 4: Multiple Responder Certificates .................8 + 3. Payload Formats .................................................9 + 3.1. MULTIPLE_AUTH_SUPPORTED Notify Payload .....................9 + 3.2. ANOTHER_AUTH_FOLLOWS Notify Payload ........................9 + 4. IANA Considerations .............................................9 + 5. Security Considerations .........................................9 + 6. Acknowledgments ................................................10 + 7. References .....................................................10 + 7.1. Normative References ......................................10 + 7.2. Informative References ....................................10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Eronen & Korhonen Experimental [Page 2] + +RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006 + + +1. Introduction + + IKEv2 [IKEv2] supports several mechanisms for parties involved in the + IKE_SA (IKE security association). These include signatures with + public-key certificates, shared secrets, and Extensible + Authentication Protocol (EAP) methods. + + Currently, each endpoint uses only one of these mechanisms to + authenticate itself. However, there are scenarios where making the + authorization decision in IKEv2 (whether to allow access or not) + requires using several of these methods. + + For instance, it may be necessary to authenticate both the host + (machine) requesting access, and the user currently using the host. + These two authentications would use two separate sets of credentials + (such as certificates and associated private keys) and might even use + different authentication mechanisms. + + To take another example, when an operator is hosting a Virtual + Private Network (VPN) gateway service for a third party, it may be + necessary to authenticate the client to both the operator (for + billing purposes) and the third party's Authentication, + Authorization, and Accounting (AAA) server (for authorizing access to + the third party's internal network). + + This document specifies an extension to IKEv2 that allows the use of + multiple authentication exchanges, using either different mechanisms + or the same mechanism. This extension allows, for instance, + performing certificate-based authentication of the client host + followed by an EAP authentication of the user. + + Each authentication exchange requiring communication with backend AAA + servers may be directed to different backend AAA servers, located + even in different administrative domains. However, details of the + communication between the IKEv2 gateway and the backend + authentication servers are beyond the scope of this document. In + particular, this document does not specify any changes to existing + AAA protocols, and it does not require the use of any particular AAA + protocol. + + In case of several EAP authentications, it is important to notice + that they are not a "sequence" (as described in Section 2.1 of + [EAP]), but separate independent EAP conversations, which are usually + also terminated in different EAP servers. Multiple authentication + methods within a single EAP conversation are still prohibited as + described in Section 2.1 of [EAP]. Using multiple independent EAP + conversations is similar to the separate Network Access Provider + (NAP) and Internet Service Provider (ISP) authentication exchanges + + + +Eronen & Korhonen Experimental [Page 3] + +RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006 + + + planned for [PANA]. The discovery of the appropriate EAP server for + each EAP authentication conversation is based on AAA routing. + +1.1. Usage Scenarios + + Figure 1 shows an example architecture of an operator-hosted VPN + scenario that could benefit from a two-phase authentication within + the IKEv2 exchange. First, the client authenticates towards the + Network Access Provider (NAP) and gets access to the NAP-hosted VPN + gateway. The first-phase authentication involves the backend AAA + server of the NAP. After the first authentication, the client + initiates the second authentication round that also involves the + Third Party's backend AAA server. If both authentications succeed, + the required IPsec tunnels are set up and the client can access + protected networks behind the Third Party. + + + Client *Network Access Provider* + +---------+ +---------+ +-----+ + | | | NAP's | | NAP | + |Protected| IPsec SAs | Tunnel | AAA Protocol | AAA | + |Endpoint |<------------------>|Endpoint |<------------>|Serv/| + | | | | |Proxy| + +---------+ +---------+ +-----+ + ^ ^ + IPsec or / AAA | + Leased Line / Protocol | + / | + v | + +---------+ *Third Party* v + |3rd Party| +-----+ + Protected | Tunnel | | 3rd | + Subnet <----|Endpoint | |Party| + | | | AAA | + +---------+ +-----+ + + Figure 1: Two-phase authentication used to gain access to + the Third Party network via Network Access Provider. AAA + traffic goes through NAP's AAA server. + + The NAP's AAA server can be used to proxy the AAA traffic to the + Third Party's backend AAA server. Alternatively, the AAA traffic + from the NAP's tunnel endpoint could go directly to the Third Party's + backend AAA servers. However, this is more or less an AAA routing + issue. + + + + + + +Eronen & Korhonen Experimental [Page 4] + +RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006 + + +1.2. Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [KEYWORDS]. + + The terms and abbreviations "authenticator", "backend authentication + server", "EAP server", and "peer" in this document are to be + interpreted as described in [EAP]. + + When messages containing IKEv2 payloads are described, optional + payloads are shown in brackets (for instance, "[FOO]"), and a plus + sign indicates that a payload can be repeated one or more times (for + instance, "FOO+"). + +2. Solution + +2.1. Solution Overview + + The peers announce support for this IKEv2 extension by including a + MULTIPLE_AUTH_SUPPORTED notification in the IKE_SA_INIT response + (responder) and the first IKE_AUTH request (initiator). + + If both peers support this extension, either of them can announce + that it wishes to have a second authentication by including an + ANOTHER_AUTH_FOLLOWS notification in any IKE_AUTH message that + contains an AUTH payload. This indicates that the peer sending the + ANOTHER_AUTH_FOLLOWS wishes to authenticate another set of + credentials to the other peer. The next IKE_AUTH message sent by + this peer will contain a second identity payload (IDi or IDr) and + starts another authentication exchange. The IKE_AUTH phase is + considered successful only if all the individual authentication + exchanges complete successfully. + + It is assumed that both peers know what credentials they want to + present; there is no negotiation about, for instance, what type of + authentication is to be done. As in IKEv2, EAP-based authentication + is always requested by the initiator (by omitting the AUTH payload). + + The AUTH payloads are calculated as specified in [IKEv2] Sections + 2.15 and 2.16, where IDi' refers to the latest IDi payload sent by + the initiator, and IDr' refers to the latest IDr payload sent by the + responder. If EAP methods that do not generate shared keys are used, + it is possible that several AUTH payloads with identical contents are + sent. When such EAP methods are used, the purpose of the AUTH + payload is simply to delimit the authentication exchanges, and ensure + that the IKE_SA_INIT request/response messages were not modified. + + + + +Eronen & Korhonen Experimental [Page 5] + +RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006 + + +2.2. Example 1: Multiple EAP Authentications + + This example shows certificate-based authentication of the responder + followed by an EAP authentication exchange (messages 1-10). When the + first EAP exchange is ending (the initiator is sending its AUTH + payload), the initiator announces that it wishes to have a second + authentication exchange by including an ANOTHER_AUTH_FOLLOWS + notification (message 9). + + After this, a second authentication exchange begins. The initiator + sends a new IDi payload but no AUTH payload (message 11), indicating + that EAP will be used. After that, another EAP authentication + exchange follows (messages 12-18). + + Initiator Responder + ----------- ----------- + 1. HDR, SA, KE, Ni --> + <-- 2. HDR, SA, KE, Nr, [CERTREQ], + N(MULTIPLE_AUTH_SUPPORTED) + 3. HDR, SK { IDi, [CERTREQ+], [IDr], + SA, TSi, TSr, N(MULTIPLE_AUTH_SUPPORTED) } --> + <-- 4. HDR, SK { IDr, [CERT+], AUTH, + EAP(Request) } + 5. HDR, SK { EAP(Response) } --> + <-- 6. HDR, SK { EAP(Request) } + 7. HDR, SK { EAP(Response) } --> + <-- 8. HDR, SK { EAP(Success) } + 9. HDR, SK { AUTH, + N(ANOTHER_AUTH_FOLLOWS) } --> + <-- 10. HDR, SK { AUTH } + 11. HDR, SK { IDi } --> + <-- 12. HDR, SK { EAP(Request) } + 13. HDR, SK { EAP(Response) } --> + <-- 14. HDR, SK { EAP(Request) } + 15. HDR, SK { EAP(Response) } --> + <-- 16. HDR, SK { EAP(Success) } + 17. HDR, SK { AUTH } --> + <-- 18. HDR, SK { AUTH, SA, TSi, TSr } + + Example 1: Certificate-based authentication of the + responder, followed by two EAP authentication exchanges. + + + + + + + + + + +Eronen & Korhonen Experimental [Page 6] + +RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006 + + +2.3. Example 2: Mixed EAP and Certificate Authentications + + Another example is shown below: here both the initiator and the + responder are first authenticated using certificates (or shared + secrets); this is followed by an EAP authentication exchange. + + Initiator Responder + ----------- ----------- + 1. HDR, SA, KE, Ni --> + <-- 2. HDR, SA, KE, Nr, [CERTREQ], + N(MULTIPLE_AUTH_SUPPORTED) + 3. HDR, SK { IDi, [CERT+], [CERTREQ+], [IDr], AUTH, + SA, TSi, TSr, N(MULTIPLE_AUTH_SUPPORTED), + N(ANOTHER_AUTH_FOLLOWS) } --> + <-- 4. HDR, SK { IDr, [CERT+], AUTH } + 5. HDR, SK { IDi } --> + <-- 6. HDR, SK { EAP(Request) } + 7. HDR, SK { EAP(Response) } --> + <-- 8. HDR, SK { EAP(Request) } + 9. HDR, SK { EAP(Response) } --> + <-- 10. HDR, SK { EAP(Success) } + 11. HDR, SK { AUTH } --> + <-- 12. HDR, SK { AUTH, SA, TSi, TSr } + + Example 2: Certificate-based (or shared-secret-based) + authentication of the initiator and the responder, + followed by an EAP authentication exchange. + + + + + + + + + + + + + + + + + + + + + + + + +Eronen & Korhonen Experimental [Page 7] + +RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006 + + +2.4. Example 3: Multiple Initiator Certificates + + This example shows yet another possibility: the initiator has two + different certificates (and associated private keys), and + authenticates both of them to the responder. + + Initiator Responder + ----------- ----------- + 1. HDR, SA, KE, Ni --> + <-- 2. HDR, SA, KE, Nr, [CERTREQ], + N(MULTIPLE_AUTH_SUPPORTED) + 3. HDR, SK { IDi, [CERT+], [CERTREQ+], [IDr], AUTH, + SA, TSi, TSr, N(MULTIPLE_AUTH_SUPPORTED), + N(ANOTHER_AUTH_FOLLOWS) } --> + <-- 4. HDR, SK { IDr, [CERT+], AUTH } + 5. HDR, SK { IDi, [CERT+], AUTH } --> + <-- 6. HDR, SK { SA, TSi, TSr } + + Example 3: Two certificate-based authentications of the + initiator, and one certificate-based authentication + of the responder. + +2.5. Example 4: Multiple Responder Certificates + + This example shows yet another possibility: the responder has two + different certificates (and associated private keys), and + authenticates both of them to the initiator. + + Initiator Responder + ----------- ----------- + 1. HDR, SA, KE, Ni --> + <-- 2. HDR, SA, KE, Nr, [CERTREQ], + N(MULTIPLE_AUTH_SUPPORTED) + 3. HDR, SK { IDi, [CERT+], [CERTREQ+], [IDr], AUTH, + SA, TSi, TSr, N(MULTIPLE_AUTH_SUPPORTED) } --> + <-- 4. HDR, SK { IDr, [CERT+], AUTH, + N(ANOTHER_AUTH_FOLLOWS) } + 5. HDR, SK { } --> + <-- 6. HDR, SK { IDr, [CERT+], AUTH, + SA, TSi, TSr } + + Example 4: Two certificate-based authentications of the + responder, and one certificate-based authentication + of the initiator. + + + + + + + +Eronen & Korhonen Experimental [Page 8] + +RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006 + + +3. Payload Formats + +3.1. MULTIPLE_AUTH_SUPPORTED Notify Payload + + The MULTIPLE_AUTH_SUPPORTED notification is included in the + IKE_SA_INIT response or the first IKE_AUTH request to indicate that + the peer supports this specification. The Notify Message Type is + MULTIPLE_AUTH_SUPPORTED (16404). The Protocol ID and SPI Size fields + MUST be set to zero, and there is no data associated with this Notify + type. + +3.2. ANOTHER_AUTH_FOLLOWS Notify Payload + + The ANOTHER_AUTH_FOLLOWS notification payload is included in an + IKE_AUTH message containing an AUTH payload to indicate that the peer + wants to continue with another authentication exchange. The Notify + Message Type is ANOTHER_AUTH_FOLLOWS (16405). The Protocol ID and + SPI Size fields MUST be set to zero, and there is no data associated + with this Notify type. + +4. IANA Considerations + + This document defines two new IKEv2 notifications, + MULTIPLE_AUTH_SUPPORTED and ANOTHER_AUTH_FOLLOWS, whose values are + allocated from the "IKEv2 Notify Message Types" namespace defined in + [IKEv2]. + + This document does not define any new namespaces to be managed by + IANA. + +5. Security Considerations + + Security considerations for IKEv2 are discussed in [IKEv2]. The + reader is encouraged to pay special attention to considerations + relating to the use of EAP methods that do not generate shared keys. + However, the use of multiple authentication exchanges results in at + least one new security consideration. + + In normal IKEv2, the responder authenticates the initiator before + revealing its identity (except when EAP is used). When multiple + authentication exchanges are used to authenticate the initiator, the + responder has to reveal its identity before all of the initiator + authentication exchanges have been completed. + + + + + + + + +Eronen & Korhonen Experimental [Page 9] + +RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006 + + +6. Acknowledgments + + The authors would like to thank Bernard Aboba, Jari Arkko, Spencer + Dawkins, Lakshminath Dondeti, Henry Haverinen, Russ Housley, Mika + Joutsenvirta, Charlie Kaufman, Tero Kivinen, Yoav Nir, Magnus + Nystrom, Mohan Parthasarathy, and Juha Savolainen for their valuable + comments. + +7. References + +7.1. Normative References + + [IKEv2] Kaufman, C., "Internet Key Exchange (IKEv2) Protocol", + RFC 4306, December 2005. + + [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", RFC 2119, March 1997. + +7.2. Informative References + + [EAP] Aboba, B., Blunk, L., Vollbrecht, J., Carlson, J., and H. + Levkowetz, "Extensible Authentication Protocol (EAP)", + RFC 3748, June 2004. + + [PANA] Yegin, A., Ohba, Y., Penno, R., Tsirtsis, G., and C. + Wang, "Protocol for Carrying Authentication for Network + Access (PANA) Requirements", RFC 4058, May 2005. + +Authors' Addresses + + Pasi Eronen + Nokia Research Center + P.O. Box 407 + FIN-00045 Nokia Group + Finland + + EMail: pasi.eronen@nokia.com + + + Jouni Korhonen + TeliaSonera + P.O. Box 970 + FIN-00051 Sonera + Finland + + EMail: jouni.korhonen@teliasonera.com + + + + + +Eronen & Korhonen Experimental [Page 10] + +RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006 + + +Full Copyright Statement + + Copyright (C) The IETF Trust (2006). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST, + AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT + THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY + IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR + PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + +Eronen & Korhonen Experimental [Page 11] + diff --git a/src/charon/encoding/generator.c b/src/charon/encoding/generator.c index 07db45f1b..efa845bb3 100644 --- a/src/charon/encoding/generator.c +++ b/src/charon/encoding/generator.c @@ -738,7 +738,7 @@ static void generate_payload (private_generator_t *this,payload_t *payload) case SPIS: case CONFIGURATION_ATTRIBUTE_VALUE: case VID_DATA: - case EAP_MESSAGE: + case EAP_DATA: { u_int32_t payload_length_position_offset; u_int16_t length_of_payload; @@ -777,7 +777,7 @@ static void generate_payload (private_generator_t *this,payload_t *payload) case CONFIGURATION_ATTRIBUTE_VALUE: header_length = CONFIGURATION_ATTRIBUTE_HEADER_LENGTH; break; - case EAP_MESSAGE: + case EAP_DATA: header_length = EAP_PAYLOAD_HEADER_LENGTH; break; default: diff --git a/src/charon/encoding/message.c b/src/charon/encoding/message.c index f1b92e934..fb37c996d 100644 --- a/src/charon/encoding/message.c +++ b/src/charon/encoding/message.c @@ -142,11 +142,12 @@ static payload_rule_t ike_sa_init_r_payload_rules[] = { */ static payload_rule_t ike_auth_i_payload_rules[] = { {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE}, + {EXTENSIBLE_AUTHENTICATION,0,1,TRUE,TRUE}, + {AUTHENTICATION,0,1,TRUE,TRUE}, {ID_INITIATOR,1,1,TRUE,FALSE}, {CERTIFICATE,0,1,TRUE,FALSE}, {CERTIFICATE_REQUEST,0,1,TRUE,FALSE}, {ID_RESPONDER,0,1,TRUE,FALSE}, - {AUTHENTICATION,1,1,TRUE,FALSE}, {SECURITY_ASSOCIATION,1,1,TRUE,FALSE}, {TRAFFIC_SELECTOR_INITIATOR,1,1,TRUE,FALSE}, {TRAFFIC_SELECTOR_RESPONDER,1,1,TRUE,FALSE}, @@ -158,12 +159,13 @@ static payload_rule_t ike_auth_i_payload_rules[] = { */ static payload_rule_t ike_auth_r_payload_rules[] = { {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,TRUE}, + {EXTENSIBLE_AUTHENTICATION,0,1,TRUE,TRUE}, {CERTIFICATE,0,1,TRUE,FALSE}, - {ID_RESPONDER,1,1,TRUE,FALSE}, - {AUTHENTICATION,1,1,TRUE,FALSE}, - {SECURITY_ASSOCIATION,1,1,TRUE,FALSE}, - {TRAFFIC_SELECTOR_INITIATOR,1,1,TRUE,FALSE}, - {TRAFFIC_SELECTOR_RESPONDER,1,1,TRUE,FALSE}, + {ID_RESPONDER,0,1,TRUE,FALSE}, + {AUTHENTICATION,0,1,TRUE,FALSE}, + {SECURITY_ASSOCIATION,0,1,TRUE,FALSE}, + {TRAFFIC_SELECTOR_INITIATOR,0,1,TRUE,FALSE}, + {TRAFFIC_SELECTOR_RESPONDER,0,1,TRUE,FALSE}, {CONFIGURATION,0,1,TRUE,FALSE}, }; diff --git a/src/charon/encoding/parser.c b/src/charon/encoding/parser.c index d7f10f711..d7caf7099 100644 --- a/src/charon/encoding/parser.c +++ b/src/charon/encoding/parser.c @@ -626,7 +626,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case U_INT_32: { @@ -635,7 +635,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case U_INT_64: { @@ -644,7 +644,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case IKE_SPI: { @@ -653,7 +653,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case RESERVED_BIT: { @@ -662,7 +662,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case RESERVED_BYTE: { @@ -680,7 +680,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case PAYLOAD_LENGTH: { @@ -690,7 +690,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ return PARSE_ERROR; } payload_length = *(u_int16_t*)(output + rule->offset); - break; + break; } case HEADER_LENGTH: { @@ -699,7 +699,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case SPI_SIZE: { @@ -709,7 +709,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ return PARSE_ERROR; } spi_size = *(u_int8_t*)(output + rule->offset); - break; + break; } case SPI: { @@ -718,7 +718,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case PROPOSALS: { @@ -728,7 +728,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case TRANSFORMS: { @@ -738,7 +738,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case TRANSFORM_ATTRIBUTES: { @@ -748,7 +748,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case CONFIGURATION_ATTRIBUTES: { @@ -758,7 +758,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case ATTRIBUTE_FORMAT: { @@ -789,7 +789,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ } attribute_length = *(u_int16_t*)(output + rule->offset); break; - } + } case ATTRIBUTE_LENGTH_OR_VALUE: { if (this->parse_uint16(this, rule_number, output + rule->offset) != SUCCESS) @@ -820,7 +820,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case ID_DATA: { @@ -830,7 +830,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ pld->destroy(pld); return PARSE_ERROR; } - break; + break; } case AUTH_DATA: { @@ -839,8 +839,8 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ { pld->destroy(pld); return PARSE_ERROR; - } - break; + } + break; } case CERT_DATA: { @@ -849,8 +849,8 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ { pld->destroy(pld); return PARSE_ERROR; - } - break; + } + break; } case CERTREQ_DATA: { @@ -859,18 +859,18 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ { pld->destroy(pld); return PARSE_ERROR; - } - break; + } + break; } - case EAP_MESSAGE: + case EAP_DATA: { size_t data_length = payload_length - EAP_PAYLOAD_HEADER_LENGTH; if (this->parse_chunk(this, rule_number, output + rule->offset, data_length) != SUCCESS) { pld->destroy(pld); return PARSE_ERROR; - } - break; + } + break; } case SPIS: { diff --git a/src/charon/encoding/payloads/eap_payload.c b/src/charon/encoding/payloads/eap_payload.c index aa886e9c4..79ab32fe5 100644 --- a/src/charon/encoding/payloads/eap_payload.c +++ b/src/charon/encoding/payloads/eap_payload.c @@ -25,6 +25,7 @@ #include "eap_payload.h" +#include <daemon.h> typedef struct private_eap_payload_t private_eap_payload_t; @@ -54,9 +55,9 @@ struct private_eap_payload_t { u_int16_t payload_length; /** - * The contained message. + * EAP message data, if available */ - chunk_t message; + chunk_t data; }; /** @@ -80,21 +81,21 @@ encoding_rule_t eap_payload_encodings[] = { { RESERVED_BIT, 0 }, { RESERVED_BIT, 0 }, /* Length of the whole payload*/ - { PAYLOAD_LENGTH, offsetof(private_eap_payload_t, payload_length)}, - /* some eap data bytes, length is defined in PAYLOAD_LENGTH */ - { EAP_MESSAGE, offsetof(private_eap_payload_t, message) } + { PAYLOAD_LENGTH, offsetof(private_eap_payload_t, payload_length) }, + /* chunt to data, starting at "code" */ + { EAP_DATA, offsetof(private_eap_payload_t, data) }, }; /* - 1 2 3 + 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Next Payload !C! RESERVED ! Payload Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! ! - ~ EAP Message ~ - ! ! + ! Code ! Identifier ! Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Type ! Type_Data... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- */ /** @@ -102,6 +103,47 @@ encoding_rule_t eap_payload_encodings[] = { */ static status_t verify(private_eap_payload_t *this) { + u_int16_t length; + u_int8_t code; + + if (this->data.len < 4) + { + DBG1(DBG_ENC, "EAP payloads EAP message too short (%d)", this->data.len); + return FAILED; + } + code = *this->data.ptr; + length = htons(*(u_int16_t*)(this->data.ptr + 2)); + if (this->data.len != length) + { + DBG1(DBG_ENC, "EAP payload length (%d) does not match contained message length (%d)", + this->data.len, length); + return FAILED; + } + switch (code) + { + case EAP_REQUEST: + case EAP_RESPONSE: + { + if (this->data.len < 4) + { + DBG1(DBG_ENC, "EAP Request/Response does not have any data"); + return FAILED; + } + break; + } + case EAP_SUCCESS: + case EAP_FAILURE: + { + if (this->data.len != 4) + { + DBG1(DBG_ENC, "EAP Success/Failure has data"); + return FAILED; + } + break; + } + default: + return FAILED; + } return SUCCESS; } @@ -147,40 +189,59 @@ static size_t get_length(private_eap_payload_t *this) } /** - * Implementation of eap_payload_t.set_message. + * Implementation of eap_payload_t.get_data. + */ +static chunk_t get_data(private_eap_payload_t *this) +{ + return this->data; +} + +/** + * Implementation of eap_payload_t.set_data. */ -static void set_message (private_eap_payload_t *this, chunk_t message) +static void set_data(private_eap_payload_t *this, chunk_t data) { - if (this->message.ptr != NULL) + chunk_free(&this->data); + this->data = chunk_clone(data); + this->payload_length = this->data.len + 4; +} + +/** + * Implementation of eap_payload_t.get_code. + */ +static eap_code_t get_code(private_eap_payload_t *this) +{ + if (this->data.len > 0) { - chunk_free(&(this->message)); + return *this->data.ptr; } - this->message.ptr = clalloc(message.ptr,message.len); - this->message.len = message.len; - this->payload_length = EAP_PAYLOAD_HEADER_LENGTH + this->message.len; + /* should not happen, as it is verified */ + return 0; } /** - * Implementation of eap_payload_t.get_message. + * Implementation of eap_payload_t.get_identifier. */ -static chunk_t get_message (private_eap_payload_t *this) +static u_int8_t get_identifier(private_eap_payload_t *this) { - return (this->message); + if (this->data.len > 1) + { + return *(this->data.ptr + 1); + } + /* should not happen, as it is verified */ + return 0; } /** - * Implementation of eap_payload_t.get_data_clone. + * Implementation of eap_payload_t.get_type. */ -static chunk_t get_message_clone (private_eap_payload_t *this) +static eap_type_t get_type(private_eap_payload_t *this) { - chunk_t cloned_message; - if (this->message.ptr == NULL) + if (this->data.len > 4) { - return (this->message); + return *(this->data.ptr + 4); } - cloned_message.ptr = clalloc(this->message.ptr,this->message.len); - cloned_message.len = this->message.len; - return cloned_message; + return 0; } /** @@ -188,12 +249,8 @@ static chunk_t get_message_clone (private_eap_payload_t *this) */ static void destroy(private_eap_payload_t *this) { - if (this->message.ptr != NULL) - { - chunk_free(&(this->message)); - } - - free(this); + chunk_free(&this->data); + free(this); } /* @@ -202,7 +259,7 @@ static void destroy(private_eap_payload_t *this) eap_payload_t *eap_payload_create() { private_eap_payload_t *this = malloc_thing(private_eap_payload_t); - + /* interface functions */ this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; @@ -214,15 +271,61 @@ eap_payload_t *eap_payload_create() /* public functions */ this->public.destroy = (void (*) (eap_payload_t *)) destroy; - this->public.set_message = (void (*) (eap_payload_t *,chunk_t)) set_message; - this->public.get_message_clone = (chunk_t (*) (eap_payload_t *)) get_message_clone; - this->public.get_message = (chunk_t (*) (eap_payload_t *)) get_message; + this->public.get_data = (chunk_t (*) (eap_payload_t*))get_data; + this->public.set_data = (void (*) (eap_payload_t *,chunk_t))set_data; + this->public.get_code = (eap_code_t (*) (eap_payload_t*))get_code; + this->public.get_identifier = (u_int8_t (*) (eap_payload_t*))get_identifier; + this->public.get_type = (eap_type_t (*) (eap_payload_t*))get_type; /* private variables */ this->critical = FALSE; this->next_payload = NO_PAYLOAD; this->payload_length = EAP_PAYLOAD_HEADER_LENGTH; - this->message = chunk_empty; + this->data = chunk_empty; + + return &(this->public); +} + +/* + * Described in header + */ +eap_payload_t *eap_payload_create_data(chunk_t data) +{ + eap_payload_t *this = eap_payload_create(); + + this->set_data(this, data); + return this; +} - return (&(this->public)); +/* + * Described in header + */ +eap_payload_t *eap_payload_create_code(eap_code_t code) +{ + eap_payload_t *this = eap_payload_create(); + chunk_t data = chunk_alloca(4); + + *(data.ptr + 0) = code; + *(data.ptr + 1) = 0; + *(u_int16_t*)(data.ptr + 2) = htons(data.len); + + this->set_data(this, data); + return this; +} + +/* + * Described in header + */ +eap_payload_t *eap_payload_create_nak() +{ + eap_payload_t *this = eap_payload_create(); + chunk_t data = chunk_alloca(5); + + *(data.ptr + 0) = EAP_RESPONSE; + *(data.ptr + 1) = 0; + *(u_int16_t*)(data.ptr + 2) = htons(data.len); + *(data.ptr + 4) = EAP_NAK; + + this->set_data(this, data); + return this; } diff --git a/src/charon/encoding/payloads/eap_payload.h b/src/charon/encoding/payloads/eap_payload.h index bf493eb7f..13c0ade80 100644 --- a/src/charon/encoding/payloads/eap_payload.h +++ b/src/charon/encoding/payloads/eap_payload.h @@ -28,6 +28,7 @@ typedef struct eap_payload_t eap_payload_t; #include <library.h> #include <encoding/payloads/payload.h> +#include <sa/authenticators/eap/eap_method.h> /** * Length of a EAP payload without the EAP Message in bytes. @@ -44,62 +45,105 @@ typedef struct eap_payload_t eap_payload_t; * @b Constructors: * - eap_payload_create() * - * @todo Implement functionality for this payload - * * @ingroup payloads */ struct eap_payload_t { + /** * The payload_t interface. */ payload_t payload_interface; /** - * @brief Set the EAP Message. - * - * Data are getting cloned. + * @brief Set the contained EAP data. + * + * This contains the FULL EAP message starting with "code". + * Chunk gets cloned. + * + * @param this calling eap_payload_t object + * @param message EAP data + */ + void (*set_data) (eap_payload_t *this, chunk_t data); + + /** + * @brief Get the contained EAP data. + * + * This contains the FULL EAP message starting with "code". * - * @param this calling eap_payload_t object - * @param message EAP message as chunk_t + * @param this calling eap_payload_t object + * @return EAP data (pointer to internal data) */ - void (*set_message) (eap_payload_t *this, chunk_t message); + chunk_t (*get_data) (eap_payload_t *this); /** - * @brief Get the EAP message. - * - * Returned data are a copy of the internal one. + * @brief Get the EAP code. * - * @param this calling eap_payload_t object - * @return EAP message as chunk_t + * @param this calling eap_payload_t object + * @return EAP message as chunk_t */ - chunk_t (*get_message_clone) (eap_payload_t *this); + eap_code_t (*get_code) (eap_payload_t *this); /** - * @brief Get the EAP message. - * - * Returned data are NOT copied. + * @brief Get the EAP identifier. * - * @param this calling eap_payload_t object - * @return EAP message as chunk_t + * @param this calling eap_payload_t object + * @return unique identifier */ - chunk_t (*get_message) (eap_payload_t *this); + u_int8_t (*get_identifier) (eap_payload_t *this); + + /** + * @brief Get the EAP method type. + * + * @param this calling eap_payload_t object + * @return EAP method type + */ + eap_type_t (*get_type) (eap_payload_t *this); /** * @brief Destroys an eap_payload_t object. * - * @param this eap_payload_t object to destroy + * @param this eap_payload_t object to destroy */ void (*destroy) (eap_payload_t *this); }; /** * @brief Creates an empty eap_payload_t object. - * + * * @return eap_payload_t object - * + * * @ingroup payloads */ eap_payload_t *eap_payload_create(void); +/** + * @brief Creates an eap_payload_t object with data. + * + * @return eap_payload_t object + * + * @ingroup payloads + */ +eap_payload_t *eap_payload_create_data(chunk_t data); + +/** + * @brief Creates an eap_payload_t object with a code. + * + * Could should be either EAP_SUCCESS/EAP_FAILURE, use + * constructor above otherwise. + * + * @return eap_payload_t object + * + * @ingroup payloads + */ +eap_payload_t *eap_payload_create_code(eap_code_t code); + +/** + * @brief Creates an eap_payload_t EAP_RESPONSE containing an EAP_NAK. + * + * @return eap_payload_t object + * + * @ingroup payloads + */ +eap_payload_t *eap_payload_create_nak(); #endif /* EAP_PAYLOAD_H_ */ diff --git a/src/charon/encoding/payloads/encodings.h b/src/charon/encoding/payloads/encodings.h index ed5596ecd..5e07fbfab 100644 --- a/src/charon/encoding/payloads/encodings.h +++ b/src/charon/encoding/payloads/encodings.h @@ -449,7 +449,7 @@ enum encoding_type_t { * * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. */ - EAP_MESSAGE, + EAP_DATA, /** * Representating the SPIS field in a DELETE payload. diff --git a/src/charon/encoding/payloads/notify_payload.c b/src/charon/encoding/payloads/notify_payload.c index b11d8f206..38ee0946d 100644 --- a/src/charon/encoding/payloads/notify_payload.c +++ b/src/charon/encoding/payloads/notify_payload.c @@ -75,7 +75,9 @@ ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, INVALID_SELECTORS, "COOKIE2", "NO_NATS_ALLOWED", "AUTH_LIFETIME"); -ENUM_END(notify_type_names, AUTH_LIFETIME); +ENUM_NEXT(notify_type_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, AUTH_LIFETIME, + "EAP_ONLY_AUTHENTICATION"); +ENUM_END(notify_type_names, EAP_ONLY_AUTHENTICATION); typedef struct private_notify_payload_t private_notify_payload_t; diff --git a/src/charon/encoding/payloads/notify_payload.h b/src/charon/encoding/payloads/notify_payload.h index 8861b9f4b..431932631 100644 --- a/src/charon/encoding/payloads/notify_payload.h +++ b/src/charon/encoding/payloads/notify_payload.h @@ -88,8 +88,10 @@ enum notify_type_t { NO_NATS_ALLOWED = 16402, /* repeated authentication extension, RFC4478 */ AUTH_LIFETIME = 16403, + /* draft-eronen-ipsec-ikev2-eap-auth, not assigned by IANA yet */ + EAP_ONLY_AUTHENTICATION = 40960, /* BEET mode, not even a draft yet. private use */ - USE_BEET_MODE = 40960, + USE_BEET_MODE = 40961, }; /** diff --git a/src/charon/sa/authenticators/authenticator.c b/src/charon/sa/authenticators/authenticator.c index 2460181f9..707aae9ad 100644 --- a/src/charon/sa/authenticators/authenticator.c +++ b/src/charon/sa/authenticators/authenticator.c @@ -26,6 +26,7 @@ #include <sa/authenticators/rsa_authenticator.h> #include <sa/authenticators/psk_authenticator.h> +#include <sa/authenticators/eap_authenticator.h> ENUM_BEGIN(auth_method_names, AUTH_RSA, AUTH_DSS, @@ -47,6 +48,8 @@ authenticator_t *authenticator_create(ike_sa_t *ike_sa, auth_method_t auth_metho return (authenticator_t*)rsa_authenticator_create(ike_sa); case AUTH_PSK: return (authenticator_t*)psk_authenticator_create(ike_sa); + case AUTH_EAP: + return (authenticator_t*)eap_authenticator_create(ike_sa); default: return NULL; } diff --git a/src/charon/sa/authenticators/eap/eap_aka.c b/src/charon/sa/authenticators/eap/eap_aka.c new file mode 100644 index 000000000..0c1bb3379 --- /dev/null +++ b/src/charon/sa/authenticators/eap/eap_aka.c @@ -0,0 +1,1399 @@ +/** + * @file eap_aka.c + * + * @brief Implementation of eap_aka_t. + * + */ + +/* + * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + + +/* The EAP-AKA method uses it's own simple parser for processing EAP-AKA + * payloads, as the IKEv2 parser is not suitable for that job. There are + * two simple methods for parsing payloads, read_header() and read_attribute(). + * Every EAP-AKA payload consists of a header and a list of attributes. Those + * functions mentioned read the data and return the type of the found + * attribute/EAP-AKA-type. For generating a EAP-AKA message, we have a + * build_aka_payload(), which builds the whole message from a variable + * argument list containing its attributes. + * The processing of messages is split up in various functions: + * - peer_process() - General processing multiplexer for the peer + * - peer_process_challenge() - Specific AKA-Challenge processor + * - peer_process_notification() - Processing of AKA-Notification + * - server_process() - General processing multiplexer for the server + * - peer_process_challenge() - Processing of a received Challenge response + * - peer_process_synchronize() - Process a sequence number synchronization + * - server_initiate() - Initiation method for the server, calls + * - server_initiate_challenge() - Initiation of AKA-Challenge + */ + +#include <string.h> +#include <unistd.h> + +#include "eap_aka.h" + +#include <daemon.h> +#include <library.h> +#include <utils/randomizer.h> +#include <crypto/hashers/hasher.h> +#include <crypto/prfs/fips_prf.h> + +/* Use test vectors specified in S.S0055 +#define TEST_VECTORS */ + +#define RAND_LENGTH 16 +#define RES_LENGTH 16 +#define SQN_LENGTH 6 +#define K_LENGTH 16 +#define MAC_LENGTH 8 +#define CK_LENGTH 16 +#define IK_LENGTH 16 +#define AK_LENGTH 6 +#define AMF_LENGTH 2 +#define FMK_LENGTH 4 +#define AUTN_LENGTH (SQN_LENGTH + AMF_LENGTH + MAC_LENGTH) +#define AUTS_LENGTH (SQN_LENGTH + MAC_LENGTH) +#define PAYLOAD_LENGTH 64 +#define MK_LENGTH 20 +#define MSK_LENGTH 64 +#define EMSK_LENGTH 64 +#define KAUTH_LENGTH 16 +#define KENCR_LENGTH 16 +#define AT_MAC_LENGTH 16 + +#define F1 0x42 +#define F1STAR 0x43 +#define F2 0x44 +#define F3 0x45 +#define F4 0x46 +#define F5 0x47 +#define F5STAR 0x48 + +ENUM_BEGIN(aka_subtype_names, AKA_CHALLENGE, AKA_IDENTITY, + "AKA_CHALLENGE", + "AKA_AUTHENTICATION_REJECT", + "AKA_3", + "AKA_SYNCHRONIZATION_FAILURE", + "AKA_IDENTITY"); +ENUM_NEXT(aka_subtype_names, AKA_NOTIFICATION, AKA_CLIENT_ERROR, AKA_IDENTITY, + "AKA_NOTIFICATION", + "AKA_REAUTHENTICATION", + "AKA_CLIENT_ERROR"); +ENUM_END(aka_subtype_names, AKA_CLIENT_ERROR); + + +ENUM_BEGIN(aka_attribute_names, AT_END, AT_CLIENT_ERROR_CODE, + "AT_END", + "AT_0", + "AT_RAND", + "AT_AUTN", + "AT_RES", + "AT_AUTS", + "AT_5", + "AT_PADDING", + "AT_NONCE_MT", + "AT_8", + "AT_9", + "AT_PERMANENT_ID_REQ", + "AT_MAC", + "AT_NOTIFICATION", + "AT_ANY_ID_REQ", + "AT_IDENTITY", + "AT_VERSION_LIST", + "AT_SELECTED_VERSION", + "AT_FULLAUTH_ID_REQ", + "AT_18", + "AT_COUNTER", + "AT_COUNTER_TOO_SMALL", + "AT_NONCE_S", + "AT_CLIENT_ERROR_CODE"); +ENUM_NEXT(aka_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE, + "AT_IV", + "AT_ENCR_DATA", + "AT_131", + "AT_NEXT_PSEUDONYM", + "AT_NEXT_REAUTH_ID", + "AT_CHECKCODE", + "AT_RESULT_IND"); +ENUM_END(aka_attribute_names, AT_RESULT_IND); + + +typedef struct private_eap_aka_t private_eap_aka_t; + +/** + * Private data of an eap_aka_t object. + */ +struct private_eap_aka_t { + + /** + * Public authenticator_t interface. + */ + eap_aka_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + + /** + * Key for EAP MAC + */ + chunk_t k_auth; + + /** + * Key for EAP encryption + */ + chunk_t k_encr; + + /** + * MSK + */ + chunk_t msk; + + /** + * Extendend MSK + */ + chunk_t emsk; + + /** + * Expected result from client XRES + */ + chunk_t xres; + + /** + * Shared secret K from ipsec.conf (padded) + */ + chunk_t k; + + /** + * random value RAND generated by server + */ + chunk_t rand; +}; + +/** Family key, as proposed in S.S0055 */ +static u_int8_t fmk_buf[] = {0x41, 0x48, 0x41, 0x47}; +static chunk_t fmk = chunk_from_buf(fmk_buf); + +/** Authentication management field */ +static u_int8_t amf_buf[] = {0x00, 0x01}; +static chunk_t amf = chunk_from_buf(amf_buf); + +/** AT_CLIENT_ERROR_CODE AKA attribute */ +static u_int8_t client_error_code_buf[] = {0, 0}; +static chunk_t client_error_code = chunk_from_buf(client_error_code_buf); + +/** previously used sqn by peer, next one must be greater */ +static u_int8_t peer_sqn_buf[6]; +static chunk_t peer_sqn = chunk_from_buf(peer_sqn_buf); + +/** set SQN to the current time */ +static void update_sqn(u_int8_t *sqn, time_t offset) +{ + timeval_t time; + gettimeofday(&time, NULL); + /* set sqb_sqn to an integer containing seconds followed by most + * significant useconds */ + time.tv_sec = htonl(time.tv_sec + offset); + /* usec's are never larger than 0x000f423f, so we shift the 12 first bits */ + time.tv_usec <<= 12; + time.tv_usec = htonl(time.tv_usec); + memcpy(sqn, &time.tv_sec, 4); + memcpy(sqn + 4, &time.tv_usec, 2); +} + +/** initialize peers SQN to the current system time at startup */ +static void __attribute__ ((constructor))init_sqn(void) +{ + update_sqn(peer_sqn_buf, 0); +} + +/** + * Binary represnation of the polynom T^160 + T^5 + T^3 + T^2 + 1 + */ +static u_int8_t g[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2d +}; + +/** + * Predefined random bits from the RAND Corporation book + */ +static u_int8_t a[] = { + 0x9d, 0xe9, 0xc9, 0xc8, 0xef, 0xd5, 0x78, 0x11, + 0x48, 0x23, 0x14, 0x01, 0x90, 0x1f, 0x2d, 0x49, + 0x3f, 0x4c, 0x63, 0x65 +}; + +/** + * Predefined random bits from the RAND Corporation book + */ +static u_int8_t b[] = { + 0x75, 0xef, 0xd1, 0x5c, 0x4b, 0x8f, 0x8f, 0x51, + 0x4e, 0xf3, 0xbc, 0xc3, 0x79, 0x4a, 0x76, 0x5e, + 0x7e, 0xec, 0x45, 0xe0 +}; + +/** + * Multiplicate two mpz_t with bits interpreted as polynoms. + */ +static void mpz_mul_poly(mpz_t r, mpz_t a, mpz_t b) +{ + mpz_t bm, rm; + int current = 0, shifted = 0, shift; + + mpz_init_set(bm, b); + mpz_init_set_ui(rm, 0); + /* scan through a, for each found bit: */ + while ((current = mpz_scan1(a, current)) != ULONG_MAX) + { + /* XOR shifted b into r */ + shift = current - shifted; + mpz_mul_2exp(bm, bm, shift); + shifted += shift; + mpz_xor(rm, rm, bm); + current++; + } + + mpz_swap(r, rm); + mpz_clear(rm); + mpz_clear(bm); +} + +/** + * Calculate the sum of a + b interpreted as polynoms. + */ +static void mpz_add_poly(mpz_t res, mpz_t a, mpz_t b) +{ + /* addition of polynominals is just the XOR */ + mpz_xor(res, a, b); +} + +/** + * Calculate the remainder of a/b interpreted as polynoms. + */ +static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b) +{ + /* Example: + * a = 10001010 + * b = 00000101 + */ + int a_bit, b_bit, diff; + mpz_t bm, am; + + mpz_init_set(am, a); + mpz_init(bm); + + a_bit = mpz_sizeinbase(a, 2); + b_bit = mpz_sizeinbase(b, 2); + + /* don't do anything if b > a */ + if (a_bit >= b_bit) + { + /* shift b left to align up most signaficant "1" to a: + * a = 10001010 + * b = 10100000 + */ + mpz_mul_2exp(bm, b, a_bit - b_bit); + do + { + /* XOR b into a, this kills the most significant "1": + * a = 00101010 + */ + mpz_xor(am, am, bm); + /* find the next most significant "1" in a, and align up b: + * a = 00101010 + * b = 00101000 + */ + diff = a_bit - mpz_sizeinbase(am, 2); + mpz_div_2exp(bm, bm, diff); + a_bit -= diff; + } + while (b_bit <= mpz_sizeinbase(bm, 2)); + /* While b is not shifted to its original value */ + } + /* after another iteration: + * a = 00000010 + * which is the polynomial modulo + */ + + mpz_swap(r, am); + mpz_clear(am); + mpz_clear(bm); +} + +/** + * Step 4 of the various fx() functions: + * Polynomial whiten calculations + */ +static void step4(u_int8_t x[]) +{ + mpz_t xm, am, bm, gm; + + mpz_init(xm); + mpz_init(am); + mpz_init(bm); + mpz_init(gm); + + mpz_import(xm, HASH_SIZE_SHA1, 1, 1, 1, 0, x); + mpz_import(am, sizeof(a), 1, 1, 1, 0, a); + mpz_import(bm, sizeof(b), 1, 1, 1, 0, b); + mpz_import(gm, sizeof(g), 1, 1, 1, 0, g); + + mpz_mul_poly(xm, am, xm); + mpz_add_poly(xm, bm, xm); + mpz_mod_poly(xm, xm, gm); + + mpz_export(x, NULL, 1, HASH_SIZE_SHA1, 1, 0, xm); + + mpz_clear(xm); + mpz_clear(am); + mpz_clear(bm); + mpz_clear(gm); +} + +/** + * Step 3 of the various fx() functions: + * XOR the key into the SHA1 IV + */ +static void step3(chunk_t k, chunk_t payload, u_int8_t h[]) +{ + u_int8_t iv[] = { + 0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA, + 0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0, + }; + + /* XOR key into IV */ + memxor(iv, k.ptr, k.len); + + /* hash it with the G() function defined in FIPS 186-2 from fips_prf.h */ + g_sha1(iv, payload, h); +} + +/** + * Calculation function for f2(), f3(), f4() + */ +static void fx(u_int8_t f, chunk_t k, chunk_t rand, u_int8_t out[]) +{ + chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); + u_int8_t h[HASH_SIZE_SHA1]; + u_int8_t i; + + for (i = 0; i < 2; i++) + { + memset(payload.ptr, 0x5c, payload.len); + payload.ptr[11] ^= f; + memxor(payload.ptr + 12, fmk.ptr, fmk.len); + memxor(payload.ptr + 24, rand.ptr, rand.len); + + payload.ptr[3] ^= i; + payload.ptr[19] ^= i; + payload.ptr[35] ^= i; + payload.ptr[51] ^= i; + + step3(k, payload, h); + step4(h); + memcpy(out + i * 8, h, 8); + } +} + +/** + * Calculation function of f1() and f1star() + */ +static void f1x(u_int8_t f, chunk_t k, chunk_t rand, chunk_t sqn, + chunk_t amf, u_int8_t mac[]) +{ + /* generate MAC = f1(FMK, SQN, RAND, AMF) + * K is loaded into hashers IV; FMK, RAND, SQN, AMF are XORed in a 512-bit + * payload which gets hashed + */ + chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); + u_int8_t h[HASH_SIZE_SHA1]; + + memset(payload.ptr, 0x5c, PAYLOAD_LENGTH); + payload.ptr[11] ^= f; + memxor(payload.ptr + 12, fmk.ptr, fmk.len); + memxor(payload.ptr + 16, rand.ptr, rand.len); + memxor(payload.ptr + 34, sqn.ptr, sqn.len); + memxor(payload.ptr + 42, amf.ptr, amf.len); + + step3(k, payload, h); + step4(h); + memcpy(mac, h, MAC_LENGTH); +} + +/** + * Calculation function of f5() and f5star() + */ +static void f5x(u_int8_t f, chunk_t k, chunk_t rand, u_int8_t ak[]) +{ + chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); + u_int8_t h[HASH_SIZE_SHA1]; + + memset(payload.ptr, 0x5c, payload.len); + payload.ptr[11] ^= f; + memxor(payload.ptr + 12, fmk.ptr, fmk.len); + memxor(payload.ptr + 16, rand.ptr, rand.len); + + step3(k, payload, h); + step4(h); + memcpy(ak, h, AK_LENGTH); +} + +/** + * Calculate the MAC from a RAND, SQN, AMF value using K + */ +static void f1(chunk_t k, chunk_t rand, chunk_t sqn, chunk_t amf, u_int8_t mac[]) +{ + f1x(F1, k, rand, sqn, amf, mac); + DBG3(DBG_IKE, "MAC %b", mac, MAC_LENGTH); +} + +/** + * Calculate the MACS from a RAND, SQN, AMF value using K + */ +static void f1star(chunk_t k, chunk_t rand, chunk_t sqn, chunk_t amf, u_int8_t macs[]) +{ + f1x(F1STAR, k, rand, sqn, amf, macs); + DBG3(DBG_IKE, "MACS %b", macs, MAC_LENGTH); +} + +/** + * Calculate RES from RAND using K + */ +static void f2(chunk_t k, chunk_t rand, u_int8_t res[]) +{ + fx(F2, k, rand, res); + DBG3(DBG_IKE, "RES %b", res, RES_LENGTH); +} + +/** + * Calculate CK from RAND using K + */ +static void f3(chunk_t k, chunk_t rand, u_int8_t ck[]) +{ + fx(F3, k, rand, ck); + DBG3(DBG_IKE, "CK %b", ck, CK_LENGTH); +} + +/** + * Calculate IK from RAND using K + */ +static void f4(chunk_t k, chunk_t rand, u_int8_t ik[]) +{ + fx(F4, k, rand, ik); + DBG3(DBG_IKE, "IK %b", ik, IK_LENGTH); +} + +/** + * Calculate AK from a RAND using K + */ +static void f5(chunk_t k, chunk_t rand, u_int8_t ak[]) +{ + f5x(F5, k, rand, ak); + DBG3(DBG_IKE, "AK %b", ak, AK_LENGTH); +} + +/** + * Calculate AKS from a RAND using K + */ +static void f5star(chunk_t k, chunk_t rand, u_int8_t aks[]) +{ + f5x(F5STAR, k, rand, aks); + DBG3(DBG_IKE, "AKS %b", aks, AK_LENGTH); +} + +/** + * derive the keys needed for EAP_AKA + */ +static void derive_keys(private_eap_aka_t *this, identification_t *id) +{ + hasher_t *hasher; + prf_t *prf; + chunk_t ck, ik, mk, identity, tmp; + + ck = chunk_alloca(CK_LENGTH); + ik = chunk_alloca(IK_LENGTH); + mk = chunk_alloca(MK_LENGTH); + identity = id->get_encoding(id); + + /* MK = SHA1( Identity | IK | CK ) */ + f3(this->k, this->rand, ck.ptr); + f4(this->k, this->rand, ik.ptr); + DBG3(DBG_IKE, "Identity %B", &identity); + tmp = chunk_cata("ccc", identity, ik, ck); + DBG3(DBG_IKE, "Identity|IK|CK %B", &tmp); + hasher = hasher_create(HASH_SHA1); + hasher->get_hash(hasher, tmp, mk.ptr); + hasher->destroy(hasher); + + /* K_encr | K_auth | MSK | EMSK = prf(0) | prf(0) + * FIPS PRF has 320 bit block size, we need 160 byte for keys + * => run prf four times */ + prf = prf_create(PRF_FIPS_SHA1_160); + prf->set_key(prf, mk); + tmp = chunk_alloca(prf->get_block_size(prf) * 4); + prf->get_bytes(prf, chunk_empty, tmp.ptr); + prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 1); + prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 2); + prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 3); + prf->destroy(prf); + chunk_free(&this->k_encr); + chunk_free(&this->k_auth); + chunk_free(&this->msk); + chunk_free(&this->emsk); + chunk_split(tmp, "aaaa", 16, &this->k_encr, 16, &this->k_auth, + 64, &this->msk, 64, &this->emsk); + DBG3(DBG_IKE, "MK %B", &mk); + DBG3(DBG_IKE, "PRF res %B", &tmp); + DBG3(DBG_IKE, "K_encr %B", &this->k_encr); + DBG3(DBG_IKE, "K_auth %B", &this->k_auth); + DBG3(DBG_IKE, "MSK %B", &this->msk); + DBG3(DBG_IKE, "EMSK %B", &this->emsk); +} + +/* + * Get a shared key from ipsec.secrets. + * We use the standard keys as used in preshared key authentication. As + * these keys have an undefined length, we: + * - strip them if they are longer + * - fill them up with '\0' if they are shorter + */ +static status_t load_key(identification_t *me, identification_t *other, chunk_t *k) +{ + chunk_t shared_key; + + if (charon->credentials->get_shared_key(charon->credentials, me, + other, &shared_key) != SUCCESS) + { + return NOT_FOUND; + } + chunk_free(k); + *k = chunk_alloc(K_LENGTH); + memset(k->ptr, '\0', k->len); + memcpy(k->ptr, shared_key.ptr, min(shared_key.len, k->len)); + chunk_free(&shared_key); + return SUCCESS; +} + +/** + * skip EAP_AKA header in message and returns its AKA subtype + */ +static aka_subtype_t read_header(chunk_t *message) +{ + aka_subtype_t type; + + if (message->len < 8) + { + *message = chunk_empty; + return 0; + } + type = *(message->ptr + 5); + *message = chunk_skip(*message, 8); + return type; +} + +/** + * read the next attribute from the chunk data + */ +static aka_attribute_t read_attribute(chunk_t *data, chunk_t *attr_data) +{ + aka_attribute_t attribute; + size_t length; + + DBG3(DBG_IKE, "reading attribute from %B", data); + + if (data->len < 2) + { + return AT_END; + } + /* read attribute and length */ + attribute = *data->ptr++; + length = *data->ptr++ * 4 - 2; + data->len -= 2; + DBG3(DBG_IKE, "found attribute %N with length %d", + aka_attribute_names, attribute, length); + if (length > data->len) + { + return AT_END; + } + /* apply attribute value to attr_data */ + attr_data->len = length; + attr_data->ptr = data->ptr; + /* update data to point to next attribute */ + *data = chunk_skip(*data, length); + return attribute; +} + +/** + * Build an AKA payload from different attributes. + * The variable argument takes an aka_attribute_t + * followed by its data in a chunk. + */ +static eap_payload_t *build_aka_payload(private_eap_aka_t *this, eap_code_t code, + u_int8_t identifier, aka_subtype_t type, ...) +{ + chunk_t message = chunk_alloca(512); /* is enought for all current messages */ + chunk_t pos = message; + eap_payload_t *payload; + va_list args; + aka_attribute_t attr; + u_int8_t *mac_pos = NULL; + + /* write EAP header, skip length bytes */ + *pos.ptr++ = code; + *pos.ptr++ = identifier; + pos.ptr += 2; + pos.len -= 4; + /* write AKA header with type and subtype, null reserved bytes */ + *pos.ptr++ = EAP_AKA; + *pos.ptr++ = type; + *pos.ptr++ = 0; + *pos.ptr++ = 0; + pos.len -= 4; + + va_start(args, type); + while ((attr = va_arg(args, aka_attribute_t)) != AT_END) + { + chunk_t data = va_arg(args, chunk_t); + + DBG3(DBG_IKE, "building %N %B", aka_attribute_names, attr, &data); + + /* write attribute header */ + *pos.ptr++ = attr; + pos.len--; + + switch (attr) + { + case AT_RES: + { + /* attribute length in 4byte words */ + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + /* RES length in bits */ + *(u_int16_t*)pos.ptr = htons(data.len * 8); + pos = chunk_skip(pos, sizeof(u_int16_t)); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_AUTN: + case AT_RAND: + { + *pos.ptr++ = data.len/4 + 1; pos.len--; + *pos.ptr++ = 0; pos.len--; + *pos.ptr++ = 0; pos.len--; + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_MAC: + { + *pos.ptr++ = 5; pos.len--; + *pos.ptr++ = 0; pos.len--; + *pos.ptr++ = 0; pos.len--; + mac_pos = pos.ptr; + /* MAC is calculated over message including zeroed AT_MAC attribute */ + memset(mac_pos, 0, AT_MAC_LENGTH); + pos.ptr += AT_MAC_LENGTH; + pos.len -= AT_MAC_LENGTH; + break; + } + default: + { + /* length is data length in 4-bytes + 1 for header */ + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + } + } + } + va_end(args); + + /* calculate message length, write into header */ + message.len = pos.ptr - message.ptr; + *(u_int16_t*)(message.ptr + 2) = htons(message.len); + + /* create MAC if AT_MAC attribte was included */ + if (mac_pos) + { + signer_t *signer = signer_create(AUTH_HMAC_SHA1_128); + signer->set_key(signer, this->k_auth); + DBG3(DBG_IKE, "AT_MAC signature of %B", &message); + DBG3(DBG_IKE, "using key %B", &this->k_auth); + signer->get_signature(signer, message, mac_pos); + DBG3(DBG_IKE, "is %b", mac_pos, AT_MAC_LENGTH); + signer->destroy(signer); + } + + /* payload constructor takes data with some bytes skipped */ + payload = eap_payload_create_data(message); + + DBG3(DBG_IKE, "created EAP message %B", &message); + return payload; +} + +/** + * Initiate a AKA-Challenge using SQN + */ +static status_t server_initiate_challenge(private_eap_aka_t *this, chunk_t sqn, eap_payload_t **out) +{ + randomizer_t *randomizer; + status_t status; + chunk_t mac, ak, autn; + + mac = chunk_alloca(MAC_LENGTH); + ak = chunk_alloca(AK_LENGTH); + chunk_free(&this->rand); + chunk_free(&this->xres); + + /* generate RAND: + * we use our standard randomizer, not f0() proposed in S.S0055 + */ + randomizer = randomizer_create(); + status = randomizer->allocate_pseudo_random_bytes(randomizer, RAND_LENGTH, &this->rand); + randomizer->destroy(randomizer); + if (status != SUCCESS) + { + DBG1(DBG_IKE, "generating RAND for EAP-AKA authentication failed"); + return FAILED; + } + +# ifdef TEST_VECTORS + /* Test vector for RAND */ + u_int8_t test_rand[] = { + 0x4b,0x05,0x2b,0x20,0xe2,0xa0,0x6c,0x8f, + 0xf7,0x00,0xda,0x51,0x2b,0x4e,0x11,0x1e, + }; + memcpy(this->rand.ptr, test_rand, this->rand.len); +# endif /* TEST_VECTORS */ + + /* Get the shared key K: */ + if (load_key(this->server, this->peer, &this->k) != SUCCESS) + { + DBG1(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate " + "with EAP-AKA", this->server, this->peer); + return FAILED; + } + +# ifdef TEST_VECTORS + /* Test vector for K */ + u_int8_t test_k[] = { + 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c, + 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d, + }; + memcpy(this->k.ptr, test_k, this->k.len); +# endif /* TEST_VECTORS */ + + /* generate MAC */ + f1(this->k, this->rand, sqn, amf, mac.ptr); + + /* generate AK */ + f5(this->k, this->rand, ak.ptr); + + /* precalculate XRES as expected from client */ + this->xres = chunk_alloc(RES_LENGTH); + f2(this->k, this->rand, this->xres.ptr); + + /* calculate AUTN = (SQN xor AK) || AMF || MAC */ + autn = chunk_cata("ccc", sqn, amf, mac); + memxor(autn.ptr, ak.ptr, ak.len); + DBG3(DBG_IKE, "AUTN %B", &autn); + + + /* derive K_encr, K_auth, MSK, EMSK */ + derive_keys(this, this->peer); + + /* build payload */ + *out = build_aka_payload(this, EAP_REQUEST, 0, AKA_CHALLENGE, + AT_RAND, this->rand, AT_AUTN, autn, AT_MAC, + chunk_empty, AT_END); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.initiate for an EAP_AKA server + */ +static status_t server_initiate(private_eap_aka_t *this, eap_payload_t **out) +{ + chunk_t sqn = chunk_alloca(SQN_LENGTH); + + /* we use an offset of 3 minutes to tolerate clock inaccuracy + * without the need to synchronize sequence numbers */ + update_sqn(sqn.ptr, 180); + +# ifdef TEST_VECTORS + /* Test vector for SQN */ + u_int8_t test_sqn[] = {0x00,0x00,0x00,0x00,0x00,0x01}; + memcpy(sqn.ptr, test_sqn, sqn.len); +# endif /* TEST_VECTORS */ + + return server_initiate_challenge(this, sqn, out); +} + +static status_t server_process_synchronize(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t attr, auts = chunk_empty, pos, message, macs, xmacs, sqn, aks, amf; + u_int i; + + message = in->get_data(in); + pos = message; + read_header(&pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_AUTS: + auts = attr; + continue; + default: + if (attribute >= 0 && attribute <= 127) + { + DBG1(DBG_IKE, "found non skippable attribute %N", + aka_attribute_names, attribute); + return FAILED; + } + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + continue; + } + break; + } + + if (auts.len != AUTS_LENGTH) + { + DBG1(DBG_IKE, "synchronization request didn't contain useable AUTS"); + return FAILED; + } + + chunk_split(auts, "mm", SQN_LENGTH, &sqn, MAC_LENGTH, &macs); + aks = chunk_alloca(AK_LENGTH); + f5star(this->k, this->rand, aks.ptr); + /* decrypt serial number by XORing AKS */ + memxor(sqn.ptr, aks.ptr, aks.len); + + /* verify MACS */ + xmacs = chunk_alloca(MAC_LENGTH); + amf = chunk_alloca(AMF_LENGTH); + /* an AMF of zero is used for MACS calculation */ + memset(amf.ptr, 0, amf.len); + f1star(this->k, this->rand, sqn, amf, xmacs.ptr); + if (!chunk_equals(macs, xmacs)) + { + DBG1(DBG_IKE, "received MACS does not match XMACS"); + DBG3(DBG_IKE, "MACS %B XMACS %B", &macs, &xmacs); + return FAILED; + } + + /* retry the challenge with the received SQN + 1*/ + for (i = SQN_LENGTH - 1; i >= 0; i--) + { + if (++sqn.ptr[i] != 0) + { + break; + } + } + return server_initiate_challenge(this, sqn, out); +} + +/** + * process an AKA_Challenge response + */ +static status_t server_process_challenge(private_eap_aka_t *this, eap_payload_t *in) +{ + chunk_t attr, res = chunk_empty, at_mac = chunk_empty, pos, message; + + message = in->get_data(in); + pos = message; + read_header(&pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_RES: + res = attr; + if (attr.len == 2 + RES_LENGTH && + *(u_int16_t*)attr.ptr == htons(RES_LENGTH * 8)) + { + res = chunk_skip(attr, 2); + } + continue; + + case AT_MAC: + attr = chunk_skip(attr, 2); + at_mac = chunk_clonea(attr); + /* zero MAC in message for MAC verification */ + memset(attr.ptr, 0, attr.len); + continue; + default: + if (attribute >= 0 && attribute <= 127) + { + DBG1(DBG_IKE, "found non skippable attribute %N", + aka_attribute_names, attribute); + return FAILED; + } + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + continue; + } + break; + } + + /* verify EAP message MAC AT_MAC */ + { + bool valid; + signer_t *signer = signer_create(AUTH_HMAC_SHA1_128); + signer->set_key(signer, this->k_auth); + DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message); + DBG3(DBG_IKE, "using key %B", &this->k_auth); + valid = signer->verify_signature(signer, message, at_mac); + signer->destroy(signer); + if (!valid) + { + DBG1(DBG_IKE, "MAC in AT_MAC attribute verification failed"); + return FAILED; + } + } + + /* compare received RES against stored precalculated XRES */ + if (!chunk_equals(res, this->xres)) + { + DBG1(DBG_IKE, "received RES does not match XRES"); + DBG3(DBG_IKE, "RES %Bb XRES %B", &res, &this->xres); + return FAILED; + } + return SUCCESS; +} + +/** + * Implementation of eap_method_t.process for EAP_AKA servers + */ +static status_t server_process(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message; + aka_subtype_t type; + + message = in->get_data(in); + type = read_header(&message); + + DBG3(DBG_IKE, "received EAP message %B", &message); + + switch (type) + { + case AKA_CHALLENGE: + { + return server_process_challenge(this, in); + } + case AKA_AUTHENTICATION_REJECT: + case AKA_CLIENT_ERROR: + { + DBG1(DBG_IKE, "received %N, authentication failed", + aka_subtype_names, type); + return FAILED; + } + case AKA_SYNCHRONIZATION_FAILURE: + { + DBG1(DBG_IKE, "received %N, retrying with received SQN", + aka_subtype_names, type); + return server_process_synchronize(this, in, out); + } + default: + DBG1(DBG_IKE, "received unknown AKA subtype %N, authentication failed", + aka_subtype_names, type); + return FAILED; + } +} + +/** + * Process an incoming AKA-Challenge client side + */ +static status_t peer_process_challenge(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t attr = chunk_empty; + chunk_t autn = chunk_empty, at_mac = chunk_empty; + chunk_t ak, sqn, sqn_ak, mac, xmac, res, amf, message, pos; + u_int8_t identifier; + + ak = chunk_alloca(AK_LENGTH); + xmac = chunk_alloca(MAC_LENGTH); + res = chunk_alloca(RES_LENGTH); + chunk_free(&this->rand); + + message = in->get_data(in); + pos = message; + read_header(&pos); + identifier = in->get_identifier(in); + + DBG3(DBG_IKE, "reading attributes from %B", &pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_RAND: + this->rand = chunk_clone(chunk_skip(attr, 2)); + continue; + case AT_AUTN: + autn = chunk_skip(attr, 2); + continue; + case AT_MAC: + attr = chunk_skip(attr, 2); + at_mac = chunk_clonea(attr); + /* set MAC in message to zero for own MAC verification */ + memset(attr.ptr, 0, attr.len); + continue; + default: + if (attribute >= 0 && attribute <= 127) + { + /* non skippable attribute, abort */ + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "found non skippable attribute %N, sending %N %d", + aka_attribute_names, attribute, + aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + continue; + } + break; + } + + if (this->rand.len != RAND_LENGTH || autn.len != AUTN_LENGTH) + { + /* required attributes wrong/not found, abort */ + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "could not find valid RAND/AUTN attribute, sending %N %d", + aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + /* split up AUTN = SQN xor AK | AMF | MAC */ + chunk_split(autn, "mmm", SQN_LENGTH, &sqn_ak, AMF_LENGTH, &amf, MAC_LENGTH, &mac); + + /* Get the shared key K: */ + chunk_free(&this->k); + if (load_key(this->peer, this->server, &this->k) != SUCCESS) + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, + AKA_AUTHENTICATION_REJECT, AT_END); + DBG3(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate " + "with EAP-AKA, sending %N", this->peer, this->server, + aka_subtype_names, AKA_AUTHENTICATION_REJECT); + return NEED_MORE; + } +# ifdef TEST_VECTORS + /* Test vector for K */ + u_int8_t test_k[] = { + 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c, + 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d, + }; + memcpy(this->k.ptr, test_k, this->k.len); +# endif /* TEST_VECTORS */ + + /* calculate anonymity key AK */ + f5(this->k, this->rand, ak.ptr); + /* XOR AK into SQN to decrypt it */ + sqn = chunk_clonea(sqn_ak); + memxor(sqn.ptr, ak.ptr, sqn.len); + + /* calculate expected MAC and compare against received one */ + f1(this->k, this->rand, sqn, amf, xmac.ptr); + if (!chunk_equals(mac, xmac)) + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, + AKA_AUTHENTICATION_REJECT, AT_END); + DBG1(DBG_IKE, "received MAC does not match XMAC, sending %N", + aka_subtype_names, AKA_AUTHENTICATION_REJECT); + DBG3(DBG_IKE, "MAC %B XMAC %B", &mac, &xmac); + return NEED_MORE; + } + + if (memcmp(peer_sqn.ptr, sqn.ptr, sqn.len) >= 0) + { + /* sequence number invalid. send AUTS */ + chunk_t auts, macs, aks, amf; + + macs = chunk_alloca(MAC_LENGTH); + aks = chunk_alloca(AK_LENGTH); + amf = chunk_alloca(AMF_LENGTH); + + /* AMF is set to zero in AKA_SYNCHRONIZATION_FAILURE */ + memset(amf.ptr, 0, amf.len); + /* AKS = f5*(RAND) */ + f5star(this->k, this->rand, aks.ptr); + /* MACS = f1*(RAND) */ + f1star(this->k, this->rand, peer_sqn, amf, macs.ptr); + /* AUTS = SQN xor AKS | MACS */ + memxor(aks.ptr, peer_sqn.ptr, aks.len); + auts = chunk_cata("cc", aks, macs); + + *out = build_aka_payload(this, EAP_RESPONSE, identifier, + AKA_SYNCHRONIZATION_FAILURE, + AT_AUTS, auts, AT_END); + DBG1(DBG_IKE, "received SQN invalid, sending %N", + aka_subtype_names, AKA_SYNCHRONIZATION_FAILURE); + DBG3(DBG_IKE, "received SQN %B\ncurrent SQN %B", &sqn, &peer_sqn); + return NEED_MORE; + } + + /* derive K_encr, K_auth, MSK, EMSK */ + derive_keys(this, this->peer); + + /* verify EAP message MAC AT_MAC */ + { + bool valid; + signer_t *signer = signer_create(AUTH_HMAC_SHA1_128); + signer->set_key(signer, this->k_auth); + + DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message); + DBG3(DBG_IKE, "using key %B", &this->k_auth); + valid = signer->verify_signature(signer, message, at_mac); + signer->destroy(signer); + if (!valid) + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "MAC in AT_MAC attribute verification " + "failed, sending %N %d", aka_attribute_names, + AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + } + + /* update stored SQN to the received one */ + memcpy(peer_sqn.ptr, sqn.ptr, sqn.len); + + /* calculate RES */ + f2(this->k, this->rand, res.ptr); + + /* build response */ + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CHALLENGE, + AT_RES, res, AT_MAC, chunk_empty, AT_END); + return NEED_MORE; +} + +/** + * Process an incoming AKA-Notification as client + */ +static status_t peer_process_notification(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, pos, attr; + u_int8_t identifier; + + message = in->get_data(in); + pos = message; + read_header(&pos); + identifier = in->get_identifier(in); + + DBG3(DBG_IKE, "reading attributes from %B", &pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_NOTIFICATION: + if (attr.len != 2) + { + DBG1(DBG_IKE, "received invalid AKA notification, ignored"); + } + else + { + DBG1(DBG_IKE, "received AKA notification code %d, ignored", + ntohs(*(u_int16_t*)attr.ptr)); + } + continue; + default: + if (attribute >= 0 && attribute <= 127) + { + DBG1(DBG_IKE, "ignoring non-skippable attribute %N in %N", + aka_attribute_names, attribute, aka_subtype_names, + AKA_NOTIFICATION); + } + else + { + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + } + continue; + } + break; + } + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.process for an EAP_AKA peer + */ +static status_t peer_process(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + aka_subtype_t type; + chunk_t message; + u_int8_t identifier; + + message = in->get_data(in); + type = read_header(&message); + identifier = in->get_identifier(in); + + DBG3(DBG_IKE, "received EAP message %B", &message); + + switch (type) + { + case AKA_CHALLENGE: + { + return peer_process_challenge(this, in, out); + } + case AKA_NOTIFICATION: + { + return peer_process_notification(this, in, out); + } + default: + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "received unsupported %N request, sending %N %d", + aka_subtype_names, type, + aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + } +} + +/** + * Implementation of eap_method_t.initiate for an EAP AKA peer + */ +static status_t peer_initiate(private_eap_aka_t *this, eap_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +/** + * Implementation of eap_method_t.get_type. + */ +static eap_type_t get_type(private_eap_aka_t *this) +{ + return EAP_AKA; +} + +/** + * Implementation of eap_method_t.get_msk. + */ +static status_t get_msk(private_eap_aka_t *this, chunk_t *msk) +{ + if (this->msk.ptr) + { + *msk = this->msk; + return SUCCESS; + } + return FAILED; +} + +/** + * Implementation of eap_method_t.is_mutual. + */ +static bool is_mutual(private_eap_aka_t *this) +{ + return TRUE; +} + +/** + * Implementation of eap_method_t.destroy. + */ +static void destroy(private_eap_aka_t *this) +{ + chunk_free(&this->k_encr); + chunk_free(&this->k_auth); + chunk_free(&this->msk); + chunk_free(&this->emsk); + chunk_free(&this->xres); + chunk_free(&this->k); + chunk_free(&this->rand); + free(this); +} + +/* + * Described in header. + */ +eap_aka_t *eap_create(eap_role_t role, + identification_t *server, identification_t *peer) +{ + private_eap_aka_t *this = malloc_thing(private_eap_aka_t); + + /* public functions */ + switch (role) + { + case EAP_SERVER: + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))server_initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))server_process; + break; + case EAP_PEER: + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))peer_initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))peer_process; + 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->server = server; + this->peer = peer; + this->k_encr = chunk_empty; + this->k_auth = chunk_empty; + this->msk = chunk_empty; + this->emsk = chunk_empty; + this->xres = chunk_empty; + this->k = chunk_empty; + this->rand = chunk_empty; + + return &this->public; +} diff --git a/src/charon/sa/authenticators/eap/eap_aka.h b/src/charon/sa/authenticators/eap/eap_aka.h new file mode 100644 index 000000000..cc740f6ad --- /dev/null +++ b/src/charon/sa/authenticators/eap/eap_aka.h @@ -0,0 +1,133 @@ +/** + * @file eap_aka.h + * + * @brief Interface of eap_aka_t. + * + */ + +/* + * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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_AKA_H_ +#define EAP_AKA_H_ + +typedef struct eap_aka_t eap_aka_t; +typedef enum aka_subtype_t aka_subtype_t; +typedef enum aka_attribute_t aka_attribute_t; + +#include <sa/authenticators/eap/eap_method.h> + + +/** + * Subtypes of AKA messages + */ +enum aka_subtype_t { + AKA_CHALLENGE = 1, + AKA_AUTHENTICATION_REJECT = 2, + AKA_SYNCHRONIZATION_FAILURE = 4, + AKA_IDENTITY = 5, + AKA_NOTIFICATION = 12, + AKA_REAUTHENTICATION = 13, + AKA_CLIENT_ERROR = 14, +}; + +/** + * enum names for aka_subtype_t + */ +extern enum_name_t *aka_subtype_names; + +/** + * Attribute types in AKA messages + */ +enum aka_attribute_t { + /** defines the end of attribute list */ + AT_END = -1, + AT_RAND = 1, + AT_AUTN = 2, + AT_RES = 3, + AT_AUTS = 4, + AT_PADDING = 6, + AT_NONCE_MT = 7, + AT_PERMANENT_ID_REQ = 10, + AT_MAC = 11, + AT_NOTIFICATION = 12, + AT_ANY_ID_REQ = 13, + AT_IDENTITY = 14, + AT_VERSION_LIST = 15, + AT_SELECTED_VERSION = 16, + AT_FULLAUTH_ID_REQ = 17, + AT_COUNTER = 19, + AT_COUNTER_TOO_SMALL = 20, + AT_NONCE_S = 21, + AT_CLIENT_ERROR_CODE = 22, + AT_IV = 129, + AT_ENCR_DATA = 130, + AT_NEXT_PSEUDONYM = 132, + AT_NEXT_REAUTH_ID = 133, + AT_CHECKCODE = 134, + AT_RESULT_IND = 135, +}; + +/** + * enum names for aka_attribute_t + */ +extern enum_name_t *aka_attribute_names; + + +/** + * @brief Implementation of the eap_method_t interface using EAP-AKA. + * + * EAP-AKA uses 3rd generation mobile phone standard authentication + * mechanism for authentication. It is a mutual authentication + * mechanism which establishs a shared key and therefore supports EAP_ONLY + * authentication. This implementation follows the standard of the + * 3GPP2 (S.S0055) and not the one of 3GGP. + * The shared key used for authentication is from ipsec.secrets. The + * peers ID is used to query it. + * The AKA mechanism uses sequence numbers to detect replay attacks. The + * peer stores the sequence number normally in a USIM and accepts + * incremental sequence numbers (incremental for lifetime of the USIM). To + * prevent a complex sequence number management, this implementation uses + * a sequence number derived from time. It is initialized to the startup + * time of the daemon. As long as the (UTC) time of the system is not + * turned back while the daemon is not running, this method is secure. + * + * @b Constructors: + * - eap_aka_create() + * - eap_client_create() using eap_method EAP_AKA + * + * @ingroup eap + */ +struct eap_aka_t { + + /** + * Implemented eap_method_t interface. + */ + eap_method_t eap_method_interface; +}; + +/** + * @brief Creates the EAP method EAP-AKA. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_aka_t object + * + * @ingroup eap + */ +eap_aka_t *eap_create(eap_role_t role, + identification_t *server, identification_t *peer); + +#endif /* EAP_AKA_H_ */ diff --git a/src/charon/sa/authenticators/eap/eap_method.c b/src/charon/sa/authenticators/eap/eap_method.c new file mode 100644 index 000000000..435aa9d1f --- /dev/null +++ b/src/charon/sa/authenticators/eap/eap_method.c @@ -0,0 +1,243 @@ +/** + * @file eap_method.c + * + * @brief Generic constructor for eap_methods. + * + */ + +/* + * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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 <string.h> +#include <sys/stat.h> +#include <dirent.h> +#include <error.h> +#include <dlfcn.h> + +#include "eap_method.h" + +#include <daemon.h> +#include <library.h> +#include <utils/linked_list.h> +#include <utils/identification.h> + + +ENUM_BEGIN(eap_type_names, EAP_IDENTITY, EAP_TOKEN_CARD, + "EAP_IDENTITY", + "EAP_NOTIFICATION", + "EAP_NAK", + "EAP_MD5", + "EAP_ONE_TIME_PASSWORD", + "EAP_TOKEN_CARD"); +ENUM_NEXT(eap_type_names, EAP_AKA, EAP_AKA, EAP_TOKEN_CARD, + "EAP_AKA"); +ENUM_END(eap_type_names, EAP_AKA); + +ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE, + "EAP_REQUEST", + "EAP_RESPONSE", + "EAP_SUCCESS", + "EAP_FAILURE", +); + +ENUM(eap_role_names, EAP_SERVER, EAP_PEER, + "EAP_SERVER", + "EAP_PEER", +); + + +typedef struct module_entry_t module_entry_t; + +/** + * Representation of a loaded module: EAP type, library handle, constructor + */ +struct module_entry_t { + eap_type_t type; + void *handle; + eap_constructor_t constructor; +}; + +/** List of module_entry_t's */ +static linked_list_t *modules = NULL; + +/** + * unload modules at daemon shutdown + */ +void eap_method_unload() +{ + if (modules) + { + module_entry_t *entry; + + while (modules->remove_last(modules, (void**)&entry) == SUCCESS) + { + DBG2(DBG_CFG, "unloaded module for %s", eap_type_names, entry->type); + dlclose(entry->handle); + free(entry); + } + modules->destroy(modules); + modules = NULL; + } +} + +/** + * Load EAP modules at daemon startup + */ +void eap_method_load(char *directory) +{ + struct dirent* entry; + struct stat stb; + DIR* dir; + + eap_method_unload(); + modules = linked_list_create(); + + if (stat(directory, &stb) == -1 || !(stb.st_mode & S_IFDIR)) + { + DBG1(DBG_CFG, "error opening EAP modules directory %s", directory); + return; + } + if (stb.st_uid != 0) + { + DBG1(DBG_CFG, "EAP modules directory %s not owned by root, skipped", directory); + return; + } + if (stb.st_mode & S_IWOTH || stb.st_mode & S_IWGRP) + { + DBG1(DBG_CFG, "EAP modules directory %s writable by others, skipped", directory); + return; + } + + dir = opendir(directory); + if (dir == NULL) + { + DBG1(DBG_CFG, "error opening EAP modules directory %s", directory); + return; + } + + DBG1(DBG_CFG, "loading EAP modules from '%s'", directory); + + while ((entry = readdir(dir)) != NULL) + { + char file[256]; + module_entry_t module, *loaded_module; + eap_method_t *method; + identification_t *id; + char *ending; + + snprintf(file, sizeof(file), "%s/%s", directory, entry->d_name); + + if (stat(file, &stb) == -1 || !(stb.st_mode & S_IFREG)) + { + DBG2(DBG_CFG, " skipping %s, doesn't look like a file", + entry->d_name); + continue; + } + ending = entry->d_name + strlen(entry->d_name) - 3; + if (ending <= entry->d_name || !streq(ending, ".so")) + { + /* skip anything which does not look like a library */ + DBG2(DBG_CFG, " skipping %s, doesn't look like a library", + entry->d_name); + continue; + } + if (stb.st_uid != 0) + { + DBG1(DBG_CFG, " skipping %s, file is not owned by root", entry->d_name); + return; + } + if (stb.st_mode & S_IWOTH || stb.st_mode & S_IWGRP) + { + DBG1(DBG_CFG, " skipping %s, file is writeable by others", entry->d_name); + continue; + } + + /* try to load the library */ + module.handle = dlopen(file, RTLD_LAZY); + if (module.handle == NULL) + { + DBG1(DBG_CFG, " opening EAP module %s failed: %s", entry->d_name, + dlerror()); + continue; + } + module.constructor = dlsym(module.handle, "eap_create"); + if (module.constructor == NULL) + { + DBG1(DBG_CFG, " EAP module %s has no eap_create() function, skipped", + entry->d_name); + dlclose(module.handle); + continue; + } + + /* get the type implemented in the method, create an instance for it */ + id = identification_create_from_string("john@doe.xyz"); + method = module.constructor(EAP_SERVER, id, id); + if (method == NULL) + { + method = module.constructor(EAP_PEER, id, id); + } + id->destroy(id); + if (method == NULL) + { + DBG1(DBG_CFG, " unable to create instance of EAP method %s, skipped", + entry->d_name); + dlclose(module.handle); + continue; + } + module.type = method->get_type(method); + method->destroy(method); + + DBG1(DBG_CFG, " loaded EAP method %N successfully from %s", + eap_type_names, module.type, entry->d_name); + + loaded_module = malloc_thing(module_entry_t); + memcpy(loaded_module, &module, sizeof(module)); + modules->insert_last(modules, loaded_module); + } + closedir(dir); +} + +/* + * Described in header. + */ +eap_method_t *eap_method_create(eap_type_t type, eap_role_t role, + identification_t *server, + identification_t *peer) +{ + eap_method_t *method = NULL; + iterator_t *iterator; + module_entry_t *entry; + + iterator = modules->create_iterator(modules, TRUE); + while (iterator->iterate(iterator, (void**)&entry)) + { + if (entry->type == type) + { + method = entry->constructor(role, server, peer); + if (method) + { + break; + } + } + } + iterator->destroy(iterator); + + if (method == NULL) + { + DBG1(DBG_CFG, "no EAP module found for %N %N", + eap_type_names, type, eap_role_names, role); + } + return method; +} diff --git a/src/charon/sa/authenticators/eap/eap_method.h b/src/charon/sa/authenticators/eap/eap_method.h new file mode 100644 index 000000000..2b09c0ff2 --- /dev/null +++ b/src/charon/sa/authenticators/eap/eap_method.h @@ -0,0 +1,241 @@ +/** + * @file eap_method.h + * + * @brief Interface eap_method_t. + * + */ + +/* + * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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_METHOD_H_ +#define EAP_METHOD_H_ + +typedef struct eap_method_t eap_method_t; +typedef enum eap_role_t eap_role_t; +typedef enum eap_type_t eap_type_t; +typedef enum eap_code_t eap_code_t; + +#include <library.h> +#include <utils/identification.h> +#include <encoding/payloads/eap_payload.h> + +/** + * Role of an eap_method, SERVER or PEER (client) + * + * @ingroup eap + */ +enum eap_role_t { + EAP_SERVER, + EAP_PEER, +}; +/** + * enum names for eap_role_t. + * + * @ingroup eap + */ +extern enum_name_t *eap_role_names; + +/** + * EAP types, defines the EAP method implementation + * + * @ingroup eap + */ +enum eap_type_t { + EAP_IDENTITY = 1, + EAP_NOTIFICATION = 2, + EAP_NAK = 3, + EAP_MD5 = 4, + EAP_ONE_TIME_PASSWORD = 5, + EAP_TOKEN_CARD = 6, + EAP_AKA = 23, +}; + +/** + * enum names for eap_type_t. + * + * @ingroup eap + */ +extern enum_name_t *eap_type_names; + +/** + * EAP code, type of an EAP message + * + * @ingroup eap + */ +enum eap_code_t { + EAP_REQUEST = 1, + EAP_RESPONSE = 2, + EAP_SUCCESS = 3, + EAP_FAILURE = 4, +}; + +/** + * enum names for eap_code_t. + * + * @ingroup eap + */ +extern enum_name_t *eap_code_names; + + +/** + * @brief Interface of an EAP method for server and client side. + * + * An EAP method initiates an EAP exchange and processes requests and + * responses. An EAP method may need multiple exchanges before succeeding, and + * the eap_authentication may use multiple EAP methods to authenticate a peer. + * To accomplish these requirements, all EAP methods have their own + * implementation while the eap_authenticatior uses one or more of these + * EAP methods. Sending of EAP(SUCCESS/FAILURE) message is not the job + * of the method, the eap_authenticator does this. + * An EAP method may establish a MSK, this is used the complete the + * authentication. Even if a mutual EAP method is used, the traditional + * AUTH payloads are required. Only these include the nonces and messages from + * ike_sa_init and therefore prevent man in the middle attacks. + * + * @b Constructors: + * - eap_method_create() + * + * @ingroup eap + */ +struct eap_method_t { + + /** + * @brief Initiate the EAP exchange. + * + * initiate() is only useable for server implementations, as clients only + * reply to server requests. + * A eap_payload is created in "out" if result is NEED_MORE. + * + * @param this calling object + * @param out eap_payload to send to the client + * @return + * - NEED_MORE, if an other exchange is required + * - FAILED, if unable to create eap request payload + */ + status_t (*initiate) (eap_method_t *this, eap_payload_t **out); + + /** + * @brief Process a received EAP message. + * + * A eap_payload is created in "out" if result is NEED_MORE. + * + * @param this calling object + * @param in eap_payload response received + * @param out created eap_payload to send + * @return + * - NEED_MORE, if an other exchange is required + * - FAILED, if EAP method failed + * - SUCCESS, if EAP method succeeded + */ + status_t (*process) (eap_method_t *this, eap_payload_t *in, + eap_payload_t **out); + + /** + * @brief Get the EAP type implemented in this method. + * + * @param this calling object + * @return type of the EAP method + */ + eap_type_t (*get_type) (eap_method_t *this); + + /** + * @brief Check if this EAP method authenticates the server. + * + * Some EAP methods provide mutual authentication and + * allow authentication using only EAP, if the peer supports it. + * + * @param this calling object + * @return TRUE if methods provides mutual authentication + */ + bool (*is_mutual) (eap_method_t *this); + + /** + * @brief Get the MSK established by this EAP method. + * + * Not all EAP methods establish a shared secret. + * + * @param this calling object + * @param msk chunk receiving internal stored MSK + * @return + * - SUCCESS, or + * - FAILED, if MSK not established (yet) + */ + status_t (*get_msk) (eap_method_t *this, chunk_t *msk); + + /** + * @brief Destroys a eap_method_t object. + * + * @param this calling object + */ + void (*destroy) (eap_method_t *this); +}; + +/** + * @brief Creates an EAP method for a specific type and role. + * + * @param eap_type EAP type to use + * @param role role of the eap_method, server or peer + * @param server ID of acting server + * @param peer ID of involved peer (client) + * @return eap_method_t object + * + * @ingroup eap + */ +eap_method_t *eap_method_create(eap_type_t eap_type, eap_role_t role, + identification_t *server, identification_t *peer); + +/** + * @brief (Re-)Load all EAP modules in the EAP modules directory. + * + * For security reasons, the directory and all it's modules must be owned + * by root and must not be writeable by someone else. + * + * @param dir directory of the EAP modules + * + * @ingroup eap + */ +void eap_method_load(char *directory); + +/** + * @brief Unload all loaded EAP modules + * + * @ingroup eap + */ +void eap_method_unload(); + +/** + * @brief Constructor definition for a pluggable EAP module. + * + * Each EAP module must define a constructor function which will return + * an initialized object with the methods defined in eap_method_t. The + * constructor must be named eap_create() and it's signature must be equal + * to that of eap_constructor_t. + * A module may implement only a single role. If it does not support the role + * requested, NULL should be returned. Multiple modules are allowed of the + * same EAP type to support seperate implementations of peer/server. + * + * @param role role the module will play, peer or server + * @param server ID of the server to use for credential lookup + * @param peer ID of the peer to use for credential lookup + * @return implementation of the eap_method_t interface + * + * @ingroup eap + */ +typedef eap_method_t *(*eap_constructor_t)(eap_role_t role, + identification_t *server, + identification_t *peer); + +#endif /* EAP_METHOD_H_ */ diff --git a/src/charon/sa/authenticators/eap_authenticator.c b/src/charon/sa/authenticators/eap_authenticator.c new file mode 100644 index 000000000..8736e05c3 --- /dev/null +++ b/src/charon/sa/authenticators/eap_authenticator.c @@ -0,0 +1,348 @@ +/** + * @file eap_authenticator.c + * + * @brief Implementation of eap_authenticator_t. + * + */ + +/* + * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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 <string.h> + +#include "eap_authenticator.h" + +#include <daemon.h> +#include <config/policies/policy.h> +#include <sa/authenticators/eap/eap_method.h> + +typedef struct private_eap_authenticator_t private_eap_authenticator_t; + +/** + * Private data of an eap_authenticator_t object. + */ +struct private_eap_authenticator_t { + + /** + * Public authenticator_t interface. + */ + eap_authenticator_t public; + + /** + * Assigned IKE_SA + */ + ike_sa_t *ike_sa; + + /** + * Role of this authenticator, PEER or SERVER + */ + eap_role_t role; + + /** + * Current EAP method processing + */ + eap_method_t *method; + + /** + * MSK used to build and verify auth payload + */ + chunk_t msk; +}; + +extern chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce, + chunk_t secret, identification_t *id, + prf_t *prf); + +/** + * Implementation of authenticator_t.verify. + */ +static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init, + chunk_t my_nonce, auth_payload_t *auth_payload) +{ + chunk_t auth_data, recv_auth_data; + identification_t *other_id = this->ike_sa->get_other_id(this->ike_sa); + prf_t *prf = this->ike_sa->get_auth_verify(this->ike_sa); + + auth_data = build_shared_key_signature(ike_sa_init, my_nonce, this->msk, + other_id, prf); + + recv_auth_data = auth_payload->get_data(auth_payload); + if (!chunk_equals(auth_data, recv_auth_data)) + { + DBG1(DBG_IKE, "verification of AUTH payload created from EAP MSK failed"); + chunk_free(&auth_data); + return FAILED; + } + chunk_free(&auth_data); + + DBG1(DBG_IKE, "authentication of '%D' with %N successful", + other_id, auth_method_names, AUTH_EAP); + return SUCCESS; +} + +/** + * Implementation of authenticator_t.build. + */ +static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init, + chunk_t other_nonce, auth_payload_t **auth_payload) +{ + chunk_t auth_data; + identification_t *my_id = this->ike_sa->get_my_id(this->ike_sa); + prf_t *prf = this->ike_sa->get_auth_build(this->ike_sa); + + DBG1(DBG_IKE, "authentication of '%D' (myself) with %N", + my_id, auth_method_names, AUTH_EAP); + + auth_data = build_shared_key_signature(ike_sa_init, other_nonce, + this->msk, my_id, prf); + + *auth_payload = auth_payload_create(); + (*auth_payload)->set_auth_method(*auth_payload, AUTH_PSK); + (*auth_payload)->set_data(*auth_payload, auth_data); + chunk_free(&auth_data); + + return SUCCESS; +} + +/** + * Implementation of eap_authenticator_t.initiate + */ +static status_t initiate(private_eap_authenticator_t *this, eap_type_t type, + eap_payload_t **out) +{ + /* if initiate() is called, role is always server */ + this->role = EAP_SERVER; + + if (type == 0) + { + DBG1(DBG_IKE, + "client requested EAP authentication, but configuration forbids it"); + *out = eap_payload_create_code(EAP_FAILURE); + return FAILED; + } + + DBG1(DBG_IKE, "requesting %N authentication", eap_type_names, type); + this->method = eap_method_create(type, this->role, + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + if (this->method == NULL) + { + DBG1(DBG_IKE, "configured EAP server method %N not supported, sending %N", + eap_type_names, type, eap_code_names, EAP_FAILURE); + *out = eap_payload_create_code(EAP_FAILURE); + return FAILED; + } + if (this->method->initiate(this->method, out) != NEED_MORE) + { + DBG1(DBG_IKE, "failed to initiate %N, sending %N", + eap_type_names, type, eap_code_names, EAP_FAILURE); + *out = eap_payload_create_code(EAP_FAILURE); + return FAILED; + } + return NEED_MORE; +} + +/** + * Processing method for a peer + */ +static status_t process_peer(private_eap_authenticator_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + eap_type_t type = in->get_type(in); + + /* create an eap_method for the first call */ + if (this->method == NULL) + { + DBG1(DBG_IKE, "EAP server requested %N authentication", + eap_type_names, type); + this->method = eap_method_create(type, EAP_PEER, + this->ike_sa->get_other_id(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa)); + if (this->method == NULL) + { + DBG1(DBG_IKE, "EAP server requested unsupported " + "EAP method %N, sending EAP_NAK", eap_type_names, type); + *out = eap_payload_create_nak(); + return NEED_MORE; + } + } + + switch (this->method->process(this->method, in, out)) + { + case NEED_MORE: + return NEED_MORE; + case SUCCESS: + if (this->method->get_msk(this->method, &this->msk) == SUCCESS) + { + DBG1(DBG_IKE, "EAP method %N succeded, MSK established", + eap_type_names, this->method->get_type(this->method)); + this->msk = chunk_clone(this->msk); + return SUCCESS; + } + DBG1(DBG_IKE, "EAP method %N succeded, but no MSK established", + eap_type_names, this->method->get_type(this->method)); + return FAILED; + case FAILED: + default: + DBG1(DBG_IKE, "EAP method %N failed", + eap_type_names, this->method->get_type(this->method)); + return FAILED; + } +} + +/** + * Processing method for a server + */ +static status_t process_server(private_eap_authenticator_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + switch (this->method->process(this->method, in, out)) + { + case NEED_MORE: + return NEED_MORE; + case SUCCESS: + if (this->method->get_msk(this->method, &this->msk) == SUCCESS) + { + DBG1(DBG_IKE, "EAP method %N succeded, MSK established", + eap_type_names, this->method->get_type(this->method)); + this->msk = chunk_clone(this->msk); + *out = eap_payload_create_code(EAP_SUCCESS); + return SUCCESS; + } + DBG1(DBG_IKE, "EAP method %N succeded, but no MSK established", + eap_type_names, this->method->get_type(this->method)); + *out = eap_payload_create_code(EAP_FAILURE); + return FAILED; + case FAILED: + default: + DBG1(DBG_IKE, "EAP method %N failed for peer %D", + eap_type_names, this->method->get_type(this->method), + this->ike_sa->get_other_id(this->ike_sa)); + *out = eap_payload_create_code(EAP_FAILURE); + return FAILED; + } +} + +/** + * Implementation of eap_authenticator_t.process + */ +static status_t process(private_eap_authenticator_t *this, eap_payload_t *in, + eap_payload_t **out) +{ + eap_code_t code = in->get_code(in); + + switch (this->role) + { + case EAP_SERVER: + { + switch (code) + { + case EAP_RESPONSE: + { + return process_server(this, in, out); + } + default: + { + DBG1(DBG_IKE, "received %N, sending %N", + eap_code_names, code, eap_code_names, EAP_FAILURE); + *out = eap_payload_create_code(EAP_FAILURE); + return FAILED; + } + } + } + case EAP_PEER: + { + switch (code) + { + case EAP_REQUEST: + { + return process_peer(this, in, out); + } + case EAP_SUCCESS: + { + if (this->method->get_msk(this->method, &this->msk) == SUCCESS) + { + DBG1(DBG_IKE, "EAP method %N succeded, MSK established", + eap_type_names, this->method->get_type(this->method)); + this->msk = chunk_clone(this->msk); + return SUCCESS; + } + DBG1(DBG_IKE, "EAP method %N succeded, but no MSK established", + eap_type_names, this->method->get_type(this->method)); + return FAILED; + } + case EAP_FAILURE: + default: + { + DBG1(DBG_IKE, "received %N, EAP authentication failed", + eap_code_names, code); + return FAILED; + } + } + } + default: + { + return FAILED; + } + } +} + +/** + * Implementation of authenticator_t.is_mutual. + */ +static bool is_mutual(private_eap_authenticator_t *this) +{ + if (this->method) + { + return this->method->is_mutual(this->method); + } + return FALSE; +} + +/** + * Implementation of authenticator_t.destroy. + */ +static void destroy(private_eap_authenticator_t *this) +{ + DESTROY_IF(this->method); + chunk_free(&this->msk); + free(this); +} + +/* + * Described in header. + */ +eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa) +{ + private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t); + + /* public functions */ + this->public.authenticator_interface.verify = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t*))verify; + this->public.authenticator_interface.build = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t**))build; + this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy; + + this->public.is_mutual = (bool(*)(eap_authenticator_t*))is_mutual; + this->public.initiate = (status_t(*)(eap_authenticator_t*,eap_type_t,eap_payload_t**))initiate; + this->public.process = (status_t(*)(eap_authenticator_t*,eap_payload_t*,eap_payload_t**))process; + + /* private data */ + this->ike_sa = ike_sa; + this->role = EAP_PEER; + this->method = NULL; + this->msk = chunk_empty; + + return &this->public; +} diff --git a/src/charon/sa/authenticators/eap_authenticator.h b/src/charon/sa/authenticators/eap_authenticator.h new file mode 100644 index 000000000..ffa162343 --- /dev/null +++ b/src/charon/sa/authenticators/eap_authenticator.h @@ -0,0 +1,156 @@ +/** + * @file eap_authenticator.h + * + * @brief Interface of eap_authenticator_t. + * + */ + +/* + * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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_AUTHENTICATOR_H_ +#define EAP_AUTHENTICATOR_H_ + +typedef struct eap_authenticator_t eap_authenticator_t; + +#include <sa/authenticators/authenticator.h> +#include <encoding/payloads/eap_payload.h> + +/** + * @brief Implementation of the authenticator_t interface using AUTH_EAP. + * + * Authentication using EAP involves the most complex authenticator. It stays + * alive over multiple ike_auth transactions and handles multiple EAP + * messages. + * EAP authentication must be clearly distinguished between using + * mutual EAP methods and using methods not providing server authentication. + * If no mutual authentication is used, the server must prove it's identity + * by traditional AUTH methods (RSA, psk). Only when the EAP method is mutual, + * the client should accept an EAP-only authentication. + * RFC4306 does always use traditional authentiction, EAP only authentication + * is described in the internet draft draft-eronen-ipsec-ikev2-eap-auth-05.txt. + * + * @verbatim + ike_sa_init + -------------------------> + <------------------------- + followed by multiple ike_auth: + + +--------+ +--------+ + | EAP | ID, SA, TS, N(EAP_ONLY) | EAP | + | client | ---------------------------> | server | + | | ID, [AUTH,] EAP | | AUTH payload is + | | <--------------------------- | | only included if + | | EAP | | authentication + | | ---------------------------> | | is not mutual. + | | EAP | | + | | <--------------------------- | | + | | EAP | | + | | ---------------------------> | | + | | EAP(SUCCESS) | | + | | <--------------------------- | | + | | AUTH | | If EAP establishes + | | ---------------------------> | | a session key, AUTH + | | AUTH, SA, TS | | payloads use this + | | <--------------------------- | | key, not SK_pi/pr + +--------+ +--------+ + + @endverbatim + * @b Constructors: + * - eap_authenticator_create() + * - authenticator_create() using auth_method AUTH_EAP + * + * @ingroup authenticators + */ +struct eap_authenticator_t { + + /** + * Implemented authenticator_t interface. + */ + authenticator_t authenticator_interface; + + /** + * @brief Check if the EAP method was/is mutual and secure. + * + * RFC4306 proposes to authenticate the EAP responder (server) by standard + * IKEv2 methods (RSA, psk). Not all, but some EAP methods + * provide mutual authentication, which would result in a redundant + * authentication. If the client supports EAP_ONLY_AUTHENTICATION, and + * the the server provides mutual authentication, authentication using + * RSA/PSK may be omitted. If the server did not include a traditional + * AUTH payload, the client must verify that the server initiated mutual + * EAP authentication before it can trust the server. + * + * @param this calling object + * @return TRUE, if no AUTH payload required, FALSE otherwise + */ + bool (*is_mutual) (eap_authenticator_t* this); + + /** + * @brief Initiate the EAP exchange. + * + * The server initiates EAP exchanges, so the client never calls + * this method. If initiate() returns NEED_MORE, the EAP authentication + * process started. In any case, a payload is created in "out". + * + * @param this calling object + * @param type EAP method to use to authenticate client + * @param out created initiaal EAP message to send + * @return + * - FAILED, if initiation failed + * - NEED_MORE, if more EAP exchanges reqired + */ + status_t (*initiate) (eap_authenticator_t* this, eap_type_t type, + eap_payload_t **out); + + /** + * @brief Process an EAP message. + * + * After receiving an EAP message "in", the peer/server processes + * the payload and creates a reply/subsequent request. + * The server side always returns NEED_MORE if another EAP message + * is excepted from the client, SUCCESS if EAP exchange completed and + * "out" is EAP_SUCCES, or FAILED if the EAP exchange failed with + * a EAP_FAILURE payload in "out". Anyway, a payload in "out" is always + * created. + * The peer (client) side only creates a "out" payload if result is + * NEED_MORE, a SUCCESS/FAILED is returned whenever a + * EAP_SUCCESS/EAP_FAILURE message is received in "in". + * If a SUCCESS is returned (on any side), the EAP authentication was + * successful and the AUTH payload can be exchanged. + * + * @param this calling object + * @param in received EAP message + * @param out created EAP message to send + * @return + * - FAILED, if authentication/EAP exchange failed + * - SUCCESS, if authentication completed + * - NEED_MORE, if more EAP exchanges reqired + */ + status_t (*process) (eap_authenticator_t* this, + eap_payload_t *in, eap_payload_t **out); +}; + +/** + * @brief Creates an authenticator for AUTH_EAP. + * + * @param ike_sa associated ike_sa + * @return eap_authenticator_t object + * + * @ingroup authenticators + */ +eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa); + +#endif /* EAP_AUTHENTICATOR_H_ */ diff --git a/src/charon/sa/authenticators/psk_authenticator.c b/src/charon/sa/authenticators/psk_authenticator.c index b3f49eff1..28edaaa8e 100644 --- a/src/charon/sa/authenticators/psk_authenticator.c +++ b/src/charon/sa/authenticators/psk_authenticator.c @@ -1,7 +1,7 @@ /** - * @file authenticator.c + * @file psk_authenticator.c * - * @brief Implementation of authenticator_t. + * @brief Implementation of psk_authenticator_t. * */ @@ -54,24 +54,35 @@ struct private_psk_authenticator_t { }; /** - * Function implemented in rsa_authenticator.c + * Builds the octets to be signed as described in section 2.15 of RFC 4306 */ -extern chunk_t build_tbs_octets(private_psk_authenticator_t *this, chunk_t ike_sa_init, - chunk_t nonce, identification_t *id, prf_t *prf); +chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce, + identification_t *id, prf_t *prf) +{ + u_int8_t id_header_buf[] = {0x00, 0x00, 0x00, 0x00}; + chunk_t id_header = chunk_from_buf(id_header_buf); + chunk_t id_with_header, id_prfd, id_encoding; + + id_header_buf[0] = id->get_type(id); + id_encoding = id->get_encoding(id); + + id_with_header = chunk_cat("cc", id_header, id_encoding); + prf->allocate_bytes(prf, id_with_header, &id_prfd); + chunk_free(&id_with_header); + + return chunk_cat("ccm", ike_sa_init, nonce, id_prfd); +} /** * Creates the AUTH data using auth method SHARED_KEY_MESSAGE_INTEGRITY_CODE. */ -static chunk_t build_shared_key_signature(private_psk_authenticator_t *this, - chunk_t ike_sa_init, - chunk_t nonce, - chunk_t secret, - identification_t *id, - prf_t *prf) +chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce, + chunk_t secret, identification_t *id, + prf_t *prf) { chunk_t key_pad, key, auth_data, octets; - octets = build_tbs_octets(this, ike_sa_init, nonce, id, prf); + octets = build_tbs_octets(ike_sa_init, nonce, id, prf); /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */ key_pad.ptr = IKEV2_KEY_PAD; key_pad.len = IKEV2_KEY_PAD_LENGTH; @@ -94,7 +105,7 @@ static chunk_t build_shared_key_signature(private_psk_authenticator_t *this, * Implementation of authenticator_t.verify. */ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init, - chunk_t my_nonce, auth_payload_t *auth_payload) + chunk_t my_nonce, auth_payload_t *auth_payload) { status_t status; chunk_t auth_data, recv_auth_data, shared_key; @@ -110,7 +121,7 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init, return status; } - auth_data = build_shared_key_signature(this, ike_sa_init, my_nonce, + auth_data = build_shared_key_signature(ike_sa_init, my_nonce, shared_key, other_id, this->ike_sa->get_auth_verify(this->ike_sa)); chunk_free(&shared_key); @@ -153,7 +164,7 @@ static status_t build(private_psk_authenticator_t *this, chunk_t ike_sa_init, return status; } - auth_data = build_shared_key_signature(this, ike_sa_init, + auth_data = build_shared_key_signature(ike_sa_init, other_nonce, shared_key, my_id, this->ike_sa->get_auth_build(this->ike_sa)); DBG2(DBG_IKE, "successfully created shared key MAC"); diff --git a/src/charon/sa/authenticators/rsa_authenticator.c b/src/charon/sa/authenticators/rsa_authenticator.c index c5b9983a1..dfa01e332 100644 --- a/src/charon/sa/authenticators/rsa_authenticator.c +++ b/src/charon/sa/authenticators/rsa_authenticator.c @@ -1,7 +1,7 @@ /** - * @file authenticator.c + * @file rsa_authenticator.c * - * @brief Implementation of authenticator_t. + * @brief Implementation of rsa_authenticator_t. * */ @@ -48,24 +48,10 @@ struct private_rsa_authenticator_t { }; /** - * Builds the octets to be signed as described in section 2.15 of RFC 4306 + * Function implemented in psk_authenticator.c */ -chunk_t build_tbs_octets(private_rsa_authenticator_t *this, chunk_t ike_sa_init, - chunk_t nonce, identification_t *id, prf_t *prf) -{ - u_int8_t id_header_buf[] = {0x00, 0x00, 0x00, 0x00}; - chunk_t id_header = chunk_from_buf(id_header_buf); - chunk_t id_with_header, id_prfd, id_encoding; - - id_header_buf[0] = id->get_type(id); - id_encoding = id->get_encoding(id); - - id_with_header = chunk_cat("cc", id_header, id_encoding); - prf->allocate_bytes(prf, id_with_header, &id_prfd); - chunk_free(&id_with_header); - - return chunk_cat("ccm", ike_sa_init, nonce, id_prfd); -} +extern chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce, + identification_t *id, prf_t *prf); /** * Implementation of authenticator_t.verify. @@ -92,7 +78,7 @@ static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init, DBG1(DBG_IKE, "no RSA public key found for '%D'", other_id); return NOT_FOUND; } - octets = build_tbs_octets(this, ike_sa_init, my_nonce, other_id, + octets = build_tbs_octets(ike_sa_init, my_nonce, other_id, this->ike_sa->get_auth_verify(this->ike_sa)); status = public_key->verify_emsa_pkcs1_signature(public_key, octets, auth_data); chunk_free(&octets); @@ -145,7 +131,7 @@ static status_t build(private_rsa_authenticator_t *this, chunk_t ike_sa_init, } DBG2(DBG_IKE, "matching RSA private key found"); - octets = build_tbs_octets(this, ike_sa_init, other_nonce, my_id, + octets = build_tbs_octets(ike_sa_init, other_nonce, my_id, this->ike_sa->get_auth_build(this->ike_sa)); status = my_key->build_emsa_pkcs1_signature(my_key, HASH_SHA1, octets, &auth_data); chunk_free(&octets); diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 62f18b5b1..e5a77edad 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -454,8 +454,7 @@ static void dpd_detected(private_ike_sa_t *this) policy = charon->policies->get_policy(charon->policies, this->my_id, this->other_id, my_ts, other_ts, - this->my_host, this->other_host, - NULL); + this->my_host, this->other_host); if (policy == NULL) { DBG1(DBG_IKE, "no policy for CHILD to handle DPD"); @@ -1021,8 +1020,7 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) policy = charon->policies->get_policy(charon->policies, this->my_id, this->other_id, my_ts, other_ts, - this->my_host, this->other_host, - NULL); + this->my_host, this->other_host); if (policy == NULL) { SIG(CHILD_UP_START, "acquiring CHILD_SA with reqid %d", reqid); @@ -1878,7 +1876,7 @@ static status_t reauth(private_ike_sa_t *this) other_ts = child_sa->get_other_traffic_selectors(child_sa); policy = charon->policies->get_policy(charon->policies, this->my_id, this->other_id, my_ts, other_ts, - this->my_host, this->other_host, NULL); + this->my_host, this->other_host); if (policy == NULL) { DBG1(DBG_IKE, "policy not found to recreate CHILD_SA, skipped"); diff --git a/src/charon/sa/transactions/create_child_sa.c b/src/charon/sa/transactions/create_child_sa.c index 1d5142b3b..67e4d782b 100644 --- a/src/charon/sa/transactions/create_child_sa.c +++ b/src/charon/sa/transactions/create_child_sa.c @@ -291,8 +291,7 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result) this->policy = charon->policies->get_policy(charon->policies, my_id, other_id, my_ts, other_ts, - me, other, - NULL); + me, other); this->reqid = this->rekeyed_sa->get_reqid(this->rekeyed_sa); @@ -694,8 +693,7 @@ static status_t get_response(private_create_child_sa_t *this, message_t *request this->policy = charon->policies->get_policy(charon->policies, my_id, other_id, my_ts, other_ts, - me, other, - NULL); + me, other); if (this->policy) { this->tsr = this->policy->select_my_traffic_selectors(this->policy, my_ts, me); diff --git a/src/charon/sa/transactions/ike_auth.c b/src/charon/sa/transactions/ike_auth.c index 017372b7e..bf7fd6d12 100644 --- a/src/charon/sa/transactions/ike_auth.c +++ b/src/charon/sa/transactions/ike_auth.c @@ -34,6 +34,7 @@ #include <encoding/payloads/auth_payload.h> #include <encoding/payloads/ts_payload.h> #include <sa/authenticators/authenticator.h> +#include <sa/authenticators/eap_authenticator.h> #include <sa/child_sa.h> @@ -130,6 +131,31 @@ struct private_ike_auth_t { u_int32_t reqid; /** + * List of CA certificates the other peer trusts + */ + linked_list_t *cacerts; + + /** + * EAP uses this authentication, which is passed along multiple ike_auths + */ + eap_authenticator_t *eap_auth; + + /** + * if the client receives a EAP request, it is stored here for later use + */ + eap_payload_t *eap_next; + + /** + * set to TRUE if authentication should be done with EAP only + */ + bool eap_only; + + /** + * has the other peer been authenticated yet? + */ + bool peer_authenticated; + + /** * mode the CHILD_SA uses: tranport, tunnel, BEET */ mode_t mode; @@ -245,6 +271,57 @@ static status_t get_request(private_ike_auth_t *this, message_t **result) /* store for retransmission */ this->message = request; + this->message_id = this->ike_sa->get_next_message_id(this->ike_sa); + request->set_message_id(request, this->message_id); + + if (this->eap_auth) + { + /* we already sent ID, SA, TS in an earlier ike_auth, we now + * continiue EAP processing */ + if (this->eap_next) + { + /* if we have another outstanding EAP response, send it */ + request->add_payload(request, (payload_t*)this->eap_next); + this->eap_next = NULL; + return SUCCESS; + } + else + { + /* if not, we have received an EAP_SUCCESS, send AUTH payload. + * we only send our data if: + * a) The peer has been authenticated using RSA/PSK, or + * b) The EAP method is mutual and gives us enough security + */ + if (this->eap_auth->is_mutual(this->eap_auth) || + this->peer_authenticated) + { + auth_payload_t *auth_payload; + authenticator_t *authenticator = (authenticator_t*)this->eap_auth; + + if (authenticator->build(authenticator, this->init_request, + this->nonce_r, &auth_payload) != SUCCESS) + { + SIG(IKE_UP_FAILED, + "EAP authentication data generation failed, deleting IKE_SA"); + SIG(CHILD_UP_FAILED, + "initiating CHILD_SA failed, unable to create IKE_SA"); + return DESTROY_ME; + } + request->add_payload(request, (payload_t*)auth_payload); + return SUCCESS; + } + else + { + SIG(IKE_UP_FAILED, + "peer didn't send authentication data, deleting IKE_SA"); + SIG(CHILD_UP_FAILED, + "initiating CHILD_SA failed, unable to create IKE_SA"); + return DESTROY_ME; + } + } + } + /* otherwise we do a normal ike_auth request... */ + { /* build ID payload */ my_id_payload = id_payload_create_from_identification(TRUE, my_id); request->add_payload(request, (payload_t*)my_id_payload); @@ -274,8 +351,8 @@ static status_t get_request(private_ike_auth_t *this, message_t **result) } /* build certificate payload. TODO: Handle certreq from init_ike_sa. */ - if (this->policy->get_auth_method(this->policy) == AUTH_RSA - && this->connection->get_cert_policy(this->connection) != CERT_NEVER_SEND) + if (this->policy->get_auth_method(this->policy) == AUTH_RSA && + this->connection->get_cert_policy(this->connection) != CERT_NEVER_SEND) { cert_payload_t *cert_payload; @@ -301,6 +378,7 @@ static status_t get_request(private_ike_auth_t *this, message_t **result) } } + if (this->policy->get_auth_method(this->policy) != AUTH_EAP) { /* build auth payload */ authenticator_t *authenticator; auth_payload_t *auth_payload; @@ -327,6 +405,12 @@ static status_t get_request(private_ike_auth_t *this, message_t **result) } request->add_payload(request, (payload_t*)auth_payload); } + else + { + this->eap_auth = eap_authenticator_create(this->ike_sa); + /* include notify that we support EAP only authentication */ + build_notify(EAP_ONLY_AUTHENTICATION, request, FALSE); + } { /* build SA payload for CHILD_SA */ linked_list_t *proposal_list; @@ -399,8 +483,6 @@ static status_t get_request(private_ike_auth_t *this, message_t **result) request->add_payload(request, (payload_t*)ts_payload); } - this->message_id = this->ike_sa->get_next_message_id(this->ike_sa); - request->set_message_id(request, this->message_id); return SUCCESS; } @@ -434,6 +516,12 @@ static status_t process_notifies(private_ike_auth_t *this, notify_payload_t *not this->build_child = FALSE; return SUCCESS; } + case EAP_ONLY_AUTHENTICATION: + { + DBG1(DBG_IKE, "peer requested EAP_ONLY_AUTHENTICATION"); + this->eap_only = TRUE; + return SUCCESS; + } case USE_TRANSPORT_MODE: { this->mode = MODE_TRANSPORT; @@ -465,38 +553,37 @@ static status_t process_notifies(private_ike_auth_t *this, notify_payload_t *not /** * Import certificate requests from a certreq payload */ -static void add_certificate_request(certreq_payload_t *certreq_payload, - linked_list_t *requested_ca_keyids) +static void process_certificate_request(private_ike_auth_t *this, + certreq_payload_t *certreq_payload) { chunk_t keyids; - cert_encoding_t encoding = certreq_payload->get_cert_encoding(certreq_payload); - + if (encoding != CERT_X509_SIGNATURE) { DBG1(DBG_IKE, "certreq payload %N not supported, ignored", cert_encoding_names, encoding); return; } - + keyids = certreq_payload->get_data(certreq_payload); - while (keyids.len >= HASH_SIZE_SHA1) { chunk_t keyid = { keyids.ptr, HASH_SIZE_SHA1}; - x509_t *cacert = charon->credentials->get_ca_certificate_by_keyid(charon->credentials, keyid); - + x509_t *cacert = charon->credentials->get_ca_certificate_by_keyid( + charon->credentials, keyid); if (cacert) { - DBG2(DBG_IKE, "request for certificate issued by ca '%D'", cacert->get_subject(cacert)); - requested_ca_keyids->insert_last(requested_ca_keyids, (void *)&keyid); + DBG2(DBG_IKE, "request for certificate issued by ca '%D'", + cacert->get_subject(cacert)); + this->cacerts->insert_last(this->cacerts, cacert); } else { DBG2(DBG_IKE, "request for certificate issued by unknown ca"); } DBG2(DBG_IKE, " with keyid %#B", &keyid); - + keyids.ptr += HASH_SIZE_SHA1; keyids.len -= HASH_SIZE_SHA1; } @@ -615,6 +702,113 @@ static status_t install_child_sa(private_ike_auth_t *this, bool initiator) } /** + * create a CHILD SA, install it, and build response message + */ +static void setup_child_sa(private_ike_auth_t *this, message_t *response) +{ + bool use_natt; + u_int32_t soft_lifetime, hard_lifetime; + host_t *me, *other; + identification_t *my_id, *other_id; + + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + my_id = this->ike_sa->get_my_id(this->ike_sa); + other_id = this->ike_sa->get_other_id(this->ike_sa); + + soft_lifetime = this->policy->get_soft_lifetime(this->policy); + hard_lifetime = this->policy->get_hard_lifetime(this->policy); + use_natt = this->ike_sa->is_natt_enabled(this->ike_sa); + this->child_sa = child_sa_create(this->reqid, me, other, my_id, other_id, + soft_lifetime, hard_lifetime, + this->policy->get_updown(this->policy), + this->policy->get_hostaccess(this->policy), + use_natt); + this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy)); + /* check mode, and include notify into reply */ + switch (this->mode) + { + case MODE_TUNNEL: + /* is the default */ + break; + case MODE_TRANSPORT: + if (!ts_list_is_host(this->tsi, other) || + !ts_list_is_host(this->tsr, me)) + { + this->mode = MODE_TUNNEL; + DBG1(DBG_IKE, "not using tranport mode, not host-to-host"); + } + else if (this->ike_sa->is_natt_enabled(this->ike_sa)) + { + this->mode = MODE_TUNNEL; + DBG1(DBG_IKE, "not using tranport mode, as connection NATed"); + } + else + { + build_notify(USE_TRANSPORT_MODE, response, FALSE); + } + break; + case MODE_BEET: + if (!ts_list_is_host(this->tsi, NULL) || + !ts_list_is_host(this->tsr, NULL)) + { + this->mode = MODE_TUNNEL; + DBG1(DBG_IKE, "not using BEET mode, not host-to-host"); + } + else + { + build_notify(USE_BEET_MODE, response, FALSE); + } + break; + } + + if (install_child_sa(this, FALSE) != SUCCESS) + { + SIG(CHILD_UP_FAILED, "installing CHILD_SA %s failed, no CHILD_SA created", + this->policy->get_name(this->policy)); + DBG1(DBG_IKE, "adding NO_PROPOSAL_CHOSEN notify to response"); + build_notify(NO_PROPOSAL_CHOSEN, response, FALSE); + } + else + { + /* build SA and TS payloads */ + SIG(CHILD_UP_SUCCESS, "CHILD_SA created"); + ts_payload_t *ts_response; + sa_payload_t *sa_response = sa_payload_create(); + sa_response->add_proposal(sa_response, this->proposal); + response->add_payload(response, (payload_t*)sa_response); + ts_response = ts_payload_create_from_traffic_selectors(TRUE, this->tsi); + response->add_payload(response, (payload_t*)ts_response); + ts_response = ts_payload_create_from_traffic_selectors(FALSE, this->tsr); + response->add_payload(response, (payload_t*)ts_response); + } +} + +/** + * clone the transaction to requeue it for EAP handling + */ +static private_ike_auth_t *clone_for_eap(private_ike_auth_t *this) +{ + private_ike_auth_t *clone; + clone = (private_ike_auth_t*)ike_auth_create(this->ike_sa); + + clone->tsi = this->tsi; this->tsi = NULL; + clone->tsr = this->tsr; this->tsr = NULL; + clone->eap_auth = this->eap_auth; this->eap_auth = NULL; + clone->eap_next = this->eap_next; this->eap_next = NULL; + clone->build_child = this->build_child; + clone->nonce_i = this->nonce_i; this->nonce_i = chunk_empty; + clone->nonce_r = this->nonce_r; this->nonce_r = chunk_empty; + clone->child_sa = this->child_sa; this->child_sa = NULL; + clone->proposal = this->proposal; this->proposal = NULL; + clone->peer_authenticated = this->peer_authenticated; + clone->connection = this->connection; this->connection = NULL; + clone->policy = this->policy; this->policy = NULL; + + return clone; +} + +/** * Implementation of transaction_t.get_response. */ static status_t get_response(private_ike_auth_t *this, message_t *request, @@ -622,7 +816,6 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, { host_t *me, *other; identification_t *my_id, *other_id; - linked_list_t *requested_ca_keyids; message_t *response; status_t status; iterator_t *payloads; @@ -635,6 +828,7 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, sa_payload_t *sa_request = NULL; ts_payload_t *tsi_request = NULL; ts_payload_t *tsr_request = NULL; + eap_payload_t *eap_request = NULL; id_payload_t *idr_response; /* check if we already have built a response (retransmission) */ @@ -648,6 +842,8 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, me = this->ike_sa->get_my_host(this->ike_sa); other = this->ike_sa->get_other_host(this->ike_sa); + my_id = this->ike_sa->get_my_id(this->ike_sa); + other_id = this->ike_sa->get_other_id(this->ike_sa); this->message_id = request->get_message_id(request); /* set up response */ @@ -668,9 +864,6 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); return DESTROY_ME; } - - /* initialize list of requested ca keyids */ - requested_ca_keyids = linked_list_create(); /* Iterate over all payloads. */ payloads = request->get_payload_iterator(request); @@ -689,7 +882,7 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, break; case CERTIFICATE_REQUEST: certreq_request = (certreq_payload_t*)payload; - add_certificate_request(certreq_request, requested_ca_keyids); + process_certificate_request(this, certreq_request); break; case CERTIFICATE: cert_request = (cert_payload_t*)payload; @@ -703,20 +896,21 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, case TRAFFIC_SELECTOR_RESPONDER: tsr_request = (ts_payload_t*)payload; break; + case EXTENSIBLE_AUTHENTICATION: + eap_request = (eap_payload_t*)payload; + break; case NOTIFY: { status = process_notifies(this, (notify_payload_t*)payload); if (status == FAILED) { payloads->destroy(payloads); - requested_ca_keyids->destroy(requested_ca_keyids); /* we return SUCCESS, returned FAILED means do next transaction */ return SUCCESS; } if (status == DESTROY_ME) { payloads->destroy(payloads); - requested_ca_keyids->destroy(requested_ca_keyids); SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); return DESTROY_ME; } @@ -732,13 +926,67 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, } payloads->destroy(payloads); - /* check if we have all payloads */ - if (!(idi_request && auth_request && sa_request && tsi_request && tsr_request)) + /* if message contains an EAP payload, we process it */ + if (eap_request && this->eap_auth) + { + eap_payload_t *eap_response; + private_ike_auth_t *next_auth; + + status = this->eap_auth->process(this->eap_auth, eap_request, &eap_response); + response->add_payload(response, (payload_t*)eap_response); + + if (status == FAILED) + { + /* shut down if EAP message is EAP_FAILURE */ + return DESTROY_ME; + } + + next_auth = clone_for_eap(this); + next_auth->message_id = this->message_id + 1; + *next = (transaction_t*)next_auth; + return SUCCESS; + } + + /* if we do EAP authentication and a AUTH payload comes in, verify it */ + if (auth_request && this->eap_auth) + { + auth_payload_t *auth_response; + authenticator_t *authenticator = (authenticator_t*)this->eap_auth; + + if (authenticator->verify(authenticator, this->init_request, + this->nonce_r, auth_request) != SUCCESS) + { + SIG(IKE_UP_FAILED, "authentication with EAP failed, deleting IKE_SA"); + SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); + build_notify(AUTHENTICATION_FAILED, response, TRUE); + return DESTROY_ME; + } + + if (authenticator->build(authenticator, this->init_response, + this->nonce_i, &auth_response) != SUCCESS) + { + SIG(IKE_UP_FAILED, "EAP authentication data generation failed, deleting IKE_SA"); + SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); + build_notify(AUTHENTICATION_FAILED, response, TRUE); + return DESTROY_ME; + } + response->add_payload(response, (payload_t*)auth_response); + + SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...%H[%D]", + this->ike_sa->get_name(this->ike_sa), me, my_id, other, other_id); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + + setup_child_sa(this, response); + + return SUCCESS; + } + + /* check if we have all payloads (AUTH is not checked, not required with EAP) */ + if (!(idi_request && sa_request && tsi_request && tsr_request)) { build_notify(INVALID_SYNTAX, response, TRUE); SIG(IKE_UP_FAILED, "request message incomplete, deleting IKE_SA"); SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); - requested_ca_keyids->destroy(requested_ca_keyids); return DESTROY_ME; } @@ -754,7 +1002,6 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, } } - { /* get a policy and process traffic selectors */ linked_list_t *my_ts, *other_ts; @@ -764,9 +1011,7 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, this->policy = charon->policies->get_policy(charon->policies, my_id, other_id, my_ts, other_ts, - me, other, - requested_ca_keyids); - requested_ca_keyids->destroy(requested_ca_keyids); + me, other); if (this->policy) { @@ -799,8 +1044,8 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, response->add_payload(response, (payload_t*)idr_response); } - if (this->policy->get_auth_method(this->policy) == AUTH_RSA - && this->connection->get_cert_policy(this->connection) != CERT_NEVER_SEND) + if (this->policy->get_auth_method(this->policy) == AUTH_RSA && + this->connection->get_cert_policy(this->connection) != CERT_NEVER_SEND) { /* build certificate payload */ x509_t *cert; cert_payload_t *cert_payload; @@ -822,33 +1067,80 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, import_certificate(cert_request); } - { /* process auth payload */ - authenticator_t *authenticator; + { /* process SA payload */ + linked_list_t *proposal_list; + + /* get proposals from request, and select one with ours */ + proposal_list = sa_request->get_proposals(sa_request); + DBG2(DBG_IKE, "selecting proposals:"); + this->proposal = this->policy->select_proposal(this->policy, proposal_list); + proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy)); + + /* do we have a proposal? */ + if (this->proposal == NULL) + { + SIG(CHILD_UP_FAILED, "CHILD_SA proposals unacceptable, no CHILD_SA created"); + DBG1(DBG_IKE, "adding NO_PROPOSAL_CHOSEN notify to response"); + build_notify(NO_PROPOSAL_CHOSEN, response, FALSE); + this->build_child = FALSE; + } + /* do we have traffic selectors? */ + else if (this->tsi->get_count(this->tsi) == 0 || this->tsr->get_count(this->tsr) == 0) + { + SIG(CHILD_UP_FAILED, "CHILD_SA traffic selectors unacceptable, no CHILD_SA created"); + DBG1(DBG_IKE, "adding TS_UNACCEPTABLE notify to response"); + build_notify(TS_UNACCEPTABLE, response, FALSE); + this->build_child = FALSE; + } + } + + if (!this->eap_only || this->policy->get_auth_method(this->policy) != AUTH_EAP) + { /* build response AUTH payload when not using a mutual EAP authentication */ auth_payload_t *auth_response; + authenticator_t *authenticator; auth_method_t auth_method; status_t status; - auth_method = auth_request->get_auth_method(auth_request); + auth_method = this->policy->get_auth_method(this->policy); + if (auth_method == AUTH_EAP) + { + SIG(IKE_UP_FAILED, + "peer does not support EAP only authentication, deleting IKE_SA"); + SIG(CHILD_UP_FAILED, + "initiating CHILD_SA failed, unable to create IKE_SA"); + build_notify(AUTHENTICATION_FAILED, response, TRUE); + return DESTROY_ME; + } + authenticator = authenticator_create(this->ike_sa, auth_method); if (authenticator == NULL) { SIG(IKE_UP_FAILED, "auth method %N not supported, deleting IKE_SA", auth_method_names, auth_method); SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); + build_notify(AUTHENTICATION_FAILED, response, TRUE); return DESTROY_ME; } - status = authenticator->verify(authenticator, this->init_request, - this->nonce_r, auth_request); + status = authenticator->build(authenticator, this->init_response, + this->nonce_i, &auth_response); authenticator->destroy(authenticator); if (status != SUCCESS) { - SIG(IKE_UP_FAILED, "authentication failed, deleting IKE_SA"); + SIG(IKE_UP_FAILED, "authentication data generation failed, deleting IKE_SA"); SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); build_notify(AUTHENTICATION_FAILED, response, TRUE); return DESTROY_ME; } + response->add_payload(response, (payload_t*)auth_response); + } + + if (auth_request) + { /* process auth payload, if not using EAP */ + authenticator_t *authenticator; + auth_method_t auth_method; + status_t status; - auth_method = this->policy->get_auth_method(this->policy); + auth_method = auth_request->get_auth_method(auth_request); authenticator = authenticator_create(this->ike_sa, auth_method); if (authenticator == NULL) { @@ -857,136 +1149,62 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); return DESTROY_ME; } - status = authenticator->build(authenticator, this->init_response, - this->nonce_i, &auth_response); + status = authenticator->verify(authenticator, this->init_request, + this->nonce_r, auth_request); authenticator->destroy(authenticator); if (status != SUCCESS) { - SIG(IKE_UP_FAILED, "authentication data generation failed, deleting IKE_SA"); + SIG(IKE_UP_FAILED, "authentication failed, deleting IKE_SA"); SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); build_notify(AUTHENTICATION_FAILED, response, TRUE); return DESTROY_ME; } - response->add_payload(response, (payload_t*)auth_response); - } - - SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...%H[%D]", - this->ike_sa->get_name(this->ike_sa), me, my_id, other, other_id); - - { /* process SA payload */ - linked_list_t *proposal_list; - sa_payload_t *sa_response; - ts_payload_t *ts_response; - bool use_natt; - u_int32_t soft_lifetime, hard_lifetime; - /* prepare reply */ - sa_response = sa_payload_create(); + SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...%H[%D]", + this->ike_sa->get_name(this->ike_sa), me, my_id, other, other_id); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - /* get proposals from request, and select one with ours */ - proposal_list = sa_request->get_proposals(sa_request); - DBG2(DBG_IKE, "selecting proposals:"); - this->proposal = this->policy->select_proposal(this->policy, proposal_list); - proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy)); - - /* do we have a proposal? */ - if (this->proposal == NULL) + /* set up CHILD_SA if negotiation succeded */ + if (this->build_child) { - SIG(CHILD_UP_FAILED, "CHILD_SA proposals unacceptable, no CHILD_SA created"); - DBG1(DBG_IKE, "adding NO_PROPOSAL_CHOSEN notify to response"); - build_notify(NO_PROPOSAL_CHOSEN, response, FALSE); + setup_child_sa(this, response); } - /* do we have traffic selectors? */ - else if (this->tsi->get_count(this->tsi) == 0 || this->tsr->get_count(this->tsr) == 0) - { - SIG(CHILD_UP_FAILED, "CHILD_SA traffic selectors unacceptable, no CHILD_SA created"); - DBG1(DBG_IKE, "adding TS_UNACCEPTABLE notify to response"); - build_notify(TS_UNACCEPTABLE, response, FALSE); - } - else + + this->peer_authenticated = TRUE; + } + else + { + /* if no AUTH payload was included, we start with an EAP exchange. + * eap_response is a request in the EAP meaning, but is + * contained in a IKEv2 response */ + eap_payload_t *eap_response; + private_ike_auth_t *next_auth; + eap_type_t eap_type; + + eap_type = this->policy->get_eap_type(this->policy); + this->eap_auth = eap_authenticator_create(this->ike_sa); + status = this->eap_auth->initiate(this->eap_auth, eap_type, &eap_response); + response->add_payload(response, (payload_t*)eap_response); + + if (status == FAILED) { - /* create child sa */ - soft_lifetime = this->policy->get_soft_lifetime(this->policy); - hard_lifetime = this->policy->get_hard_lifetime(this->policy); - use_natt = this->ike_sa->is_natt_enabled(this->ike_sa); - this->child_sa = child_sa_create(this->reqid, me, other, my_id, other_id, - soft_lifetime, hard_lifetime, - this->policy->get_updown(this->policy), - this->policy->get_hostaccess(this->policy), - use_natt); - this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy)); - - /* check mode, and include notify into reply */ - switch (this->mode) - { - case MODE_TUNNEL: - /* is the default */ - break; - case MODE_TRANSPORT: - if (!ts_list_is_host(this->tsi, other) || - !ts_list_is_host(this->tsr, me)) - { - this->mode = MODE_TUNNEL; - DBG1(DBG_IKE, "not using tranport mode, not host-to-host"); - } - else if (this->ike_sa->is_natt_enabled(this->ike_sa)) - { - this->mode = MODE_TUNNEL; - DBG1(DBG_IKE, "not using tranport mode, as connection NATed"); - } - else - { - build_notify(USE_TRANSPORT_MODE, response, FALSE); - } - break; - case MODE_BEET: - if (!ts_list_is_host(this->tsi, NULL) || - !ts_list_is_host(this->tsr, NULL)) - { - this->mode = MODE_TUNNEL; - DBG1(DBG_IKE, "not using BEET mode, not host-to-host"); - } - else - { - build_notify(USE_BEET_MODE, response, FALSE); - } - break; - } - - if (install_child_sa(this, FALSE) != SUCCESS) - { - SIG(CHILD_UP_FAILED, "installing CHILD_SA '%s' failed, no CHILD_SA created", - this->policy->get_name(this->policy)); - DBG1(DBG_IKE, "adding NO_PROPOSAL_CHOSEN notify to response"); - build_notify(NO_PROPOSAL_CHOSEN, response, FALSE); - } - else - { - /* add proposal to sa payload */ - sa_response->add_proposal(sa_response, this->proposal); - SIG(CHILD_UP_SUCCESS, "CHILD_SA '%s' created", - this->policy->get_name(this->policy)); - } + /* EAP initiaton failed, we send the EAP_FAILURE message and quit */ + return DESTROY_ME; } - response->add_payload(response, (payload_t*)sa_response); - - /* add ts payload after sa payload */ - ts_response = ts_payload_create_from_traffic_selectors(TRUE, this->tsi); - response->add_payload(response, (payload_t*)ts_response); - ts_response = ts_payload_create_from_traffic_selectors(FALSE, this->tsr); - response->add_payload(response, (payload_t*)ts_response); + /* we send an EAP request. to handle the reply, we reschedule + * this transaction, as it knows how to handle the reply */ + next_auth = clone_for_eap(this); + next_auth->message_id = this->message_id + 1; + *next = (transaction_t*)next_auth; } - /* set established state */ - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); return SUCCESS; } - /** * Implementation of transaction_t.conclude */ static status_t conclude(private_ike_auth_t *this, message_t *response, - transaction_t **transaction) + transaction_t **next) { iterator_t *payloads; payload_t *payload; @@ -998,6 +1216,7 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, cert_payload_t *cert_payload = NULL; auth_payload_t *auth_payload = NULL; sa_payload_t *sa_payload = NULL; + eap_payload_t *eap_payload = NULL; status_t status; /* check message type */ @@ -1010,6 +1229,8 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, me = this->ike_sa->get_my_host(this->ike_sa); other = this->ike_sa->get_other_host(this->ike_sa); + my_id = this->ike_sa->get_my_id(this->ike_sa); + other_id = this->ike_sa->get_other_id(this->ike_sa); /* Iterate over all payloads to collect them */ payloads = response->get_payload_iterator(response); @@ -1035,6 +1256,9 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, case TRAFFIC_SELECTOR_RESPONDER: tsr_payload = (ts_payload_t*)payload; break; + case EXTENSIBLE_AUTHENTICATION: + eap_payload = (eap_payload_t*)payload; + break; case NOTIFY: { status = process_notifies(this, (notify_payload_t*)payload); @@ -1062,13 +1286,7 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, } payloads->destroy(payloads); - if (!(idr_payload && auth_payload && sa_payload && tsi_payload && tsr_payload)) - { - SIG(IKE_UP_FAILED, "response message incomplete, deleting IKE_SA"); - SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); - return DESTROY_ME; - } - + if (idr_payload) { /* process idr payload */ identification_t *configured_other_id; int wildcards; @@ -1080,7 +1298,7 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, { other_id->destroy(other_id); SIG(IKE_UP_FAILED, "other peer uses unacceptable ID (%D, excepted " - "%D), deleting IKE_SA", other_id, configured_other_id); + "%D), deleting IKE_SA", other_id, configured_other_id); SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); return DESTROY_ME; } @@ -1093,6 +1311,7 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, import_certificate(cert_payload); } + if (auth_payload && idr_payload) { /* authenticate peer */ authenticator_t *authenticator; auth_method_t auth_method; @@ -1118,10 +1337,72 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); return DESTROY_ME; } + this->peer_authenticated = TRUE; + } + + if (eap_payload && this->eap_auth) + { + switch (this->eap_auth->process(this->eap_auth, eap_payload, &this->eap_next)) + { + case SUCCESS: + { + /* EAP message was EAP_SUCCESS, send AUTH in next transaction */ + DBG2(DBG_IKE, "EAP authentication exchanges completed successful"); + this->eap_next = NULL; + /* fall through */ + } + case NEED_MORE: + { + /* EAP message was a EAP_REQUEST, handle it in next transaction */ + private_ike_auth_t *next_auth = clone_for_eap(this); + next_auth->message_id = this->message_id + 1; + *next = (transaction_t*)next_auth; + return SUCCESS; + } + case FAILED: + default: + { + /* EAP message was EAP_FAILURE */ + SIG(IKE_UP_FAILED, "EAP authentication failed, deleting IKE_SA"); + SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); + return DESTROY_ME; + } + } + } + + if (!(auth_payload && sa_payload && tsi_payload && tsr_payload)) + { + SIG(IKE_UP_FAILED, "response message incomplete, deleting IKE_SA"); + SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); + return DESTROY_ME; + } + + /* if we do EAP authentication and a AUTH payload comes in, verify it */ + if (this->eap_auth && + (this->eap_auth->is_mutual(this->eap_auth) || this->peer_authenticated)) + { + authenticator_t *authenticator = (authenticator_t*)this->eap_auth; + + if (authenticator->verify(authenticator, this->init_response, + this->nonce_i, auth_payload) != SUCCESS) + { + SIG(IKE_UP_FAILED, "authentication with EAP failed, deleting IKE_SA"); + SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); + return DESTROY_ME; + } + this->peer_authenticated = TRUE; + } + + if (!this->peer_authenticated) + { + SIG(IKE_UP_FAILED, "server didn't send authentication data, deleting IKE_SA"); + SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA"); + return DESTROY_ME; } SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...%H[%D]", this->ike_sa->get_name(this->ike_sa), me, my_id, other, other_id); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); { /* process traffic selectors for us */ linked_list_t *ts_received = tsi_payload->get_traffic_selectors(tsi_payload); @@ -1198,8 +1479,6 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, } } } - /* set new state */ - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); return SUCCESS; } @@ -1213,6 +1492,12 @@ static void destroy(private_ike_auth_t *this) DESTROY_IF(this->child_sa); DESTROY_IF(this->policy); DESTROY_IF(this->connection); + DESTROY_IF(this->cacerts); + if (this->eap_auth) + { + this->eap_auth->authenticator_interface.destroy(&this->eap_auth->authenticator_interface); + } + DESTROY_IF(this->eap_next); if (this->tsi) { this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); @@ -1260,10 +1545,17 @@ ike_auth_t *ike_auth_create(ike_sa_t *ike_sa) this->init_response = chunk_empty; this->child_sa = NULL; this->proposal = NULL; + this->policy = NULL; + this->connection = NULL; this->tsi = NULL; this->tsr = NULL; this->build_child = TRUE; + this->eap_auth = NULL; + this->eap_next = NULL; + this->eap_only = FALSE; + this->peer_authenticated = FALSE; this->reqid = 0; + this->cacerts = linked_list_create(); this->mode = MODE_TUNNEL; return &this->public; diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c index 950947378..dc8c96ec7 100755 --- a/src/charon/threads/stroke_interface.c +++ b/src/charon/threads/stroke_interface.c @@ -393,7 +393,7 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) } policy = policy_create(msg->add_conn.name, my_id, other_id, - msg->add_conn.auth_method, + msg->add_conn.auth_method, msg->add_conn.eap_type, msg->add_conn.rekey.ipsec_lifetime, msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin, msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 9f1dd4fbc..7fa20e4b2 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -12,6 +12,7 @@ asn1/pem.c asn1/pem.h \ asn1/ttodata.c asn1/ttodata.h \ crypto/rsa/rsa_private_key.c crypto/rsa/rsa_private_key.h \ crypto/rsa/rsa_public_key.h crypto/rsa/rsa_public_key.c \ +crypto/prfs/fips_prf.c crypto/prfs/fips_prf.h \ crypto/prfs/hmac_prf.c crypto/prfs/hmac_prf.h \ crypto/prfs/prf.c crypto/prfs/prf.h \ crypto/signers/hmac_signer.c crypto/signers/hmac_signer.h \ diff --git a/src/libstrongswan/chunk.c b/src/libstrongswan/chunk.c index 811a9757a..f2c8a3efb 100644 --- a/src/libstrongswan/chunk.c +++ b/src/libstrongswan/chunk.c @@ -35,13 +35,22 @@ chunk_t chunk_empty = { NULL, 0 }; /** * Described in header. */ -chunk_t chunk_clone(chunk_t chunk) +chunk_t chunk_create(u_char *ptr, size_t len) +{ + chunk_t chunk = {ptr, len}; + return chunk; +} + +/** + * Described in header. + */ +chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk) { chunk_t clone = chunk_empty; if (chunk.ptr && chunk.len > 0) { - clone.ptr = malloc(chunk.len); + clone.ptr = ptr; clone.len = chunk.len; memcpy(clone.ptr, chunk.ptr, chunk.len); } @@ -52,45 +61,66 @@ chunk_t chunk_clone(chunk_t chunk) /** * Decribed in header. */ -chunk_t chunk_cat(const char* mode, ...) +size_t chunk_length(const char* mode, ...) { - chunk_t construct; va_list chunks; - u_char *pos; - int i; - int count = strlen(mode); - - /* sum up lengths of individual chunks */ + size_t length = 0; + va_start(chunks, mode); - construct.len = 0; - for (i = 0; i < count; i++) + while (TRUE) { - chunk_t ch = va_arg(chunks, chunk_t); - construct.len += ch.len; + switch (*mode++) + { + case 'm': + case 'c': + { + chunk_t ch = va_arg(chunks, chunk_t); + length += ch.len; + continue; + } + default: + break; + } + break; } va_end(chunks); + return length; +} - /* allocate needed memory for construct */ - construct.ptr = malloc(construct.len); - pos = construct.ptr; - - /* copy or move the chunks */ +/** + * Decribed in header. + */ +chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...) +{ + va_list chunks; + chunk_t construct = chunk_create(ptr, 0); + va_start(chunks, mode); - for (i = 0; i < count; i++) + while (TRUE) { - chunk_t ch = va_arg(chunks, chunk_t); + bool free_chunk = FALSE; switch (*mode++) { case 'm': - memcpy(pos, ch.ptr, ch.len); - pos += ch.len; - free(ch.ptr); - break; + { + free_chunk = TRUE; + } case 'c': + { + chunk_t ch = va_arg(chunks, chunk_t); + memcpy(ptr, ch.ptr, ch.len); + ptr += ch.len; + construct.len += ch.len; + if (free_chunk) + { + free(ch.ptr); + } + continue; + } default: - memcpy(pos, ch.ptr, ch.len); - pos += ch.len; + break; } + break; } va_end(chunks); @@ -98,6 +128,85 @@ chunk_t chunk_cat(const char* mode, ...) } /** + * Decribed in header. + */ +void chunk_split(chunk_t chunk, const char *mode, ...) +{ + va_list chunks; + size_t len; + chunk_t *ch; + + va_start(chunks, mode); + while (TRUE) + { + if (*mode == '\0') + { + break; + } + len = va_arg(chunks, size_t); + ch = va_arg(chunks, chunk_t*); + /* a null chunk means skip len bytes */ + if (ch == NULL) + { + chunk = chunk_skip(chunk, len); + continue; + } + switch (*mode++) + { + case 'm': + { + ch->len = min(chunk.len, len); + if (ch->len) + { + ch->ptr = chunk.ptr; + } + else + { + ch->ptr = NULL; + } + chunk = chunk_skip(chunk, ch->len); + continue; + } + case 'a': + { + ch->len = min(chunk.len, len); + if (ch->len) + { + ch->ptr = malloc(ch->len); + memcpy(ch->ptr, chunk.ptr, ch->len); + } + else + { + ch->ptr = NULL; + } + chunk = chunk_skip(chunk, ch->len); + continue; + } + case 'c': + { + ch->len = min(ch->len, chunk.len); + ch->len = min(ch->len, len); + if (ch->len) + { + memcpy(ch->ptr, chunk.ptr, ch->len); + } + else + { + ch->ptr = NULL; + } + chunk = chunk_skip(chunk, ch->len); + continue; + } + default: + break; + } + break; + } + va_end(chunks); +} + + +/** * Described in header. */ void chunk_free(chunk_t *chunk) @@ -110,12 +219,15 @@ void chunk_free(chunk_t *chunk) /** * Described in header. */ -chunk_t chunk_alloc(size_t bytes) +chunk_t chunk_skip(chunk_t chunk, size_t bytes) { - chunk_t new_chunk; - new_chunk.ptr = malloc(bytes); - new_chunk.len = bytes; - return new_chunk; + if (chunk.len > bytes) + { + chunk.ptr += bytes; + chunk.len -= bytes; + return chunk; + } + return chunk_empty; } /** diff --git a/src/libstrongswan/chunk.h b/src/libstrongswan/chunk.h index 93c4b512f..d3477eba8 100644 --- a/src/libstrongswan/chunk.h +++ b/src/libstrongswan/chunk.h @@ -47,21 +47,36 @@ struct chunk_t { extern chunk_t chunk_empty; /** - * Initialize a chunk to point to a static(!) buffer + * Create a new chunk pointing to "ptr" with length "len" */ -#define chunk_from_buf(str) { str, sizeof(str) } +chunk_t chunk_create(u_char *ptr, size_t len); + +/** + * Create a clone of a chunk pointing to "ptr" + */ +chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk); /** - * Clone chunk contents in a newly allocated chunk + * Calculate length of multiple chunks */ -chunk_t chunk_clone(chunk_t chunk); +size_t chunk_length(const char *mode, ...); /** - * Allocate a chunk from concatenation of other chunks. - * mode is a string 'm' and 'c, 'm' means move chunk, - * 'c' means copy chunk. + * Concatenate chunks into a chunk pointing to "ptr", + * "mode" is a string of "c" (copy) and "m" (move), which says + * how to handle to chunks in "..." */ -chunk_t chunk_cat(const char* mode, ...); +chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...); + +/** + * Split up a chunk into parts, "mode" is a string of "a" (alloc), + * "c" (copy) and "m" (move). Each letter say for the corresponding chunk if + * it should get allocated on heap, copied into existing chunk, or the chunk + * should point into "chunk". The length of each part is an argument before + * each target chunk. E.g.: + * chunk_split(chunk, "mcac", 3, &a, 7, &b, 5, &c, d.len, &d); + */ +void chunk_split(chunk_t chunk, const char *mode, ...); /** * Free contents of a chunk @@ -69,9 +84,44 @@ chunk_t chunk_cat(const char* mode, ...); void chunk_free(chunk_t *chunk); /** - * Allocate a chunk + * Initialize a chunk to point to buffer inspectable by sizeof() + */ +#define chunk_from_buf(str) { str, sizeof(str) } + +/** + * Allocate a chunk on the heap + */ +#define chunk_alloc(bytes) chunk_create(malloc(bytes), bytes) + +/** + * Allocate a chunk on the stack + */ +#define chunk_alloca(bytes) chunk_create(alloca(bytes), bytes) + +/** + * Clone a chunk on heap + */ +#define chunk_clone(chunk) chunk_create_clone(malloc(chunk.len), chunk) + +/** + * Clone a chunk on stack + */ +#define chunk_clonea(chunk) chunk_create_clone(alloca(chunk.len), chunk) + +/** + * Concatenate chunks into a chunk on heap + */ +#define chunk_cat(mode, ...) chunk_create_cat(malloc(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__) + +/** + * Concatenate chunks into a chunk on stack + */ +#define chunk_cata(mode, ...) chunk_create_cat(alloca(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__) + +/** + * Skip n bytes in chunk (forward pointer, shorten length) */ -chunk_t chunk_alloc(size_t bytes); +chunk_t chunk_skip(chunk_t chunk, size_t bytes); /** * Compare two chunks for equality, diff --git a/src/libstrongswan/crypto/hashers/hasher.h b/src/libstrongswan/crypto/hashers/hasher.h index a1b5f5805..9b226b2a1 100644 --- a/src/libstrongswan/crypto/hashers/hasher.h +++ b/src/libstrongswan/crypto/hashers/hasher.h @@ -123,9 +123,23 @@ struct hasher_t { void (*reset) (hasher_t *this); /** + * @brief Get the state of the hasher. + * + * A hasher stores internal state information. This state may be + * manipulated to include a "seed" into the hashing operation. It used by + * some exotic protocols (such as AKA). + * The data pointed by chunk may be manipulated, but not replaced nor freed. + * This is more a hack than a feature. The hasher's state may be byte + * order dependant; use with care. + * + * @param this calling object + */ + chunk_t (*get_state) (hasher_t *this); + + /** * @brief Destroys a hasher object. * - * @param this calling object + * @param this calling object */ void (*destroy) (hasher_t *this); }; diff --git a/src/libstrongswan/crypto/hashers/md5_hasher.c b/src/libstrongswan/crypto/hashers/md5_hasher.c index fa61cac5b..5330676d4 100644 --- a/src/libstrongswan/crypto/hashers/md5_hasher.c +++ b/src/libstrongswan/crypto/hashers/md5_hasher.c @@ -364,6 +364,19 @@ static void reset(private_md5_hasher_t *this) } /** + * Implementation of hasher_t.get_state + */ +static chunk_t get_state(private_md5_hasher_t *this) +{ + chunk_t chunk; + + chunk.ptr = (u_char*)&this->state[0]; + chunk.len = sizeof(this->state); + + return chunk; +} + +/** * Implementation of hasher_t.destroy. */ static void destroy(private_md5_hasher_t *this) @@ -382,6 +395,7 @@ md5_hasher_t *md5_hasher_create(void) this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash; this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size; this->public.hasher_interface.reset = (void (*) (hasher_t*))reset; + this->public.hasher_interface.get_state = (chunk_t (*) (hasher_t*))get_state; this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy; /* initialize */ diff --git a/src/libstrongswan/crypto/hashers/sha1_hasher.c b/src/libstrongswan/crypto/hashers/sha1_hasher.c index cca336694..6a86937ae 100644 --- a/src/libstrongswan/crypto/hashers/sha1_hasher.c +++ b/src/libstrongswan/crypto/hashers/sha1_hasher.c @@ -223,7 +223,7 @@ static size_t get_hash_size(private_sha1_hasher_t *this) { return HASH_SIZE_SHA1; } - + /** * Implementation of hasher_t.reset. */ @@ -237,6 +237,20 @@ static void reset(private_sha1_hasher_t *this) this->count[0] = 0; this->count[1] = 0; } + +/** + * Implementation of hasher_t.get_state + */ +static chunk_t get_state(private_sha1_hasher_t *this) +{ + chunk_t chunk; + + chunk.ptr = (u_char*)&this->state[0]; + chunk.len = sizeof(this->state); + + return chunk; +} + /** * Implementation of hasher_t.destroy. */ @@ -256,6 +270,7 @@ sha1_hasher_t *sha1_hasher_create(void) this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash; this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size; this->public.hasher_interface.reset = (void (*) (hasher_t*))reset; + this->public.hasher_interface.get_state = (chunk_t (*) (hasher_t*))get_state; this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy; /* initialize */ diff --git a/src/libstrongswan/crypto/hashers/sha2_hasher.c b/src/libstrongswan/crypto/hashers/sha2_hasher.c index f6fd0404e..b68972cec 100644 --- a/src/libstrongswan/crypto/hashers/sha2_hasher.c +++ b/src/libstrongswan/crypto/hashers/sha2_hasher.c @@ -587,6 +587,38 @@ static void reset512(private_sha512_hasher_t *ctx) } /** + * Implementation of hasher_t.get_state for SHA256 + */ +static chunk_t get_state256(private_sha256_hasher_t *ctx) +{ + chunk_t chunk; + chunk.ptr = (u_char*)&ctx->sha_H[0]; + chunk.len = HASH_SIZE_SHA256; + return chunk; +} + +/** + * Implementation of hasher_t.get_state for SHA384 + */ +static chunk_t get_state384(private_sha512_hasher_t *ctx) +{ + chunk_t chunk; + chunk.ptr = (u_char*)&ctx->sha_H[0]; + chunk.len = HASH_SIZE_SHA384; + return chunk; +} +/** + * Implementation of hasher_t.get_state for SHA512 + */ +static chunk_t get_state512(private_sha512_hasher_t *ctx) +{ + chunk_t chunk; + chunk.ptr = (u_char*)&ctx->sha_H[0]; + chunk.len = HASH_SIZE_SHA512; + return chunk; +} + +/** * Implementation of hasher_t.destroy. */ static void destroy(sha2_hasher_t *this) @@ -606,6 +638,7 @@ sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm) case HASH_SHA256: this = (sha2_hasher_t*)malloc_thing(private_sha256_hasher_t); this->hasher_interface.reset = (void(*)(hasher_t*))reset256; + this->hasher_interface.get_state = (chunk_t(*)(hasher_t*))get_state256; this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size256; this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash256; this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash256; @@ -614,6 +647,7 @@ sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm) /* uses SHA512 data structure */ this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t); this->hasher_interface.reset = (void(*)(hasher_t*))reset384; + this->hasher_interface.get_state = (chunk_t(*)(hasher_t*))get_state384; this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size384; this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash384; this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash384; @@ -621,6 +655,7 @@ sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm) case HASH_SHA512: this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t); this->hasher_interface.reset = (void(*)(hasher_t*))reset512; + this->hasher_interface.get_state = (chunk_t(*)(hasher_t*))get_state512; this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size512; this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash512; this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash512; diff --git a/src/libstrongswan/crypto/prfs/fips_prf.c b/src/libstrongswan/crypto/prfs/fips_prf.c new file mode 100644 index 000000000..320e56dfc --- /dev/null +++ b/src/libstrongswan/crypto/prfs/fips_prf.c @@ -0,0 +1,258 @@ +/** + * @file fips_prf.c + * + * @brief Implementation for fips_prf_t. + * + */ + +/* + * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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 "fips_prf.h" + +#include <arpa/inet.h> + +#include <debug.h> + +typedef struct private_fips_prf_t private_fips_prf_t; + +/** + * Private data of a fips_prf_t object. + */ +struct private_fips_prf_t { + /** + * Public fips_prf_t interface. + */ + fips_prf_t public; + + /** + * key of prf function, "b" long + */ + u_int8_t *key; + + /** + * size of "b" in bytes + */ + size_t b; + + /** + * G function, either SHA1 or DES + */ + void (*g)(u_int8_t t[], chunk_t c, u_int8_t res[]); +}; + +/** + * t used in G(), equals to initial SHA1 value + */ +static u_int8_t t[] = { + 0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA, + 0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0, +}; + +/** + * sum = (a + b) mod 2 ^ (length * 8) + */ +static void add_mod(size_t length, u_int8_t a[], u_int8_t b[], u_int8_t sum[]) +{ + int i; + + for(i = length - 1; i >= 0; i--) + { + u_int32_t tmp; + int c = 0; + + tmp = a[i] + b[i] + c; + sum[i] = 0xff & tmp; + c = tmp >> 8; + } +} + +/** + * calculate "chunk mod 2^(length*8)" and save it into buffer + */ +static void chunk_mod(size_t length, chunk_t chunk, u_int8_t buffer[]) +{ + if (chunk.len < length) + { + /* apply seed as least significant bits, others are zero */ + memset(buffer, 0, length - chunk.len); + memcpy(buffer + length - chunk.len, chunk.ptr, chunk.len); + } + else + { + /* use least significant bytes from seed, as we use mod 2^b */ + memcpy(buffer, chunk.ptr + chunk.len - length, length); + } +} + +/** + * Implementation of prf_t.get_bytes. + * + * Test vector: + * + * key: + * 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b, + * 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f, + * 0xeb, 0x5a, 0x38, 0xb6 + * + * seed: + * 0x00 + * + * result: + * 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f, + * 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49, + * 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba, + * 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78, + * 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16 + */ +static void get_bytes(private_fips_prf_t *this, chunk_t seed, u_int8_t w[]) +{ + int i; + u_int8_t xval[this->b]; + u_int8_t xseed[this->b]; + u_int8_t *xkey = this->key; + u_int8_t one[this->b]; + chunk_t xval_chunk = chunk_from_buf(xval); + + memset(one, 0, this->b); + one[this->b - 1] = 0x01; + + /* 3.1 */ + chunk_mod(this->b, seed, xseed); + + /* 3.2 */ + for (i = 0; i < 2; i++) /* twice */ + { + /* a. XVAL = (XKEY + XSEED j) mod 2^b */ + add_mod(this->b, xkey, xseed, xval); + DBG3("XVAL %b", xval, this->b); + /* b. wi = G(t, XVAL ) */ + this->g(t, xval_chunk, &w[i * this->b]); + DBG3("w[%d] %b", i, &w[i * this->b], this->b); + /* c. XKEY = (1 + XKEY + wi) mod 2b */ + add_mod(this->b, xkey, one, xkey); + add_mod(this->b, xkey, &w[i * this->b], xkey); + DBG3("XKEY %b", xkey, this->b); + } + + /* 3.3 done already, mod q not used */ +} + +/** + * Implementation of prf_t.get_block_size. + */ +static size_t get_block_size(private_fips_prf_t *this) +{ + return 2 * this->b; +} +/** + * Implementation of prf_t.allocate_bytes. + */ +static void allocate_bytes(private_fips_prf_t *this, chunk_t seed, chunk_t *chunk) +{ + *chunk = chunk_alloc(get_block_size(this)); + get_bytes(this, seed, chunk->ptr); +} + +/** + * Implementation of prf_t.get_key_size. + */ +static size_t get_key_size(private_fips_prf_t *this) +{ + return this->b; +} + +/** + * Implementation of prf_t.set_key. + */ +static void set_key(private_fips_prf_t *this, chunk_t key) +{ + /* save key as "key mod 2^b" */ + chunk_mod(this->b, key, this->key); +} + +/** + * Implementation of the G() function based on SHA1 + */ +void g_sha1(u_int8_t t[], chunk_t c, u_int8_t res[]) +{ + hasher_t *hasher; + u_int8_t buf[64]; + chunk_t state_chunk; + u_int32_t *state, *iv, *hash; + + if (c.len < sizeof(buf)) + { + /* pad c with zeros */ + memset(buf, 0, sizeof(buf)); + memcpy(buf, c.ptr, c.len); + c.ptr = buf; + c.len = sizeof(buf); + } + else + { + /* not more than 512 bits can be G()-ed */ + c.len = sizeof(buf); + } + + /* our SHA1 hasher's state is 32-Bit integers in host order. We must + * convert them */ + hasher = hasher_create(HASH_SHA1); + state_chunk = hasher->get_state(hasher); + state = (u_int32_t*)state_chunk.ptr; + iv = (u_int32_t*)t; + hash = (u_int32_t*)res; + state[0] = htonl(iv[0]); + state[1] = htonl(iv[1]); + state[2] = htonl(iv[2]); + state[3] = htonl(iv[3]); + hasher->get_hash(hasher, c, NULL); + hash[0] = htonl(state[0]); + hash[1] = htonl(state[1]); + hash[2] = htonl(state[2]); + hash[3] = htonl(state[3]); + hash[4] = htonl(state[4]); + hasher->destroy(hasher); +} + +/** + * Implementation of prf_t.destroy. + */ +static void destroy(private_fips_prf_t *this) +{ + free(this->key); + free(this); +} + +/* + * Described in header. + */ +fips_prf_t *fips_prf_create(size_t b, void(*g)(u_int8_t[],chunk_t,u_int8_t[])) +{ + private_fips_prf_t *this = malloc_thing(private_fips_prf_t); + + this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes; + this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes; + this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size; + this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size; + this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key; + this->public.prf_interface.destroy = (void (*) (prf_t *))destroy; + + this->g = g; + this->b = b; + this->key = malloc(b); + + return &(this->public); +} diff --git a/src/libstrongswan/crypto/prfs/fips_prf.h b/src/libstrongswan/crypto/prfs/fips_prf.h new file mode 100644 index 000000000..283ee1f61 --- /dev/null +++ b/src/libstrongswan/crypto/prfs/fips_prf.h @@ -0,0 +1,80 @@ +/** + * @file fips_prf.h + * + * @brief Interface of fips_prf_t. + * + */ + +/* + * Copyright (C) 2006 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 <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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 FIPS_PRF_H_ +#define FIPS_PRF_H_ + +typedef struct fips_prf_t fips_prf_t; + +#include <library.h> +#include <crypto/prfs/prf.h> +#include <crypto/hashers/hasher.h> + +/** + * @brief Implementation of prf_t using the FIPS 186-2-change1 standard. + * + * FIPS defines a "General Purpose Random Number Generator" (Revised + * Algorithm for Computing m values of x (Appendix 3.1 of FIPS 186-2)). This + * implementation is not intended for private key generation and therefore does + * not include the "mod q" operation (see FIPS 186-2-change1 p74). + * The FIPS PRF is stateful; the key changes every time when bytes are acquired. + * + * @b Constructors: + * - fips_prf_create() + * - prf_create() using one of the FIPS algorithms + * + * @ingroup prfs + */ +struct fips_prf_t { + + /** + * Generic prf_t interface for this fips_prf_t class. + */ + prf_t prf_interface; +}; + +/** + * @brief Creates a new fips_prf_t object. + * + * FIPS 186-2 defines G() functions used in the PRF function. It can + * be implemented either based on SHA1 or DES. + * + * @param b size of b (in bytes, not bits) + * @param g G() function to use (e.g. g_sha1) + * @return + * - fips_prf_t object + * - NULL if b invalid not supported + * + * @ingroup prfs + */ +fips_prf_t *fips_prf_create(size_t b, void(*g)(u_int8_t[],chunk_t,u_int8_t[])); + +/** + * @brief Implementation of the G() function based on SHA1. + * + * @param t initialization vector for SHA1 hasher, 20 bytes long + * @param c value to hash, not longer than 512 bit + * @param res result of G(), requries 20 bytes + */ +void g_sha1(u_int8_t t[], chunk_t c, u_int8_t res[]); + +#endif /* FIPS_PRF_H_ */ diff --git a/src/libstrongswan/crypto/prfs/prf.c b/src/libstrongswan/crypto/prfs/prf.c index aa5d1d2b7..f3b05ea00 100644 --- a/src/libstrongswan/crypto/prfs/prf.c +++ b/src/libstrongswan/crypto/prfs/prf.c @@ -26,10 +26,13 @@ #include <crypto/hashers/hasher.h> #include <crypto/prfs/hmac_prf.h> +#include <crypto/prfs/fips_prf.h> -ENUM_BEGIN(pseudo_random_function_names, PRF_UNDEFINED, PRF_UNDEFINED, - "PRF_UNDEFINED"); -ENUM_NEXT(pseudo_random_function_names, PRF_HMAC_MD5, PRF_AES128_CBC, PRF_UNDEFINED, +ENUM_BEGIN(pseudo_random_function_names, PRF_UNDEFINED, PRF_FIPS_DES, + "PRF_UNDEFINED", + "PRF_FIPS_SHA1_160", + "PRF_FIPS_DES"); +ENUM_NEXT(pseudo_random_function_names, PRF_HMAC_MD5, PRF_AES128_CBC, PRF_FIPS_DES, "PRF_HMAC_MD5", "PRF_HMAC_SHA1", "PRF_HMAC_TIGER", @@ -44,13 +47,12 @@ prf_t *prf_create(pseudo_random_function_t pseudo_random_function) switch (pseudo_random_function) { case PRF_HMAC_SHA1: - { return (prf_t*)hmac_prf_create(HASH_SHA1); - } case PRF_HMAC_MD5: - { return (prf_t*)hmac_prf_create(HASH_MD5); - } + case PRF_FIPS_SHA1_160: + return (prf_t*)fips_prf_create(20, g_sha1); + case PRF_FIPS_DES: case PRF_HMAC_TIGER: case PRF_AES128_CBC: default: diff --git a/src/libstrongswan/crypto/prfs/prf.h b/src/libstrongswan/crypto/prfs/prf.h index 897cf906b..7a4501866 100644 --- a/src/libstrongswan/crypto/prfs/prf.h +++ b/src/libstrongswan/crypto/prfs/prf.h @@ -31,11 +31,10 @@ typedef struct prf_t prf_t; /** * @brief Pseudo random function, as in IKEv2 RFC 3.3.2. - * - * Currently only the following algorithms are implemented: - * - PRF_HMAC_MD5 - * - PRF_HMAC_SHA1 - * + * + * PRF algorithms not defined in IKEv2 are allocated in "private use" + * space. + * * @ingroup prfs */ enum pseudo_random_function_t { @@ -46,6 +45,10 @@ enum pseudo_random_function_t { PRF_HMAC_SHA1 = 2, PRF_HMAC_TIGER = 3, PRF_AES128_CBC = 4, + /** Implemented via fips_prf_t, other output sizes would be possible */ + PRF_FIPS_SHA1_160 = 1025, + /** Could be implemented via fips_prf_t, uses fixed output size of 160bit */ + PRF_FIPS_DES = 1026, }; /** @@ -93,6 +96,9 @@ struct prf_t { /** * @brief Get the key size of this prf_t object. + * + * This is a suggestion only, all implemented PRFs accept variable key + * length. * * @param this calling object * @return key size in bytes diff --git a/src/libstrongswan/crypto/signers/hmac_signer.c b/src/libstrongswan/crypto/signers/hmac_signer.c index c4a6173b5..76e1ce50e 100644 --- a/src/libstrongswan/crypto/signers/hmac_signer.c +++ b/src/libstrongswan/crypto/signers/hmac_signer.c @@ -27,11 +27,6 @@ #include <crypto/prfs/hmac_prf.h> -/** - * This class represents a hmac signer with 12 byte (96 bit) output. - */ -#define BLOCK_SIZE 12 - typedef struct private_hmac_signer_t private_hmac_signer_t; /** @@ -43,10 +38,15 @@ struct private_hmac_signer_t { */ hmac_signer_t public; - /* + /** * Assigned hmac function. */ prf_t *hmac_prf; + + /** + * Block size (truncation of HMAC Hash) + */ + size_t block_size; }; /** @@ -56,10 +56,10 @@ static void get_signature (private_hmac_signer_t *this, chunk_t data, u_int8_t * { u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)]; - this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac); + this->hmac_prf->get_bytes(this->hmac_prf, data, full_mac); - /* copy mac aka signature :-) */ - memcpy(buffer,full_mac,BLOCK_SIZE); + /* copy MAC depending on truncation */ + memcpy(buffer, full_mac, this->block_size); } /** @@ -72,11 +72,11 @@ static void allocate_signature (private_hmac_signer_t *this, chunk_t data, chunk this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac); - signature.ptr = malloc(BLOCK_SIZE); - signature.len = BLOCK_SIZE; + signature.ptr = malloc(this->block_size); + signature.len = this->block_size; /* copy signature */ - memcpy(signature.ptr,full_mac,BLOCK_SIZE); + memcpy(signature.ptr, full_mac, this->block_size); *chunk = signature; } @@ -84,19 +84,19 @@ static void allocate_signature (private_hmac_signer_t *this, chunk_t data, chunk /** * Implementation of signer_t.verify_signature. */ -static bool verify_signature (private_hmac_signer_t *this, chunk_t data, chunk_t signature) +static bool verify_signature(private_hmac_signer_t *this, chunk_t data, chunk_t signature) { u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)]; - this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac); + this->hmac_prf->get_bytes(this->hmac_prf, data, full_mac); - if (signature.len != BLOCK_SIZE) + if (signature.len != this->block_size) { return FALSE; } /* compare mac aka signature :-) */ - if (memcmp(signature.ptr,full_mac,BLOCK_SIZE) == 0) + if (memcmp(signature.ptr, full_mac, this->block_size) == 0) { return TRUE; } @@ -109,7 +109,7 @@ static bool verify_signature (private_hmac_signer_t *this, chunk_t data, chunk_t /** * Implementation of signer_t.get_key_size. */ -static size_t get_key_size (private_hmac_signer_t *this) +static size_t get_key_size(private_hmac_signer_t *this) { /* for HMAC signer, IKEv2 uses block size as key size */ return this->hmac_prf->get_block_size(this->hmac_prf); @@ -118,17 +118,17 @@ static size_t get_key_size (private_hmac_signer_t *this) /** * Implementation of signer_t.get_block_size. */ -static size_t get_block_size (private_hmac_signer_t *this) +static size_t get_block_size(private_hmac_signer_t *this) { - return BLOCK_SIZE; + return this->block_size; } /** * Implementation of signer_t.set_key. */ -static void set_key (private_hmac_signer_t *this, chunk_t key) +static void set_key(private_hmac_signer_t *this, chunk_t key) { - this->hmac_prf->set_key(this->hmac_prf,key); + this->hmac_prf->set_key(this->hmac_prf, key); } /** @@ -144,12 +144,12 @@ static status_t destroy(private_hmac_signer_t *this) /* * Described in header */ -hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm) +hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm, size_t block_size) { + size_t hmac_block_size; private_hmac_signer_t *this = malloc_thing(private_hmac_signer_t); this->hmac_prf = (prf_t *) hmac_prf_create(hash_algoritm); - if (this->hmac_prf == NULL) { /* algorithm not supported */ @@ -157,6 +157,10 @@ hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm) return NULL; } + /* prevent invalid truncation */ + hmac_block_size = this->hmac_prf->get_block_size(this->hmac_prf); + this->block_size = min(block_size, hmac_block_size); + /* interface functions */ this->public.signer_interface.get_signature = (void (*) (signer_t*, chunk_t, u_int8_t*))get_signature; this->public.signer_interface.allocate_signature = (void (*) (signer_t*, chunk_t, chunk_t*))allocate_signature; diff --git a/src/libstrongswan/crypto/signers/hmac_signer.h b/src/libstrongswan/crypto/signers/hmac_signer.h index 5b9549086..2449069bd 100644 --- a/src/libstrongswan/crypto/signers/hmac_signer.h +++ b/src/libstrongswan/crypto/signers/hmac_signer.h @@ -30,9 +30,11 @@ typedef struct hmac_signer_t hmac_signer_t; #include <crypto/hashers/hasher.h> /** - * @brief Implementation of signer_t interface using the - * HMAC algorithm in combination with either MD5 or SHA1. - * + * @brief Implementation of signer_t interface using HMAC. + * + * HMAC uses a standard hash function implemented in a hasher_t to build + * a MAC. + * * @ingroup signers */ struct hmac_signer_t { @@ -45,15 +47,22 @@ struct hmac_signer_t { /** * @brief Creates a new hmac_signer_t. - * + * + * HMAC signatures are often truncated to shorten them to a more usable, but + * still secure enough length. + * Block size must be equal or smaller then the hash algorithms + * hash. + * * @param hash_algoritm Hash algorithm to use with signer + * @param block_size Size of resulting signature (truncated to block_size) * @return * - hmac_signer_t * - NULL if hash algorithm not supported * * @ingroup signers */ -hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm); +hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm, + size_t block_size); #endif /*HMAC_SIGNER_H_*/ diff --git a/src/libstrongswan/crypto/signers/signer.c b/src/libstrongswan/crypto/signers/signer.c index d6037c545..250d64b71 100644 --- a/src/libstrongswan/crypto/signers/signer.c +++ b/src/libstrongswan/crypto/signers/signer.c @@ -25,9 +25,10 @@ #include <crypto/signers/hmac_signer.h> -ENUM_BEGIN(integrity_algorithm_names, AUTH_UNDEFINED, AUTH_UNDEFINED, - "UNDEFINED"); -ENUM_NEXT(integrity_algorithm_names, AUTH_HMAC_MD5_96, AUTH_AES_XCBC_96, AUTH_UNDEFINED, +ENUM_BEGIN(integrity_algorithm_names, AUTH_UNDEFINED, AUTH_HMAC_SHA1_128, + "UNDEFINED", + "AUTH_HMAC_SHA1_128"); +ENUM_NEXT(integrity_algorithm_names, AUTH_HMAC_MD5_96, AUTH_AES_XCBC_96, AUTH_HMAC_SHA1_128, "HMAC_MD5_96", "HMAC_SHA1_96", "DES_MAC", @@ -43,13 +44,11 @@ signer_t *signer_create(integrity_algorithm_t integrity_algorithm) switch(integrity_algorithm) { case AUTH_HMAC_SHA1_96: - { - return ((signer_t *) hmac_signer_create(HASH_SHA1)); - } + return (signer_t *)hmac_signer_create(HASH_SHA1, 12); + case AUTH_HMAC_SHA1_128: + return (signer_t *)hmac_signer_create(HASH_SHA1, 16); case AUTH_HMAC_MD5_96: - { - return ((signer_t *) hmac_signer_create(HASH_MD5)); - } + return (signer_t *)hmac_signer_create(HASH_MD5, 12); default: return NULL; } diff --git a/src/libstrongswan/crypto/signers/signer.h b/src/libstrongswan/crypto/signers/signer.h index 57f7d8fe6..436161a66 100644 --- a/src/libstrongswan/crypto/signers/signer.h +++ b/src/libstrongswan/crypto/signers/signer.h @@ -31,11 +31,9 @@ typedef struct signer_t signer_t; /** * @brief Integrity algorithm, as in IKEv2 RFC 3.3.2. - * - * Currently only the following algorithms are implemented and therefore supported: - * - AUTH_HMAC_MD5_96 - * - AUTH_HMAC_SHA1_96 - * + * + * Algorithms not specified in IKEv2 are allocated in private use space. + * * @ingroup signers */ enum integrity_algorithm_t { @@ -46,7 +44,9 @@ enum integrity_algorithm_t { AUTH_HMAC_SHA1_96 = 2, AUTH_DES_MAC = 3, AUTH_KPDK_MD5 = 4, - AUTH_AES_XCBC_96 = 5 + AUTH_AES_XCBC_96 = 5, + /** Implemented via hmac_signer_t */ + AUTH_HMAC_SHA1_128 = 1025, }; /** diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c index ce3f827fa..3a76a5a05 100644 --- a/src/libstrongswan/library.c +++ b/src/libstrongswan/library.c @@ -43,6 +43,7 @@ ENUM(status_names, SUCCESS, DESTROY_ME, "VERIFY_ERROR", "INVALID_STATE", "DESTROY_ME", + "NEED_MORE", ); /** @@ -59,6 +60,18 @@ void *clalloc(void * pointer, size_t size) } /** + * Described in header. + */ +void memxor(u_int8_t dest[], u_int8_t src[], size_t n) +{ + size_t i; + for (i = 0; i < n; i++) + { + dest[i] ^= src[i]; + } +} + +/** * We use a single mutex for all refcount variables. This * is not optimal for performance, but the critical section * is not that long... diff --git a/src/libstrongswan/library.h b/src/libstrongswan/library.h index 12aa0cb3c..7c7f087f0 100644 --- a/src/libstrongswan/library.h +++ b/src/libstrongswan/library.h @@ -226,6 +226,11 @@ enum status_t { * Destroy object which called method belongs to. */ DESTROY_ME, + + /** + * Another call to the method is required. + */ + NEED_MORE, }; /** @@ -260,6 +265,11 @@ typedef struct sockaddr sockaddr_t; void *clalloc(void *pointer, size_t size); /** + * Same as memcpy, but XORs src into dst instead of copy + */ +void memxor(u_int8_t dest[], u_int8_t src[], size_t n); + +/** * Special type to count references */ typedef volatile u_int refcount_t; diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index 099e1170c..2c1cde707 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -186,6 +186,7 @@ whitelist_t whitelist[] = { {getservbyport, 311}, {register_printf_function, 159}, {syslog, 45}, + {dlopen, 109}, }; /** diff --git a/src/starter/Makefile.am b/src/starter/Makefile.am index 77d58e79b..7d5a4b69a 100644 --- a/src/starter/Makefile.am +++ b/src/starter/Makefile.am @@ -6,7 +6,7 @@ keywords.c files.h keywords.h cmp.c starter.c cmp.h exec.c invokecharon.c \ exec.h invokecharon.h lex.yy.c INCLUDES = -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/pluto -I$(top_srcdir)/src/whack -I$(top_srcdir)/src/stroke -AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DDEBUG +AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_EAPDIR=\"${eapdir}\" -DDEBUG starter_LDADD = loglite.o defs.o $(top_srcdir)/src/libfreeswan/libfreeswan.a EXTRA_DIST = parser.l parser.y keywords.txt ipsec.conf dist_man_MANS = ipsec.conf.5 diff --git a/src/starter/args.c b/src/starter/args.c index d689a40fd..009622c89 100644 --- a/src/starter/args.c +++ b/src/starter/args.c @@ -165,6 +165,7 @@ static const token_info_t token_info[] = { ARG_ENUM, offsetof(starter_config_t, setup.nat_traversal), LST_bool }, { ARG_TIME, offsetof(starter_config_t, setup.keep_alive), NULL }, { ARG_STR, offsetof(starter_config_t, setup.virtual_private), NULL }, + { ARG_STR, offsetof(starter_config_t, setup.eapdir), NULL }, { ARG_STR, offsetof(starter_config_t, setup.pkcs11module), NULL }, { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11keepstate), LST_bool }, { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11proxy), LST_bool }, @@ -184,6 +185,7 @@ static const token_info_t token_info[] = { ARG_MISC, 0, NULL /* KW_COMPRESS */ }, { ARG_MISC, 0, NULL /* KW_AUTH */ }, { ARG_MISC, 0, NULL /* KW_AUTHBY */ }, + { ARG_MISC, 0, NULL /* KW_EAP */ }, { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL }, { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL }, { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL }, diff --git a/src/starter/confread.c b/src/starter/confread.c index 03b223878..66f70e5f9 100644 --- a/src/starter/confread.c +++ b/src/starter/confread.c @@ -63,6 +63,7 @@ static void default_values(starter_config_t *cfg) cfg->setup.interfaces = new_list("%defaultroute"); cfg->setup.charonstart = TRUE; cfg->setup.plutostart = TRUE; + cfg->setup.eapdir = IPSEC_EAPDIR; cfg->conn_default.seen = LEMPTY; cfg->conn_default.startup = STARTUP_NO; @@ -414,7 +415,7 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg) case KW_AUTHBY: conn->policy &= ~(POLICY_ID_AUTH_MASK | POLICY_ENCRYPT); - if (strcmp(kw->value, "never") != 0) + if (!(streq(kw->value, "never") || streq(kw->value, "eap"))) { char *value = kw->value; char *second = strchr(kw->value, '|'); @@ -446,6 +447,20 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg) } } break; + case KW_EAP: + /* TODO: a gperf function for all EAP types */ + if (streq(kw->value, "aka")) + conn->eap = 23; + else + { + conn->eap = atoi(kw->value); + if (conn->eap == 0) + { + plog("# unknown EAP type: %s=%s", kw->entry->name, kw->value); + cfg->err++; + } + } + break; case KW_REKEY: KW_POLICY_FLAG("no", "yes", POLICY_DONT_REKEY) break; diff --git a/src/starter/confread.h b/src/starter/confread.h index 24b048965..0b303c5bf 100644 --- a/src/starter/confread.h +++ b/src/starter/confread.h @@ -95,6 +95,7 @@ struct starter_conn { starter_state_t state; keyexchange_t keyexchange; + int eap; lset_t policy; time_t sa_ike_life_seconds; time_t sa_ipsec_life_seconds; @@ -167,6 +168,7 @@ struct starter_config { bool nat_traversal; u_int keep_alive; char *virtual_private; + char *eapdir; char *pkcs11module; bool pkcs11keepstate; bool pkcs11proxy; diff --git a/src/starter/invokecharon.c b/src/starter/invokecharon.c index 02239daf1..29b241234 100644 --- a/src/starter/invokecharon.c +++ b/src/starter/invokecharon.c @@ -116,6 +116,8 @@ starter_start_charon (starter_config_t *cfg, bool debug) { arg[argc++] = "--strictcrlpolicy"; } + arg[argc++] = "--eapdir"; + arg[argc++] = cfg->setup.eapdir; { /* parse debug string */ char *pos, *level, *buf_pos, type[4], buffer[512]; diff --git a/src/starter/keywords.h b/src/starter/keywords.h index 66f86679e..2f677e367 100644 --- a/src/starter/keywords.h +++ b/src/starter/keywords.h @@ -39,6 +39,7 @@ typedef enum { KW_NAT_TRAVERSAL, KW_KEEP_ALIVE, KW_VIRTUAL_PRIVATE, + KW_EAPDIR, KW_PKCS11MODULE, KW_PKCS11KEEPSTATE, KW_PKCS11PROXY, @@ -67,6 +68,7 @@ typedef enum { KW_COMPRESS, KW_AUTH, KW_AUTHBY, + KW_EAP, KW_IKELIFETIME, KW_KEYLIFE, KW_REKEYMARGIN, diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt index e8e489fea..bf9422b9e 100644 --- a/src/starter/keywords.txt +++ b/src/starter/keywords.txt @@ -47,6 +47,8 @@ nocrsend, KW_NOCRSEND nat_traversal, KW_NAT_TRAVERSAL keep_alive, KW_KEEP_ALIVE virtual_private, KW_VIRTUAL_PRIVATE +eap, KW_EAP +eapdir, KW_EAPDIR pkcs11module, KW_PKCS11MODULE pkcs11keepstate, KW_PKCS11KEEPSTATE pkcs11proxy, KW_PKCS11PROXY diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index 9d4e0a13a..47e7348e4 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -37,29 +37,13 @@ #include "files.h" /** - * AUTH Method to use. - * - * @ingroup config + * Authentication mehtods, must be the same values as in charon */ enum auth_method_t { - /** - * Computed as specified in section 2.15 of RFC using - * an RSA private key over a PKCS#1 padded hash. - */ - RSA_DIGITAL_SIGNATURE = 1, - - /** - * Computed as specified in section 2.15 of RFC using the - * shared key associated with the identity in the ID payload - * and the negotiated prf function - */ - SHARED_KEY_MESSAGE_INTEGRITY_CODE = 2, - - /** - * Computed as specified in section 2.15 of RFC using a - * DSS private key over a SHA-1 hash. - */ - DSS_DIGITAL_SIGNATURE = 3, + AUTH_RSA = 1, + AUTH_PSK = 2, + AUTH_DSS = 3, + AUTH_EAP = 201, }; static char* push_string(stroke_msg_t *msg, char *string) @@ -192,8 +176,22 @@ int starter_stroke_add_conn(starter_conn_t *conn) msg.length = offsetof(stroke_msg_t, buffer); msg.add_conn.ikev2 = conn->keyexchange == KEY_EXCHANGE_IKEV2; msg.add_conn.name = push_string(&msg, connection_name(conn)); - msg.add_conn.auth_method = (conn->policy & POLICY_PSK)? - SHARED_KEY_MESSAGE_INTEGRITY_CODE : RSA_DIGITAL_SIGNATURE; + + /* RSA is preferred before PSK and EAP */ + if (conn->policy & POLICY_RSASIG) + { + msg.add_conn.auth_method = AUTH_RSA; + } + else if (conn->policy & POLICY_PSK) + { + msg.add_conn.auth_method = AUTH_PSK; + } + else + { + msg.add_conn.auth_method = AUTH_EAP; + } + msg.add_conn.eap_type = conn->eap; + if (conn->policy & POLICY_TUNNEL) { msg.add_conn.mode = 1; /* XFRM_MODE_TRANSPORT */ diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c index 31293a7d3..ebb12b710 100644 --- a/src/stroke/stroke.c +++ b/src/stroke/stroke.c @@ -106,6 +106,8 @@ static int add_connection(char *name, msg.add_conn.name = push_string(&msg, name); msg.add_conn.ikev2 = 1; + msg.add_conn.auth_method = 2; + msg.add_conn.eap_type = 0; msg.add_conn.mode = 1; msg.add_conn.rekey.reauth = 0; diff --git a/src/stroke/stroke.h b/src/stroke/stroke.h index bbc1e6e01..7d3f45d13 100644 --- a/src/stroke/stroke.h +++ b/src/stroke/stroke.h @@ -137,6 +137,7 @@ struct stroke_msg_t { char *name; int ikev2; int auth_method; + int eap_type; int mode; struct { char *ike; diff --git a/testing/start-testing b/testing/start-testing index 375a82be5..28f9c3bf5 100755 --- a/testing/start-testing +++ b/testing/start-testing @@ -47,6 +47,10 @@ case $UMLSTARTMODE in cecho "Start the uml instances (scripts/kstart-umls)" $DIR/scripts/kstart-umls $HOSTS ;; + gnome-terminal) + cecho "Start the uml instances (scripts/gstart-umls)" + $DIR/scripts/gstart-umls $HOSTS + ;; xterm) cecho "Start the uml instances (scripts/xstart-umls)" $DIR/scripts/xstart-umls $HOSTS diff --git a/testing/testing.conf b/testing/testing.conf index 5f404727d..b683e5402 100755 --- a/testing/testing.conf +++ b/testing/testing.conf @@ -17,7 +17,7 @@ # RCSID $Id: testing.conf,v 1.52 2006/04/24 16:58:03 as Exp $ # Root directory of testing -UMLTESTDIR=~/strongswan-testing +UMLTESTDIR=/home/strongswan-testing # Bzipped kernel sources # (file extension .tar.bz2 required) @@ -49,13 +49,13 @@ ROOTFSSIZE=544 # Amount of Memory to use per UML [MB]. # If "auto" is stated 1/12 of total host ram will be used. # Examples: MEM=64, MEM="128", MEM="auto" -MEM=64 +MEM=96 # Directory where the UML kernels and file system will be built BUILDDIR=$UMLTESTDIR/umlbuild # Filename of the built UML Kernel -UMLKERNEL=$BUILDDIR/linux-uml-$KERNELVERSION +UMLKERNEL=$UMLTESTDIR/linux # Directory where test results will be stored TESTRESULTSDIR=$UMLTESTDIR/testresults @@ -63,7 +63,7 @@ TESTRESULTSDIR=$UMLTESTDIR/testresults # Path to a full strongswan tree on the host system, which is # mounted into /root/strongswan-shared. This gives us an easy # way to apply and test changes instantly. -#SHAREDTREE=/home/mwilli/strongswan/trunk +SHAREDTREE=/home/martin/strongswan/trunk # Timezone for the UMLs, look in /usr/share/zoneinfo! TZUML="Europe/Zurich" @@ -72,22 +72,22 @@ TZUML="Europe/Zurich" # Enable particular steps in the make-testing and # start-testing scripts # -ENABLE_BUILD_UMLKERNEL="yes" +ENABLE_BUILD_UMLKERNEL="no" ENABLE_BUILD_SSHKEYS="yes" ENABLE_BUILD_HOSTCONFIG="yes" ENABLE_BUILD_UMLROOTFS="yes" ENABLE_BUILD_UMLHOSTFS="yes" -ENABLE_START_TESTING="yes" -ENABLE_DO_TESTS="yes" +ENABLE_START_TESTING="no" +ENABLE_DO_TESTS="no" ENABLE_STOP_TESTING="no" ############################################################## # How to start the UMLs? # # Start the UML instance in KDE konsole (requires KDE) -UMLSTARTMODE="konsole" +#UMLSTARTMODE="gnome-terminal" # Start the UML instance in an xterm (requires X11R6) -# UMLSTARTMODE="xterm" +UMLSTARTMODE="xterm" # Start the UML instance without a terminal window # but screen -r <host> can open a window anytime # UMLSTARTMODE="screen" @@ -100,7 +100,7 @@ SELECTEDTESTSONLY="no" # Tests to do if $SELECTEDTESTSONLY is set "yes". # -SELECTEDTESTS="net2net-cert" +SELECTEDTESTS="ikev2-net2net ikev2-rw" ############################################################## # hostname and corresponding IPv4 and IPv6 addresses |