merged EAP framework from branch into trunk
includes a lot of other modifications
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <sa/authenticators/rsa_authenticator.h>
|
||||
#include <sa/authenticators/psk_authenticator.h>
|
||||
#include <sa/authenticators/eap_authenticator.h>
|
||||
|
||||
|
||||
ENUM_BEGIN(auth_method_names, AUTH_RSA, AUTH_DSS,
|
||||
@@ -47,6 +48,8 @@ authenticator_t *authenticator_create(ike_sa_t *ike_sa, auth_method_t auth_metho
|
||||
return (authenticator_t*)rsa_authenticator_create(ike_sa);
|
||||
case AUTH_PSK:
|
||||
return (authenticator_t*)psk_authenticator_create(ike_sa);
|
||||
case AUTH_EAP:
|
||||
return (authenticator_t*)eap_authenticator_create(ike_sa);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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_ */
|
||||
@@ -0,0 +1,348 @@
|
||||
/**
|
||||
* @file eap_authenticator.c
|
||||
*
|
||||
* @brief Implementation of eap_authenticator_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "eap_authenticator.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <config/policies/policy.h>
|
||||
#include <sa/authenticators/eap/eap_method.h>
|
||||
|
||||
typedef struct private_eap_authenticator_t private_eap_authenticator_t;
|
||||
|
||||
/**
|
||||
* Private data of an eap_authenticator_t object.
|
||||
*/
|
||||
struct private_eap_authenticator_t {
|
||||
|
||||
/**
|
||||
* Public authenticator_t interface.
|
||||
*/
|
||||
eap_authenticator_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Role of this authenticator, PEER or SERVER
|
||||
*/
|
||||
eap_role_t role;
|
||||
|
||||
/**
|
||||
* Current EAP method processing
|
||||
*/
|
||||
eap_method_t *method;
|
||||
|
||||
/**
|
||||
* MSK used to build and verify auth payload
|
||||
*/
|
||||
chunk_t msk;
|
||||
};
|
||||
|
||||
extern chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce,
|
||||
chunk_t secret, identification_t *id,
|
||||
prf_t *prf);
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t.verify.
|
||||
*/
|
||||
static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init,
|
||||
chunk_t my_nonce, auth_payload_t *auth_payload)
|
||||
{
|
||||
chunk_t auth_data, recv_auth_data;
|
||||
identification_t *other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
prf_t *prf = this->ike_sa->get_auth_verify(this->ike_sa);
|
||||
|
||||
auth_data = build_shared_key_signature(ike_sa_init, my_nonce, this->msk,
|
||||
other_id, prf);
|
||||
|
||||
recv_auth_data = auth_payload->get_data(auth_payload);
|
||||
if (!chunk_equals(auth_data, recv_auth_data))
|
||||
{
|
||||
DBG1(DBG_IKE, "verification of AUTH payload created from EAP MSK failed");
|
||||
chunk_free(&auth_data);
|
||||
return FAILED;
|
||||
}
|
||||
chunk_free(&auth_data);
|
||||
|
||||
DBG1(DBG_IKE, "authentication of '%D' with %N successful",
|
||||
other_id, auth_method_names, AUTH_EAP);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t.build.
|
||||
*/
|
||||
static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init,
|
||||
chunk_t other_nonce, auth_payload_t **auth_payload)
|
||||
{
|
||||
chunk_t auth_data;
|
||||
identification_t *my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
prf_t *prf = this->ike_sa->get_auth_build(this->ike_sa);
|
||||
|
||||
DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
|
||||
my_id, auth_method_names, AUTH_EAP);
|
||||
|
||||
auth_data = build_shared_key_signature(ike_sa_init, other_nonce,
|
||||
this->msk, my_id, prf);
|
||||
|
||||
*auth_payload = auth_payload_create();
|
||||
(*auth_payload)->set_auth_method(*auth_payload, AUTH_PSK);
|
||||
(*auth_payload)->set_data(*auth_payload, auth_data);
|
||||
chunk_free(&auth_data);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of eap_authenticator_t.initiate
|
||||
*/
|
||||
static status_t initiate(private_eap_authenticator_t *this, eap_type_t type,
|
||||
eap_payload_t **out)
|
||||
{
|
||||
/* if initiate() is called, role is always server */
|
||||
this->role = EAP_SERVER;
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
DBG1(DBG_IKE,
|
||||
"client requested EAP authentication, but configuration forbids it");
|
||||
*out = eap_payload_create_code(EAP_FAILURE);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
DBG1(DBG_IKE, "requesting %N authentication", eap_type_names, type);
|
||||
this->method = eap_method_create(type, this->role,
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
|
||||
if (this->method == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "configured EAP server method %N not supported, sending %N",
|
||||
eap_type_names, type, eap_code_names, EAP_FAILURE);
|
||||
*out = eap_payload_create_code(EAP_FAILURE);
|
||||
return FAILED;
|
||||
}
|
||||
if (this->method->initiate(this->method, out) != NEED_MORE)
|
||||
{
|
||||
DBG1(DBG_IKE, "failed to initiate %N, sending %N",
|
||||
eap_type_names, type, eap_code_names, EAP_FAILURE);
|
||||
*out = eap_payload_create_code(EAP_FAILURE);
|
||||
return FAILED;
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processing method for a peer
|
||||
*/
|
||||
static status_t process_peer(private_eap_authenticator_t *this,
|
||||
eap_payload_t *in, eap_payload_t **out)
|
||||
{
|
||||
eap_type_t type = in->get_type(in);
|
||||
|
||||
/* create an eap_method for the first call */
|
||||
if (this->method == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "EAP server requested %N authentication",
|
||||
eap_type_names, type);
|
||||
this->method = eap_method_create(type, EAP_PEER,
|
||||
this->ike_sa->get_other_id(this->ike_sa),
|
||||
this->ike_sa->get_my_id(this->ike_sa));
|
||||
if (this->method == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "EAP server requested unsupported "
|
||||
"EAP method %N, sending EAP_NAK", eap_type_names, type);
|
||||
*out = eap_payload_create_nak();
|
||||
return NEED_MORE;
|
||||
}
|
||||
}
|
||||
|
||||
switch (this->method->process(this->method, in, out))
|
||||
{
|
||||
case NEED_MORE:
|
||||
return NEED_MORE;
|
||||
case SUCCESS:
|
||||
if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "EAP method %N succeded, MSK established",
|
||||
eap_type_names, this->method->get_type(this->method));
|
||||
this->msk = chunk_clone(this->msk);
|
||||
return SUCCESS;
|
||||
}
|
||||
DBG1(DBG_IKE, "EAP method %N succeded, but no MSK established",
|
||||
eap_type_names, this->method->get_type(this->method));
|
||||
return FAILED;
|
||||
case FAILED:
|
||||
default:
|
||||
DBG1(DBG_IKE, "EAP method %N failed",
|
||||
eap_type_names, this->method->get_type(this->method));
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processing method for a server
|
||||
*/
|
||||
static status_t process_server(private_eap_authenticator_t *this,
|
||||
eap_payload_t *in, eap_payload_t **out)
|
||||
{
|
||||
switch (this->method->process(this->method, in, out))
|
||||
{
|
||||
case NEED_MORE:
|
||||
return NEED_MORE;
|
||||
case SUCCESS:
|
||||
if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "EAP method %N succeded, MSK established",
|
||||
eap_type_names, this->method->get_type(this->method));
|
||||
this->msk = chunk_clone(this->msk);
|
||||
*out = eap_payload_create_code(EAP_SUCCESS);
|
||||
return SUCCESS;
|
||||
}
|
||||
DBG1(DBG_IKE, "EAP method %N succeded, but no MSK established",
|
||||
eap_type_names, this->method->get_type(this->method));
|
||||
*out = eap_payload_create_code(EAP_FAILURE);
|
||||
return FAILED;
|
||||
case FAILED:
|
||||
default:
|
||||
DBG1(DBG_IKE, "EAP method %N failed for peer %D",
|
||||
eap_type_names, this->method->get_type(this->method),
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
*out = eap_payload_create_code(EAP_FAILURE);
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of eap_authenticator_t.process
|
||||
*/
|
||||
static status_t process(private_eap_authenticator_t *this, eap_payload_t *in,
|
||||
eap_payload_t **out)
|
||||
{
|
||||
eap_code_t code = in->get_code(in);
|
||||
|
||||
switch (this->role)
|
||||
{
|
||||
case EAP_SERVER:
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case EAP_RESPONSE:
|
||||
{
|
||||
return process_server(this, in, out);
|
||||
}
|
||||
default:
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N, sending %N",
|
||||
eap_code_names, code, eap_code_names, EAP_FAILURE);
|
||||
*out = eap_payload_create_code(EAP_FAILURE);
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
case EAP_PEER:
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case EAP_REQUEST:
|
||||
{
|
||||
return process_peer(this, in, out);
|
||||
}
|
||||
case EAP_SUCCESS:
|
||||
{
|
||||
if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "EAP method %N succeded, MSK established",
|
||||
eap_type_names, this->method->get_type(this->method));
|
||||
this->msk = chunk_clone(this->msk);
|
||||
return SUCCESS;
|
||||
}
|
||||
DBG1(DBG_IKE, "EAP method %N succeded, but no MSK established",
|
||||
eap_type_names, this->method->get_type(this->method));
|
||||
return FAILED;
|
||||
}
|
||||
case EAP_FAILURE:
|
||||
default:
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N, EAP authentication failed",
|
||||
eap_code_names, code);
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t.is_mutual.
|
||||
*/
|
||||
static bool is_mutual(private_eap_authenticator_t *this)
|
||||
{
|
||||
if (this->method)
|
||||
{
|
||||
return this->method->is_mutual(this->method);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t.destroy.
|
||||
*/
|
||||
static void destroy(private_eap_authenticator_t *this)
|
||||
{
|
||||
DESTROY_IF(this->method);
|
||||
chunk_free(&this->msk);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa)
|
||||
{
|
||||
private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t);
|
||||
|
||||
/* public functions */
|
||||
this->public.authenticator_interface.verify = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t*))verify;
|
||||
this->public.authenticator_interface.build = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t**))build;
|
||||
this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy;
|
||||
|
||||
this->public.is_mutual = (bool(*)(eap_authenticator_t*))is_mutual;
|
||||
this->public.initiate = (status_t(*)(eap_authenticator_t*,eap_type_t,eap_payload_t**))initiate;
|
||||
this->public.process = (status_t(*)(eap_authenticator_t*,eap_payload_t*,eap_payload_t**))process;
|
||||
|
||||
/* private data */
|
||||
this->ike_sa = ike_sa;
|
||||
this->role = EAP_PEER;
|
||||
this->method = NULL;
|
||||
this->msk = chunk_empty;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file authenticator.c
|
||||
* @file psk_authenticator.c
|
||||
*
|
||||
* @brief Implementation of authenticator_t.
|
||||
* @brief Implementation of psk_authenticator_t.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -54,24 +54,35 @@ struct private_psk_authenticator_t {
|
||||
};
|
||||
|
||||
/**
|
||||
* Function implemented in rsa_authenticator.c
|
||||
* Builds the octets to be signed as described in section 2.15 of RFC 4306
|
||||
*/
|
||||
extern chunk_t build_tbs_octets(private_psk_authenticator_t *this, chunk_t ike_sa_init,
|
||||
chunk_t nonce, identification_t *id, prf_t *prf);
|
||||
chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce,
|
||||
identification_t *id, prf_t *prf)
|
||||
{
|
||||
u_int8_t id_header_buf[] = {0x00, 0x00, 0x00, 0x00};
|
||||
chunk_t id_header = chunk_from_buf(id_header_buf);
|
||||
chunk_t id_with_header, id_prfd, id_encoding;
|
||||
|
||||
id_header_buf[0] = id->get_type(id);
|
||||
id_encoding = id->get_encoding(id);
|
||||
|
||||
id_with_header = chunk_cat("cc", id_header, id_encoding);
|
||||
prf->allocate_bytes(prf, id_with_header, &id_prfd);
|
||||
chunk_free(&id_with_header);
|
||||
|
||||
return chunk_cat("ccm", ike_sa_init, nonce, id_prfd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the AUTH data using auth method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
|
||||
*/
|
||||
static chunk_t build_shared_key_signature(private_psk_authenticator_t *this,
|
||||
chunk_t ike_sa_init,
|
||||
chunk_t nonce,
|
||||
chunk_t secret,
|
||||
identification_t *id,
|
||||
prf_t *prf)
|
||||
chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce,
|
||||
chunk_t secret, identification_t *id,
|
||||
prf_t *prf)
|
||||
{
|
||||
chunk_t key_pad, key, auth_data, octets;
|
||||
|
||||
octets = build_tbs_octets(this, ike_sa_init, nonce, id, prf);
|
||||
octets = build_tbs_octets(ike_sa_init, nonce, id, prf);
|
||||
/* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */
|
||||
key_pad.ptr = IKEV2_KEY_PAD;
|
||||
key_pad.len = IKEV2_KEY_PAD_LENGTH;
|
||||
@@ -94,7 +105,7 @@ static chunk_t build_shared_key_signature(private_psk_authenticator_t *this,
|
||||
* Implementation of authenticator_t.verify.
|
||||
*/
|
||||
static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init,
|
||||
chunk_t my_nonce, auth_payload_t *auth_payload)
|
||||
chunk_t my_nonce, auth_payload_t *auth_payload)
|
||||
{
|
||||
status_t status;
|
||||
chunk_t auth_data, recv_auth_data, shared_key;
|
||||
@@ -110,7 +121,7 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init,
|
||||
return status;
|
||||
}
|
||||
|
||||
auth_data = build_shared_key_signature(this, ike_sa_init, my_nonce,
|
||||
auth_data = build_shared_key_signature(ike_sa_init, my_nonce,
|
||||
shared_key, other_id,
|
||||
this->ike_sa->get_auth_verify(this->ike_sa));
|
||||
chunk_free(&shared_key);
|
||||
@@ -153,7 +164,7 @@ static status_t build(private_psk_authenticator_t *this, chunk_t ike_sa_init,
|
||||
return status;
|
||||
}
|
||||
|
||||
auth_data = build_shared_key_signature(this, ike_sa_init,
|
||||
auth_data = build_shared_key_signature(ike_sa_init,
|
||||
other_nonce, shared_key, my_id,
|
||||
this->ike_sa->get_auth_build(this->ike_sa));
|
||||
DBG2(DBG_IKE, "successfully created shared key MAC");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file authenticator.c
|
||||
* @file rsa_authenticator.c
|
||||
*
|
||||
* @brief Implementation of authenticator_t.
|
||||
* @brief Implementation of rsa_authenticator_t.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -48,24 +48,10 @@ struct private_rsa_authenticator_t {
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds the octets to be signed as described in section 2.15 of RFC 4306
|
||||
* Function implemented in psk_authenticator.c
|
||||
*/
|
||||
chunk_t build_tbs_octets(private_rsa_authenticator_t *this, chunk_t ike_sa_init,
|
||||
chunk_t nonce, identification_t *id, prf_t *prf)
|
||||
{
|
||||
u_int8_t id_header_buf[] = {0x00, 0x00, 0x00, 0x00};
|
||||
chunk_t id_header = chunk_from_buf(id_header_buf);
|
||||
chunk_t id_with_header, id_prfd, id_encoding;
|
||||
|
||||
id_header_buf[0] = id->get_type(id);
|
||||
id_encoding = id->get_encoding(id);
|
||||
|
||||
id_with_header = chunk_cat("cc", id_header, id_encoding);
|
||||
prf->allocate_bytes(prf, id_with_header, &id_prfd);
|
||||
chunk_free(&id_with_header);
|
||||
|
||||
return chunk_cat("ccm", ike_sa_init, nonce, id_prfd);
|
||||
}
|
||||
extern chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce,
|
||||
identification_t *id, prf_t *prf);
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t.verify.
|
||||
@@ -92,7 +78,7 @@ static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init,
|
||||
DBG1(DBG_IKE, "no RSA public key found for '%D'", other_id);
|
||||
return NOT_FOUND;
|
||||
}
|
||||
octets = build_tbs_octets(this, ike_sa_init, my_nonce, other_id,
|
||||
octets = build_tbs_octets(ike_sa_init, my_nonce, other_id,
|
||||
this->ike_sa->get_auth_verify(this->ike_sa));
|
||||
status = public_key->verify_emsa_pkcs1_signature(public_key, octets, auth_data);
|
||||
chunk_free(&octets);
|
||||
@@ -145,7 +131,7 @@ static status_t build(private_rsa_authenticator_t *this, chunk_t ike_sa_init,
|
||||
}
|
||||
DBG2(DBG_IKE, "matching RSA private key found");
|
||||
|
||||
octets = build_tbs_octets(this, ike_sa_init, other_nonce, my_id,
|
||||
octets = build_tbs_octets(ike_sa_init, other_nonce, my_id,
|
||||
this->ike_sa->get_auth_build(this->ike_sa));
|
||||
status = my_key->build_emsa_pkcs1_signature(my_key, HASH_SHA1, octets, &auth_data);
|
||||
chunk_free(&octets);
|
||||
|
||||
@@ -454,8 +454,7 @@ static void dpd_detected(private_ike_sa_t *this)
|
||||
policy = charon->policies->get_policy(charon->policies,
|
||||
this->my_id, this->other_id,
|
||||
my_ts, other_ts,
|
||||
this->my_host, this->other_host,
|
||||
NULL);
|
||||
this->my_host, this->other_host);
|
||||
if (policy == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "no policy for CHILD to handle DPD");
|
||||
@@ -1021,8 +1020,7 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
|
||||
policy = charon->policies->get_policy(charon->policies,
|
||||
this->my_id, this->other_id,
|
||||
my_ts, other_ts,
|
||||
this->my_host, this->other_host,
|
||||
NULL);
|
||||
this->my_host, this->other_host);
|
||||
if (policy == NULL)
|
||||
{
|
||||
SIG(CHILD_UP_START, "acquiring CHILD_SA with reqid %d", reqid);
|
||||
@@ -1878,7 +1876,7 @@ static status_t reauth(private_ike_sa_t *this)
|
||||
other_ts = child_sa->get_other_traffic_selectors(child_sa);
|
||||
policy = charon->policies->get_policy(charon->policies,
|
||||
this->my_id, this->other_id, my_ts, other_ts,
|
||||
this->my_host, this->other_host, NULL);
|
||||
this->my_host, this->other_host);
|
||||
if (policy == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "policy not found to recreate CHILD_SA, skipped");
|
||||
|
||||
@@ -291,8 +291,7 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result)
|
||||
this->policy = charon->policies->get_policy(charon->policies,
|
||||
my_id, other_id,
|
||||
my_ts, other_ts,
|
||||
me, other,
|
||||
NULL);
|
||||
me, other);
|
||||
|
||||
this->reqid = this->rekeyed_sa->get_reqid(this->rekeyed_sa);
|
||||
|
||||
@@ -694,8 +693,7 @@ static status_t get_response(private_create_child_sa_t *this, message_t *request
|
||||
this->policy = charon->policies->get_policy(charon->policies,
|
||||
my_id, other_id,
|
||||
my_ts, other_ts,
|
||||
me, other,
|
||||
NULL);
|
||||
me, other);
|
||||
if (this->policy)
|
||||
{
|
||||
this->tsr = this->policy->select_my_traffic_selectors(this->policy, my_ts, me);
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
#include <encoding/payloads/ts_payload.h>
|
||||
#include <sa/authenticators/authenticator.h>
|
||||
#include <sa/authenticators/eap_authenticator.h>
|
||||
#include <sa/child_sa.h>
|
||||
|
||||
|
||||
@@ -129,6 +130,31 @@ struct private_ike_auth_t {
|
||||
*/
|
||||
u_int32_t reqid;
|
||||
|
||||
/**
|
||||
* List of CA certificates the other peer trusts
|
||||
*/
|
||||
linked_list_t *cacerts;
|
||||
|
||||
/**
|
||||
* EAP uses this authentication, which is passed along multiple ike_auths
|
||||
*/
|
||||
eap_authenticator_t *eap_auth;
|
||||
|
||||
/**
|
||||
* if the client receives a EAP request, it is stored here for later use
|
||||
*/
|
||||
eap_payload_t *eap_next;
|
||||
|
||||
/**
|
||||
* set to TRUE if authentication should be done with EAP only
|
||||
*/
|
||||
bool eap_only;
|
||||
|
||||
/**
|
||||
* has the other peer been authenticated yet?
|
||||
*/
|
||||
bool peer_authenticated;
|
||||
|
||||
/**
|
||||
* mode the CHILD_SA uses: tranport, tunnel, BEET
|
||||
*/
|
||||
@@ -245,6 +271,57 @@ static status_t get_request(private_ike_auth_t *this, message_t **result)
|
||||
/* store for retransmission */
|
||||
this->message = request;
|
||||
|
||||
this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
|
||||
request->set_message_id(request, this->message_id);
|
||||
|
||||
if (this->eap_auth)
|
||||
{
|
||||
/* we already sent ID, SA, TS in an earlier ike_auth, we now
|
||||
* continiue EAP processing */
|
||||
if (this->eap_next)
|
||||
{
|
||||
/* if we have another outstanding EAP response, send it */
|
||||
request->add_payload(request, (payload_t*)this->eap_next);
|
||||
this->eap_next = NULL;
|
||||
return SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if not, we have received an EAP_SUCCESS, send AUTH payload.
|
||||
* we only send our data if:
|
||||
* a) The peer has been authenticated using RSA/PSK, or
|
||||
* b) The EAP method is mutual and gives us enough security
|
||||
*/
|
||||
if (this->eap_auth->is_mutual(this->eap_auth) ||
|
||||
this->peer_authenticated)
|
||||
{
|
||||
auth_payload_t *auth_payload;
|
||||
authenticator_t *authenticator = (authenticator_t*)this->eap_auth;
|
||||
|
||||
if (authenticator->build(authenticator, this->init_request,
|
||||
this->nonce_r, &auth_payload) != SUCCESS)
|
||||
{
|
||||
SIG(IKE_UP_FAILED,
|
||||
"EAP authentication data generation failed, deleting IKE_SA");
|
||||
SIG(CHILD_UP_FAILED,
|
||||
"initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
request->add_payload(request, (payload_t*)auth_payload);
|
||||
return SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
SIG(IKE_UP_FAILED,
|
||||
"peer didn't send authentication data, deleting IKE_SA");
|
||||
SIG(CHILD_UP_FAILED,
|
||||
"initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* otherwise we do a normal ike_auth request... */
|
||||
|
||||
{ /* build ID payload */
|
||||
my_id_payload = id_payload_create_from_identification(TRUE, my_id);
|
||||
request->add_payload(request, (payload_t*)my_id_payload);
|
||||
@@ -274,8 +351,8 @@ static status_t get_request(private_ike_auth_t *this, message_t **result)
|
||||
}
|
||||
|
||||
/* build certificate payload. TODO: Handle certreq from init_ike_sa. */
|
||||
if (this->policy->get_auth_method(this->policy) == AUTH_RSA
|
||||
&& this->connection->get_cert_policy(this->connection) != CERT_NEVER_SEND)
|
||||
if (this->policy->get_auth_method(this->policy) == AUTH_RSA &&
|
||||
this->connection->get_cert_policy(this->connection) != CERT_NEVER_SEND)
|
||||
{
|
||||
cert_payload_t *cert_payload;
|
||||
|
||||
@@ -301,6 +378,7 @@ static status_t get_request(private_ike_auth_t *this, message_t **result)
|
||||
}
|
||||
}
|
||||
|
||||
if (this->policy->get_auth_method(this->policy) != AUTH_EAP)
|
||||
{ /* build auth payload */
|
||||
authenticator_t *authenticator;
|
||||
auth_payload_t *auth_payload;
|
||||
@@ -327,6 +405,12 @@ static status_t get_request(private_ike_auth_t *this, message_t **result)
|
||||
}
|
||||
request->add_payload(request, (payload_t*)auth_payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->eap_auth = eap_authenticator_create(this->ike_sa);
|
||||
/* include notify that we support EAP only authentication */
|
||||
build_notify(EAP_ONLY_AUTHENTICATION, request, FALSE);
|
||||
}
|
||||
|
||||
{ /* build SA payload for CHILD_SA */
|
||||
linked_list_t *proposal_list;
|
||||
@@ -399,8 +483,6 @@ static status_t get_request(private_ike_auth_t *this, message_t **result)
|
||||
request->add_payload(request, (payload_t*)ts_payload);
|
||||
}
|
||||
|
||||
this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
|
||||
request->set_message_id(request, this->message_id);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -434,6 +516,12 @@ static status_t process_notifies(private_ike_auth_t *this, notify_payload_t *not
|
||||
this->build_child = FALSE;
|
||||
return SUCCESS;
|
||||
}
|
||||
case EAP_ONLY_AUTHENTICATION:
|
||||
{
|
||||
DBG1(DBG_IKE, "peer requested EAP_ONLY_AUTHENTICATION");
|
||||
this->eap_only = TRUE;
|
||||
return SUCCESS;
|
||||
}
|
||||
case USE_TRANSPORT_MODE:
|
||||
{
|
||||
this->mode = MODE_TRANSPORT;
|
||||
@@ -465,38 +553,37 @@ static status_t process_notifies(private_ike_auth_t *this, notify_payload_t *not
|
||||
/**
|
||||
* Import certificate requests from a certreq payload
|
||||
*/
|
||||
static void add_certificate_request(certreq_payload_t *certreq_payload,
|
||||
linked_list_t *requested_ca_keyids)
|
||||
static void process_certificate_request(private_ike_auth_t *this,
|
||||
certreq_payload_t *certreq_payload)
|
||||
{
|
||||
chunk_t keyids;
|
||||
|
||||
cert_encoding_t encoding = certreq_payload->get_cert_encoding(certreq_payload);
|
||||
|
||||
|
||||
if (encoding != CERT_X509_SIGNATURE)
|
||||
{
|
||||
DBG1(DBG_IKE, "certreq payload %N not supported, ignored",
|
||||
cert_encoding_names, encoding);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
keyids = certreq_payload->get_data(certreq_payload);
|
||||
|
||||
while (keyids.len >= HASH_SIZE_SHA1)
|
||||
{
|
||||
chunk_t keyid = { keyids.ptr, HASH_SIZE_SHA1};
|
||||
x509_t *cacert = charon->credentials->get_ca_certificate_by_keyid(charon->credentials, keyid);
|
||||
|
||||
x509_t *cacert = charon->credentials->get_ca_certificate_by_keyid(
|
||||
charon->credentials, keyid);
|
||||
if (cacert)
|
||||
{
|
||||
DBG2(DBG_IKE, "request for certificate issued by ca '%D'", cacert->get_subject(cacert));
|
||||
requested_ca_keyids->insert_last(requested_ca_keyids, (void *)&keyid);
|
||||
DBG2(DBG_IKE, "request for certificate issued by ca '%D'",
|
||||
cacert->get_subject(cacert));
|
||||
this->cacerts->insert_last(this->cacerts, cacert);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG2(DBG_IKE, "request for certificate issued by unknown ca");
|
||||
}
|
||||
DBG2(DBG_IKE, " with keyid %#B", &keyid);
|
||||
|
||||
|
||||
keyids.ptr += HASH_SIZE_SHA1;
|
||||
keyids.len -= HASH_SIZE_SHA1;
|
||||
}
|
||||
@@ -614,6 +701,113 @@ static status_t install_child_sa(private_ike_auth_t *this, bool initiator)
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* create a CHILD SA, install it, and build response message
|
||||
*/
|
||||
static void setup_child_sa(private_ike_auth_t *this, message_t *response)
|
||||
{
|
||||
bool use_natt;
|
||||
u_int32_t soft_lifetime, hard_lifetime;
|
||||
host_t *me, *other;
|
||||
identification_t *my_id, *other_id;
|
||||
|
||||
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||
other = this->ike_sa->get_other_host(this->ike_sa);
|
||||
my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
|
||||
soft_lifetime = this->policy->get_soft_lifetime(this->policy);
|
||||
hard_lifetime = this->policy->get_hard_lifetime(this->policy);
|
||||
use_natt = this->ike_sa->is_natt_enabled(this->ike_sa);
|
||||
this->child_sa = child_sa_create(this->reqid, me, other, my_id, other_id,
|
||||
soft_lifetime, hard_lifetime,
|
||||
this->policy->get_updown(this->policy),
|
||||
this->policy->get_hostaccess(this->policy),
|
||||
use_natt);
|
||||
this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
|
||||
/* check mode, and include notify into reply */
|
||||
switch (this->mode)
|
||||
{
|
||||
case MODE_TUNNEL:
|
||||
/* is the default */
|
||||
break;
|
||||
case MODE_TRANSPORT:
|
||||
if (!ts_list_is_host(this->tsi, other) ||
|
||||
!ts_list_is_host(this->tsr, me))
|
||||
{
|
||||
this->mode = MODE_TUNNEL;
|
||||
DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
|
||||
}
|
||||
else if (this->ike_sa->is_natt_enabled(this->ike_sa))
|
||||
{
|
||||
this->mode = MODE_TUNNEL;
|
||||
DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
|
||||
}
|
||||
else
|
||||
{
|
||||
build_notify(USE_TRANSPORT_MODE, response, FALSE);
|
||||
}
|
||||
break;
|
||||
case MODE_BEET:
|
||||
if (!ts_list_is_host(this->tsi, NULL) ||
|
||||
!ts_list_is_host(this->tsr, NULL))
|
||||
{
|
||||
this->mode = MODE_TUNNEL;
|
||||
DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
|
||||
}
|
||||
else
|
||||
{
|
||||
build_notify(USE_BEET_MODE, response, FALSE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (install_child_sa(this, FALSE) != SUCCESS)
|
||||
{
|
||||
SIG(CHILD_UP_FAILED, "installing CHILD_SA %s failed, no CHILD_SA created",
|
||||
this->policy->get_name(this->policy));
|
||||
DBG1(DBG_IKE, "adding NO_PROPOSAL_CHOSEN notify to response");
|
||||
build_notify(NO_PROPOSAL_CHOSEN, response, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* build SA and TS payloads */
|
||||
SIG(CHILD_UP_SUCCESS, "CHILD_SA created");
|
||||
ts_payload_t *ts_response;
|
||||
sa_payload_t *sa_response = sa_payload_create();
|
||||
sa_response->add_proposal(sa_response, this->proposal);
|
||||
response->add_payload(response, (payload_t*)sa_response);
|
||||
ts_response = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
|
||||
response->add_payload(response, (payload_t*)ts_response);
|
||||
ts_response = ts_payload_create_from_traffic_selectors(FALSE, this->tsr);
|
||||
response->add_payload(response, (payload_t*)ts_response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clone the transaction to requeue it for EAP handling
|
||||
*/
|
||||
static private_ike_auth_t *clone_for_eap(private_ike_auth_t *this)
|
||||
{
|
||||
private_ike_auth_t *clone;
|
||||
clone = (private_ike_auth_t*)ike_auth_create(this->ike_sa);
|
||||
|
||||
clone->tsi = this->tsi; this->tsi = NULL;
|
||||
clone->tsr = this->tsr; this->tsr = NULL;
|
||||
clone->eap_auth = this->eap_auth; this->eap_auth = NULL;
|
||||
clone->eap_next = this->eap_next; this->eap_next = NULL;
|
||||
clone->build_child = this->build_child;
|
||||
clone->nonce_i = this->nonce_i; this->nonce_i = chunk_empty;
|
||||
clone->nonce_r = this->nonce_r; this->nonce_r = chunk_empty;
|
||||
clone->child_sa = this->child_sa; this->child_sa = NULL;
|
||||
clone->proposal = this->proposal; this->proposal = NULL;
|
||||
clone->peer_authenticated = this->peer_authenticated;
|
||||
clone->connection = this->connection; this->connection = NULL;
|
||||
clone->policy = this->policy; this->policy = NULL;
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of transaction_t.get_response.
|
||||
*/
|
||||
@@ -622,7 +816,6 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
|
||||
{
|
||||
host_t *me, *other;
|
||||
identification_t *my_id, *other_id;
|
||||
linked_list_t *requested_ca_keyids;
|
||||
message_t *response;
|
||||
status_t status;
|
||||
iterator_t *payloads;
|
||||
@@ -635,6 +828,7 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
|
||||
sa_payload_t *sa_request = NULL;
|
||||
ts_payload_t *tsi_request = NULL;
|
||||
ts_payload_t *tsr_request = NULL;
|
||||
eap_payload_t *eap_request = NULL;
|
||||
id_payload_t *idr_response;
|
||||
|
||||
/* check if we already have built a response (retransmission) */
|
||||
@@ -648,6 +842,8 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
|
||||
|
||||
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||
other = this->ike_sa->get_other_host(this->ike_sa);
|
||||
my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
this->message_id = request->get_message_id(request);
|
||||
|
||||
/* set up response */
|
||||
@@ -668,9 +864,6 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* initialize list of requested ca keyids */
|
||||
requested_ca_keyids = linked_list_create();
|
||||
|
||||
/* Iterate over all payloads. */
|
||||
payloads = request->get_payload_iterator(request);
|
||||
@@ -689,7 +882,7 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
|
||||
break;
|
||||
case CERTIFICATE_REQUEST:
|
||||
certreq_request = (certreq_payload_t*)payload;
|
||||
add_certificate_request(certreq_request, requested_ca_keyids);
|
||||
process_certificate_request(this, certreq_request);
|
||||
break;
|
||||
case CERTIFICATE:
|
||||
cert_request = (cert_payload_t*)payload;
|
||||
@@ -703,20 +896,21 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
|
||||
case TRAFFIC_SELECTOR_RESPONDER:
|
||||
tsr_request = (ts_payload_t*)payload;
|
||||
break;
|
||||
case EXTENSIBLE_AUTHENTICATION:
|
||||
eap_request = (eap_payload_t*)payload;
|
||||
break;
|
||||
case NOTIFY:
|
||||
{
|
||||
status = process_notifies(this, (notify_payload_t*)payload);
|
||||
if (status == FAILED)
|
||||
{
|
||||
payloads->destroy(payloads);
|
||||
requested_ca_keyids->destroy(requested_ca_keyids);
|
||||
/* we return SUCCESS, returned FAILED means do next transaction */
|
||||
return SUCCESS;
|
||||
}
|
||||
if (status == DESTROY_ME)
|
||||
{
|
||||
payloads->destroy(payloads);
|
||||
requested_ca_keyids->destroy(requested_ca_keyids);
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
@@ -732,13 +926,67 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
|
||||
}
|
||||
payloads->destroy(payloads);
|
||||
|
||||
/* check if we have all payloads */
|
||||
if (!(idi_request && auth_request && sa_request && tsi_request && tsr_request))
|
||||
/* if message contains an EAP payload, we process it */
|
||||
if (eap_request && this->eap_auth)
|
||||
{
|
||||
eap_payload_t *eap_response;
|
||||
private_ike_auth_t *next_auth;
|
||||
|
||||
status = this->eap_auth->process(this->eap_auth, eap_request, &eap_response);
|
||||
response->add_payload(response, (payload_t*)eap_response);
|
||||
|
||||
if (status == FAILED)
|
||||
{
|
||||
/* shut down if EAP message is EAP_FAILURE */
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
next_auth = clone_for_eap(this);
|
||||
next_auth->message_id = this->message_id + 1;
|
||||
*next = (transaction_t*)next_auth;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* if we do EAP authentication and a AUTH payload comes in, verify it */
|
||||
if (auth_request && this->eap_auth)
|
||||
{
|
||||
auth_payload_t *auth_response;
|
||||
authenticator_t *authenticator = (authenticator_t*)this->eap_auth;
|
||||
|
||||
if (authenticator->verify(authenticator, this->init_request,
|
||||
this->nonce_r, auth_request) != SUCCESS)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "authentication with EAP failed, deleting IKE_SA");
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
build_notify(AUTHENTICATION_FAILED, response, TRUE);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
if (authenticator->build(authenticator, this->init_response,
|
||||
this->nonce_i, &auth_response) != SUCCESS)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "EAP authentication data generation failed, deleting IKE_SA");
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
build_notify(AUTHENTICATION_FAILED, response, TRUE);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
response->add_payload(response, (payload_t*)auth_response);
|
||||
|
||||
SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...%H[%D]",
|
||||
this->ike_sa->get_name(this->ike_sa), me, my_id, other, other_id);
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
|
||||
|
||||
setup_child_sa(this, response);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* check if we have all payloads (AUTH is not checked, not required with EAP) */
|
||||
if (!(idi_request && sa_request && tsi_request && tsr_request))
|
||||
{
|
||||
build_notify(INVALID_SYNTAX, response, TRUE);
|
||||
SIG(IKE_UP_FAILED, "request message incomplete, deleting IKE_SA");
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
requested_ca_keyids->destroy(requested_ca_keyids);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
@@ -754,7 +1002,6 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{ /* get a policy and process traffic selectors */
|
||||
linked_list_t *my_ts, *other_ts;
|
||||
|
||||
@@ -764,9 +1011,7 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
|
||||
this->policy = charon->policies->get_policy(charon->policies,
|
||||
my_id, other_id,
|
||||
my_ts, other_ts,
|
||||
me, other,
|
||||
requested_ca_keyids);
|
||||
requested_ca_keyids->destroy(requested_ca_keyids);
|
||||
me, other);
|
||||
|
||||
if (this->policy)
|
||||
{
|
||||
@@ -799,8 +1044,8 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
|
||||
response->add_payload(response, (payload_t*)idr_response);
|
||||
}
|
||||
|
||||
if (this->policy->get_auth_method(this->policy) == AUTH_RSA
|
||||
&& this->connection->get_cert_policy(this->connection) != CERT_NEVER_SEND)
|
||||
if (this->policy->get_auth_method(this->policy) == AUTH_RSA &&
|
||||
this->connection->get_cert_policy(this->connection) != CERT_NEVER_SEND)
|
||||
{ /* build certificate payload */
|
||||
x509_t *cert;
|
||||
cert_payload_t *cert_payload;
|
||||
@@ -822,9 +1067,76 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
|
||||
import_certificate(cert_request);
|
||||
}
|
||||
|
||||
{ /* process auth payload */
|
||||
authenticator_t *authenticator;
|
||||
{ /* process SA payload */
|
||||
linked_list_t *proposal_list;
|
||||
|
||||
/* get proposals from request, and select one with ours */
|
||||
proposal_list = sa_request->get_proposals(sa_request);
|
||||
DBG2(DBG_IKE, "selecting proposals:");
|
||||
this->proposal = this->policy->select_proposal(this->policy, proposal_list);
|
||||
proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
|
||||
|
||||
/* do we have a proposal? */
|
||||
if (this->proposal == NULL)
|
||||
{
|
||||
SIG(CHILD_UP_FAILED, "CHILD_SA proposals unacceptable, no CHILD_SA created");
|
||||
DBG1(DBG_IKE, "adding NO_PROPOSAL_CHOSEN notify to response");
|
||||
build_notify(NO_PROPOSAL_CHOSEN, response, FALSE);
|
||||
this->build_child = FALSE;
|
||||
}
|
||||
/* do we have traffic selectors? */
|
||||
else if (this->tsi->get_count(this->tsi) == 0 || this->tsr->get_count(this->tsr) == 0)
|
||||
{
|
||||
SIG(CHILD_UP_FAILED, "CHILD_SA traffic selectors unacceptable, no CHILD_SA created");
|
||||
DBG1(DBG_IKE, "adding TS_UNACCEPTABLE notify to response");
|
||||
build_notify(TS_UNACCEPTABLE, response, FALSE);
|
||||
this->build_child = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->eap_only || this->policy->get_auth_method(this->policy) != AUTH_EAP)
|
||||
{ /* build response AUTH payload when not using a mutual EAP authentication */
|
||||
auth_payload_t *auth_response;
|
||||
authenticator_t *authenticator;
|
||||
auth_method_t auth_method;
|
||||
status_t status;
|
||||
|
||||
auth_method = this->policy->get_auth_method(this->policy);
|
||||
if (auth_method == AUTH_EAP)
|
||||
{
|
||||
SIG(IKE_UP_FAILED,
|
||||
"peer does not support EAP only authentication, deleting IKE_SA");
|
||||
SIG(CHILD_UP_FAILED,
|
||||
"initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
build_notify(AUTHENTICATION_FAILED, response, TRUE);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
authenticator = authenticator_create(this->ike_sa, auth_method);
|
||||
if (authenticator == NULL)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "auth method %N not supported, deleting IKE_SA",
|
||||
auth_method_names, auth_method);
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
build_notify(AUTHENTICATION_FAILED, response, TRUE);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
status = authenticator->build(authenticator, this->init_response,
|
||||
this->nonce_i, &auth_response);
|
||||
authenticator->destroy(authenticator);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "authentication data generation failed, deleting IKE_SA");
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
build_notify(AUTHENTICATION_FAILED, response, TRUE);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
response->add_payload(response, (payload_t*)auth_response);
|
||||
}
|
||||
|
||||
if (auth_request)
|
||||
{ /* process auth payload, if not using EAP */
|
||||
authenticator_t *authenticator;
|
||||
auth_method_t auth_method;
|
||||
status_t status;
|
||||
|
||||
@@ -848,145 +1160,51 @@ static status_t get_response(private_ike_auth_t *this, message_t *request,
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
auth_method = this->policy->get_auth_method(this->policy);
|
||||
authenticator = authenticator_create(this->ike_sa, auth_method);
|
||||
if (authenticator == NULL)
|
||||
SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...%H[%D]",
|
||||
this->ike_sa->get_name(this->ike_sa), me, my_id, other, other_id);
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
|
||||
|
||||
/* set up CHILD_SA if negotiation succeded */
|
||||
if (this->build_child)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "auth method %N not supported, deleting IKE_SA",
|
||||
auth_method_names, auth_method);
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
setup_child_sa(this, response);
|
||||
}
|
||||
|
||||
this->peer_authenticated = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if no AUTH payload was included, we start with an EAP exchange.
|
||||
* eap_response is a request in the EAP meaning, but is
|
||||
* contained in a IKEv2 response */
|
||||
eap_payload_t *eap_response;
|
||||
private_ike_auth_t *next_auth;
|
||||
eap_type_t eap_type;
|
||||
|
||||
eap_type = this->policy->get_eap_type(this->policy);
|
||||
this->eap_auth = eap_authenticator_create(this->ike_sa);
|
||||
status = this->eap_auth->initiate(this->eap_auth, eap_type, &eap_response);
|
||||
response->add_payload(response, (payload_t*)eap_response);
|
||||
|
||||
if (status == FAILED)
|
||||
{
|
||||
/* EAP initiaton failed, we send the EAP_FAILURE message and quit */
|
||||
return DESTROY_ME;
|
||||
}
|
||||
status = authenticator->build(authenticator, this->init_response,
|
||||
this->nonce_i, &auth_response);
|
||||
authenticator->destroy(authenticator);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "authentication data generation failed, deleting IKE_SA");
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
build_notify(AUTHENTICATION_FAILED, response, TRUE);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
response->add_payload(response, (payload_t*)auth_response);
|
||||
/* we send an EAP request. to handle the reply, we reschedule
|
||||
* this transaction, as it knows how to handle the reply */
|
||||
next_auth = clone_for_eap(this);
|
||||
next_auth->message_id = this->message_id + 1;
|
||||
*next = (transaction_t*)next_auth;
|
||||
}
|
||||
|
||||
SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...%H[%D]",
|
||||
this->ike_sa->get_name(this->ike_sa), me, my_id, other, other_id);
|
||||
|
||||
{ /* process SA payload */
|
||||
linked_list_t *proposal_list;
|
||||
sa_payload_t *sa_response;
|
||||
ts_payload_t *ts_response;
|
||||
bool use_natt;
|
||||
u_int32_t soft_lifetime, hard_lifetime;
|
||||
|
||||
/* prepare reply */
|
||||
sa_response = sa_payload_create();
|
||||
|
||||
/* get proposals from request, and select one with ours */
|
||||
proposal_list = sa_request->get_proposals(sa_request);
|
||||
DBG2(DBG_IKE, "selecting proposals:");
|
||||
this->proposal = this->policy->select_proposal(this->policy, proposal_list);
|
||||
proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
|
||||
|
||||
/* do we have a proposal? */
|
||||
if (this->proposal == NULL)
|
||||
{
|
||||
SIG(CHILD_UP_FAILED, "CHILD_SA proposals unacceptable, no CHILD_SA created");
|
||||
DBG1(DBG_IKE, "adding NO_PROPOSAL_CHOSEN notify to response");
|
||||
build_notify(NO_PROPOSAL_CHOSEN, response, FALSE);
|
||||
}
|
||||
/* do we have traffic selectors? */
|
||||
else if (this->tsi->get_count(this->tsi) == 0 || this->tsr->get_count(this->tsr) == 0)
|
||||
{
|
||||
SIG(CHILD_UP_FAILED, "CHILD_SA traffic selectors unacceptable, no CHILD_SA created");
|
||||
DBG1(DBG_IKE, "adding TS_UNACCEPTABLE notify to response");
|
||||
build_notify(TS_UNACCEPTABLE, response, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* create child sa */
|
||||
soft_lifetime = this->policy->get_soft_lifetime(this->policy);
|
||||
hard_lifetime = this->policy->get_hard_lifetime(this->policy);
|
||||
use_natt = this->ike_sa->is_natt_enabled(this->ike_sa);
|
||||
this->child_sa = child_sa_create(this->reqid, me, other, my_id, other_id,
|
||||
soft_lifetime, hard_lifetime,
|
||||
this->policy->get_updown(this->policy),
|
||||
this->policy->get_hostaccess(this->policy),
|
||||
use_natt);
|
||||
this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
|
||||
|
||||
/* check mode, and include notify into reply */
|
||||
switch (this->mode)
|
||||
{
|
||||
case MODE_TUNNEL:
|
||||
/* is the default */
|
||||
break;
|
||||
case MODE_TRANSPORT:
|
||||
if (!ts_list_is_host(this->tsi, other) ||
|
||||
!ts_list_is_host(this->tsr, me))
|
||||
{
|
||||
this->mode = MODE_TUNNEL;
|
||||
DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
|
||||
}
|
||||
else if (this->ike_sa->is_natt_enabled(this->ike_sa))
|
||||
{
|
||||
this->mode = MODE_TUNNEL;
|
||||
DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
|
||||
}
|
||||
else
|
||||
{
|
||||
build_notify(USE_TRANSPORT_MODE, response, FALSE);
|
||||
}
|
||||
break;
|
||||
case MODE_BEET:
|
||||
if (!ts_list_is_host(this->tsi, NULL) ||
|
||||
!ts_list_is_host(this->tsr, NULL))
|
||||
{
|
||||
this->mode = MODE_TUNNEL;
|
||||
DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
|
||||
}
|
||||
else
|
||||
{
|
||||
build_notify(USE_BEET_MODE, response, FALSE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (install_child_sa(this, FALSE) != SUCCESS)
|
||||
{
|
||||
SIG(CHILD_UP_FAILED, "installing CHILD_SA '%s' failed, no CHILD_SA created",
|
||||
this->policy->get_name(this->policy));
|
||||
DBG1(DBG_IKE, "adding NO_PROPOSAL_CHOSEN notify to response");
|
||||
build_notify(NO_PROPOSAL_CHOSEN, response, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* add proposal to sa payload */
|
||||
sa_response->add_proposal(sa_response, this->proposal);
|
||||
SIG(CHILD_UP_SUCCESS, "CHILD_SA '%s' created",
|
||||
this->policy->get_name(this->policy));
|
||||
}
|
||||
}
|
||||
response->add_payload(response, (payload_t*)sa_response);
|
||||
|
||||
/* add ts payload after sa payload */
|
||||
ts_response = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
|
||||
response->add_payload(response, (payload_t*)ts_response);
|
||||
ts_response = ts_payload_create_from_traffic_selectors(FALSE, this->tsr);
|
||||
response->add_payload(response, (payload_t*)ts_response);
|
||||
}
|
||||
/* set established state */
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of transaction_t.conclude
|
||||
*/
|
||||
static status_t conclude(private_ike_auth_t *this, message_t *response,
|
||||
transaction_t **transaction)
|
||||
transaction_t **next)
|
||||
{
|
||||
iterator_t *payloads;
|
||||
payload_t *payload;
|
||||
@@ -998,6 +1216,7 @@ static status_t conclude(private_ike_auth_t *this, message_t *response,
|
||||
cert_payload_t *cert_payload = NULL;
|
||||
auth_payload_t *auth_payload = NULL;
|
||||
sa_payload_t *sa_payload = NULL;
|
||||
eap_payload_t *eap_payload = NULL;
|
||||
status_t status;
|
||||
|
||||
/* check message type */
|
||||
@@ -1010,6 +1229,8 @@ static status_t conclude(private_ike_auth_t *this, message_t *response,
|
||||
|
||||
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||
other = this->ike_sa->get_other_host(this->ike_sa);
|
||||
my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
|
||||
/* Iterate over all payloads to collect them */
|
||||
payloads = response->get_payload_iterator(response);
|
||||
@@ -1035,6 +1256,9 @@ static status_t conclude(private_ike_auth_t *this, message_t *response,
|
||||
case TRAFFIC_SELECTOR_RESPONDER:
|
||||
tsr_payload = (ts_payload_t*)payload;
|
||||
break;
|
||||
case EXTENSIBLE_AUTHENTICATION:
|
||||
eap_payload = (eap_payload_t*)payload;
|
||||
break;
|
||||
case NOTIFY:
|
||||
{
|
||||
status = process_notifies(this, (notify_payload_t*)payload);
|
||||
@@ -1062,13 +1286,7 @@ static status_t conclude(private_ike_auth_t *this, message_t *response,
|
||||
}
|
||||
payloads->destroy(payloads);
|
||||
|
||||
if (!(idr_payload && auth_payload && sa_payload && tsi_payload && tsr_payload))
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "response message incomplete, deleting IKE_SA");
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
if (idr_payload)
|
||||
{ /* process idr payload */
|
||||
identification_t *configured_other_id;
|
||||
int wildcards;
|
||||
@@ -1080,7 +1298,7 @@ static status_t conclude(private_ike_auth_t *this, message_t *response,
|
||||
{
|
||||
other_id->destroy(other_id);
|
||||
SIG(IKE_UP_FAILED, "other peer uses unacceptable ID (%D, excepted "
|
||||
"%D), deleting IKE_SA", other_id, configured_other_id);
|
||||
"%D), deleting IKE_SA", other_id, configured_other_id);
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
@@ -1093,6 +1311,7 @@ static status_t conclude(private_ike_auth_t *this, message_t *response,
|
||||
import_certificate(cert_payload);
|
||||
}
|
||||
|
||||
if (auth_payload && idr_payload)
|
||||
{ /* authenticate peer */
|
||||
authenticator_t *authenticator;
|
||||
auth_method_t auth_method;
|
||||
@@ -1118,10 +1337,72 @@ static status_t conclude(private_ike_auth_t *this, message_t *response,
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
this->peer_authenticated = TRUE;
|
||||
}
|
||||
|
||||
if (eap_payload && this->eap_auth)
|
||||
{
|
||||
switch (this->eap_auth->process(this->eap_auth, eap_payload, &this->eap_next))
|
||||
{
|
||||
case SUCCESS:
|
||||
{
|
||||
/* EAP message was EAP_SUCCESS, send AUTH in next transaction */
|
||||
DBG2(DBG_IKE, "EAP authentication exchanges completed successful");
|
||||
this->eap_next = NULL;
|
||||
/* fall through */
|
||||
}
|
||||
case NEED_MORE:
|
||||
{
|
||||
/* EAP message was a EAP_REQUEST, handle it in next transaction */
|
||||
private_ike_auth_t *next_auth = clone_for_eap(this);
|
||||
next_auth->message_id = this->message_id + 1;
|
||||
*next = (transaction_t*)next_auth;
|
||||
return SUCCESS;
|
||||
}
|
||||
case FAILED:
|
||||
default:
|
||||
{
|
||||
/* EAP message was EAP_FAILURE */
|
||||
SIG(IKE_UP_FAILED, "EAP authentication failed, deleting IKE_SA");
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(auth_payload && sa_payload && tsi_payload && tsr_payload))
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "response message incomplete, deleting IKE_SA");
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
/* if we do EAP authentication and a AUTH payload comes in, verify it */
|
||||
if (this->eap_auth &&
|
||||
(this->eap_auth->is_mutual(this->eap_auth) || this->peer_authenticated))
|
||||
{
|
||||
authenticator_t *authenticator = (authenticator_t*)this->eap_auth;
|
||||
|
||||
if (authenticator->verify(authenticator, this->init_response,
|
||||
this->nonce_i, auth_payload) != SUCCESS)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "authentication with EAP failed, deleting IKE_SA");
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
this->peer_authenticated = TRUE;
|
||||
}
|
||||
|
||||
if (!this->peer_authenticated)
|
||||
{
|
||||
SIG(IKE_UP_FAILED, "server didn't send authentication data, deleting IKE_SA");
|
||||
SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...%H[%D]",
|
||||
this->ike_sa->get_name(this->ike_sa), me, my_id, other, other_id);
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
|
||||
|
||||
{ /* process traffic selectors for us */
|
||||
linked_list_t *ts_received = tsi_payload->get_traffic_selectors(tsi_payload);
|
||||
@@ -1198,8 +1479,6 @@ static status_t conclude(private_ike_auth_t *this, message_t *response,
|
||||
}
|
||||
}
|
||||
}
|
||||
/* set new state */
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1213,6 +1492,12 @@ static void destroy(private_ike_auth_t *this)
|
||||
DESTROY_IF(this->child_sa);
|
||||
DESTROY_IF(this->policy);
|
||||
DESTROY_IF(this->connection);
|
||||
DESTROY_IF(this->cacerts);
|
||||
if (this->eap_auth)
|
||||
{
|
||||
this->eap_auth->authenticator_interface.destroy(&this->eap_auth->authenticator_interface);
|
||||
}
|
||||
DESTROY_IF(this->eap_next);
|
||||
if (this->tsi)
|
||||
{
|
||||
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
|
||||
@@ -1260,10 +1545,17 @@ ike_auth_t *ike_auth_create(ike_sa_t *ike_sa)
|
||||
this->init_response = chunk_empty;
|
||||
this->child_sa = NULL;
|
||||
this->proposal = NULL;
|
||||
this->policy = NULL;
|
||||
this->connection = NULL;
|
||||
this->tsi = NULL;
|
||||
this->tsr = NULL;
|
||||
this->build_child = TRUE;
|
||||
this->eap_auth = NULL;
|
||||
this->eap_next = NULL;
|
||||
this->eap_only = FALSE;
|
||||
this->peer_authenticated = FALSE;
|
||||
this->reqid = 0;
|
||||
this->cacerts = linked_list_create();
|
||||
this->mode = MODE_TUNNEL;
|
||||
|
||||
return &this->public;
|
||||
|
||||
Reference in New Issue
Block a user