aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.in29
-rwxr-xr-xscripts/cfg-leak4
-rwxr-xr-xscripts/cfg-nodebug3
-rwxr-xr-xscripts/cfg-norm3
-rw-r--r--src/charon/Makefile.am10
-rw-r--r--src/charon/config/policies/local_policy_store.c5
-rw-r--r--src/charon/config/policies/policy.c17
-rw-r--r--src/charon/config/policies/policy.h12
-rwxr-xr-xsrc/charon/config/policies/policy_store.h18
-rw-r--r--src/charon/daemon.c10
-rw-r--r--src/charon/daemon.h8
-rw-r--r--src/charon/doc/standards/rfc3748.txt3755
-rw-r--r--src/charon/doc/standards/rfc4739.txt619
-rw-r--r--src/charon/encoding/generator.c4
-rw-r--r--src/charon/encoding/message.c14
-rw-r--r--src/charon/encoding/parser.c52
-rw-r--r--src/charon/encoding/payloads/eap_payload.c181
-rw-r--r--src/charon/encoding/payloads/eap_payload.h90
-rw-r--r--src/charon/encoding/payloads/encodings.h2
-rw-r--r--src/charon/encoding/payloads/notify_payload.c4
-rw-r--r--src/charon/encoding/payloads/notify_payload.h4
-rw-r--r--src/charon/sa/authenticators/authenticator.c3
-rw-r--r--src/charon/sa/authenticators/eap/eap_aka.c1399
-rw-r--r--src/charon/sa/authenticators/eap/eap_aka.h133
-rw-r--r--src/charon/sa/authenticators/eap/eap_method.c243
-rw-r--r--src/charon/sa/authenticators/eap/eap_method.h241
-rw-r--r--src/charon/sa/authenticators/eap_authenticator.c348
-rw-r--r--src/charon/sa/authenticators/eap_authenticator.h156
-rw-r--r--src/charon/sa/authenticators/psk_authenticator.c41
-rw-r--r--src/charon/sa/authenticators/rsa_authenticator.c28
-rw-r--r--src/charon/sa/ike_sa.c8
-rw-r--r--src/charon/sa/transactions/create_child_sa.c6
-rw-r--r--src/charon/sa/transactions/ike_auth.c606
-rwxr-xr-xsrc/charon/threads/stroke_interface.c2
-rw-r--r--src/libstrongswan/Makefile.am1
-rw-r--r--src/libstrongswan/chunk.c174
-rw-r--r--src/libstrongswan/chunk.h70
-rw-r--r--src/libstrongswan/crypto/hashers/hasher.h16
-rw-r--r--src/libstrongswan/crypto/hashers/md5_hasher.c14
-rw-r--r--src/libstrongswan/crypto/hashers/sha1_hasher.c17
-rw-r--r--src/libstrongswan/crypto/hashers/sha2_hasher.c35
-rw-r--r--src/libstrongswan/crypto/prfs/fips_prf.c258
-rw-r--r--src/libstrongswan/crypto/prfs/fips_prf.h80
-rw-r--r--src/libstrongswan/crypto/prfs/prf.c16
-rw-r--r--src/libstrongswan/crypto/prfs/prf.h16
-rw-r--r--src/libstrongswan/crypto/signers/hmac_signer.c50
-rw-r--r--src/libstrongswan/crypto/signers/hmac_signer.h19
-rw-r--r--src/libstrongswan/crypto/signers/signer.c17
-rw-r--r--src/libstrongswan/crypto/signers/signer.h12
-rw-r--r--src/libstrongswan/library.c13
-rw-r--r--src/libstrongswan/library.h10
-rw-r--r--src/libstrongswan/utils/leak_detective.c1
-rw-r--r--src/starter/Makefile.am2
-rw-r--r--src/starter/args.c2
-rw-r--r--src/starter/confread.c17
-rw-r--r--src/starter/confread.h2
-rw-r--r--src/starter/invokecharon.c2
-rw-r--r--src/starter/keywords.h2
-rw-r--r--src/starter/keywords.txt2
-rw-r--r--src/starter/starterstroke.c44
-rw-r--r--src/stroke/stroke.c2
-rw-r--r--src/stroke/stroke.h1
-rwxr-xr-xtesting/start-testing4
-rwxr-xr-xtesting/testing.conf20
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