reintegrated eap-radius branch into trunk
This commit is contained in:
parent
623bca407b
commit
4a6b84a934
10
configure.in
10
configure.in
|
@ -465,6 +465,14 @@ AC_ARG_ENABLE(
|
|||
fi]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[eap-radius],
|
||||
AS_HELP_STRING([--enable-eap-radius],[build RADIUS proxy authenication module for EAP (default is NO).]),
|
||||
[if test x$enableval = xyes; then
|
||||
eap_radius=true
|
||||
fi]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[kernel-netlink],
|
||||
AS_HELP_STRING([--disable-kernel-netlink],[disable the netlink kernel interface. (default is NO).]),
|
||||
|
@ -963,6 +971,7 @@ AM_CONDITIONAL(USE_EAP_MD5, test x$eap_md5 = xtrue)
|
|||
AM_CONDITIONAL(USE_EAP_GTC, test x$eap_gtc = xtrue)
|
||||
AM_CONDITIONAL(USE_EAP_AKA, test x$eap_aka = xtrue)
|
||||
AM_CONDITIONAL(USE_EAP_MSCHAPV2, test x$eap_mschapv2 = xtrue)
|
||||
AM_CONDITIONAL(USE_EAP_RADIUS, test x$eap_radius = xtrue)
|
||||
AM_CONDITIONAL(USE_KERNEL_NETLINK, test x$kernel_netlink = xtrue)
|
||||
AM_CONDITIONAL(USE_KERNEL_PFKEY, test x$kernel_pfkey = xtrue)
|
||||
AM_CONDITIONAL(USE_KERNEL_KLIPS, test x$kernel_klips = xtrue)
|
||||
|
@ -1044,6 +1053,7 @@ AC_OUTPUT(
|
|||
src/charon/plugins/eap_sim/Makefile
|
||||
src/charon/plugins/eap_sim_file/Makefile
|
||||
src/charon/plugins/eap_mschapv2/Makefile
|
||||
src/charon/plugins/eap_radius/Makefile
|
||||
src/charon/plugins/kernel_netlink/Makefile
|
||||
src/charon/plugins/kernel_pfkey/Makefile
|
||||
src/charon/plugins/kernel_klips/Makefile
|
||||
|
|
|
@ -221,6 +221,11 @@ if USE_EAP_MSCHAPV2
|
|||
PLUGINS += eapmschapv2
|
||||
endif
|
||||
|
||||
if USE_EAP_RADIUS
|
||||
SUBDIRS += plugins/eap_radius
|
||||
PLUGINS += eapradius
|
||||
endif
|
||||
|
||||
if USE_MEDSRV
|
||||
SUBDIRS += plugins/medsrv
|
||||
PLUGINS += medsrv
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-eapradius.la
|
||||
|
||||
libstrongswan_eapradius_la_SOURCES = \
|
||||
eap_radius_plugin.h eap_radius_plugin.c \
|
||||
eap_radius.h eap_radius.c \
|
||||
radius_client.h radius_client.c \
|
||||
radius_message.h radius_message.c
|
||||
libstrongswan_eapradius_la_LDFLAGS = -module
|
||||
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "eap_radius.h"
|
||||
|
||||
#include "radius_message.h"
|
||||
#include "radius_client.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
|
||||
typedef struct private_eap_radius_t private_eap_radius_t;
|
||||
|
||||
/**
|
||||
* Private data of an eap_radius_t object.
|
||||
*/
|
||||
struct private_eap_radius_t {
|
||||
|
||||
/**
|
||||
* Public authenticator_t interface.
|
||||
*/
|
||||
eap_radius_t public;
|
||||
|
||||
/**
|
||||
* ID of the server
|
||||
*/
|
||||
identification_t *server;
|
||||
|
||||
/**
|
||||
* ID of the peer
|
||||
*/
|
||||
identification_t *peer;
|
||||
|
||||
/**
|
||||
* EAP method type we are proxying
|
||||
*/
|
||||
eap_type_t type;
|
||||
|
||||
/**
|
||||
* EAP vendor, if any
|
||||
*/
|
||||
u_int32_t vendor;
|
||||
|
||||
/**
|
||||
* EAP MSK, if method established one
|
||||
*/
|
||||
chunk_t msk;
|
||||
|
||||
/**
|
||||
* RADIUS client instance
|
||||
*/
|
||||
radius_client_t *client;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add EAP-Identity to RADIUS message
|
||||
*/
|
||||
static void add_eap_identity(private_eap_radius_t *this,
|
||||
radius_message_t *request)
|
||||
{
|
||||
struct {
|
||||
/** EAP code (REQUEST/RESPONSE) */
|
||||
u_int8_t code;
|
||||
/** unique message identifier */
|
||||
u_int8_t identifier;
|
||||
/** length of whole message */
|
||||
u_int16_t length;
|
||||
/** EAP type */
|
||||
u_int8_t type;
|
||||
/** identity data */
|
||||
u_int8_t data[];
|
||||
} __attribute__((__packed__)) *hdr;
|
||||
chunk_t id;
|
||||
size_t len;
|
||||
|
||||
id = this->peer->get_encoding(this->peer);
|
||||
len = sizeof(*hdr) + id.len;
|
||||
|
||||
hdr = alloca(len);
|
||||
hdr->code = EAP_RESPONSE;
|
||||
hdr->identifier = 0;
|
||||
hdr->length = htons(len);
|
||||
hdr->type = EAP_IDENTITY;
|
||||
memcpy(hdr->data, id.ptr, id.len);
|
||||
|
||||
request->add(request, RAT_EAP_MESSAGE, chunk_create((u_char*)hdr, len));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy EAP-Message attribute from RADIUS message to an new EAP payload
|
||||
*/
|
||||
static bool radius2ike(private_eap_radius_t *this,
|
||||
radius_message_t *msg, eap_payload_t **out)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
eap_payload_t *payload;
|
||||
chunk_t data;
|
||||
int type;
|
||||
|
||||
enumerator = msg->create_enumerator(msg);
|
||||
while (enumerator->enumerate(enumerator, &type, &data))
|
||||
{
|
||||
if (type == RAT_EAP_MESSAGE)
|
||||
{
|
||||
*out = payload = eap_payload_create_data(data);
|
||||
/* apply EAP method selected by RADIUS server */
|
||||
this->type = payload->get_type(payload, &this->vendor);
|
||||
enumerator->destroy(enumerator);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of eap_method_t.initiate
|
||||
*/
|
||||
static status_t initiate(private_eap_radius_t *this, eap_payload_t **out)
|
||||
{
|
||||
radius_message_t *request, *response;
|
||||
status_t status = FAILED;
|
||||
|
||||
request = radius_message_create_request();
|
||||
request->add(request, RAT_USER_NAME, this->peer->get_encoding(this->peer));
|
||||
add_eap_identity(this, request);
|
||||
response = this->client->request(this->client, request);
|
||||
if (response)
|
||||
{
|
||||
if (radius2ike(this, response, out))
|
||||
{
|
||||
status = NEED_MORE;
|
||||
}
|
||||
response->destroy(response);
|
||||
}
|
||||
request->destroy(request);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of eap_method_t.process
|
||||
*/
|
||||
static status_t process(private_eap_radius_t *this,
|
||||
eap_payload_t *in, eap_payload_t **out)
|
||||
{
|
||||
radius_message_t *request, *response;
|
||||
status_t status = FAILED;
|
||||
|
||||
request = radius_message_create_request();
|
||||
request->add(request, RAT_USER_NAME, this->peer->get_encoding(this->peer));
|
||||
request->add(request, RAT_EAP_MESSAGE, in->get_data(in));
|
||||
|
||||
response = this->client->request(this->client, request);
|
||||
if (response)
|
||||
{
|
||||
switch (response->get_code(response))
|
||||
{
|
||||
case RMC_ACCESS_CHALLENGE:
|
||||
if (radius2ike(this, response, out))
|
||||
{
|
||||
status = NEED_MORE;
|
||||
break;
|
||||
}
|
||||
status = FAILED;
|
||||
break;
|
||||
case RMC_ACCESS_ACCEPT:
|
||||
this->msk = this->client->decrypt_msk(this->client,
|
||||
response, request);
|
||||
status = SUCCESS;
|
||||
break;
|
||||
case RMC_ACCESS_REJECT:
|
||||
default:
|
||||
DBG1(DBG_CFG, "received %N from RADIUS server",
|
||||
radius_message_code_names, response->get_code(response));
|
||||
status = FAILED;
|
||||
break;
|
||||
}
|
||||
response->destroy(response);
|
||||
}
|
||||
request->destroy(request);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of eap_method_t.get_type.
|
||||
*/
|
||||
static eap_type_t get_type(private_eap_radius_t *this, u_int32_t *vendor)
|
||||
{
|
||||
*vendor = this->vendor;
|
||||
return this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of eap_method_t.get_msk.
|
||||
*/
|
||||
static status_t get_msk(private_eap_radius_t *this, chunk_t *msk)
|
||||
{
|
||||
if (this->msk.ptr)
|
||||
{
|
||||
*msk = this->msk;
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of eap_method_t.is_mutual.
|
||||
*/
|
||||
static bool is_mutual(private_eap_radius_t *this)
|
||||
{
|
||||
switch (this->type)
|
||||
{
|
||||
case EAP_AKA:
|
||||
case EAP_SIM:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of eap_method_t.destroy.
|
||||
*/
|
||||
static void destroy(private_eap_radius_t *this)
|
||||
{
|
||||
this->peer->destroy(this->peer);
|
||||
this->server->destroy(this->server);
|
||||
this->client->destroy(this->client);
|
||||
chunk_clear(&this->msk);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic constructor
|
||||
*/
|
||||
eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer)
|
||||
{
|
||||
private_eap_radius_t *this = malloc_thing(private_eap_radius_t);
|
||||
|
||||
this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate;
|
||||
this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process;
|
||||
this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type;
|
||||
this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
|
||||
this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
|
||||
this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
|
||||
|
||||
this->client = radius_client_create();
|
||||
if (!this->client)
|
||||
{
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
this->peer = peer->clone(peer);
|
||||
this->server = server->clone(server);
|
||||
/* initially EAP_RADIUS, but is set to the method selected by RADIUS */
|
||||
this->type = EAP_RADIUS;
|
||||
this->vendor = 0;
|
||||
this->msk = chunk_empty;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup eap_radius_i eap_radius
|
||||
* @{ @ingroup eap_radius
|
||||
*/
|
||||
|
||||
#ifndef EAP_RADIUS_H_
|
||||
#define EAP_RADIUS_H_
|
||||
|
||||
typedef struct eap_radius_t eap_radius_t;
|
||||
|
||||
#include <sa/authenticators/eap/eap_method.h>
|
||||
|
||||
/**
|
||||
* Implementation of the eap_method_t interface using a RADIUS server.
|
||||
*/
|
||||
struct eap_radius_t {
|
||||
|
||||
/**
|
||||
* Implemented eap_method_t interface.
|
||||
*/
|
||||
eap_method_t eap_method_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a EAP RADIUS proxy.
|
||||
*
|
||||
* @param server ID of the EAP server
|
||||
* @param peer ID of the EAP client
|
||||
* @return eap_radius_t object
|
||||
*/
|
||||
eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer);
|
||||
|
||||
#endif /* EAP_RADIUS_H_ @}*/
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "eap_radius_plugin.h"
|
||||
|
||||
#include "eap_radius.h"
|
||||
#include "radius_client.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
/**
|
||||
* Implementation of plugin_t.destroy
|
||||
*/
|
||||
static void destroy(eap_radius_plugin_t *this)
|
||||
{
|
||||
charon->eap->remove_method(charon->eap, (eap_constructor_t)eap_radius_create);
|
||||
radius_client_cleanup();
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
plugin_t *plugin_create()
|
||||
{
|
||||
eap_radius_plugin_t *this;
|
||||
|
||||
if (!radius_client_init())
|
||||
{
|
||||
DBG1(DBG_CFG, "RADIUS plugin initialization failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this = malloc_thing(eap_radius_plugin_t);
|
||||
this->plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||
|
||||
charon->eap->add_method(charon->eap, EAP_RADIUS, 0,
|
||||
EAP_SERVER, (eap_constructor_t)eap_radius_create);
|
||||
|
||||
return &this->plugin;
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup eap_radius eap_radius
|
||||
* @ingroup cplugins
|
||||
*
|
||||
* @defgroup eap_radius_plugin eap_radius_plugin
|
||||
* @{ @ingroup eap_radius
|
||||
*/
|
||||
|
||||
#ifndef EAP_RADIUS_PLUGIN_H_
|
||||
#define EAP_RADIUS_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct eap_radius_plugin_t eap_radius_plugin_t;
|
||||
|
||||
/**
|
||||
* EAP RADIUS proxy plugin.
|
||||
*
|
||||
* This plugin provides not a single EAP method, but a proxy to forwared
|
||||
* EAP packets to a RADIUS server. It only provides server implementations.
|
||||
*/
|
||||
struct eap_radius_plugin_t {
|
||||
|
||||
/**
|
||||
* implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a eap_radius_plugin instance.
|
||||
*/
|
||||
plugin_t *plugin_create();
|
||||
|
||||
#endif /* EAP_RADIUS_PLUGIN_H_ @}*/
|
|
@ -0,0 +1,493 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "radius_client.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <daemon.h>
|
||||
#include <utils/host.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <utils/mutex.h>
|
||||
|
||||
/**
|
||||
* Default RADIUS server port, when not configured
|
||||
*/
|
||||
#define RADIUS_PORT 1812
|
||||
|
||||
/**
|
||||
* Vendor-Id of Microsoft specific attributes
|
||||
*/
|
||||
#define VENDOR_ID_MICROSOFT 311
|
||||
|
||||
/**
|
||||
* Microsoft specific vendor attributes
|
||||
*/
|
||||
#define MS_MPPE_SEND_KEY 16
|
||||
#define MS_MPPE_RECV_KEY 17
|
||||
|
||||
typedef struct private_radius_client_t private_radius_client_t;
|
||||
|
||||
typedef struct entry_t entry_t;
|
||||
|
||||
/**
|
||||
* A socket pool entry.
|
||||
*/
|
||||
struct entry_t {
|
||||
/** socket file descriptor */
|
||||
int fd;
|
||||
/** current RADIUS identifier */
|
||||
u_int8_t identifier;
|
||||
/** hasher to use for response verification */
|
||||
hasher_t *hasher;
|
||||
/** HMAC-MD5 signer to build Message-Authenticator attribute */
|
||||
signer_t *signer;
|
||||
/** random number generator for RADIUS request authenticator */
|
||||
rng_t *rng;
|
||||
};
|
||||
|
||||
/**
|
||||
* Private data of an radius_client_t object.
|
||||
*/
|
||||
struct private_radius_client_t {
|
||||
|
||||
/**
|
||||
* Public radius_client_t interface.
|
||||
*/
|
||||
radius_client_t public;
|
||||
|
||||
/**
|
||||
* The clients socket from the pool
|
||||
*/
|
||||
entry_t *socket;
|
||||
|
||||
/**
|
||||
* RADIUS servers State attribute
|
||||
*/
|
||||
chunk_t state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Global list of radius sockets, contains entry_t's
|
||||
*/
|
||||
static linked_list_t *sockets;
|
||||
|
||||
/**
|
||||
* mutex to lock sockets list
|
||||
*/
|
||||
static mutex_t *mutex;
|
||||
|
||||
/**
|
||||
* condvar to wait for sockets
|
||||
*/
|
||||
static condvar_t *condvar;
|
||||
|
||||
/**
|
||||
* RADIUS secret
|
||||
*/
|
||||
static chunk_t secret;
|
||||
|
||||
/**
|
||||
* NAS-Identifier
|
||||
*/
|
||||
static chunk_t nas_identifier;
|
||||
|
||||
/**
|
||||
* Clean up socket list
|
||||
*/
|
||||
void radius_client_cleanup()
|
||||
{
|
||||
entry_t *entry;
|
||||
|
||||
mutex->destroy(mutex);
|
||||
condvar->destroy(condvar);
|
||||
while (sockets->remove_last(sockets, (void**)&entry) == SUCCESS)
|
||||
{
|
||||
entry->rng->destroy(entry->rng);
|
||||
entry->hasher->destroy(entry->hasher);
|
||||
entry->signer->destroy(entry->signer);
|
||||
close(entry->fd);
|
||||
free(entry);
|
||||
}
|
||||
sockets->destroy(sockets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the socket list
|
||||
*/
|
||||
bool radius_client_init()
|
||||
{
|
||||
int i, count, fd;
|
||||
u_int16_t port;
|
||||
entry_t *entry;
|
||||
host_t *host;
|
||||
char *server;
|
||||
|
||||
nas_identifier.ptr = lib->settings->get_str(lib->settings,
|
||||
"charon.plugins.eap_radius.nas_identifier", "strongSwan");
|
||||
nas_identifier.len = strlen(nas_identifier.ptr);
|
||||
|
||||
secret.ptr = lib->settings->get_str(lib->settings,
|
||||
"charon.plugins.eap_radius.secret", NULL);
|
||||
if (!secret.ptr)
|
||||
{
|
||||
DBG1(DBG_CFG, "no RADUIS secret defined");
|
||||
return FALSE;
|
||||
}
|
||||
secret.len = strlen(secret.ptr);
|
||||
server = lib->settings->get_str(lib->settings,
|
||||
"charon.plugins.eap_radius.server", NULL);
|
||||
if (!server)
|
||||
{
|
||||
DBG1(DBG_CFG, "no RADUIS server defined");
|
||||
return FALSE;
|
||||
}
|
||||
port = lib->settings->get_int(lib->settings,
|
||||
"charon.plugins.eap_radius.port", RADIUS_PORT);
|
||||
host = host_create_from_dns(server, 0, port);
|
||||
if (!host)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
count = lib->settings->get_int(lib->settings,
|
||||
"charon.plugins.eap_radius.sockets", 5);
|
||||
|
||||
sockets = linked_list_create();
|
||||
mutex = mutex_create(MUTEX_DEFAULT);
|
||||
condvar = condvar_create(CONDVAR_DEFAULT);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
fd = socket(host->get_family(host), SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (fd < 0)
|
||||
{
|
||||
DBG1(DBG_CFG, "opening RADIUS socket failed");
|
||||
host->destroy(host);
|
||||
radius_client_cleanup();
|
||||
return FALSE;
|
||||
}
|
||||
if (connect(fd, host->get_sockaddr(host),
|
||||
*host->get_sockaddr_len(host)) < 0)
|
||||
{
|
||||
DBG1(DBG_CFG, "connecting RADIUS socket failed");
|
||||
host->destroy(host);
|
||||
radius_client_cleanup();
|
||||
return FALSE;
|
||||
}
|
||||
entry = malloc_thing(entry_t);
|
||||
entry->fd = fd;
|
||||
/* we use per-socket crypto elements: this reduces overhead, but
|
||||
* is still thread-save. */
|
||||
entry->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
|
||||
entry->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128);
|
||||
entry->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||
if (!entry->hasher || !entry->signer || !entry->rng)
|
||||
{
|
||||
DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/RNG required");
|
||||
DESTROY_IF(entry->hasher);
|
||||
DESTROY_IF(entry->signer);
|
||||
DESTROY_IF(entry->rng);
|
||||
free(entry);
|
||||
host->destroy(host);
|
||||
radius_client_cleanup();
|
||||
return FALSE;
|
||||
}
|
||||
entry->signer->set_key(entry->signer, secret);
|
||||
/* we use a random identifier, helps if we restart often (testing) */
|
||||
entry->identifier = random();
|
||||
sockets->insert_last(sockets, entry);
|
||||
}
|
||||
host->destroy(host);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a socket from the pool, block if none available
|
||||
*/
|
||||
static entry_t* get_socket()
|
||||
{
|
||||
entry_t *entry;
|
||||
|
||||
mutex->lock(mutex);
|
||||
while (sockets->remove_first(sockets, (void**)&entry) != SUCCESS)
|
||||
{
|
||||
condvar->wait(condvar, mutex);
|
||||
}
|
||||
mutex->unlock(mutex);
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release a socket to the pool
|
||||
*/
|
||||
static void put_socket(entry_t *entry)
|
||||
{
|
||||
mutex->lock(mutex);
|
||||
sockets->insert_last(sockets, entry);
|
||||
mutex->unlock(mutex);
|
||||
condvar->signal(condvar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the state attribute to include in further request
|
||||
*/
|
||||
static void save_state(private_radius_client_t *this, radius_message_t *msg)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
int type;
|
||||
chunk_t data;
|
||||
|
||||
enumerator = msg->create_enumerator(msg);
|
||||
while (enumerator->enumerate(enumerator, &type, &data))
|
||||
{
|
||||
if (type == RAT_STATE)
|
||||
{
|
||||
free(this->state.ptr);
|
||||
this->state = chunk_clone(data);
|
||||
enumerator->destroy(enumerator);
|
||||
return;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
/* no state attribute found, remove state */
|
||||
chunk_free(&this->state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of radius_client_t.request
|
||||
*/
|
||||
static radius_message_t* request(private_radius_client_t *this,
|
||||
radius_message_t *req)
|
||||
{
|
||||
char virtual[] = {0x00,0x00,0x00,0x05};
|
||||
radius_message_t *response;
|
||||
chunk_t data;
|
||||
fd_set fds;
|
||||
int i;
|
||||
|
||||
/* set Message Identifier */
|
||||
req->set_identifier(req, this->socket->identifier++);
|
||||
/* we add the "Virtual" NAS-Port-Type, as we SHOULD include one */
|
||||
req->add(req, RAT_NAS_PORT_TYPE, chunk_create(virtual, sizeof(virtual)));
|
||||
/* add our NAS-Identifier */
|
||||
req->add(req, RAT_NAS_IDENTIFIER, nas_identifier);
|
||||
/* add State attribute, if server sent one */
|
||||
if (this->state.ptr)
|
||||
{
|
||||
req->add(req, RAT_STATE, this->state);
|
||||
}
|
||||
/* sign the request */
|
||||
req->sign(req, this->socket->rng, this->socket->signer);
|
||||
|
||||
data = req->get_encoding(req);
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(this->socket->fd, &fds);
|
||||
/* timeout after 2, 3, 4, 5 seconds */
|
||||
for (i = 2; i <= 5; i++)
|
||||
{
|
||||
bool retransmit = FALSE;
|
||||
struct timeval tv;
|
||||
char buf[1024];
|
||||
int res, retry = 0;
|
||||
|
||||
if (send(this->socket->fd, data.ptr, data.len, 0) != data.len)
|
||||
{
|
||||
DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
while (TRUE)
|
||||
{
|
||||
tv.tv_sec = i;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
res = select(this->socket->fd + 1, &fds, NULL, NULL, &tv);
|
||||
if (res < 0)
|
||||
{ /* failed */
|
||||
DBG1(DBG_CFG, "waiting for RADIUS message failed: %s",
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
if (res == 0)
|
||||
{ /* timeout */
|
||||
DBG1(DBG_CFG, "retransmitting RADIUS message");
|
||||
retransmit = TRUE;
|
||||
break;
|
||||
}
|
||||
res = recv(this->socket->fd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
if (res <= 0)
|
||||
{
|
||||
DBG1(DBG_CFG, "receiving RADIUS message failed: %s",
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
response = radius_message_parse_response(chunk_create(buf, res));
|
||||
if (response)
|
||||
{
|
||||
if (response->verify(response, req->get_authenticator(req),
|
||||
secret, this->socket->hasher, this->socket->signer))
|
||||
{
|
||||
save_state(this, response);
|
||||
return response;
|
||||
}
|
||||
response->destroy(response);
|
||||
}
|
||||
/* might be a maliciously injected packet, read onother one.
|
||||
* Limit the number of retries, an attacker could us trick into
|
||||
* a loop otherwise. */
|
||||
if (retry++ > 5)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!retransmit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
DBG1(DBG_CFG, "RADIUS server is not responding");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt a MS-MPPE-Send/Recv-Key
|
||||
*/
|
||||
static chunk_t decrypt_mppe_key(private_radius_client_t *this, u_int16_t salt,
|
||||
chunk_t C, radius_message_t *request)
|
||||
{
|
||||
chunk_t A, R, P, seed;
|
||||
u_char *c, *p;
|
||||
|
||||
/**
|
||||
* From RFC2548 (encryption):
|
||||
* b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
|
||||
* b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
|
||||
* . . .
|
||||
* b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
|
||||
*/
|
||||
|
||||
if (C.len % HASH_SIZE_MD5 || C.len < HASH_SIZE_MD5)
|
||||
{
|
||||
return chunk_empty;
|
||||
}
|
||||
|
||||
A = chunk_create((u_char*)&salt, sizeof(salt));
|
||||
R = chunk_create(request->get_authenticator(request), HASH_SIZE_MD5);
|
||||
P = chunk_alloca(C.len);
|
||||
p = P.ptr;
|
||||
c = C.ptr;
|
||||
|
||||
seed = chunk_cata("cc", R, A);
|
||||
|
||||
while (c < C.ptr + C.len)
|
||||
{
|
||||
/* b(i) = MD5(S + c(i-1)) */
|
||||
this->socket->hasher->get_hash(this->socket->hasher, secret, NULL);
|
||||
this->socket->hasher->get_hash(this->socket->hasher, seed, p);
|
||||
|
||||
/* p(i) = b(i) xor c(1) */
|
||||
memxor(p, c, HASH_SIZE_MD5);
|
||||
|
||||
/* prepare next round */
|
||||
seed = chunk_create(c, HASH_SIZE_MD5);
|
||||
c += HASH_SIZE_MD5;
|
||||
p += HASH_SIZE_MD5;
|
||||
}
|
||||
|
||||
/* remove truncation, first byte is key length */
|
||||
if (*P.ptr >= P.len)
|
||||
{ /* decryption failed? */
|
||||
return chunk_empty;
|
||||
}
|
||||
return chunk_clone(chunk_create(P.ptr + 1, *P.ptr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of radius_client_t.decrypt_msk
|
||||
*/
|
||||
static chunk_t decrypt_msk(private_radius_client_t *this,
|
||||
radius_message_t *response, radius_message_t *request)
|
||||
{
|
||||
struct {
|
||||
u_int32_t id;
|
||||
u_int8_t type;
|
||||
u_int8_t length;
|
||||
u_int16_t salt;
|
||||
u_int8_t key[];
|
||||
} __attribute__((packed)) *mppe_key;
|
||||
enumerator_t *enumerator;
|
||||
chunk_t data, send = chunk_empty, recv = chunk_empty;
|
||||
int type;
|
||||
|
||||
enumerator = response->create_enumerator(response);
|
||||
while (enumerator->enumerate(enumerator, &type, &data))
|
||||
{
|
||||
if (type == RAT_VENDOR_SPECIFIC &&
|
||||
data.len > sizeof(*mppe_key))
|
||||
{
|
||||
mppe_key = (void*)data.ptr;
|
||||
if (ntohl(mppe_key->id) == VENDOR_ID_MICROSOFT &&
|
||||
mppe_key->length == data.len - sizeof(mppe_key->id))
|
||||
{
|
||||
data = chunk_create(mppe_key->key, data.len - sizeof(*mppe_key));
|
||||
if (mppe_key->type == MS_MPPE_SEND_KEY)
|
||||
{
|
||||
send = decrypt_mppe_key(this, mppe_key->salt, data, request);
|
||||
}
|
||||
if (mppe_key->type == MS_MPPE_RECV_KEY)
|
||||
{
|
||||
recv = decrypt_mppe_key(this, mppe_key->salt, data, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
if (send.ptr && recv.ptr)
|
||||
{
|
||||
return chunk_cat("mm", recv, send);
|
||||
}
|
||||
chunk_clear(&send);
|
||||
chunk_clear(&recv);
|
||||
return chunk_empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of radius_client_t.destroy.
|
||||
*/
|
||||
static void destroy(private_radius_client_t *this)
|
||||
{
|
||||
put_socket(this->socket);
|
||||
free(this->state.ptr);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
radius_client_t *radius_client_create()
|
||||
{
|
||||
private_radius_client_t *this = malloc_thing(private_radius_client_t);
|
||||
|
||||
this->public.request = (radius_message_t*(*)(radius_client_t*, radius_message_t *msg))request;
|
||||
this->public.decrypt_msk = (chunk_t(*)(radius_client_t*, radius_message_t *, radius_message_t *))decrypt_msk;
|
||||
this->public.destroy = (void(*)(radius_client_t*))destroy;
|
||||
|
||||
this->socket = get_socket();
|
||||
this->state = chunk_empty;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup radius_client radius_client
|
||||
* @{ @ingroup eap_radius
|
||||
*/
|
||||
|
||||
#ifndef RADIUS_CLIENT_H_
|
||||
#define RADIUS_CLIENT_H_
|
||||
|
||||
#include "radius_message.h"
|
||||
|
||||
typedef struct radius_client_t radius_client_t;
|
||||
|
||||
/**
|
||||
* RADIUS client functionality.
|
||||
*
|
||||
* To communicate with a RADIUS server, create a client and send messages over
|
||||
* it. All instances share a fixed size pool of sockets. During construction,
|
||||
* one sockets gets reserved for the client, so each client uses a different
|
||||
* but fixed port during its lifetime. On destruction, the socket is restored
|
||||
* to the pool.
|
||||
*/
|
||||
struct radius_client_t {
|
||||
|
||||
/**
|
||||
* Send a RADIUS request and wait for the response.
|
||||
*
|
||||
* The client fills in RADIUS Message identifier, NAS-Identifier,
|
||||
* NAS-Port-Type, builds a Request-Authenticator and calculates the
|
||||
* Message-Authenticator attribute.
|
||||
* The received response gets verified using the Response-Identifier
|
||||
* and the Message-Authenticator attribute.
|
||||
*
|
||||
* @param msg RADIUS request message to send
|
||||
* @return response, NULL if timed out/verification failed
|
||||
*/
|
||||
radius_message_t* (*request)(radius_client_t *this, radius_message_t *msg);
|
||||
|
||||
/**
|
||||
* Decrypt the MSK encoded in a messages MS-MPPE-Send/Recv-Key.
|
||||
*
|
||||
* @param response RADIUS response message containing attributes
|
||||
* @param request associated RADIUS request message
|
||||
* @return allocated MSK, empty chunk if none found
|
||||
*/
|
||||
chunk_t (*decrypt_msk)(radius_client_t *this, radius_message_t *response,
|
||||
radius_message_t *request);
|
||||
|
||||
/**
|
||||
* Destroy the client, release the socket.
|
||||
*/
|
||||
void (*destroy)(radius_client_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a RADIUS client, acquire a socket.
|
||||
*
|
||||
* This call might block if the socket pool is empty.
|
||||
*
|
||||
* @return radius_client_t object
|
||||
*/
|
||||
radius_client_t *radius_client_create();
|
||||
|
||||
/**
|
||||
* Initialize the socket pool.
|
||||
*
|
||||
* @return TRUE if initialization successful
|
||||
*/
|
||||
bool radius_client_init();
|
||||
|
||||
/**
|
||||
* Cleanup the socket pool.
|
||||
*/
|
||||
void radius_client_cleanup();
|
||||
|
||||
#endif /* radius_client_H_ @}*/
|
|
@ -0,0 +1,465 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "radius_message.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
|
||||
typedef struct private_radius_message_t private_radius_message_t;
|
||||
typedef struct rmsg_t rmsg_t;
|
||||
typedef struct rattr_t rattr_t;
|
||||
|
||||
/**
|
||||
* RADIUS message header
|
||||
*/
|
||||
struct rmsg_t {
|
||||
/** message code, radius_message_code_t */
|
||||
u_int8_t code;
|
||||
/** message identifier */
|
||||
u_int8_t identifier;
|
||||
/** length of Code, Identifier, Length, Authenticator and Attributes */
|
||||
u_int16_t length;
|
||||
/** message authenticator, MD5 hash */
|
||||
u_int8_t authenticator[HASH_SIZE_MD5];
|
||||
/** variable list of packed attributes */
|
||||
u_int8_t attributes[];
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* RADIUS message attribute.
|
||||
*/
|
||||
struct rattr_t {
|
||||
/** attribute type, radius_attribute_type_t */
|
||||
u_int8_t type;
|
||||
/** length of the attriubte, including the Type, Length and Value fields */
|
||||
u_int8_t length;
|
||||
/** variable length attribute value */
|
||||
u_int8_t value[];
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* Private data of an radius_message_t object.
|
||||
*/
|
||||
struct private_radius_message_t {
|
||||
|
||||
/**
|
||||
* Public radius_message_t interface.
|
||||
*/
|
||||
radius_message_t public;
|
||||
|
||||
/**
|
||||
* message data, allocated
|
||||
*/
|
||||
rmsg_t *msg;
|
||||
};
|
||||
|
||||
ENUM_BEGIN(radius_message_code_names, RMC_ACCESS_REQUEST, RMC_ACCOUNTING_RESPONSE,
|
||||
"Access-Request",
|
||||
"Access-Accept",
|
||||
"Access-Reject",
|
||||
"Accounting-Request",
|
||||
"Accounting-Response");
|
||||
ENUM_NEXT(radius_message_code_names, RMC_ACCESS_CHALLENGE, RMC_ACCESS_CHALLENGE, RMC_ACCOUNTING_RESPONSE,
|
||||
"Access-Challenge");
|
||||
ENUM_END(radius_message_code_names, RMC_ACCESS_CHALLENGE);
|
||||
|
||||
ENUM(radius_attribute_type_names, RAT_USER_NAME, RAT_MIP6_HOME_LINK_PREFIX,
|
||||
"User-Name",
|
||||
"User-Password",
|
||||
"CHAP-Password",
|
||||
"NAS-IP-Address",
|
||||
"NAS-Port",
|
||||
"Service-Type",
|
||||
"Framed-Protocol",
|
||||
"Framed-IP-Address",
|
||||
"Framed-IP-Netmask",
|
||||
"Framed-Routing",
|
||||
"Filter-Id",
|
||||
"Framed-MTU",
|
||||
"Framed-Compression",
|
||||
"Login-IP-Host",
|
||||
"Login-Service",
|
||||
"Login-TCP-Port",
|
||||
"Unassigned",
|
||||
"Reply-Message",
|
||||
"Callback-Number",
|
||||
"Callback-Id",
|
||||
"Unassigned",
|
||||
"Framed-Route",
|
||||
"Framed-IPX-Network",
|
||||
"State",
|
||||
"Class",
|
||||
"Vendor-Specific",
|
||||
"Session-Timeout",
|
||||
"Idle-Timeout",
|
||||
"Termination-Action",
|
||||
"Called-Station-Id",
|
||||
"Calling-Station-Id",
|
||||
"NAS-Identifier",
|
||||
"Proxy-State",
|
||||
"Login-LAT-Service",
|
||||
"Login-LAT-Node",
|
||||
"Login-LAT-Group",
|
||||
"Framed-AppleTalk-Link",
|
||||
"Framed-AppleTalk-Network",
|
||||
"Framed-AppleTalk-Zone",
|
||||
"Acct-Status-Type",
|
||||
"Acct-Delay-Time",
|
||||
"Acct-Input-Octets",
|
||||
"Acct-Output-Octets",
|
||||
"Acct-Session-Id",
|
||||
"Acct-Authentic",
|
||||
"Acct-Session-Time",
|
||||
"Acct-Input-Packets",
|
||||
"Acct-Output-Packets",
|
||||
"Acct-Terminate-Cause",
|
||||
"Acct-Multi-Session-Id",
|
||||
"Acct-Link-Count",
|
||||
"Acct-Input-Gigawords",
|
||||
"Acct-Output-Gigawords",
|
||||
"Unassigned",
|
||||
"Event-Timestamp",
|
||||
"Egress-VLANID",
|
||||
"Ingress-Filters",
|
||||
"Egress-VLAN-Name",
|
||||
"User-Priority-Table",
|
||||
"CHAP-Challenge",
|
||||
"NAS-Port-Type",
|
||||
"Port-Limit",
|
||||
"Login-LAT-Port",
|
||||
"Tunnel-Type",
|
||||
"Tunnel-Medium-Type",
|
||||
"Tunnel-Client-Endpoint",
|
||||
"Tunnel-Server-Endpoint",
|
||||
"Acct-Tunnel-Connection",
|
||||
"Tunnel-Password",
|
||||
"ARAP-Password",
|
||||
"ARAP-Features",
|
||||
"ARAP-Zone-Access",
|
||||
"ARAP-Security",
|
||||
"ARAP-Security-Data",
|
||||
"Password-Retry",
|
||||
"Prompt",
|
||||
"Connect-Info",
|
||||
"Configuration-Token",
|
||||
"EAP-Message",
|
||||
"Message-Authenticator",
|
||||
"Tunnel-Private-Group-ID",
|
||||
"Tunnel-Assignment-ID",
|
||||
"Tunnel-Preference",
|
||||
"ARAP-Challenge-Response",
|
||||
"Acct-Interim-Interval",
|
||||
"Acct-Tunnel-Packets-Lost",
|
||||
"NAS-Port-Id",
|
||||
"Framed-Pool",
|
||||
"CUI",
|
||||
"Tunnel-Client-Auth-ID",
|
||||
"Tunnel-Server-Auth-ID",
|
||||
"NAS-Filter-Rule",
|
||||
"Unassigned",
|
||||
"Originating-Line-Info",
|
||||
"NAS-IPv6-Address",
|
||||
"Framed-Interface-Id",
|
||||
"Framed-IPv6-Prefix",
|
||||
"Login-IPv6-Host",
|
||||
"Framed-IPv6-Route",
|
||||
"Framed-IPv6-Pool",
|
||||
"Error-Cause",
|
||||
"EAP-Key-Name",
|
||||
"Digest-Response",
|
||||
"Digest-Realm",
|
||||
"Digest-Nonce",
|
||||
"Digest-Response-Auth",
|
||||
"Digest-Nextnonce",
|
||||
"Digest-Method",
|
||||
"Digest-URI",
|
||||
"Digest-Qop",
|
||||
"Digest-Algorithm",
|
||||
"Digest-Entity-Body-Hash",
|
||||
"Digest-CNonce",
|
||||
"Digest-Nonce-Count",
|
||||
"Digest-Username",
|
||||
"Digest-Opaque",
|
||||
"Digest-Auth-Param",
|
||||
"Digest-AKA-Auts",
|
||||
"Digest-Domain",
|
||||
"Digest-Stale",
|
||||
"Digest-HA1",
|
||||
"SIP-AOR",
|
||||
"Delegated-IPv6-Prefix",
|
||||
"MIP6-Feature-Vector",
|
||||
"MIP6-Home-Link-Prefix");
|
||||
|
||||
/**
|
||||
* Attribute enumerator implementation
|
||||
*/
|
||||
typedef struct {
|
||||
/** implements enumerator interface */
|
||||
enumerator_t public;
|
||||
/** currently pointing attribute */
|
||||
rattr_t *next;
|
||||
/** bytes left */
|
||||
int left;
|
||||
} attribute_enumerator_t;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of attribute_enumerator_t.enumerate
|
||||
*/
|
||||
static bool attribute_enumerate(attribute_enumerator_t *this,
|
||||
int *type, chunk_t *data)
|
||||
|
||||
{
|
||||
if (this->left == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (this->left < sizeof(rattr_t) ||
|
||||
this->left < this->next->length)
|
||||
{
|
||||
DBG1(DBG_IKE, "RADIUS message truncated");
|
||||
return FALSE;
|
||||
}
|
||||
*type = this->next->type;
|
||||
data->ptr = this->next->value;
|
||||
data->len = this->next->length - sizeof(rattr_t);
|
||||
this->left -= this->next->length;
|
||||
this->next = ((void*)this->next) + this->next->length;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of radius_message_t.create_enumerator
|
||||
*/
|
||||
static enumerator_t* create_enumerator(private_radius_message_t *this)
|
||||
{
|
||||
attribute_enumerator_t *e;
|
||||
|
||||
if (ntohs(this->msg->length) < sizeof(rmsg_t) + sizeof(rattr_t))
|
||||
{
|
||||
return enumerator_create_empty();
|
||||
}
|
||||
|
||||
e = malloc_thing(attribute_enumerator_t);
|
||||
e->public.enumerate = (void*)attribute_enumerate;
|
||||
e->public.destroy = (void*)free;
|
||||
e->next = (rattr_t*)this->msg->attributes;
|
||||
e->left = ntohs(this->msg->length) - sizeof(rmsg_t);
|
||||
return &e->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of radius_message_t.add
|
||||
*/
|
||||
static void add(private_radius_message_t *this, radius_attribute_type_t type,
|
||||
chunk_t data)
|
||||
{
|
||||
rattr_t *attribute;
|
||||
|
||||
this->msg = realloc(this->msg,
|
||||
ntohs(this->msg->length) + sizeof(rattr_t) + data.len);
|
||||
attribute = ((void*)this->msg) + ntohs(this->msg->length);
|
||||
attribute->type = type;
|
||||
attribute->length = data.len + sizeof(rattr_t);
|
||||
memcpy(attribute->value, data.ptr, data.len);
|
||||
this->msg->length = htons(ntohs(this->msg->length) + attribute->length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of radius_message_t.sign
|
||||
*/
|
||||
static void sign(private_radius_message_t *this, rng_t *rng, signer_t *signer)
|
||||
{
|
||||
char buf[HASH_SIZE_MD5];
|
||||
|
||||
/* build Request-Authenticator */
|
||||
rng->get_bytes(rng, HASH_SIZE_MD5, this->msg->authenticator);
|
||||
|
||||
/* build Message-Authenticator attribute, using 16 null bytes */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
add(this, RAT_MESSAGE_AUTHENTICATOR, chunk_create(buf, sizeof(buf)));
|
||||
signer->get_signature(signer,
|
||||
chunk_create((u_char*)this->msg, ntohs(this->msg->length)),
|
||||
((u_char*)this->msg) + ntohs(this->msg->length) - HASH_SIZE_MD5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of radius_message_t.verify
|
||||
*/
|
||||
static bool verify(private_radius_message_t *this, u_int8_t *req_auth,
|
||||
chunk_t secret, hasher_t *hasher, signer_t *signer)
|
||||
{
|
||||
char buf[HASH_SIZE_MD5], res_auth[HASH_SIZE_MD5];
|
||||
enumerator_t *enumerator;
|
||||
int type;
|
||||
chunk_t data, msg;
|
||||
|
||||
/* replace Response by Request Authenticator for verification */
|
||||
memcpy(res_auth, this->msg->authenticator, HASH_SIZE_MD5);
|
||||
memcpy(this->msg->authenticator, req_auth, HASH_SIZE_MD5);
|
||||
msg = chunk_create((u_char*)this->msg, ntohs(this->msg->length));
|
||||
|
||||
/* verify Response-Authenticator */
|
||||
hasher->get_hash(hasher, msg, NULL);
|
||||
hasher->get_hash(hasher, secret, buf);
|
||||
if (!memeq(buf, res_auth, HASH_SIZE_MD5))
|
||||
{
|
||||
DBG1(DBG_CFG, "RADIUS Response-Authenticator verification failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* verify Message-Authenticator attribute */
|
||||
enumerator = create_enumerator(this);
|
||||
while (enumerator->enumerate(enumerator, &type, &data))
|
||||
{
|
||||
if (type == RAT_MESSAGE_AUTHENTICATOR)
|
||||
{
|
||||
if (data.len != HASH_SIZE_MD5)
|
||||
{
|
||||
DBG1(DBG_CFG, "RADIUS Message-Authenticator invalid length");
|
||||
enumerator->destroy(enumerator);
|
||||
return FALSE;
|
||||
}
|
||||
memcpy(buf, data.ptr, data.len);
|
||||
memset(data.ptr, 0, data.len);
|
||||
if (signer->verify_signature(signer, msg,
|
||||
chunk_create(buf, sizeof(buf))))
|
||||
{ /* good, restore Authenticators */
|
||||
memcpy(this->msg->authenticator, res_auth, HASH_SIZE_MD5);
|
||||
memcpy(data.ptr, buf, data.len);
|
||||
enumerator->destroy(enumerator);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, "RADIUS Message-Authenticator verification failed");
|
||||
enumerator->destroy(enumerator);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
DBG1(DBG_CFG, "RADIUS Message-Authenticator attribute missing");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of radius_message_t.get_code
|
||||
*/
|
||||
static radius_message_code_t get_code(private_radius_message_t *this)
|
||||
{
|
||||
return this->msg->code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of radius_message_t.get_identifier
|
||||
*/
|
||||
static u_int8_t get_identifier(private_radius_message_t *this)
|
||||
{
|
||||
return this->msg->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of radius_message_t.set_identifier
|
||||
*/
|
||||
static void set_identifier(private_radius_message_t *this, u_int8_t identifier)
|
||||
{
|
||||
this->msg->identifier = identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of radius_message_t.get_authenticator
|
||||
*/
|
||||
static u_int8_t* get_authenticator(private_radius_message_t *this)
|
||||
{
|
||||
return this->msg->authenticator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of radius_message_t.get_encoding
|
||||
*/
|
||||
static chunk_t get_encoding(private_radius_message_t *this)
|
||||
{
|
||||
return chunk_create((u_char*)this->msg, ntohs(this->msg->length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of radius_message_t.destroy.
|
||||
*/
|
||||
static void destroy(private_radius_message_t *this)
|
||||
{
|
||||
free(this->msg);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic constructor
|
||||
*/
|
||||
static private_radius_message_t *radius_message_create()
|
||||
{
|
||||
private_radius_message_t *this = malloc_thing(private_radius_message_t);
|
||||
|
||||
this->public.create_enumerator = (enumerator_t*(*)(radius_message_t*))create_enumerator;
|
||||
this->public.add = (void(*)(radius_message_t*, radius_attribute_type_t,chunk_t))add;
|
||||
this->public.get_code = (radius_message_code_t(*)(radius_message_t*))get_code;
|
||||
this->public.get_identifier = (u_int8_t(*)(radius_message_t*))get_identifier;
|
||||
this->public.set_identifier = (void(*)(radius_message_t*, u_int8_t identifier))set_identifier;
|
||||
this->public.get_authenticator = (u_int8_t*(*)(radius_message_t*))get_authenticator;
|
||||
this->public.get_encoding = (chunk_t(*)(radius_message_t*))get_encoding;
|
||||
this->public.sign = (void(*)(radius_message_t*, rng_t *rng, signer_t *signer))sign;
|
||||
this->public.verify = (bool(*)(radius_message_t*, u_int8_t *req_auth, chunk_t secret, hasher_t *hasher, signer_t *signer))verify;
|
||||
this->public.destroy = (void(*)(radius_message_t*))destroy;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
radius_message_t *radius_message_create_request()
|
||||
{
|
||||
private_radius_message_t *this = radius_message_create();
|
||||
|
||||
this->msg = malloc_thing(rmsg_t);
|
||||
this->msg->code = RMC_ACCESS_REQUEST;
|
||||
this->msg->identifier = 0;
|
||||
this->msg->length = htons(sizeof(rmsg_t));
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
radius_message_t *radius_message_parse_response(chunk_t data)
|
||||
{
|
||||
private_radius_message_t *this = radius_message_create();
|
||||
|
||||
this->msg = malloc(data.len);
|
||||
memcpy(this->msg, data.ptr, data.len);
|
||||
if (data.len < sizeof(rmsg_t) ||
|
||||
ntohs(this->msg->length) != data.len)
|
||||
{
|
||||
DBG1(DBG_IKE, "RADIUS message has invalid length");
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup radius_message radius_message
|
||||
* @{ @ingroup eap_radius
|
||||
*/
|
||||
|
||||
#ifndef RADIUS_MESSAGE_H_
|
||||
#define RADIUS_MESSAGE_H_
|
||||
|
||||
#include <library.h>
|
||||
|
||||
typedef struct radius_message_t radius_message_t;
|
||||
typedef enum radius_message_code_t radius_message_code_t;
|
||||
typedef enum radius_attribute_type_t radius_attribute_type_t;
|
||||
|
||||
/**
|
||||
* RADIUS Message Codes.
|
||||
*/
|
||||
enum radius_message_code_t {
|
||||
RMC_ACCESS_REQUEST = 1,
|
||||
RMC_ACCESS_ACCEPT = 2,
|
||||
RMC_ACCESS_REJECT = 3,
|
||||
RMC_ACCOUNTING_REQUEST = 4,
|
||||
RMC_ACCOUNTING_RESPONSE = 5,
|
||||
RMC_ACCESS_CHALLENGE = 11,
|
||||
};
|
||||
|
||||
/**
|
||||
* Enum names for radius_attribute_type_t.
|
||||
*/
|
||||
extern enum_name_t *radius_message_code_names;
|
||||
|
||||
/**
|
||||
* RADIUS Attribute Types.
|
||||
*/
|
||||
enum radius_attribute_type_t {
|
||||
RAT_USER_NAME = 1,
|
||||
RAT_USER_PASSWORD = 2,
|
||||
RAT_CHAP_PASSWORD = 3,
|
||||
RAT_NAS_IP_ADDRESS = 4,
|
||||
RAT_NAS_PORT = 5,
|
||||
RAT_SERVICE_TYPE = 6,
|
||||
RAT_FRAMED_PROTOCOL = 7,
|
||||
RAT_FRAMED_IP_ADDRESS = 8,
|
||||
RAT_FRAMED_IP_NETMASK = 9,
|
||||
RAT_FRAMED_ROUTING = 10,
|
||||
RAT_FILTER_ID = 11,
|
||||
RAT_FRAMED_MTU = 12,
|
||||
RAT_FRAMED_COMPRESSION = 13,
|
||||
RAT_LOGIN_IP_HOST = 14,
|
||||
RAT_LOGIN_SERVICE = 15,
|
||||
RAT_LOGIN_TCP_PORT = 16,
|
||||
RAT_REPLY_MESSAGE = 18,
|
||||
RAT_CALLBACK_NUMBER = 19,
|
||||
RAT_CALLBACK_ID = 20,
|
||||
RAT_FRAMED_ROUTE = 22,
|
||||
RAT_FRAMED_IPX_NETWORK = 23,
|
||||
RAT_STATE = 24,
|
||||
RAT_CLASS = 25,
|
||||
RAT_VENDOR_SPECIFIC = 26,
|
||||
RAT_SESSION_TIMEOUT = 27,
|
||||
RAT_IDLE_TIMEOUT = 28,
|
||||
RAT_TERMINATION_ACTION = 29,
|
||||
RAT_CALLED_STATION_ID = 30,
|
||||
RAT_CALLING_STATION_ID = 31,
|
||||
RAT_NAS_IDENTIFIER = 32,
|
||||
RAT_PROXY_STATE = 33,
|
||||
RAT_LOGIN_LAT_SERVICE = 34,
|
||||
RAT_LOGIN_LAT_NODE = 35,
|
||||
RAT_LOGIN_LAT_GROUP = 36,
|
||||
RAT_FRAMED_APPLETALK_LINK = 37,
|
||||
RAT_FRAMED_APPLETALK_NETWORK = 38,
|
||||
RAT_FRAMED_APPLETALK_ZONE = 39,
|
||||
RAT_ACCT_STATUS_TYPE = 40,
|
||||
RAT_ACCT_DELAY_TIME = 41,
|
||||
RAT_ACCT_INPUT_OCTETS = 42,
|
||||
RAT_ACCT_OUTPUT_OCTETS = 43,
|
||||
RAT_ACCT_SESSION_ID = 44,
|
||||
RAT_ACCT_AUTHENTIC = 45,
|
||||
RAT_ACCT_SESSION_TIME = 46,
|
||||
RAT_ACCT_INPUT_PACKETS = 47,
|
||||
RAT_ACCT_OUTPUT_PACKETS = 48,
|
||||
RAT_ACCT_TERMINATE_CAUSE = 49,
|
||||
RAT_ACCT_MULTI_SESSION_ID = 50,
|
||||
RAT_ACCT_LINK_COUNT = 51,
|
||||
RAT_ACCT_INPUT_GIGAWORDS = 52,
|
||||
RAT_ACCT_OUTPUT_GIGAWORDS = 53,
|
||||
RAT_EVENT_TIMESTAMP = 55,
|
||||
RAT_EGRESS_VLANID = 56,
|
||||
RAT_INGRESS_FILTERS = 57,
|
||||
RAT_EGRESS_VLAN_NAME = 58,
|
||||
RAT_USER_PRIORITY_TABLE = 59,
|
||||
RAT_CHAP_CHALLENGE = 60,
|
||||
RAT_NAS_PORT_TYPE = 61,
|
||||
RAT_PORT_LIMIT = 62,
|
||||
RAT_LOGIN_LAT_PORT = 63,
|
||||
RAT_TUNNEL_TYPE = 64,
|
||||
RAT_TUNNEL_MEDIUM_TYPE = 65,
|
||||
RAT_TUNNEL_CLIENT_ENDPOINT = 66,
|
||||
RAT_TUNNEL_SERVER_ENDPOINT = 67,
|
||||
RAT_ACCT_TUNNEL_CONNECTION = 68,
|
||||
RAT_TUNNEL_PASSWORD = 69,
|
||||
RAT_ARAP_PASSWORD = 70,
|
||||
RAT_ARAP_FEATURES = 71,
|
||||
RAT_ARAP_ZONE_ACCESS = 72,
|
||||
RAT_ARAP_SECURITY = 73,
|
||||
RAT_ARAP_SECURITY_DATA = 74,
|
||||
RAT_PASSWORD_RETRY = 75,
|
||||
RAT_PROMPT = 76,
|
||||
RAT_CONNECT_INFO = 77,
|
||||
RAT_CONFIGURATION_TOKEN = 78,
|
||||
RAT_EAP_MESSAGE = 79,
|
||||
RAT_MESSAGE_AUTHENTICATOR = 80,
|
||||
RAT_TUNNEL_PRIVATE_GROUP_ID = 81,
|
||||
RAT_TUNNEL_ASSIGNMENT_ID = 82,
|
||||
RAT_TUNNEL_PREFERENCE = 83,
|
||||
RAT_ARAP_CHALLENGE_RESPONSE = 84,
|
||||
RAT_ACCT_INTERIM_INTERVAL = 85,
|
||||
RAT_ACCT_TUNNEL_PACKETS_LOST = 86,
|
||||
RAT_NAS_PORT_ID = 87,
|
||||
RAT_FRAMED_POOL = 88,
|
||||
RAT_CUI = 89,
|
||||
RAT_TUNNEL_CLIENT_AUTH_ID = 90,
|
||||
RAT_TUNNEL_SERVER_AUTH_ID = 91,
|
||||
RAT_NAS_FILTER_RULE = 92,
|
||||
RAT_UNASSIGNED = 93,
|
||||
RAT_ORIGINATING_LINE_INFO = 94,
|
||||
RAT_NAS_IPV6_ADDRESS = 95,
|
||||
RAT_FRAMED_INTERFACE_ID = 96,
|
||||
RAT_FRAMED_IPV6_PREFIX = 97,
|
||||
RAT_LOGIN_IPV6_HOST = 98,
|
||||
RAT_FRAMED_IPV6_ROUTE = 99,
|
||||
RAT_FRAMED_IPV6_POOL = 100,
|
||||
RAT_ERROR_CAUSE = 101,
|
||||
RAT_EAP_KEY_NAME = 102,
|
||||
RAT_DIGEST_RESPONSE = 103,
|
||||
RAT_DIGEST_REALM = 104,
|
||||
RAT_DIGEST_NONCE = 105,
|
||||
RAT_DIGEST_RESPONSE_AUTH = 106,
|
||||
RAT_DIGEST_NEXTNONCE = 107,
|
||||
RAT_DIGEST_METHOD = 108,
|
||||
RAT_DIGEST_URI = 109,
|
||||
RAT_DIGEST_QOP = 110,
|
||||
RAT_DIGEST_ALGORITHM = 111,
|
||||
RAT_DIGEST_ENTITY_BODY_HASH = 112,
|
||||
RAT_DIGEST_CNONCE = 113,
|
||||
RAT_DIGEST_NONCE_COUNT = 114,
|
||||
RAT_DIGEST_USERNAME = 115,
|
||||
RAT_DIGEST_OPAQUE = 116,
|
||||
RAT_DIGEST_AUTH_PARAM = 117,
|
||||
RAT_DIGEST_AKA_AUTS = 118,
|
||||
RAT_DIGEST_DOMAIN = 119,
|
||||
RAT_DIGEST_STALE = 120,
|
||||
RAT_DIGEST_HA1 = 121,
|
||||
RAT_SIP_AOR = 122,
|
||||
RAT_DELEGATED_IPV6_PREFIX = 123,
|
||||
RAT_MIP6_FEATURE_VECTOR = 124,
|
||||
RAT_MIP6_HOME_LINK_PREFIX = 125,
|
||||
};
|
||||
|
||||
/**
|
||||
* Enum names for radius_attribute_type_t.
|
||||
*/
|
||||
extern enum_name_t *radius_attribute_type_names;
|
||||
|
||||
/**
|
||||
* A RADIUS message, contains attributes.
|
||||
*/
|
||||
struct radius_message_t {
|
||||
|
||||
/**
|
||||
* Create an enumerator over contained RADIUS attributes.
|
||||
*
|
||||
* @return enumerator over (int type, chunk_t data)
|
||||
*/
|
||||
enumerator_t* (*create_enumerator)(radius_message_t *this);
|
||||
|
||||
/**
|
||||
* Add a RADIUS attribute to the message.
|
||||
*
|
||||
* @param type type of attribute to add
|
||||
* @param attribute data, gets cloned
|
||||
*/
|
||||
void (*add)(radius_message_t *this, radius_attribute_type_t type,
|
||||
chunk_t data);
|
||||
|
||||
/**
|
||||
* Get the message type (code).
|
||||
*
|
||||
* @return message code
|
||||
*/
|
||||
radius_message_code_t (*get_code)(radius_message_t *this);
|
||||
|
||||
/**
|
||||
* Get the message identifier.
|
||||
*
|
||||
* @return message identifier
|
||||
*/
|
||||
u_int8_t (*get_identifier)(radius_message_t *this);
|
||||
|
||||
/**
|
||||
* Set the message identifier.
|
||||
*
|
||||
* @param identifier message identifier
|
||||
*/
|
||||
void (*set_identifier)(radius_message_t *this, u_int8_t identifier);
|
||||
|
||||
/**
|
||||
* Get the 16 byte authenticator.
|
||||
*
|
||||
* @return pointer to the Authenticator field
|
||||
*/
|
||||
u_int8_t* (*get_authenticator)(radius_message_t *this);
|
||||
|
||||
/**
|
||||
* Get the RADIUS message in its encoded form.
|
||||
*
|
||||
* @return chunk pointing to internal RADIUS message.
|
||||
*/
|
||||
chunk_t (*get_encoding)(radius_message_t *this);
|
||||
|
||||
/**
|
||||
* Calculate and add the Message-Authenticator attribute to the message.
|
||||
*
|
||||
* @param rng RNG to create Request-Authenticator
|
||||
* @param signer HMAC-MD5 signer with secret set
|
||||
*/
|
||||
void (*sign)(radius_message_t *this, rng_t *rng, signer_t *signer);
|
||||
|
||||
/**
|
||||
* Verify the integrity of a received RADIUS response.
|
||||
*
|
||||
* @param req_auth 16 byte Authenticator of the corresponding request
|
||||
* @param secret shared RADIUS secret
|
||||
* @param hasher hasher to verify Response-Authenticator
|
||||
* @param signer signer to verify Message-Authenticator attribute
|
||||
*/
|
||||
bool (*verify)(radius_message_t *this, u_int8_t *req_auth, chunk_t secret,
|
||||
hasher_t *hasher, signer_t *signer);
|
||||
|
||||
/**
|
||||
* Destroy the message.
|
||||
*/
|
||||
void (*destroy)(radius_message_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an empty RADIUS request message (RMT_ACCESS_REQUEST).
|
||||
*
|
||||
* @param identifier RADIUS message identifier
|
||||
* @return radius_message_t object
|
||||
*/
|
||||
radius_message_t *radius_message_create_request();
|
||||
|
||||
/**
|
||||
* Parse and verify a recevied RADIUS response.
|
||||
*
|
||||
* @param data received message data
|
||||
* @return radius_message_t object, NULL if length invalid
|
||||
*/
|
||||
radius_message_t *radius_message_parse_response(chunk_t data);
|
||||
|
||||
#endif /* RADIUS_MESSAGE_H_ @}*/
|
|
@ -30,7 +30,8 @@ ENUM_NEXT(eap_type_names, EAP_AKA, EAP_AKA, EAP_SIM,
|
|||
"EAP_AKA");
|
||||
ENUM_NEXT(eap_type_names, EAP_MSCHAPV2, EAP_MSCHAPV2, EAP_AKA,
|
||||
"EAP_MSCHAPV2");
|
||||
ENUM_NEXT(eap_type_names, EAP_EXPANDED, EAP_EXPERIMENTAL, EAP_MSCHAPV2,
|
||||
ENUM_NEXT(eap_type_names, EAP_RADIUS, EAP_EXPERIMENTAL, EAP_MSCHAPV2,
|
||||
"EAP_RADIUS",
|
||||
"EAP_EXPANDED",
|
||||
"EAP_EXPERIMENTAL");
|
||||
ENUM_END(eap_type_names, EAP_EXPERIMENTAL);
|
||||
|
|
|
@ -57,6 +57,8 @@ enum eap_type_t {
|
|||
EAP_SIM = 18,
|
||||
EAP_AKA = 23,
|
||||
EAP_MSCHAPV2 = 26,
|
||||
/** not a method, but an implementation providing different methods */
|
||||
EAP_RADIUS = 253,
|
||||
EAP_EXPANDED = 254,
|
||||
EAP_EXPERIMENTAL = 255,
|
||||
};
|
||||
|
|
|
@ -141,7 +141,8 @@ static identification_t *get_peer_id(private_eap_authenticator_t *this)
|
|||
{
|
||||
config = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
auth = config->get_auth(config);
|
||||
if (!auth->get_item(auth, AUTHN_EAP_IDENTITY, (void**)&id))
|
||||
if (!auth->get_item(auth, AUTHN_EAP_IDENTITY, (void**)&id) ||
|
||||
id->get_type(id) == ID_ANY)
|
||||
{
|
||||
if (this->role == EAP_PEER)
|
||||
{
|
||||
|
@ -252,7 +253,7 @@ static status_t initiate(private_eap_authenticator_t *this, eap_type_t type,
|
|||
if (this->method->initiate(this->method, out) != NEED_MORE)
|
||||
{
|
||||
DBG1(DBG_IKE, "failed to initiate EAP exchange, sending %N",
|
||||
eap_type_names, type, eap_code_names, EAP_FAILURE);
|
||||
eap_code_names, EAP_FAILURE);
|
||||
*out = eap_payload_create_code(EAP_FAILURE, 0);
|
||||
return FAILED;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ enum integrity_algorithm_t {
|
|||
AUTH_HMAC_SHA2_512_256 = 14,
|
||||
/** Implemented via hmac_signer_t */
|
||||
AUTH_HMAC_SHA1_128 = 1025,
|
||||
/** Implemented via hmac_signer_t */
|
||||
AUTH_HMAC_MD5_128 = 1026,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -74,6 +74,8 @@ plugin_t *plugin_create()
|
|||
(signer_constructor_t)hmac_signer_create);
|
||||
lib->crypto->add_signer(lib->crypto, AUTH_HMAC_MD5_96,
|
||||
(signer_constructor_t)hmac_signer_create);
|
||||
lib->crypto->add_signer(lib->crypto, AUTH_HMAC_MD5_128,
|
||||
(signer_constructor_t)hmac_signer_create);
|
||||
lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA2_384_192,
|
||||
(signer_constructor_t)hmac_signer_create);
|
||||
lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA2_512_256,
|
||||
|
|
|
@ -159,6 +159,10 @@ hmac_signer_t *hmac_signer_create(integrity_algorithm_t algo)
|
|||
hash = HASH_MD5;
|
||||
trunc = 12;
|
||||
break;
|
||||
case AUTH_HMAC_MD5_128:
|
||||
hash = HASH_MD5;
|
||||
trunc = 16;
|
||||
break;
|
||||
case AUTH_HMAC_SHA2_256_128:
|
||||
hash = HASH_SHA256;
|
||||
trunc = 16;
|
||||
|
|
|
@ -625,6 +625,10 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg)
|
|||
{
|
||||
conn->eap_type = 26;
|
||||
}
|
||||
else if (streq(kw->value, "radius"))
|
||||
{ /* pseudo-type */
|
||||
conn->eap_type = 253;
|
||||
}
|
||||
else
|
||||
{
|
||||
conn->eap_type = atoi(kw->value);
|
||||
|
|
|
@ -369,6 +369,10 @@ in the form
|
|||
(e.g.
|
||||
.B eap=7-12345
|
||||
) can be used to specify vendor specific EAP types.
|
||||
|
||||
To forward EAP authentication to a RADIUS server using the EAP-RADIUS plugin,
|
||||
set
|
||||
.B eap=radius
|
||||
.TP
|
||||
.B eap_identity
|
||||
defines the identity the client uses to reply to a EAP Identity request.
|
||||
|
|
Loading…
Reference in New Issue