merged EAP framework from branch into trunk
includes a lot of other modifications
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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_ */
|
||||
@@ -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("[email protected]");
|
||||
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;
|
||||
}
|
||||
@@ -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_ */
|
||||
Reference in New Issue
Block a user