summaryrefslogtreecommitdiff
path: root/src/charon/sa/authenticators
diff options
context:
space:
mode:
Diffstat (limited to 'src/charon/sa/authenticators')
-rw-r--r--src/charon/sa/authenticators/authenticator.c56
-rw-r--r--src/charon/sa/authenticators/authenticator.h139
-rw-r--r--src/charon/sa/authenticators/eap/eap_identity.c135
-rw-r--r--src/charon/sa/authenticators/eap/eap_identity.h59
-rw-r--r--src/charon/sa/authenticators/eap/eap_method.c245
-rw-r--r--src/charon/sa/authenticators/eap/eap_method.h242
-rw-r--r--src/charon/sa/authenticators/eap/eap_sim.c703
-rw-r--r--src/charon/sa/authenticators/eap/eap_sim.h141
-rw-r--r--src/charon/sa/authenticators/eap_authenticator.c360
-rw-r--r--src/charon/sa/authenticators/eap_authenticator.h156
-rw-r--r--src/charon/sa/authenticators/psk_authenticator.c204
-rw-r--r--src/charon/sa/authenticators/psk_authenticator.h57
-rw-r--r--src/charon/sa/authenticators/rsa_authenticator.c180
-rw-r--r--src/charon/sa/authenticators/rsa_authenticator.h57
14 files changed, 2734 insertions, 0 deletions
diff --git a/src/charon/sa/authenticators/authenticator.c b/src/charon/sa/authenticators/authenticator.c
new file mode 100644
index 000000000..707aae9ad
--- /dev/null
+++ b/src/charon/sa/authenticators/authenticator.c
@@ -0,0 +1,56 @@
+/**
+ * @file authenticator.c
+ *
+ * @brief Generic constructor for authenticators.
+ *
+ */
+
+/*
+ * 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 "authenticator.h"
+
+#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,
+ "RSA signature",
+ "pre-shared key",
+ "DSS signature");
+ENUM_NEXT(auth_method_names, AUTH_EAP, AUTH_EAP, AUTH_DSS,
+ "EAP");
+ENUM_END(auth_method_names, AUTH_EAP);
+
+/*
+ * Described in header.
+ */
+authenticator_t *authenticator_create(ike_sa_t *ike_sa, auth_method_t auth_method)
+{
+ switch (auth_method)
+ {
+ case AUTH_RSA:
+ 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/authenticator.h b/src/charon/sa/authenticators/authenticator.h
new file mode 100644
index 000000000..c7b0fc81a
--- /dev/null
+++ b/src/charon/sa/authenticators/authenticator.h
@@ -0,0 +1,139 @@
+/**
+ * @file authenticator.h
+ *
+ * @brief Interface of authenticator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * 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 AUTHENTICATOR_H_
+#define AUTHENTICATOR_H_
+
+typedef enum auth_method_t auth_method_t;
+typedef struct authenticator_t authenticator_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <encoding/payloads/auth_payload.h>
+
+/**
+ * Method to use for authentication.
+ *
+ * @ingroup authenticators
+ */
+enum auth_method_t {
+ /**
+ * Computed as specified in section 2.15 of RFC using
+ * an RSA private key over a PKCS#1 padded hash.
+ */
+ AUTH_RSA = 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
+ */
+ AUTH_PSK = 2,
+
+ /**
+ * Computed as specified in section 2.15 of RFC using a
+ * DSS private key over a SHA-1 hash.
+ */
+ AUTH_DSS = 3,
+
+ /**
+ * EAP authentication. This value is never negotiated and therefore
+ * a value from private use.
+ */
+ AUTH_EAP = 201,
+};
+
+/**
+ * enum names for auth_method_t.
+ *
+ * @ingroup authenticators
+ */
+extern enum_name_t *auth_method_names;
+
+/**
+ * @brief Authenticator interface implemented by the various authenticators.
+ *
+ * Currently the following two AUTH methods are supported:
+ * - shared key message integrity code (AUTH_PSK)
+ * - RSA digital signature (AUTH_RSA)
+ *
+ * @b Constructors:
+ * - authenticator_create()
+ *
+ * @ingroup authenticators
+ */
+struct authenticator_t {
+
+ /**
+ * @brief Verify a received authentication payload.
+ *
+ * @param this calling object
+ * @param ike_sa_init binary representation of received ike_sa_init
+ * @param my_nonce the sent nonce
+ * @param auth_payload authentication payload to verify
+ *
+ * @return
+ * - SUCCESS,
+ * - FAILED if verification failed
+ * - INVALID_ARG if auth_method does not match
+ * - NOT_FOUND if credentials not found
+ */
+ status_t (*verify) (authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t my_nonce, auth_payload_t *auth_payload);
+
+ /**
+ * @brief Build an authentication payload to send to the other peer.
+ *
+ * @param this calling object
+ * @param ike_sa_init binary representation of sent ike_sa_init
+ * @param other_nonce the received nonce
+ * @param[out] auth_payload the resulting authentication payload
+ *
+ * @return
+ * - SUCCESS,
+ * - NOT_FOUND if the data for AUTH method could not be found
+ */
+ status_t (*build) (authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t other_nonce, auth_payload_t **auth_payload);
+
+ /**
+ * @brief Destroys a authenticator_t object.
+ *
+ * @param this calling object
+ */
+ void (*destroy) (authenticator_t *this);
+};
+
+/**
+ * @brief Creates an authenticator for the specified auth method.
+ *
+ * @param ike_sa associated ike_sa
+ * @param auth_method authentication method to use for build()/verify()
+ *
+ * @return authenticator_t object
+ *
+ * @ingroup authenticators
+ */
+authenticator_t *authenticator_create(ike_sa_t *ike_sa, auth_method_t auth_method);
+
+#endif /* AUTHENTICATOR_H_ */
diff --git a/src/charon/sa/authenticators/eap/eap_identity.c b/src/charon/sa/authenticators/eap/eap_identity.c
new file mode 100644
index 000000000..12a8bf7cc
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_identity.c
@@ -0,0 +1,135 @@
+/**
+ * @file eap_identity.c
+ *
+ * @brief Implementation of eap_identity_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <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 "eap_identity.h"
+
+#include <daemon.h>
+#include <library.h>
+
+typedef struct private_eap_identity_t private_eap_identity_t;
+
+/**
+ * Private data of an eap_identity_t object.
+ */
+struct private_eap_identity_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ eap_identity_t public;
+
+ /**
+ * ID of the peer
+ */
+ identification_t *peer;
+};
+
+/**
+ * Implementation of eap_method_t.process for the peer
+ */
+static status_t process(private_eap_identity_t *this,
+ eap_payload_t *in, eap_payload_t **out)
+{
+ chunk_t id, hdr;
+
+ hdr = chunk_alloca(5);
+ id = this->peer->get_encoding(this->peer);
+
+ *(hdr.ptr + 0) = EAP_RESPONSE;
+ *(hdr.ptr + 1) = in->get_identifier(in);
+ *(u_int16_t*)(hdr.ptr + 2) = htons(hdr.len + id.len);
+ *(hdr.ptr + 4) = EAP_IDENTITY;
+
+ *out = eap_payload_create_data(chunk_cata("cc", hdr, id));
+ return SUCCESS;
+
+}
+
+/**
+ * Implementation of eap_method_t.initiate for the peer
+ */
+static status_t initiate(private_eap_identity_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_identity_t *this)
+{
+ return EAP_IDENTITY;
+}
+
+/**
+ * Implementation of eap_method_t.get_msk.
+ */
+static status_t get_msk(private_eap_identity_t *this, chunk_t *msk)
+{
+ return FAILED;
+}
+
+/**
+ * Implementation of eap_method_t.is_mutual.
+ */
+static bool is_mutual(private_eap_identity_t *this)
+{
+ return FALSE;
+}
+
+/**
+ * Implementation of eap_method_t.destroy.
+ */
+static void destroy(private_eap_identity_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+eap_identity_t *eap_create(eap_role_t role,
+ identification_t *server, identification_t *peer)
+{
+ private_eap_identity_t *this;
+
+ if (role != EAP_PEER)
+ {
+ return NULL;
+ }
+
+ this = malloc_thing(private_eap_identity_t);
+
+ /* public functions */
+ this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate;
+ this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process;
+ this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*))get_type;
+ this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
+ this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
+ this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
+
+ /* private data */
+ this->peer = peer;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/authenticators/eap/eap_identity.h b/src/charon/sa/authenticators/eap/eap_identity.h
new file mode 100644
index 000000000..20f0f0b67
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_identity.h
@@ -0,0 +1,59 @@
+/**
+ * @file eap_identity.h
+ *
+ * @brief Interface of eap_identity_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <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_IDENTITY_H_
+#define EAP_IDENTITY_H_
+
+typedef struct eap_identity_t eap_identity_t;
+
+#include <sa/authenticators/eap/eap_method.h>
+
+/**
+ * @brief Implementation of the eap_method_t interface using EAP Identity.
+ *
+ * @b Constructors:
+ * - eap_identity_create()
+ * - eap_client_create() using eap_method EAP_IDENTITY
+ *
+ * @ingroup eap
+ */
+struct eap_identity_t {
+
+ /**
+ * Implemented eap_method_t interface.
+ */
+ eap_method_t eap_method_interface;
+};
+
+/**
+ * @brief Creates the EAP method EAP Identity.
+ *
+ * @param server ID of the EAP server
+ * @param peer ID of the EAP client
+ * @return eap_identity_t object
+ *
+ * @ingroup eap
+ */
+eap_identity_t *eap_create(eap_role_t role,
+ identification_t *server, identification_t *peer);
+
+#endif /* EAP_IDENTITY_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..a4d8abb58
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_method.c
@@ -0,0 +1,245 @@
+/**
+ * @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_SIM, EAP_SIM, EAP_TOKEN_CARD,
+ "EAP_SIM");
+ENUM_NEXT(eap_type_names, EAP_AKA, EAP_AKA, EAP_SIM,
+ "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..d43dc001f
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_method.h
@@ -0,0 +1,242 @@
+/**
+ * @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_SIM = 18,
+ 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/eap_sim.c b/src/charon/sa/authenticators/eap/eap_sim.c
new file mode 100644
index 000000000..3dc59fb6b
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_sim.c
@@ -0,0 +1,703 @@
+/**
+ * @file eap_sim.c
+ *
+ * @brief Implementation of eap_sim_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <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 "eap_sim.h"
+
+#include <dlfcn.h>
+
+#include <daemon.h>
+#include <library.h>
+
+#define MAX_TRIES 3
+
+ENUM(sim_subtype_names, SIM_START, SIM_CLIENT_ERROR,
+ "SIM_START",
+ "SIM_CHALLENGE",
+ "SIM_NOTIFICATION",
+ "SIM_13",
+ "SIM_CLIENT_ERROR",
+);
+
+ENUM_BEGIN(sim_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(sim_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(sim_attribute_names, AT_RESULT_IND);
+
+
+typedef struct private_eap_sim_t private_eap_sim_t;
+
+/**
+ * Private data of an eap_sim_t object.
+ */
+struct private_eap_sim_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ eap_sim_t public;
+
+ /**
+ * ID of ourself
+ */
+ identification_t *peer;
+
+ /**
+ * SIM cardreader function loaded from library
+ */
+ sim_algo_t alg;
+
+ /**
+ * handle of the loaded library
+ */
+ void *handle;
+
+ /**
+ * how many times we try to authenticate
+ */
+ int tries;
+
+ /**
+ * version this implementation uses
+ */
+ chunk_t version;
+
+ /**
+ * version list received from server
+ */
+ chunk_t version_list;
+
+ /**
+ * Nonce value used in AT_NONCE_MT
+ */
+ chunk_t nonce;
+
+ /**
+ * k_encr key derived from MK
+ */
+ chunk_t k_encr;
+
+ /**
+ * k_auth key derived from MK, used for AT_MAC verification
+ */
+ chunk_t k_auth;
+
+ /**
+ * MSK, used for EAP-SIM based IKEv2 authentication
+ */
+ chunk_t msk;
+
+ /**
+ * EMSK, extendes MSK for further uses
+ */
+ chunk_t emsk;
+};
+
+/** length of the AT_NONCE_MT nonce value */
+#define NONCE_LEN 16
+/** length of the AT_MAC value */
+#define MAC_LEN 16
+/** length of the AT_RAND value */
+#define RAND_LEN 16
+/** length of the k_encr key */
+#define KENCR_LEN 16
+/** length of the k_auth key */
+#define KAUTH_LEN 16
+/** length of the MSK */
+#define MSK_LEN 64
+/** length of the EMSK */
+#define EMSK_LEN 64
+
+/* client error codes used in AT_CLIENT_ERROR_CODE */
+char client_error_general_buf[] = {0x00, 0x01};
+char client_error_unsupported_buf[] = {0x00, 0x02};
+char client_error_insufficient_buf[] = {0x00, 0x03};
+char client_error_notfresh_buf[] = {0x00, 0x04};
+chunk_t client_error_general = chunk_from_buf(client_error_general_buf);
+chunk_t client_error_unsupported = chunk_from_buf(client_error_unsupported_buf);
+chunk_t client_error_insufficient = chunk_from_buf(client_error_insufficient_buf);
+chunk_t client_error_notfresh = chunk_from_buf(client_error_notfresh_buf);
+
+/**
+ * Read EAP and EAP-SIM header, return SIM type
+ */
+static sim_subtype_t read_header(chunk_t *message)
+{
+ sim_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 sim_attribute_t read_attribute(chunk_t *message, chunk_t *data)
+{
+ sim_attribute_t attribute;
+ size_t length;
+
+ DBG3(DBG_IKE, "reading attribute from %B", message);
+
+ if (message->len < 2)
+ {
+ return AT_END;
+ }
+ attribute = *message->ptr++;
+ length = *message->ptr++ * 4 - 2;
+ message->len -= 2;
+ DBG3(DBG_IKE, "found attribute %N with length %d",
+ sim_attribute_names, attribute, length);
+
+ if (length > message->len)
+ {
+ return AT_END;
+ }
+ data->len = length;
+ data->ptr = message->ptr;
+ *message = chunk_skip(*message, length);
+ return attribute;
+}
+
+/**
+ * Build an EAP-SIM payload using a variable length attribute list.
+ * The variable argument takes a sim_attribute_t followed by its data in a chunk.
+ */
+static eap_payload_t *build_payload(private_eap_sim_t *this, u_int8_t identifier,
+ sim_subtype_t type, ...)
+{
+ chunk_t message = chunk_alloca(512);
+ chunk_t pos = message;
+ eap_payload_t *payload;
+ va_list args;
+ sim_attribute_t attr;
+ u_int8_t *mac_pos = NULL;
+ chunk_t mac_data = chunk_empty;
+
+ /* write EAP header, skip length bytes */
+ *pos.ptr++ = EAP_RESPONSE;
+ *pos.ptr++ = identifier;
+ pos.ptr += 2;
+ pos.len -= 4;
+ /* write SIM header with type and subtype, zero reserved bytes */
+ *pos.ptr++ = EAP_SIM;
+ *pos.ptr++ = type;
+ *pos.ptr++ = 0;
+ *pos.ptr++ = 0;
+ pos.len -= 4;
+
+ va_start(args, type);
+ while ((attr = va_arg(args, sim_attribute_t)) != AT_END)
+ {
+ chunk_t data = va_arg(args, chunk_t);
+
+ DBG3(DBG_IKE, "building %N %B", sim_attribute_names, attr, &data);
+
+ /* write attribute header */
+ *pos.ptr++ = attr;
+ pos.len--;
+
+ switch (attr)
+ {
+ case AT_CLIENT_ERROR_CODE:
+ case AT_SELECTED_VERSION:
+ {
+ *pos.ptr = data.len/4 + 1;
+ pos = chunk_skip(pos, 1);
+ memcpy(pos.ptr, data.ptr, data.len);
+ pos = chunk_skip(pos, data.len);
+ break;
+ }
+ case AT_IDENTITY:
+ {
+ /* align up to four byte */
+ if (data.len % 4)
+ {
+ chunk_t tmp = chunk_alloca((data.len/4)*4 + 4);
+ memset(tmp.ptr, 0, tmp.len);
+ memcpy(tmp.ptr, data.ptr, data.len);
+ data = tmp;
+ }
+ *pos.ptr = data.len/4 + 1;
+ pos = chunk_skip(pos, 1);
+ /* actual length in bytes */
+ *(u_int16_t*)pos.ptr = htons(data.len);
+ pos = chunk_skip(pos, sizeof(u_int16_t));
+ memcpy(pos.ptr, data.ptr, data.len);
+ pos = chunk_skip(pos, data.len);
+ break;
+ }
+ case AT_NONCE_MT:
+ {
+ *pos.ptr = data.len/4 + 1;
+ pos = chunk_skip(pos, 1);
+ memset(pos.ptr, 0, 2);
+ pos = chunk_skip(pos, 2);
+ 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;
+ memset(mac_pos, 0, MAC_LEN);
+ pos = chunk_skip(pos, MAC_LEN);
+ mac_data = data;
+ break;
+ }
+ 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;
+ }
+ default:
+ DBG1(DBG_IKE, "no rule to build EAP_SIM attribute %N, skipped",
+ sim_attribute_names, attr);
+ break;
+ }
+ }
+ 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. Append supplied va_arg
+ * chunk mac_data to "to-sign" chunk */
+ if (mac_pos)
+ {
+ signer_t *signer = signer_create(AUTH_HMAC_SHA1_128);
+ signer->set_key(signer, this->k_auth);
+ mac_data = chunk_cata("cc", message, mac_data);
+ signer->get_signature(signer, mac_data, mac_pos);
+ DBG3(DBG_IKE, "AT_MAC signature of %B\n is %b",
+ &mac_data, mac_pos, MAC_LEN);
+ signer->destroy(signer);
+ }
+
+ payload = eap_payload_create_data(message);
+
+ DBG3(DBG_IKE, "created EAP message %B", &message);
+ return payload;
+}
+
+/**
+ * process an EAP-SIM/Request/Start message
+ */
+static status_t process_start(private_eap_sim_t *this, eap_payload_t *in,
+ eap_payload_t **out)
+{
+ chunk_t message, data;
+ sim_attribute_t attribute, include_id = AT_END;
+ u_int8_t identifier;
+
+ identifier = in->get_identifier(in);
+ message = in->get_data(in);
+ read_header(&message);
+
+ while ((attribute = read_attribute(&message, &data)) != AT_END)
+ {
+ switch (attribute)
+ {
+ case AT_VERSION_LIST:
+ {
+ /* check if server supports our implementation */
+ bool found = FALSE;
+ if (data.len > 2)
+ {
+ /* read actual length first */
+ data.len = min(data.len, ntohs(*(u_int16_t*)data.ptr) + 2);
+ data = chunk_skip(data, 2);
+ chunk_free(&this->version_list);
+ this->version_list = chunk_clone(data);
+ while (data.len >= this->version.len)
+ {
+ if (memeq(data.ptr, this->version.ptr, this->version.len))
+ {
+ found = TRUE;
+ break;
+ }
+ data = chunk_skip(data, this->version.len);
+ }
+ }
+ if (!found)
+ {
+ DBG1(DBG_IKE, "server does not support EAP_SIM "
+ "version number %#B", &this->version);
+ *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_unsupported,
+ AT_END);
+ return NEED_MORE;
+ }
+ break;
+ }
+ case AT_PERMANENT_ID_REQ:
+ case AT_FULLAUTH_ID_REQ:
+ case AT_ANY_ID_REQ:
+ /* only include AT_IDENTITY if requested */
+ include_id = AT_IDENTITY;
+ break;
+ default:
+ DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
+ sim_attribute_names, attribute);
+ break;
+ }
+ }
+
+ /* build payload. If "include_id" is AT_END, AT_IDENTITY is ommited */
+ *out = build_payload(this, identifier, SIM_START,
+ AT_SELECTED_VERSION, this->version,
+ AT_NONCE_MT, this->nonce,
+ include_id, this->peer->get_encoding(this->peer),
+ AT_END);
+ return NEED_MORE;
+}
+
+/**
+ * process an EAP-SIM/Request/Challenge message
+ */
+static status_t process_challenge(private_eap_sim_t *this, eap_payload_t *in,
+ eap_payload_t **out)
+{
+ chunk_t message, data, tmp, kcs, kc, sreses, sres, mk;
+ sim_attribute_t attribute;
+ u_int8_t identifier, i;
+ chunk_t mac = chunk_empty, rands = chunk_empty;
+ signer_t *signer;
+ hasher_t *hasher;
+ prf_t *prf;
+
+ if (this->tries-- <= 0)
+ {
+ /* give up without notification. This hack is required as some buggy
+ * server implementations won't respect our client-error. */
+ return FAILED;
+ }
+
+ identifier = in->get_identifier(in);
+ message = in->get_data(in);
+ read_header(&message);
+
+ while ((attribute = read_attribute(&message, &data)) != AT_END)
+ {
+ switch (attribute)
+ {
+ case AT_RAND:
+ {
+ rands = chunk_skip(data, 2);
+ break;
+ }
+ case AT_MAC:
+ {
+ /* backup MAC, zero it inline for later verification */
+ data = chunk_skip(data, 2);
+ mac = chunk_clonea(data);
+ memset(data.ptr, 0, data.len);
+ break;
+ }
+ default:
+ DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
+ sim_attribute_names, attribute);
+ break;
+ }
+ }
+
+ /* excepting two or three RAND, each 16 bytes. We require two valid
+ * and different RANDs */
+ if ((rands.len != 2 * RAND_LEN && rands.len != 3 * RAND_LEN) ||
+ memeq(rands.ptr, rands.ptr + RAND_LEN, RAND_LEN))
+ {
+ DBG1(DBG_IKE, "no valid AT_RAND received");
+ *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_insufficient,
+ AT_END);
+ return FAILED;
+ }
+ if (mac.len != MAC_LEN)
+ {
+ DBG1(DBG_IKE, "no valid AT_MAC received");
+ *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_general,
+ AT_END);
+ return NEED_MORE;
+ }
+
+ /* get two or three KCs/SRESes from SIM using RANDs */
+ kcs = kc = chunk_alloca(rands.len / 2);
+ sreses = sres = chunk_alloca(rands.len / 4);
+ while (rands.len > 0)
+ {
+ int kc_len = kc.len, sres_len = sres.len;
+
+ if (this->alg(rands.ptr, RAND_LEN, sres.ptr, &sres_len, kc.ptr, &kc_len))
+ {
+ DBG1(DBG_IKE, "unable to get triplets from SIM");
+ *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_general,
+ AT_END);
+ return NEED_MORE;
+ }
+ DBG3(DBG_IKE, "got triplet for RAND %b\n Kc %b\n SRES %b",
+ rands.ptr, RAND_LEN, sres.ptr, sres_len, kc.ptr, kc_len);
+ kc = chunk_skip(kc, kc_len);
+ sres = chunk_skip(sres, sres_len);
+ rands = chunk_skip(rands, RAND_LEN);
+ }
+
+ /* build MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
+ tmp = chunk_cata("ccccc", this->peer->get_encoding(this->peer), kcs,
+ this->nonce, this->version_list, this->version);
+ hasher = hasher_create(HASH_SHA1);
+ mk = chunk_alloca(hasher->get_hash_size(hasher));
+ hasher->get_hash(hasher, tmp, mk.ptr);
+ hasher->destroy(hasher);
+ DBG3(DBG_IKE, "MK = SHA1(%B\n) = %B", &tmp, &mk);
+
+ /* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf()
+ * 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);
+ for (i = 0; i < 4; i++)
+ {
+ prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * i);
+ }
+ 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", KENCR_LEN, &this->k_encr, KAUTH_LEN, &this->k_auth,
+ MSK_LEN, &this->msk, EMSK_LEN, &this->emsk);
+ DBG3(DBG_IKE, "K_encr %B\nK_auth %B\nMSK %B\nEMSK %B",
+ &this->k_encr, &this->k_auth, &this->msk, &this->emsk);
+
+ /* verify AT_MAC attribute, signature is over "EAP packet | NONCE_MT" */
+ signer = signer_create(AUTH_HMAC_SHA1_128);
+ signer->set_key(signer, this->k_auth);
+ tmp = chunk_cata("cc", in->get_data(in), this->nonce);
+ if (!signer->verify_signature(signer, tmp, mac))
+ {
+ DBG1(DBG_IKE, "AT_MAC verification failed");
+ signer->destroy(signer);
+ *out = build_payload(this, identifier, SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_general,
+ AT_END);
+ return NEED_MORE;
+ }
+ signer->destroy(signer);
+
+ /* build response, AT_MAC is built over "EAP packet | n*SRES" */
+ *out = build_payload(this, identifier, SIM_CHALLENGE,
+ AT_MAC, sreses,
+ AT_END);
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of eap_method_t.process for the peer
+ */
+static status_t process(private_eap_sim_t *this,
+ eap_payload_t *in, eap_payload_t **out)
+{
+ sim_subtype_t type;
+ chunk_t message;
+
+ message = in->get_data(in);
+ type = read_header(&message);
+
+ switch (type)
+ {
+ case SIM_START:
+ return process_start(this, in, out);
+ case SIM_CHALLENGE:
+ return process_challenge(this, in, out);
+ default:
+ DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N",
+ sim_subtype_names, type);
+ *out = build_payload(this, in->get_identifier(in), SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_general, AT_END);
+ return NEED_MORE;
+ }
+}
+
+/**
+ * Implementation of eap_method_t.initiate for the peer
+ */
+static status_t initiate(private_eap_sim_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_sim_t *this)
+{
+ return EAP_SIM;
+}
+
+/**
+ * Implementation of eap_method_t.get_msk.
+ */
+static status_t get_msk(private_eap_sim_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_sim_t *this)
+{
+ return TRUE;
+}
+
+/**
+ * Implementation of eap_method_t.destroy.
+ */
+static void destroy(private_eap_sim_t *this)
+{
+ dlclose(this->handle);
+ chunk_free(&this->nonce);
+ chunk_free(&this->version_list);
+ chunk_free(&this->k_auth);
+ chunk_free(&this->k_encr);
+ chunk_free(&this->msk);
+ chunk_free(&this->emsk);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+eap_sim_t *eap_create(eap_role_t role,
+ identification_t *server, identification_t *peer)
+{
+ private_eap_sim_t *this;
+ randomizer_t *randomizer;
+ static char version[] = {0x00,0x01};
+
+ if (role != EAP_PEER)
+ {
+ return NULL;
+ }
+ this = malloc_thing(private_eap_sim_t);
+
+ this->handle = dlopen(SIM_READER_LIB, RTLD_LAZY);
+ if (this->handle == NULL)
+ {
+ DBG1(DBG_IKE, "unable to open SIM reader '%s'", SIM_READER_LIB);
+ free(this);
+ return NULL;
+ }
+ this->alg = dlsym(this->handle, SIM_READER_ALG);
+ if (this->alg == NULL)
+ {
+ DBG1(DBG_IKE, "unable to open SIM reader function '%s' in '%s'",
+ SIM_READER_ALG, SIM_READER_LIB);
+ dlclose(this->handle);
+ free(this);
+ return NULL;
+ }
+
+ randomizer = randomizer_create();
+ if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_LEN,
+ &this->nonce))
+ {
+ DBG1(DBG_IKE, "unable to generate NONCE for EAP_SIM");
+ randomizer->destroy(randomizer);
+ free(this);
+ return NULL;
+ }
+ randomizer->destroy(randomizer);
+
+ /* public functions */
+ this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate;
+ this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process;
+ this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*))get_type;
+ this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
+ this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
+ this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
+
+ /* private data */
+ this->peer = peer;
+ this->tries = MAX_TRIES;
+ this->version.ptr = version;
+ this->version.len = sizeof(version);
+ this->version_list = chunk_empty;
+ this->k_auth = chunk_empty;
+ this->k_encr = chunk_empty;
+ this->msk = chunk_empty;
+ this->emsk = chunk_empty;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/authenticators/eap/eap_sim.h b/src/charon/sa/authenticators/eap/eap_sim.h
new file mode 100644
index 000000000..10640babe
--- /dev/null
+++ b/src/charon/sa/authenticators/eap/eap_sim.h
@@ -0,0 +1,141 @@
+/**
+ * @file eap_sim.h
+ *
+ * @brief Interface of eap_sim_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <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_SIM_H_
+#define EAP_SIM_H_
+
+typedef struct eap_sim_t eap_sim_t;
+typedef enum sim_subtype_t sim_subtype_t;
+typedef enum sim_attribute_t sim_attribute_t;
+
+#include <sa/authenticators/eap/eap_method.h>
+
+/**
+ * Subtypes of SIM messages
+ */
+enum sim_subtype_t {
+ SIM_START = 10,
+ SIM_CHALLENGE = 11,
+ SIM_NOTIFICATION = 12,
+ SIM_CLIENT_ERROR = 14,
+};
+
+/**
+ * enum names for sim_subtype_t
+ */
+extern enum_name_t *sim_subtype_names;
+
+enum sim_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 sim_subtype_t
+ */
+extern enum_name_t *sim_attribute_names;
+
+/**
+ * @brief Cardreaders SIM function.
+ *
+ * @param rand RAND to run algo with
+ * @param rand_length length of value in rand
+ * @param sres buffer to get SRES
+ * @param sres_length size of buffer in sres, returns bytes written to SRES
+ * @param kc buffer to get Kc
+ * @param kc_length size of buffer in Kc, returns bytes written to Kc
+ * @return zero on success
+ */
+typedef int (*sim_algo_t)(const unsigned char *rand, int rand_length,
+ unsigned char *sres, int *sres_length,
+ unsigned char *kc, int *kc_length);
+
+#ifndef SIM_READER_LIB
+/** the library containing the cardreader with the SIM function */
+#error SIM_READER_LIB not specified, use --with-sim-reader option
+#endif /* SIM_READER_LIB */
+
+#ifndef SIM_READER_ALG
+/** the SIM_READER_LIB's algorithm, uses sim_algo_t signature */
+#define SIM_READER_ALG "sim_run_alg"
+#endif /* SIM_READER_ALG */
+
+
+/**
+ * @brief Implementation of the eap_method_t interface using EAP-SIM.
+ *
+ * This EAP-SIM client implementation uses another pluggable library to
+ * access the SIM card. This module is specified using the SIM_READER_LIB
+ * definition. The function to run the algorithm has the sim_algo_t type and
+ * is named as SIM_READER_ALG is defined.
+ *
+ * @b Constructors:
+ * - eap_create() of this module
+ * - eap_client_create() using eap_method EAP_SIM
+ *
+ * @ingroup eap
+ */
+struct eap_sim_t {
+
+ /**
+ * Implemented eap_method_t interface.
+ */
+ eap_method_t eap_method_interface;
+};
+
+/**
+ * @brief Creates the EAP method EAP-SIM.
+ *
+ * @param server ID of the EAP server
+ * @param peer ID of the EAP client
+ * @return eap_sim_t object
+ *
+ * @ingroup eap
+ */
+eap_sim_t *eap_create(eap_role_t role,
+ identification_t *server, identification_t *peer);
+
+#endif /* EAP_SIM_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..6c8ca8d8f
--- /dev/null
+++ b/src/charon/sa/authenticators/eap_authenticator.c
@@ -0,0 +1,360 @@
+/**
+ * @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_skp, 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);
+
+ auth_data = build_shared_key_signature(ike_sa_init, my_nonce, this->msk,
+ other_id, this->ike_sa->get_auth_verify(this->ike_sa),
+ this->ike_sa->get_prf(this->ike_sa));
+
+ 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);
+
+ 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, this->ike_sa->get_auth_build(this->ike_sa),
+ this->ike_sa->get_prf(this->ike_sa));
+
+ *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);
+
+ if (type == EAP_IDENTITY)
+ {
+ eap_method_t *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 (method == NULL || method->process(method, in, out) != SUCCESS)
+ {
+ DBG1(DBG_IKE, "EAP server requested %N, but unable to process",
+ eap_type_names, type);
+ DESTROY_IF(method);
+ return FAILED;
+ }
+
+ DBG1(DBG_IKE, "EAP server requested %N, sending IKE identity",
+ eap_type_names, type);
+
+ method->destroy(method);
+ return NEED_MORE;
+ }
+
+ /* 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:
+ DBG1(DBG_IKE, "EAP method %N succeded",
+ eap_type_names, this->method->get_type(this->method));
+ return SUCCESS;
+ 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)
+ {
+ this->msk = chunk_clone(this->msk);
+ return SUCCESS;
+ }
+ DBG1(DBG_IKE, "EAP method %N has 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
new file mode 100644
index 000000000..43aec0971
--- /dev/null
+++ b/src/charon/sa/authenticators/psk_authenticator.c
@@ -0,0 +1,204 @@
+/**
+ * @file psk_authenticator.c
+ *
+ * @brief Implementation of psk_authenticator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * 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 "psk_authenticator.h"
+
+#include <config/policies/policy.h>
+#include <daemon.h>
+
+/**
+ * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
+ */
+#define IKEV2_KEY_PAD "Key Pad for IKEv2"
+#define IKEV2_KEY_PAD_LENGTH 17
+
+
+typedef struct private_psk_authenticator_t private_psk_authenticator_t;
+
+/**
+ * Private data of an psk_authenticator_t object.
+ */
+struct private_psk_authenticator_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ psk_authenticator_t public;
+
+ /**
+ * Assigned IKE_SA
+ */
+ ike_sa_t *ike_sa;
+};
+
+/**
+ * Builds the octets to be signed as described in section 2.15 of RFC 4306
+ */
+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.
+ */
+chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce,
+ chunk_t secret, identification_t *id,
+ prf_t *prf_skp, prf_t *prf)
+{
+ chunk_t key_pad, key, auth_data, octets;
+
+ octets = build_tbs_octets(ike_sa_init, nonce, id, prf_skp);
+ /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */
+ key_pad.ptr = IKEV2_KEY_PAD;
+ key_pad.len = IKEV2_KEY_PAD_LENGTH;
+ prf->set_key(prf, secret);
+ prf->allocate_bytes(prf, key_pad, &key);
+ prf->set_key(prf, key);
+ prf->allocate_bytes(prf, octets, &auth_data);
+ DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", &octets);
+ DBG3(DBG_IKE, "secret %B", &secret);
+ DBG3(DBG_IKE, "keypad %B", &key_pad);
+ DBG3(DBG_IKE, "prf(secret, keypad) %B", &key);
+ DBG3(DBG_IKE, "AUTH = prf(prf(secret, keypad), octets) %B", &auth_data);
+ chunk_free(&octets);
+ chunk_free(&key);
+
+ return auth_data;
+}
+
+/**
+ * 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)
+{
+ status_t status;
+ chunk_t auth_data, recv_auth_data, shared_key;
+ identification_t *my_id, *other_id;
+
+ my_id = this->ike_sa->get_my_id(this->ike_sa);
+ other_id = this->ike_sa->get_other_id(this->ike_sa);
+ status = charon->credentials->get_shared_key(charon->credentials, my_id,
+ other_id, &shared_key);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id);
+ return status;
+ }
+
+ auth_data = build_shared_key_signature(ike_sa_init, my_nonce, shared_key,
+ other_id, this->ike_sa->get_auth_verify(this->ike_sa),
+ this->ike_sa->get_prf(this->ike_sa));
+ chunk_free(&shared_key);
+
+ recv_auth_data = auth_payload->get_data(auth_payload);
+ if (auth_data.len != recv_auth_data.len ||
+ !memeq(auth_data.ptr, recv_auth_data.ptr, auth_data.len))
+ {
+ DBG1(DBG_IKE, "PSK MAC verification 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_PSK);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of authenticator_t.build.
+ */
+static status_t build(private_psk_authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t other_nonce, auth_payload_t **auth_payload)
+{
+ chunk_t shared_key;
+ chunk_t auth_data;
+ status_t status;
+ identification_t *my_id, *other_id;
+
+ my_id = this->ike_sa->get_my_id(this->ike_sa);
+ other_id = this->ike_sa->get_other_id(this->ike_sa);
+ DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
+ my_id, auth_method_names, AUTH_PSK);
+ status = charon->credentials->get_shared_key(charon->credentials, my_id,
+ other_id, &shared_key);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id);
+ return status;
+ }
+
+ auth_data = build_shared_key_signature(ike_sa_init, other_nonce, shared_key,
+ my_id, this->ike_sa->get_auth_build(this->ike_sa),
+ this->ike_sa->get_prf(this->ike_sa));
+ DBG2(DBG_IKE, "successfully created shared key MAC");
+ chunk_free(&shared_key);
+ *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 authenticator_t.destroy.
+ */
+static void destroy(private_psk_authenticator_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+psk_authenticator_t *psk_authenticator_create(ike_sa_t *ike_sa)
+{
+ private_psk_authenticator_t *this = malloc_thing(private_psk_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;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/authenticators/psk_authenticator.h b/src/charon/sa/authenticators/psk_authenticator.h
new file mode 100644
index 000000000..c1c5bcaac
--- /dev/null
+++ b/src/charon/sa/authenticators/psk_authenticator.h
@@ -0,0 +1,57 @@
+/**
+ * @file psk_authenticator.h
+ *
+ * @brief Interface of psk_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 PSK_AUTHENTICATOR_H_
+#define PSK_AUTHENTICATOR_H_
+
+typedef struct psk_authenticator_t psk_authenticator_t;
+
+#include <sa/authenticators/authenticator.h>
+
+/**
+ * @brief Implementation of the authenticator_t interface using AUTH_PSK.
+ *
+ * @b Constructors:
+ * - psk_authenticator_create()
+ * - authenticator_create() using auth_method AUTH_PSK
+ *
+ * @ingroup authenticators
+ */
+struct psk_authenticator_t {
+
+ /**
+ * Implemented authenticator_t interface.
+ */
+ authenticator_t authenticator_interface;
+};
+
+/**
+ * @brief Creates an authenticator for AUTH_PSK.
+ *
+ * @param ike_sa associated ike_sa
+ * @return psk_authenticator_t object
+ *
+ * @ingroup authenticators
+ */
+psk_authenticator_t *psk_authenticator_create(ike_sa_t *ike_sa);
+
+#endif /* PSK_AUTHENTICATOR_H_ */
diff --git a/src/charon/sa/authenticators/rsa_authenticator.c b/src/charon/sa/authenticators/rsa_authenticator.c
new file mode 100644
index 000000000..dfa01e332
--- /dev/null
+++ b/src/charon/sa/authenticators/rsa_authenticator.c
@@ -0,0 +1,180 @@
+/**
+ * @file rsa_authenticator.c
+ *
+ * @brief Implementation of rsa_authenticator_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * 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 "rsa_authenticator.h"
+
+#include <config/policies/policy.h>
+#include <daemon.h>
+
+
+typedef struct private_rsa_authenticator_t private_rsa_authenticator_t;
+
+/**
+ * Private data of an rsa_authenticator_t object.
+ */
+struct private_rsa_authenticator_t {
+
+ /**
+ * Public authenticator_t interface.
+ */
+ rsa_authenticator_t public;
+
+ /**
+ * Assigned IKE_SA
+ */
+ ike_sa_t *ike_sa;
+};
+
+/**
+ * Function implemented in psk_authenticator.c
+ */
+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.
+ */
+static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t my_nonce, auth_payload_t *auth_payload)
+{
+ status_t status;
+ chunk_t auth_data, octets;
+ rsa_public_key_t *public_key;
+ identification_t *other_id;
+
+ other_id = this->ike_sa->get_other_id(this->ike_sa);
+
+ if (auth_payload->get_auth_method(auth_payload) != AUTH_RSA)
+ {
+ return INVALID_ARG;
+ }
+ auth_data = auth_payload->get_data(auth_payload);
+ public_key = charon->credentials->get_trusted_public_key(charon->credentials,
+ other_id);
+ if (public_key == NULL)
+ {
+ DBG1(DBG_IKE, "no RSA public key found for '%D'", other_id);
+ return NOT_FOUND;
+ }
+ 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);
+
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_IKE, "RSA signature verification failed");
+ return status;
+ }
+
+ DBG1(DBG_IKE, "authentication of '%D' with %N successful",
+ other_id, auth_method_names, AUTH_RSA);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of authenticator_t.build.
+ */
+static status_t build(private_rsa_authenticator_t *this, chunk_t ike_sa_init,
+ chunk_t other_nonce, auth_payload_t **auth_payload)
+{
+ chunk_t chunk;
+ chunk_t octets;
+ chunk_t auth_data;
+ status_t status;
+ rsa_public_key_t *my_pubkey;
+ rsa_private_key_t *my_key;
+ identification_t *my_id;
+
+ my_id = this->ike_sa->get_my_id(this->ike_sa);
+ DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
+ my_id, auth_method_names, AUTH_RSA);
+ DBG2(DBG_IKE, "looking for RSA public key belonging to '%D'", my_id);
+
+ my_pubkey = charon->credentials->get_rsa_public_key(charon->credentials, my_id);
+ if (my_pubkey == NULL)
+ {
+ DBG1(DBG_IKE, "no RSA public key found for '%D'", my_id);
+ return NOT_FOUND;
+ }
+ DBG2(DBG_IKE, "matching RSA public key found");
+ chunk = my_pubkey->get_keyid(my_pubkey);
+ DBG2(DBG_IKE, "looking for RSA private key with keyid %#B", &chunk);
+ my_key = charon->credentials->get_rsa_private_key(charon->credentials, my_pubkey);
+ if (my_key == NULL)
+ {
+ DBG1(DBG_IKE, "no RSA private key found with for %D with keyid %#B",
+ my_id, &chunk);
+ return NOT_FOUND;
+ }
+ DBG2(DBG_IKE, "matching RSA private key found");
+
+ 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);
+
+ if (status != SUCCESS)
+ {
+ my_key->destroy(my_key);
+ DBG1(DBG_IKE, "build signature of SHA1 hash failed");
+ return status;
+ }
+ DBG2(DBG_IKE, "successfully signed with RSA private key");
+
+ *auth_payload = auth_payload_create();
+ (*auth_payload)->set_auth_method(*auth_payload, AUTH_RSA);
+ (*auth_payload)->set_data(*auth_payload, auth_data);
+
+ my_key->destroy(my_key);
+ chunk_free(&auth_data);
+ return SUCCESS;
+}
+
+/**
+ * Implementation of authenticator_t.destroy.
+ */
+static void destroy(private_rsa_authenticator_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+rsa_authenticator_t *rsa_authenticator_create(ike_sa_t *ike_sa)
+{
+ private_rsa_authenticator_t *this = malloc_thing(private_rsa_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;
+
+ /* private data */
+ this->ike_sa = ike_sa;
+
+ return &this->public;
+}
diff --git a/src/charon/sa/authenticators/rsa_authenticator.h b/src/charon/sa/authenticators/rsa_authenticator.h
new file mode 100644
index 000000000..cc5cc0150
--- /dev/null
+++ b/src/charon/sa/authenticators/rsa_authenticator.h
@@ -0,0 +1,57 @@
+/**
+ * @file rsa_authenticator.h
+ *
+ * @brief Interface of rsa_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 RSA_AUTHENTICATOR_H_
+#define RSA_AUTHENTICATOR_H_
+
+typedef struct rsa_authenticator_t rsa_authenticator_t;
+
+#include <sa/authenticators/authenticator.h>
+
+/**
+ * @brief Implementation of the authenticator_t interface using AUTH_RSA.
+ *
+ * @b Constructors:
+ * - rsa_authenticator_create()
+ * - authenticator_create() using auth_method AUTH_RSA
+ *
+ * @ingroup authenticators
+ */
+struct rsa_authenticator_t {
+
+ /**
+ * Implemented authenticator_t interface.
+ */
+ authenticator_t authenticator_interface;
+};
+
+/**
+ * @brief Creates an authenticator for AUTH_RSA.
+ *
+ * @param ike_sa associated ike_sa
+ * @return rsa_authenticator_t object
+ *
+ * @ingroup authenticators
+ */
+rsa_authenticator_t *rsa_authenticator_create(ike_sa_t *ike_sa);
+
+#endif /* RSA_AUTHENTICATOR_H_ */