merged EAP framework from branch into trunk
includes a lot of other modifications
This commit is contained in:
+24
-5
@@ -19,9 +19,7 @@ dnl ===========================
|
||||
AC_INIT(strongSwan,4.0.8)
|
||||
AM_INIT_AUTOMAKE(tar-ustar)
|
||||
AC_C_BIGENDIAN
|
||||
AC_SUBST(ipsecdir, '${libexecdir}/ipsec')
|
||||
AC_SUBST(confdir, '${sysconfdir}')
|
||||
AC_SUBST(piddir, '/var/run')
|
||||
|
||||
dnl =================================
|
||||
dnl check --enable-xxx & --with-xxx
|
||||
@@ -30,7 +28,7 @@ dnl =================================
|
||||
|
||||
AC_ARG_WITH(
|
||||
[default-pkcs11],
|
||||
AS_HELP_STRING([--with-default-pkcs11=lib],[set the default PKCS11 library other than /usr/lib/opensc-pkcs11.so]),
|
||||
AS_HELP_STRING([--with-default-pkcs11=lib],[set the default PKCS11 library other than "/usr/lib/opensc-pkcs11.so"]),
|
||||
[AC_DEFINE_UNQUOTED(PKCS11_DEFAULT_LIB, "$withval")],
|
||||
[AC_DEFINE_UNQUOTED(PKCS11_DEFAULT_LIB, "/usr/lib/opensc-pkcs11.so")]
|
||||
)
|
||||
@@ -43,18 +41,39 @@ AC_ARG_WITH(
|
||||
|
||||
AC_ARG_WITH(
|
||||
[random-device],
|
||||
AS_HELP_STRING([--with-random-device=dev],[set the device for real random data other than /dev/random]),
|
||||
AS_HELP_STRING([--with-random-device=dev],[set the device for real random data other than "/dev/random"]),
|
||||
[AC_DEFINE_UNQUOTED(DEV_RANDOM, "$withval")],
|
||||
[AC_DEFINE_UNQUOTED(DEV_RANDOM, "/dev/random")]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(
|
||||
[urandom-device],
|
||||
AS_HELP_STRING([--with-urandom-device=dev],[set the device for pseudo random data other than /dev/urandom]),
|
||||
AS_HELP_STRING([--with-urandom-device=dev],[set the device for pseudo random data other than "/dev/urandom"]),
|
||||
[AC_DEFINE_UNQUOTED(DEV_URANDOM, "$withval")],
|
||||
[AC_DEFINE_UNQUOTED(DEV_URANDOM, "/dev/urandom")]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(
|
||||
[ipsecdir],
|
||||
AS_HELP_STRING([--with-ipsecdir=dir],[installation path for ipsec tools other than "libexecdir/ipsec"]),
|
||||
[AC_SUBST(ipsecdir, "$withval")],
|
||||
[AC_SUBST(ipsecdir, "${libexecdir}/ipsec")]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(
|
||||
[piddir],
|
||||
AS_HELP_STRING([--with-piddir=dir],[path for PID and UNIX socket files other than "/var/run"]),
|
||||
[AC_SUBST(piddir, "$withval")],
|
||||
[AC_SUBST(piddir, "/var/run")]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(
|
||||
[eapdir],
|
||||
AS_HELP_STRING([--with-eapdir=dir],[path for pluggable EAP modules other than "ipsecdir/eap"]),
|
||||
[AC_SUBST(eapdir, "$withval")],
|
||||
[AC_SUBST(eapdir, "${ipsecdir}/eap")]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[http],
|
||||
AS_HELP_STRING([--enable-http],[enable OCSP and fetching of Certificates and CRLs over HTTP (default is NO). Requires libcurl.]),
|
||||
|
||||
+3
-1
@@ -1,2 +1,4 @@
|
||||
#!/bin/bash
|
||||
CFLAGS="-Wall -Wno-format -Wno-pointer-sign -Wno-strict-aliasing -g -O2" ./configure --sysconfdir=/etc --with-random-device=/dev/urandom --enable-ldap --enable-http --enable-leak-detective
|
||||
CFLAGS="-Wall -Wno-format -Wno-pointer-sign -Wno-strict-aliasing -g -O2" ./configure \
|
||||
--sysconfdir=/etc --with-random-device=/dev/urandom --enable-ldap --enable-http \
|
||||
--enable-leak-detective
|
||||
|
||||
+2
-1
@@ -1,2 +1,3 @@
|
||||
#!/bin/bash
|
||||
CFLAGS="-Wall -Wno-format -Wno-pointer-sign -Wno-strict-aliasing -O2 -DDEBUG_LEVEL=0" ./configure --sysconfdir=/etc --with-random-device=/dev/urandom --enable-ldap --enable-http
|
||||
CFLAGS="-Wall -Wno-format -Wno-pointer-sign -Wno-strict-aliasing -O2 -DDEBUG_LEVEL=0" ./configure \
|
||||
--sysconfdir=/etc --with-random-device=/dev/urandom --enable-ldap --enable-http
|
||||
|
||||
+2
-1
@@ -1,2 +1,3 @@
|
||||
#!/bin/bash
|
||||
CFLAGS="-Wall -Wno-format -Wno-pointer-sign -Wno-strict-aliasing -g -O2" ./configure --sysconfdir=/etc --with-random-device=/dev/urandom --enable-ldap --enable-http
|
||||
CFLAGS="-Wall -Wno-format -Wno-pointer-sign -Wno-strict-aliasing -g -O2" ./configure \
|
||||
--sysconfdir=/etc --with-random-device=/dev/urandom --enable-ldap --enable-http
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# SUBDIRS = . testing
|
||||
|
||||
eap_LTLIBRARIES =
|
||||
|
||||
# build optional EAP modules
|
||||
|
||||
ipsec_PROGRAMS = charon
|
||||
|
||||
charon_SOURCES = \
|
||||
@@ -24,6 +28,8 @@ sa/transactions/rekey_ike_sa.h sa/transactions/rekey_ike_sa.c \
|
||||
sa/authenticators/authenticator.h sa/authenticators/authenticator.c \
|
||||
sa/authenticators/rsa_authenticator.h sa/authenticators/rsa_authenticator.c \
|
||||
sa/authenticators/psk_authenticator.h sa/authenticators/psk_authenticator.c \
|
||||
sa/authenticators/eap_authenticator.h sa/authenticators/eap_authenticator.c \
|
||||
sa/authenticators/eap/eap_method.h sa/authenticators/eap/eap_method.c \
|
||||
sa/child_sa.c sa/child_sa.h sa/ike_sa.c sa/ike_sa.h sa/ike_sa_manager.c sa/ike_sa_manager.h \
|
||||
sa/ike_sa_id.c sa/ike_sa_id.h encoding/payloads/encryption_payload.c \
|
||||
encoding/payloads/cert_payload.c encoding/payloads/payload.h encoding/payloads/traffic_selector_substructure.c \
|
||||
@@ -59,5 +65,5 @@ threads/sender.h threads/kernel_interface.h threads/scheduler.h threads/receiver
|
||||
threads/thread_pool.h threads/receiver.h threads/stroke_interface.h
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon -I$(top_srcdir)/src/stroke
|
||||
AM_CFLAGS = -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\"
|
||||
charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lgmp -lpthread -lm
|
||||
AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_EAPDIR=\"${eapdir}\"
|
||||
charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lgmp -lpthread -lm -ldl
|
||||
|
||||
@@ -92,8 +92,7 @@ static bool contains_traffic_selectors(policy_t *policy, bool mine,
|
||||
static policy_t *get_policy(private_local_policy_store_t *this,
|
||||
identification_t *my_id, identification_t *other_id,
|
||||
linked_list_t *my_ts, linked_list_t *other_ts,
|
||||
host_t *my_host, host_t *other_host,
|
||||
linked_list_t *requested_ca_keyids)
|
||||
host_t *my_host, host_t *other_host)
|
||||
{
|
||||
typedef enum {
|
||||
PRIO_UNDEFINED = 0x00,
|
||||
@@ -254,7 +253,7 @@ local_policy_store_t *local_policy_store_create(void)
|
||||
|
||||
this->public.policy_store.add_policy = (void (*) (policy_store_t*,policy_t*))add_policy;
|
||||
this->public.policy_store.get_policy = (policy_t* (*) (policy_store_t*,identification_t*,identification_t*,
|
||||
linked_list_t*,linked_list_t*,host_t*,host_t*,linked_list_t*))get_policy;
|
||||
linked_list_t*,linked_list_t*,host_t*,host_t*))get_policy;
|
||||
this->public.policy_store.get_policy_by_name = (policy_t* (*) (policy_store_t*,char*))get_policy_by_name;
|
||||
this->public.policy_store.delete_policy = (status_t (*) (policy_store_t*,char*))delete_policy;
|
||||
this->public.policy_store.create_iterator = (iterator_t* (*) (policy_store_t*))create_iterator;
|
||||
|
||||
@@ -83,6 +83,11 @@ struct private_policy_t {
|
||||
*/
|
||||
auth_method_t auth_method;
|
||||
|
||||
/**
|
||||
* EAP type to use for peer authentication
|
||||
*/
|
||||
eap_type_t eap_type;
|
||||
|
||||
/**
|
||||
* we have a cert issued by this CA
|
||||
*/
|
||||
@@ -193,6 +198,14 @@ static auth_method_t get_auth_method(private_policy_t *this)
|
||||
return this->auth_method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of connection_t.get_eap_type.
|
||||
*/
|
||||
static eap_type_t get_eap_type(private_policy_t *this)
|
||||
{
|
||||
return this->eap_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get traffic selectors, with wildcard-address update
|
||||
*/
|
||||
@@ -492,7 +505,7 @@ static void destroy(private_policy_t *this)
|
||||
* Described in header-file
|
||||
*/
|
||||
policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id,
|
||||
auth_method_t auth_method,
|
||||
auth_method_t auth_method, eap_type_t eap_type,
|
||||
u_int32_t hard_lifetime, u_int32_t soft_lifetime,
|
||||
u_int32_t jitter, char *updown, bool hostaccess,
|
||||
mode_t mode, dpd_action_t dpd_action)
|
||||
@@ -506,6 +519,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
|
||||
this->public.get_my_ca = (identification_t* (*) (policy_t*))get_my_ca;
|
||||
this->public.get_other_ca = (identification_t* (*) (policy_t*))get_other_ca;
|
||||
this->public.get_auth_method = (auth_method_t (*) (policy_t*)) get_auth_method;
|
||||
this->public.get_eap_type = (eap_type_t (*) (policy_t*)) get_eap_type;
|
||||
this->public.get_my_traffic_selectors = (linked_list_t* (*) (policy_t*,host_t*))get_my_traffic_selectors;
|
||||
this->public.get_other_traffic_selectors = (linked_list_t* (*) (policy_t*,host_t*))get_other_traffic_selectors;
|
||||
this->public.select_my_traffic_selectors = (linked_list_t* (*) (policy_t*,linked_list_t*,host_t*))select_my_traffic_selectors;
|
||||
@@ -530,6 +544,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
|
||||
this->my_id = my_id;
|
||||
this->other_id = other_id;
|
||||
this->auth_method = auth_method;
|
||||
this->eap_type = eap_type;
|
||||
this->hard_lifetime = hard_lifetime;
|
||||
this->soft_lifetime = soft_lifetime;
|
||||
this->jitter = jitter;
|
||||
|
||||
@@ -32,6 +32,7 @@ typedef struct policy_t policy_t;
|
||||
#include <config/traffic_selector.h>
|
||||
#include <config/proposal.h>
|
||||
#include <sa/authenticators/authenticator.h>
|
||||
#include <sa/authenticators/eap/eap_method.h>
|
||||
|
||||
|
||||
/**
|
||||
@@ -148,6 +149,14 @@ struct policy_t {
|
||||
* @return authentication method
|
||||
*/
|
||||
auth_method_t (*get_auth_method) (policy_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the EAP type to use for peer authentication.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return authentication method
|
||||
*/
|
||||
eap_type_t (*get_eap_type) (policy_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get configured traffic selectors for our site.
|
||||
@@ -358,6 +367,7 @@ struct policy_t {
|
||||
* @param my_id identification_t for ourselves
|
||||
* @param other_id identification_t for the remote guy
|
||||
* @param auth_method Authentication method to use for our(!) auth data
|
||||
* @param eap_type EAP type to use for peer authentication
|
||||
* @param hard_lifetime lifetime before deleting an SA
|
||||
* @param soft_lifetime lifetime before rekeying an SA
|
||||
* @param jitter range of randomization time
|
||||
@@ -371,7 +381,7 @@ struct policy_t {
|
||||
*/
|
||||
policy_t *policy_create(char *name,
|
||||
identification_t *my_id, identification_t *other_id,
|
||||
auth_method_t auth_method,
|
||||
auth_method_t auth_method, eap_type_t eap_type,
|
||||
u_int32_t hard_lifetime, u_int32_t soft_lifetime,
|
||||
u_int32_t jitter, char *updown, bool hostaccess,
|
||||
mode_t mode, dpd_action_t dpd_action);
|
||||
|
||||
@@ -49,14 +49,13 @@ struct policy_store_t {
|
||||
* other_id must be fully qualified. my_id may be %any, as the
|
||||
* other peer may not include an IDr Request.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param my_id own ID of the policy
|
||||
* @param other_id others ID of the policy
|
||||
* @param my_ts traffic selectors requested for local host
|
||||
* @param other_ts traffic selectors requested for remote host
|
||||
* @param my_host host to use for wilcards in TS compare
|
||||
* @param other_host host to use for wildcards in TS compare
|
||||
* @param requested_ca_keyids list of requested CA keyids
|
||||
* @param this calling object
|
||||
* @param my_id own ID of the policy
|
||||
* @param other_id others ID of the policy
|
||||
* @param my_ts traffic selectors requested for local host
|
||||
* @param other_ts traffic selectors requested for remote host
|
||||
* @param my_host host to use for wilcards in TS compare
|
||||
* @param other_host host to use for wildcards in TS compare
|
||||
* @return
|
||||
* - matching policy_t, if found
|
||||
* - NULL otherwise
|
||||
@@ -64,8 +63,7 @@ struct policy_store_t {
|
||||
policy_t *(*get_policy) (policy_store_t *this,
|
||||
identification_t *my_id, identification_t *other_id,
|
||||
linked_list_t *my_ts, linked_list_t *other_ts,
|
||||
host_t *my_host, host_t* other_host,
|
||||
linked_list_t *requested_ca_keyids);
|
||||
host_t *my_host, host_t* other_host);
|
||||
|
||||
/**
|
||||
* @brief Returns a policy identified by a connection name.
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <config/credentials/local_credential_store.h>
|
||||
#include <config/connections/local_connection_store.h>
|
||||
#include <config/policies/local_policy_store.h>
|
||||
#include <sa/authenticators/eap/eap_method.h>
|
||||
|
||||
|
||||
typedef struct private_daemon_t private_daemon_t;
|
||||
@@ -393,6 +394,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
bool strict_crl_policy = FALSE;
|
||||
bool use_syslog = FALSE;
|
||||
char *eapdir = IPSEC_EAPDIR;
|
||||
|
||||
private_daemon_t *private_charon;
|
||||
FILE *pid_file;
|
||||
@@ -416,6 +418,7 @@ int main(int argc, char *argv[])
|
||||
{ "version", no_argument, NULL, 'v' },
|
||||
{ "use-syslog", no_argument, NULL, 'l' },
|
||||
{ "strictcrlpolicy", no_argument, NULL, 'r' },
|
||||
{ "eapdir", required_argument, NULL, 'e' },
|
||||
/* TODO: handle "debug-all" */
|
||||
{ "debug-dmn", required_argument, &signal, DBG_DMN },
|
||||
{ "debug-mgr", required_argument, &signal, DBG_MGR },
|
||||
@@ -447,6 +450,9 @@ int main(int argc, char *argv[])
|
||||
case 'r':
|
||||
strict_crl_policy = TRUE;
|
||||
continue;
|
||||
case 'e':
|
||||
eapdir = optarg;
|
||||
continue;
|
||||
case 0:
|
||||
/* option is in signal */
|
||||
levels[signal] = atoi(optarg);
|
||||
@@ -463,6 +469,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* initialize daemon */
|
||||
initialize(private_charon, strict_crl_policy, use_syslog, levels);
|
||||
/* load pluggable EAP modules */
|
||||
eap_method_load(eapdir);
|
||||
|
||||
/* check/setup PID file */
|
||||
if (stat(PID_FILE, &stb) == 0)
|
||||
@@ -477,6 +485,7 @@ int main(int argc, char *argv[])
|
||||
fprintf(pid_file, "%d\n", getpid());
|
||||
fclose(pid_file);
|
||||
}
|
||||
|
||||
/* log socket info */
|
||||
list = charon->socket->create_local_address_list(charon->socket);
|
||||
DBG1(DBG_NET, "listening on %d addresses:", list->get_count(list));
|
||||
@@ -490,6 +499,7 @@ int main(int argc, char *argv[])
|
||||
/* run daemon */
|
||||
run(private_charon);
|
||||
|
||||
eap_method_unload();
|
||||
/* normal termination, cleanup and exit */
|
||||
destroy(private_charon);
|
||||
unlink(PID_FILE);
|
||||
|
||||
@@ -179,6 +179,14 @@ typedef struct daemon_t daemon_t;
|
||||
* @ingroup sa
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup eap eap
|
||||
*
|
||||
* EAP authentication module interface and it's implementations.
|
||||
*
|
||||
* @ingroup authenticators
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup threads threads
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,619 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group P. Eronen
|
||||
Request for Comments: 4739 Nokia
|
||||
Category: Experimental J. Korhonen
|
||||
TeliaSonera
|
||||
November 2006
|
||||
|
||||
|
||||
Multiple Authentication Exchanges
|
||||
in the Internet Key Exchange (IKEv2) Protocol
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This memo defines an Experimental Protocol for the Internet
|
||||
community. It does not specify an Internet standard of any kind.
|
||||
Discussion and suggestions for improvement are requested.
|
||||
Distribution of this memo is unlimited.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The IETF Trust (2006).
|
||||
|
||||
Abstract
|
||||
|
||||
The Internet Key Exchange (IKEv2) protocol supports several
|
||||
mechanisms for authenticating the parties, including signatures with
|
||||
public-key certificates, shared secrets, and Extensible
|
||||
Authentication Protocol (EAP) methods. Currently, each endpoint uses
|
||||
only one of these mechanisms to authenticate itself. This document
|
||||
specifies an extension to IKEv2 that allows the use of multiple
|
||||
authentication exchanges, using either different mechanisms or the
|
||||
same mechanism. This extension allows, for instance, performing
|
||||
certificate-based authentication of the client host followed by an
|
||||
EAP authentication of the user. When backend authentication servers
|
||||
are used, they can belong to different administrative domains, such
|
||||
as the network access provider and the service provider.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Eronen & Korhonen Experimental [Page 1]
|
||||
|
||||
RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006
|
||||
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction ....................................................3
|
||||
1.1. Usage Scenarios ............................................4
|
||||
1.2. Terminology ................................................5
|
||||
2. Solution ........................................................5
|
||||
2.1. Solution Overview ..........................................5
|
||||
2.2. Example 1: Multiple EAP Authentications ....................6
|
||||
2.3. Example 2: Mixed EAP and Certificate Authentications .......7
|
||||
2.4. Example 3: Multiple Initiator Certificates .................8
|
||||
2.5. Example 4: Multiple Responder Certificates .................8
|
||||
3. Payload Formats .................................................9
|
||||
3.1. MULTIPLE_AUTH_SUPPORTED Notify Payload .....................9
|
||||
3.2. ANOTHER_AUTH_FOLLOWS Notify Payload ........................9
|
||||
4. IANA Considerations .............................................9
|
||||
5. Security Considerations .........................................9
|
||||
6. Acknowledgments ................................................10
|
||||
7. References .....................................................10
|
||||
7.1. Normative References ......................................10
|
||||
7.2. Informative References ....................................10
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Eronen & Korhonen Experimental [Page 2]
|
||||
|
||||
RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006
|
||||
|
||||
|
||||
1. Introduction
|
||||
|
||||
IKEv2 [IKEv2] supports several mechanisms for parties involved in the
|
||||
IKE_SA (IKE security association). These include signatures with
|
||||
public-key certificates, shared secrets, and Extensible
|
||||
Authentication Protocol (EAP) methods.
|
||||
|
||||
Currently, each endpoint uses only one of these mechanisms to
|
||||
authenticate itself. However, there are scenarios where making the
|
||||
authorization decision in IKEv2 (whether to allow access or not)
|
||||
requires using several of these methods.
|
||||
|
||||
For instance, it may be necessary to authenticate both the host
|
||||
(machine) requesting access, and the user currently using the host.
|
||||
These two authentications would use two separate sets of credentials
|
||||
(such as certificates and associated private keys) and might even use
|
||||
different authentication mechanisms.
|
||||
|
||||
To take another example, when an operator is hosting a Virtual
|
||||
Private Network (VPN) gateway service for a third party, it may be
|
||||
necessary to authenticate the client to both the operator (for
|
||||
billing purposes) and the third party's Authentication,
|
||||
Authorization, and Accounting (AAA) server (for authorizing access to
|
||||
the third party's internal network).
|
||||
|
||||
This document specifies an extension to IKEv2 that allows the use of
|
||||
multiple authentication exchanges, using either different mechanisms
|
||||
or the same mechanism. This extension allows, for instance,
|
||||
performing certificate-based authentication of the client host
|
||||
followed by an EAP authentication of the user.
|
||||
|
||||
Each authentication exchange requiring communication with backend AAA
|
||||
servers may be directed to different backend AAA servers, located
|
||||
even in different administrative domains. However, details of the
|
||||
communication between the IKEv2 gateway and the backend
|
||||
authentication servers are beyond the scope of this document. In
|
||||
particular, this document does not specify any changes to existing
|
||||
AAA protocols, and it does not require the use of any particular AAA
|
||||
protocol.
|
||||
|
||||
In case of several EAP authentications, it is important to notice
|
||||
that they are not a "sequence" (as described in Section 2.1 of
|
||||
[EAP]), but separate independent EAP conversations, which are usually
|
||||
also terminated in different EAP servers. Multiple authentication
|
||||
methods within a single EAP conversation are still prohibited as
|
||||
described in Section 2.1 of [EAP]. Using multiple independent EAP
|
||||
conversations is similar to the separate Network Access Provider
|
||||
(NAP) and Internet Service Provider (ISP) authentication exchanges
|
||||
|
||||
|
||||
|
||||
Eronen & Korhonen Experimental [Page 3]
|
||||
|
||||
RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006
|
||||
|
||||
|
||||
planned for [PANA]. The discovery of the appropriate EAP server for
|
||||
each EAP authentication conversation is based on AAA routing.
|
||||
|
||||
1.1. Usage Scenarios
|
||||
|
||||
Figure 1 shows an example architecture of an operator-hosted VPN
|
||||
scenario that could benefit from a two-phase authentication within
|
||||
the IKEv2 exchange. First, the client authenticates towards the
|
||||
Network Access Provider (NAP) and gets access to the NAP-hosted VPN
|
||||
gateway. The first-phase authentication involves the backend AAA
|
||||
server of the NAP. After the first authentication, the client
|
||||
initiates the second authentication round that also involves the
|
||||
Third Party's backend AAA server. If both authentications succeed,
|
||||
the required IPsec tunnels are set up and the client can access
|
||||
protected networks behind the Third Party.
|
||||
|
||||
|
||||
Client *Network Access Provider*
|
||||
+---------+ +---------+ +-----+
|
||||
| | | NAP's | | NAP |
|
||||
|Protected| IPsec SAs | Tunnel | AAA Protocol | AAA |
|
||||
|Endpoint |<------------------>|Endpoint |<------------>|Serv/|
|
||||
| | | | |Proxy|
|
||||
+---------+ +---------+ +-----+
|
||||
^ ^
|
||||
IPsec or / AAA |
|
||||
Leased Line / Protocol |
|
||||
/ |
|
||||
v |
|
||||
+---------+ *Third Party* v
|
||||
|3rd Party| +-----+
|
||||
Protected | Tunnel | | 3rd |
|
||||
Subnet <----|Endpoint | |Party|
|
||||
| | | AAA |
|
||||
+---------+ +-----+
|
||||
|
||||
Figure 1: Two-phase authentication used to gain access to
|
||||
the Third Party network via Network Access Provider. AAA
|
||||
traffic goes through NAP's AAA server.
|
||||
|
||||
The NAP's AAA server can be used to proxy the AAA traffic to the
|
||||
Third Party's backend AAA server. Alternatively, the AAA traffic
|
||||
from the NAP's tunnel endpoint could go directly to the Third Party's
|
||||
backend AAA servers. However, this is more or less an AAA routing
|
||||
issue.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Eronen & Korhonen Experimental [Page 4]
|
||||
|
||||
RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006
|
||||
|
||||
|
||||
1.2. Terminology
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in [KEYWORDS].
|
||||
|
||||
The terms and abbreviations "authenticator", "backend authentication
|
||||
server", "EAP server", and "peer" in this document are to be
|
||||
interpreted as described in [EAP].
|
||||
|
||||
When messages containing IKEv2 payloads are described, optional
|
||||
payloads are shown in brackets (for instance, "[FOO]"), and a plus
|
||||
sign indicates that a payload can be repeated one or more times (for
|
||||
instance, "FOO+").
|
||||
|
||||
2. Solution
|
||||
|
||||
2.1. Solution Overview
|
||||
|
||||
The peers announce support for this IKEv2 extension by including a
|
||||
MULTIPLE_AUTH_SUPPORTED notification in the IKE_SA_INIT response
|
||||
(responder) and the first IKE_AUTH request (initiator).
|
||||
|
||||
If both peers support this extension, either of them can announce
|
||||
that it wishes to have a second authentication by including an
|
||||
ANOTHER_AUTH_FOLLOWS notification in any IKE_AUTH message that
|
||||
contains an AUTH payload. This indicates that the peer sending the
|
||||
ANOTHER_AUTH_FOLLOWS wishes to authenticate another set of
|
||||
credentials to the other peer. The next IKE_AUTH message sent by
|
||||
this peer will contain a second identity payload (IDi or IDr) and
|
||||
starts another authentication exchange. The IKE_AUTH phase is
|
||||
considered successful only if all the individual authentication
|
||||
exchanges complete successfully.
|
||||
|
||||
It is assumed that both peers know what credentials they want to
|
||||
present; there is no negotiation about, for instance, what type of
|
||||
authentication is to be done. As in IKEv2, EAP-based authentication
|
||||
is always requested by the initiator (by omitting the AUTH payload).
|
||||
|
||||
The AUTH payloads are calculated as specified in [IKEv2] Sections
|
||||
2.15 and 2.16, where IDi' refers to the latest IDi payload sent by
|
||||
the initiator, and IDr' refers to the latest IDr payload sent by the
|
||||
responder. If EAP methods that do not generate shared keys are used,
|
||||
it is possible that several AUTH payloads with identical contents are
|
||||
sent. When such EAP methods are used, the purpose of the AUTH
|
||||
payload is simply to delimit the authentication exchanges, and ensure
|
||||
that the IKE_SA_INIT request/response messages were not modified.
|
||||
|
||||
|
||||
|
||||
|
||||
Eronen & Korhonen Experimental [Page 5]
|
||||
|
||||
RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006
|
||||
|
||||
|
||||
2.2. Example 1: Multiple EAP Authentications
|
||||
|
||||
This example shows certificate-based authentication of the responder
|
||||
followed by an EAP authentication exchange (messages 1-10). When the
|
||||
first EAP exchange is ending (the initiator is sending its AUTH
|
||||
payload), the initiator announces that it wishes to have a second
|
||||
authentication exchange by including an ANOTHER_AUTH_FOLLOWS
|
||||
notification (message 9).
|
||||
|
||||
After this, a second authentication exchange begins. The initiator
|
||||
sends a new IDi payload but no AUTH payload (message 11), indicating
|
||||
that EAP will be used. After that, another EAP authentication
|
||||
exchange follows (messages 12-18).
|
||||
|
||||
Initiator Responder
|
||||
----------- -----------
|
||||
1. HDR, SA, KE, Ni -->
|
||||
<-- 2. HDR, SA, KE, Nr, [CERTREQ],
|
||||
N(MULTIPLE_AUTH_SUPPORTED)
|
||||
3. HDR, SK { IDi, [CERTREQ+], [IDr],
|
||||
SA, TSi, TSr, N(MULTIPLE_AUTH_SUPPORTED) } -->
|
||||
<-- 4. HDR, SK { IDr, [CERT+], AUTH,
|
||||
EAP(Request) }
|
||||
5. HDR, SK { EAP(Response) } -->
|
||||
<-- 6. HDR, SK { EAP(Request) }
|
||||
7. HDR, SK { EAP(Response) } -->
|
||||
<-- 8. HDR, SK { EAP(Success) }
|
||||
9. HDR, SK { AUTH,
|
||||
N(ANOTHER_AUTH_FOLLOWS) } -->
|
||||
<-- 10. HDR, SK { AUTH }
|
||||
11. HDR, SK { IDi } -->
|
||||
<-- 12. HDR, SK { EAP(Request) }
|
||||
13. HDR, SK { EAP(Response) } -->
|
||||
<-- 14. HDR, SK { EAP(Request) }
|
||||
15. HDR, SK { EAP(Response) } -->
|
||||
<-- 16. HDR, SK { EAP(Success) }
|
||||
17. HDR, SK { AUTH } -->
|
||||
<-- 18. HDR, SK { AUTH, SA, TSi, TSr }
|
||||
|
||||
Example 1: Certificate-based authentication of the
|
||||
responder, followed by two EAP authentication exchanges.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Eronen & Korhonen Experimental [Page 6]
|
||||
|
||||
RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006
|
||||
|
||||
|
||||
2.3. Example 2: Mixed EAP and Certificate Authentications
|
||||
|
||||
Another example is shown below: here both the initiator and the
|
||||
responder are first authenticated using certificates (or shared
|
||||
secrets); this is followed by an EAP authentication exchange.
|
||||
|
||||
Initiator Responder
|
||||
----------- -----------
|
||||
1. HDR, SA, KE, Ni -->
|
||||
<-- 2. HDR, SA, KE, Nr, [CERTREQ],
|
||||
N(MULTIPLE_AUTH_SUPPORTED)
|
||||
3. HDR, SK { IDi, [CERT+], [CERTREQ+], [IDr], AUTH,
|
||||
SA, TSi, TSr, N(MULTIPLE_AUTH_SUPPORTED),
|
||||
N(ANOTHER_AUTH_FOLLOWS) } -->
|
||||
<-- 4. HDR, SK { IDr, [CERT+], AUTH }
|
||||
5. HDR, SK { IDi } -->
|
||||
<-- 6. HDR, SK { EAP(Request) }
|
||||
7. HDR, SK { EAP(Response) } -->
|
||||
<-- 8. HDR, SK { EAP(Request) }
|
||||
9. HDR, SK { EAP(Response) } -->
|
||||
<-- 10. HDR, SK { EAP(Success) }
|
||||
11. HDR, SK { AUTH } -->
|
||||
<-- 12. HDR, SK { AUTH, SA, TSi, TSr }
|
||||
|
||||
Example 2: Certificate-based (or shared-secret-based)
|
||||
authentication of the initiator and the responder,
|
||||
followed by an EAP authentication exchange.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Eronen & Korhonen Experimental [Page 7]
|
||||
|
||||
RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006
|
||||
|
||||
|
||||
2.4. Example 3: Multiple Initiator Certificates
|
||||
|
||||
This example shows yet another possibility: the initiator has two
|
||||
different certificates (and associated private keys), and
|
||||
authenticates both of them to the responder.
|
||||
|
||||
Initiator Responder
|
||||
----------- -----------
|
||||
1. HDR, SA, KE, Ni -->
|
||||
<-- 2. HDR, SA, KE, Nr, [CERTREQ],
|
||||
N(MULTIPLE_AUTH_SUPPORTED)
|
||||
3. HDR, SK { IDi, [CERT+], [CERTREQ+], [IDr], AUTH,
|
||||
SA, TSi, TSr, N(MULTIPLE_AUTH_SUPPORTED),
|
||||
N(ANOTHER_AUTH_FOLLOWS) } -->
|
||||
<-- 4. HDR, SK { IDr, [CERT+], AUTH }
|
||||
5. HDR, SK { IDi, [CERT+], AUTH } -->
|
||||
<-- 6. HDR, SK { SA, TSi, TSr }
|
||||
|
||||
Example 3: Two certificate-based authentications of the
|
||||
initiator, and one certificate-based authentication
|
||||
of the responder.
|
||||
|
||||
2.5. Example 4: Multiple Responder Certificates
|
||||
|
||||
This example shows yet another possibility: the responder has two
|
||||
different certificates (and associated private keys), and
|
||||
authenticates both of them to the initiator.
|
||||
|
||||
Initiator Responder
|
||||
----------- -----------
|
||||
1. HDR, SA, KE, Ni -->
|
||||
<-- 2. HDR, SA, KE, Nr, [CERTREQ],
|
||||
N(MULTIPLE_AUTH_SUPPORTED)
|
||||
3. HDR, SK { IDi, [CERT+], [CERTREQ+], [IDr], AUTH,
|
||||
SA, TSi, TSr, N(MULTIPLE_AUTH_SUPPORTED) } -->
|
||||
<-- 4. HDR, SK { IDr, [CERT+], AUTH,
|
||||
N(ANOTHER_AUTH_FOLLOWS) }
|
||||
5. HDR, SK { } -->
|
||||
<-- 6. HDR, SK { IDr, [CERT+], AUTH,
|
||||
SA, TSi, TSr }
|
||||
|
||||
Example 4: Two certificate-based authentications of the
|
||||
responder, and one certificate-based authentication
|
||||
of the initiator.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Eronen & Korhonen Experimental [Page 8]
|
||||
|
||||
RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006
|
||||
|
||||
|
||||
3. Payload Formats
|
||||
|
||||
3.1. MULTIPLE_AUTH_SUPPORTED Notify Payload
|
||||
|
||||
The MULTIPLE_AUTH_SUPPORTED notification is included in the
|
||||
IKE_SA_INIT response or the first IKE_AUTH request to indicate that
|
||||
the peer supports this specification. The Notify Message Type is
|
||||
MULTIPLE_AUTH_SUPPORTED (16404). The Protocol ID and SPI Size fields
|
||||
MUST be set to zero, and there is no data associated with this Notify
|
||||
type.
|
||||
|
||||
3.2. ANOTHER_AUTH_FOLLOWS Notify Payload
|
||||
|
||||
The ANOTHER_AUTH_FOLLOWS notification payload is included in an
|
||||
IKE_AUTH message containing an AUTH payload to indicate that the peer
|
||||
wants to continue with another authentication exchange. The Notify
|
||||
Message Type is ANOTHER_AUTH_FOLLOWS (16405). The Protocol ID and
|
||||
SPI Size fields MUST be set to zero, and there is no data associated
|
||||
with this Notify type.
|
||||
|
||||
4. IANA Considerations
|
||||
|
||||
This document defines two new IKEv2 notifications,
|
||||
MULTIPLE_AUTH_SUPPORTED and ANOTHER_AUTH_FOLLOWS, whose values are
|
||||
allocated from the "IKEv2 Notify Message Types" namespace defined in
|
||||
[IKEv2].
|
||||
|
||||
This document does not define any new namespaces to be managed by
|
||||
IANA.
|
||||
|
||||
5. Security Considerations
|
||||
|
||||
Security considerations for IKEv2 are discussed in [IKEv2]. The
|
||||
reader is encouraged to pay special attention to considerations
|
||||
relating to the use of EAP methods that do not generate shared keys.
|
||||
However, the use of multiple authentication exchanges results in at
|
||||
least one new security consideration.
|
||||
|
||||
In normal IKEv2, the responder authenticates the initiator before
|
||||
revealing its identity (except when EAP is used). When multiple
|
||||
authentication exchanges are used to authenticate the initiator, the
|
||||
responder has to reveal its identity before all of the initiator
|
||||
authentication exchanges have been completed.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Eronen & Korhonen Experimental [Page 9]
|
||||
|
||||
RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006
|
||||
|
||||
|
||||
6. Acknowledgments
|
||||
|
||||
The authors would like to thank Bernard Aboba, Jari Arkko, Spencer
|
||||
Dawkins, Lakshminath Dondeti, Henry Haverinen, Russ Housley, Mika
|
||||
Joutsenvirta, Charlie Kaufman, Tero Kivinen, Yoav Nir, Magnus
|
||||
Nystrom, Mohan Parthasarathy, and Juha Savolainen for their valuable
|
||||
comments.
|
||||
|
||||
7. References
|
||||
|
||||
7.1. Normative References
|
||||
|
||||
[IKEv2] Kaufman, C., "Internet Key Exchange (IKEv2) Protocol",
|
||||
RFC 4306, December 2005.
|
||||
|
||||
[KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", RFC 2119, March 1997.
|
||||
|
||||
7.2. Informative References
|
||||
|
||||
[EAP] Aboba, B., Blunk, L., Vollbrecht, J., Carlson, J., and H.
|
||||
Levkowetz, "Extensible Authentication Protocol (EAP)",
|
||||
RFC 3748, June 2004.
|
||||
|
||||
[PANA] Yegin, A., Ohba, Y., Penno, R., Tsirtsis, G., and C.
|
||||
Wang, "Protocol for Carrying Authentication for Network
|
||||
Access (PANA) Requirements", RFC 4058, May 2005.
|
||||
|
||||
Authors' Addresses
|
||||
|
||||
Pasi Eronen
|
||||
Nokia Research Center
|
||||
P.O. Box 407
|
||||
FIN-00045 Nokia Group
|
||||
Finland
|
||||
|
||||
EMail: pasi.eronen@nokia.com
|
||||
|
||||
|
||||
Jouni Korhonen
|
||||
TeliaSonera
|
||||
P.O. Box 970
|
||||
FIN-00051 Sonera
|
||||
Finland
|
||||
|
||||
EMail: jouni.korhonen@teliasonera.com
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Eronen & Korhonen Experimental [Page 10]
|
||||
|
||||
RFC 4739 Multiple Auth. Exchanges in IKEv2 November 2006
|
||||
|
||||
|
||||
Full Copyright Statement
|
||||
|
||||
Copyright (C) The IETF Trust (2006).
|
||||
|
||||
This document is subject to the rights, licenses and restrictions
|
||||
contained in BCP 78, and except as set forth therein, the authors
|
||||
retain all their rights.
|
||||
|
||||
This document and the information contained herein are provided on an
|
||||
"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
|
||||
OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST,
|
||||
AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT
|
||||
THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
|
||||
Intellectual Property
|
||||
|
||||
The IETF takes no position regarding the validity or scope of any
|
||||
Intellectual Property Rights or other rights that might be claimed to
|
||||
pertain to the implementation or use of the technology described in
|
||||
this document or the extent to which any license under such rights
|
||||
might or might not be available; nor does it represent that it has
|
||||
made any independent effort to identify any such rights. Information
|
||||
on the procedures with respect to rights in RFC documents can be
|
||||
found in BCP 78 and BCP 79.
|
||||
|
||||
Copies of IPR disclosures made to the IETF Secretariat and any
|
||||
assurances of licenses to be made available, or the result of an
|
||||
attempt made to obtain a general license or permission for the use of
|
||||
such proprietary rights by implementers or users of this
|
||||
specification can be obtained from the IETF on-line IPR repository at
|
||||
http://www.ietf.org/ipr.
|
||||
|
||||
The IETF invites any interested party to bring to its attention any
|
||||
copyrights, patents or patent applications, or other proprietary
|
||||
rights that may cover technology that may be required to implement
|
||||
this standard. Please address the information to the IETF at
|
||||
ietf-ipr@ietf.org.
|
||||
|
||||
Acknowledgement
|
||||
|
||||
Funding for the RFC Editor function is currently provided by the
|
||||
Internet Society.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Eronen & Korhonen Experimental [Page 11]
|
||||
|
||||
@@ -738,7 +738,7 @@ static void generate_payload (private_generator_t *this,payload_t *payload)
|
||||
case SPIS:
|
||||
case CONFIGURATION_ATTRIBUTE_VALUE:
|
||||
case VID_DATA:
|
||||
case EAP_MESSAGE:
|
||||
case EAP_DATA:
|
||||
{
|
||||
u_int32_t payload_length_position_offset;
|
||||
u_int16_t length_of_payload;
|
||||
@@ -777,7 +777,7 @@ static void generate_payload (private_generator_t *this,payload_t *payload)
|
||||
case CONFIGURATION_ATTRIBUTE_VALUE:
|
||||
header_length = CONFIGURATION_ATTRIBUTE_HEADER_LENGTH;
|
||||
break;
|
||||
case EAP_MESSAGE:
|
||||
case EAP_DATA:
|
||||
header_length = EAP_PAYLOAD_HEADER_LENGTH;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -142,11 +142,12 @@ static payload_rule_t ike_sa_init_r_payload_rules[] = {
|
||||
*/
|
||||
static payload_rule_t ike_auth_i_payload_rules[] = {
|
||||
{NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE},
|
||||
{EXTENSIBLE_AUTHENTICATION,0,1,TRUE,TRUE},
|
||||
{AUTHENTICATION,0,1,TRUE,TRUE},
|
||||
{ID_INITIATOR,1,1,TRUE,FALSE},
|
||||
{CERTIFICATE,0,1,TRUE,FALSE},
|
||||
{CERTIFICATE_REQUEST,0,1,TRUE,FALSE},
|
||||
{ID_RESPONDER,0,1,TRUE,FALSE},
|
||||
{AUTHENTICATION,1,1,TRUE,FALSE},
|
||||
{SECURITY_ASSOCIATION,1,1,TRUE,FALSE},
|
||||
{TRAFFIC_SELECTOR_INITIATOR,1,1,TRUE,FALSE},
|
||||
{TRAFFIC_SELECTOR_RESPONDER,1,1,TRUE,FALSE},
|
||||
@@ -158,12 +159,13 @@ static payload_rule_t ike_auth_i_payload_rules[] = {
|
||||
*/
|
||||
static payload_rule_t ike_auth_r_payload_rules[] = {
|
||||
{NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,TRUE},
|
||||
{EXTENSIBLE_AUTHENTICATION,0,1,TRUE,TRUE},
|
||||
{CERTIFICATE,0,1,TRUE,FALSE},
|
||||
{ID_RESPONDER,1,1,TRUE,FALSE},
|
||||
{AUTHENTICATION,1,1,TRUE,FALSE},
|
||||
{SECURITY_ASSOCIATION,1,1,TRUE,FALSE},
|
||||
{TRAFFIC_SELECTOR_INITIATOR,1,1,TRUE,FALSE},
|
||||
{TRAFFIC_SELECTOR_RESPONDER,1,1,TRUE,FALSE},
|
||||
{ID_RESPONDER,0,1,TRUE,FALSE},
|
||||
{AUTHENTICATION,0,1,TRUE,FALSE},
|
||||
{SECURITY_ASSOCIATION,0,1,TRUE,FALSE},
|
||||
{TRAFFIC_SELECTOR_INITIATOR,0,1,TRUE,FALSE},
|
||||
{TRAFFIC_SELECTOR_RESPONDER,0,1,TRUE,FALSE},
|
||||
{CONFIGURATION,0,1,TRUE,FALSE},
|
||||
};
|
||||
|
||||
|
||||
@@ -626,7 +626,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case U_INT_32:
|
||||
{
|
||||
@@ -635,7 +635,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case U_INT_64:
|
||||
{
|
||||
@@ -644,7 +644,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case IKE_SPI:
|
||||
{
|
||||
@@ -653,7 +653,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case RESERVED_BIT:
|
||||
{
|
||||
@@ -662,7 +662,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case RESERVED_BYTE:
|
||||
{
|
||||
@@ -680,7 +680,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case PAYLOAD_LENGTH:
|
||||
{
|
||||
@@ -690,7 +690,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
payload_length = *(u_int16_t*)(output + rule->offset);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case HEADER_LENGTH:
|
||||
{
|
||||
@@ -699,7 +699,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case SPI_SIZE:
|
||||
{
|
||||
@@ -709,7 +709,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
spi_size = *(u_int8_t*)(output + rule->offset);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case SPI:
|
||||
{
|
||||
@@ -718,7 +718,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case PROPOSALS:
|
||||
{
|
||||
@@ -728,7 +728,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case TRANSFORMS:
|
||||
{
|
||||
@@ -738,7 +738,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case TRANSFORM_ATTRIBUTES:
|
||||
{
|
||||
@@ -748,7 +748,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case CONFIGURATION_ATTRIBUTES:
|
||||
{
|
||||
@@ -758,7 +758,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case ATTRIBUTE_FORMAT:
|
||||
{
|
||||
@@ -789,7 +789,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
}
|
||||
attribute_length = *(u_int16_t*)(output + rule->offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case ATTRIBUTE_LENGTH_OR_VALUE:
|
||||
{
|
||||
if (this->parse_uint16(this, rule_number, output + rule->offset) != SUCCESS)
|
||||
@@ -820,7 +820,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case ID_DATA:
|
||||
{
|
||||
@@ -830,7 +830,7 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case AUTH_DATA:
|
||||
{
|
||||
@@ -839,8 +839,8 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
{
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CERT_DATA:
|
||||
{
|
||||
@@ -849,8 +849,8 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
{
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CERTREQ_DATA:
|
||||
{
|
||||
@@ -859,18 +859,18 @@ static status_t parse_payload(private_parser_t *this, payload_type_t payload_typ
|
||||
{
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EAP_MESSAGE:
|
||||
case EAP_DATA:
|
||||
{
|
||||
size_t data_length = payload_length - EAP_PAYLOAD_HEADER_LENGTH;
|
||||
if (this->parse_chunk(this, rule_number, output + rule->offset, data_length) != SUCCESS)
|
||||
{
|
||||
pld->destroy(pld);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPIS:
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "eap_payload.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
typedef struct private_eap_payload_t private_eap_payload_t;
|
||||
|
||||
@@ -54,9 +55,9 @@ struct private_eap_payload_t {
|
||||
u_int16_t payload_length;
|
||||
|
||||
/**
|
||||
* The contained message.
|
||||
* EAP message data, if available
|
||||
*/
|
||||
chunk_t message;
|
||||
chunk_t data;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -80,21 +81,21 @@ encoding_rule_t eap_payload_encodings[] = {
|
||||
{ RESERVED_BIT, 0 },
|
||||
{ RESERVED_BIT, 0 },
|
||||
/* Length of the whole payload*/
|
||||
{ PAYLOAD_LENGTH, offsetof(private_eap_payload_t, payload_length)},
|
||||
/* some eap data bytes, length is defined in PAYLOAD_LENGTH */
|
||||
{ EAP_MESSAGE, offsetof(private_eap_payload_t, message) }
|
||||
{ PAYLOAD_LENGTH, offsetof(private_eap_payload_t, payload_length) },
|
||||
/* chunt to data, starting at "code" */
|
||||
{ EAP_DATA, offsetof(private_eap_payload_t, data) },
|
||||
};
|
||||
|
||||
/*
|
||||
1 2 3
|
||||
1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
! Next Payload !C! RESERVED ! Payload Length !
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
! !
|
||||
~ EAP Message ~
|
||||
! !
|
||||
! Code ! Identifier ! Length !
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
! Type ! Type_Data...
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -102,6 +103,47 @@ encoding_rule_t eap_payload_encodings[] = {
|
||||
*/
|
||||
static status_t verify(private_eap_payload_t *this)
|
||||
{
|
||||
u_int16_t length;
|
||||
u_int8_t code;
|
||||
|
||||
if (this->data.len < 4)
|
||||
{
|
||||
DBG1(DBG_ENC, "EAP payloads EAP message too short (%d)", this->data.len);
|
||||
return FAILED;
|
||||
}
|
||||
code = *this->data.ptr;
|
||||
length = htons(*(u_int16_t*)(this->data.ptr + 2));
|
||||
if (this->data.len != length)
|
||||
{
|
||||
DBG1(DBG_ENC, "EAP payload length (%d) does not match contained message length (%d)",
|
||||
this->data.len, length);
|
||||
return FAILED;
|
||||
}
|
||||
switch (code)
|
||||
{
|
||||
case EAP_REQUEST:
|
||||
case EAP_RESPONSE:
|
||||
{
|
||||
if (this->data.len < 4)
|
||||
{
|
||||
DBG1(DBG_ENC, "EAP Request/Response does not have any data");
|
||||
return FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EAP_SUCCESS:
|
||||
case EAP_FAILURE:
|
||||
{
|
||||
if (this->data.len != 4)
|
||||
{
|
||||
DBG1(DBG_ENC, "EAP Success/Failure has data");
|
||||
return FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -147,40 +189,59 @@ static size_t get_length(private_eap_payload_t *this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of eap_payload_t.set_message.
|
||||
* Implementation of eap_payload_t.get_data.
|
||||
*/
|
||||
static void set_message (private_eap_payload_t *this, chunk_t message)
|
||||
static chunk_t get_data(private_eap_payload_t *this)
|
||||
{
|
||||
if (this->message.ptr != NULL)
|
||||
{
|
||||
chunk_free(&(this->message));
|
||||
}
|
||||
this->message.ptr = clalloc(message.ptr,message.len);
|
||||
this->message.len = message.len;
|
||||
this->payload_length = EAP_PAYLOAD_HEADER_LENGTH + this->message.len;
|
||||
return this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of eap_payload_t.get_message.
|
||||
* Implementation of eap_payload_t.set_data.
|
||||
*/
|
||||
static chunk_t get_message (private_eap_payload_t *this)
|
||||
static void set_data(private_eap_payload_t *this, chunk_t data)
|
||||
{
|
||||
return (this->message);
|
||||
chunk_free(&this->data);
|
||||
this->data = chunk_clone(data);
|
||||
this->payload_length = this->data.len + 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of eap_payload_t.get_data_clone.
|
||||
* Implementation of eap_payload_t.get_code.
|
||||
*/
|
||||
static chunk_t get_message_clone (private_eap_payload_t *this)
|
||||
static eap_code_t get_code(private_eap_payload_t *this)
|
||||
{
|
||||
chunk_t cloned_message;
|
||||
if (this->message.ptr == NULL)
|
||||
if (this->data.len > 0)
|
||||
{
|
||||
return (this->message);
|
||||
return *this->data.ptr;
|
||||
}
|
||||
cloned_message.ptr = clalloc(this->message.ptr,this->message.len);
|
||||
cloned_message.len = this->message.len;
|
||||
return cloned_message;
|
||||
/* should not happen, as it is verified */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of eap_payload_t.get_identifier.
|
||||
*/
|
||||
static u_int8_t get_identifier(private_eap_payload_t *this)
|
||||
{
|
||||
if (this->data.len > 1)
|
||||
{
|
||||
return *(this->data.ptr + 1);
|
||||
}
|
||||
/* should not happen, as it is verified */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of eap_payload_t.get_type.
|
||||
*/
|
||||
static eap_type_t get_type(private_eap_payload_t *this)
|
||||
{
|
||||
if (this->data.len > 4)
|
||||
{
|
||||
return *(this->data.ptr + 4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,12 +249,8 @@ static chunk_t get_message_clone (private_eap_payload_t *this)
|
||||
*/
|
||||
static void destroy(private_eap_payload_t *this)
|
||||
{
|
||||
if (this->message.ptr != NULL)
|
||||
{
|
||||
chunk_free(&(this->message));
|
||||
}
|
||||
|
||||
free(this);
|
||||
chunk_free(&this->data);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -202,7 +259,7 @@ static void destroy(private_eap_payload_t *this)
|
||||
eap_payload_t *eap_payload_create()
|
||||
{
|
||||
private_eap_payload_t *this = malloc_thing(private_eap_payload_t);
|
||||
|
||||
|
||||
/* interface functions */
|
||||
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
|
||||
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
|
||||
@@ -214,15 +271,61 @@ eap_payload_t *eap_payload_create()
|
||||
|
||||
/* public functions */
|
||||
this->public.destroy = (void (*) (eap_payload_t *)) destroy;
|
||||
this->public.set_message = (void (*) (eap_payload_t *,chunk_t)) set_message;
|
||||
this->public.get_message_clone = (chunk_t (*) (eap_payload_t *)) get_message_clone;
|
||||
this->public.get_message = (chunk_t (*) (eap_payload_t *)) get_message;
|
||||
this->public.get_data = (chunk_t (*) (eap_payload_t*))get_data;
|
||||
this->public.set_data = (void (*) (eap_payload_t *,chunk_t))set_data;
|
||||
this->public.get_code = (eap_code_t (*) (eap_payload_t*))get_code;
|
||||
this->public.get_identifier = (u_int8_t (*) (eap_payload_t*))get_identifier;
|
||||
this->public.get_type = (eap_type_t (*) (eap_payload_t*))get_type;
|
||||
|
||||
/* private variables */
|
||||
this->critical = FALSE;
|
||||
this->next_payload = NO_PAYLOAD;
|
||||
this->payload_length = EAP_PAYLOAD_HEADER_LENGTH;
|
||||
this->message = chunk_empty;
|
||||
this->data = chunk_empty;
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
|
||||
return (&(this->public));
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
eap_payload_t *eap_payload_create_data(chunk_t data)
|
||||
{
|
||||
eap_payload_t *this = eap_payload_create();
|
||||
|
||||
this->set_data(this, data);
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
eap_payload_t *eap_payload_create_code(eap_code_t code)
|
||||
{
|
||||
eap_payload_t *this = eap_payload_create();
|
||||
chunk_t data = chunk_alloca(4);
|
||||
|
||||
*(data.ptr + 0) = code;
|
||||
*(data.ptr + 1) = 0;
|
||||
*(u_int16_t*)(data.ptr + 2) = htons(data.len);
|
||||
|
||||
this->set_data(this, data);
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
eap_payload_t *eap_payload_create_nak()
|
||||
{
|
||||
eap_payload_t *this = eap_payload_create();
|
||||
chunk_t data = chunk_alloca(5);
|
||||
|
||||
*(data.ptr + 0) = EAP_RESPONSE;
|
||||
*(data.ptr + 1) = 0;
|
||||
*(u_int16_t*)(data.ptr + 2) = htons(data.len);
|
||||
*(data.ptr + 4) = EAP_NAK;
|
||||
|
||||
this->set_data(this, data);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ typedef struct eap_payload_t eap_payload_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <encoding/payloads/payload.h>
|
||||
#include <sa/authenticators/eap/eap_method.h>
|
||||
|
||||
/**
|
||||
* Length of a EAP payload without the EAP Message in bytes.
|
||||
@@ -44,62 +45,105 @@ typedef struct eap_payload_t eap_payload_t;
|
||||
* @b Constructors:
|
||||
* - eap_payload_create()
|
||||
*
|
||||
* @todo Implement functionality for this payload
|
||||
*
|
||||
* @ingroup payloads
|
||||
*/
|
||||
struct eap_payload_t {
|
||||
|
||||
/**
|
||||
* The payload_t interface.
|
||||
*/
|
||||
payload_t payload_interface;
|
||||
|
||||
/**
|
||||
* @brief Set the EAP Message.
|
||||
*
|
||||
* Data are getting cloned.
|
||||
* @brief Set the contained EAP data.
|
||||
*
|
||||
* @param this calling eap_payload_t object
|
||||
* @param message EAP message as chunk_t
|
||||
* This contains the FULL EAP message starting with "code".
|
||||
* Chunk gets cloned.
|
||||
*
|
||||
* @param this calling eap_payload_t object
|
||||
* @param message EAP data
|
||||
*/
|
||||
void (*set_message) (eap_payload_t *this, chunk_t message);
|
||||
void (*set_data) (eap_payload_t *this, chunk_t data);
|
||||
|
||||
/**
|
||||
* @brief Get the EAP message.
|
||||
*
|
||||
* Returned data are a copy of the internal one.
|
||||
* @brief Get the contained EAP data.
|
||||
*
|
||||
* @param this calling eap_payload_t object
|
||||
* @return EAP message as chunk_t
|
||||
* This contains the FULL EAP message starting with "code".
|
||||
*
|
||||
* @param this calling eap_payload_t object
|
||||
* @return EAP data (pointer to internal data)
|
||||
*/
|
||||
chunk_t (*get_message_clone) (eap_payload_t *this);
|
||||
chunk_t (*get_data) (eap_payload_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the EAP message.
|
||||
*
|
||||
* Returned data are NOT copied.
|
||||
* @brief Get the EAP code.
|
||||
*
|
||||
* @param this calling eap_payload_t object
|
||||
* @return EAP message as chunk_t
|
||||
* @param this calling eap_payload_t object
|
||||
* @return EAP message as chunk_t
|
||||
*/
|
||||
chunk_t (*get_message) (eap_payload_t *this);
|
||||
eap_code_t (*get_code) (eap_payload_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the EAP identifier.
|
||||
*
|
||||
* @param this calling eap_payload_t object
|
||||
* @return unique identifier
|
||||
*/
|
||||
u_int8_t (*get_identifier) (eap_payload_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the EAP method type.
|
||||
*
|
||||
* @param this calling eap_payload_t object
|
||||
* @return EAP method type
|
||||
*/
|
||||
eap_type_t (*get_type) (eap_payload_t *this);
|
||||
|
||||
/**
|
||||
* @brief Destroys an eap_payload_t object.
|
||||
*
|
||||
* @param this eap_payload_t object to destroy
|
||||
* @param this eap_payload_t object to destroy
|
||||
*/
|
||||
void (*destroy) (eap_payload_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates an empty eap_payload_t object.
|
||||
*
|
||||
*
|
||||
* @return eap_payload_t object
|
||||
*
|
||||
*
|
||||
* @ingroup payloads
|
||||
*/
|
||||
eap_payload_t *eap_payload_create(void);
|
||||
|
||||
/**
|
||||
* @brief Creates an eap_payload_t object with data.
|
||||
*
|
||||
* @return eap_payload_t object
|
||||
*
|
||||
* @ingroup payloads
|
||||
*/
|
||||
eap_payload_t *eap_payload_create_data(chunk_t data);
|
||||
|
||||
/**
|
||||
* @brief Creates an eap_payload_t object with a code.
|
||||
*
|
||||
* Could should be either EAP_SUCCESS/EAP_FAILURE, use
|
||||
* constructor above otherwise.
|
||||
*
|
||||
* @return eap_payload_t object
|
||||
*
|
||||
* @ingroup payloads
|
||||
*/
|
||||
eap_payload_t *eap_payload_create_code(eap_code_t code);
|
||||
|
||||
/**
|
||||
* @brief Creates an eap_payload_t EAP_RESPONSE containing an EAP_NAK.
|
||||
*
|
||||
* @return eap_payload_t object
|
||||
*
|
||||
* @ingroup payloads
|
||||
*/
|
||||
eap_payload_t *eap_payload_create_nak();
|
||||
|
||||
#endif /* EAP_PAYLOAD_H_ */
|
||||
|
||||
@@ -449,7 +449,7 @@ enum encoding_type_t {
|
||||
*
|
||||
* When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
|
||||
*/
|
||||
EAP_MESSAGE,
|
||||
EAP_DATA,
|
||||
|
||||
/**
|
||||
* Representating the SPIS field in a DELETE payload.
|
||||
|
||||
@@ -75,7 +75,9 @@ ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, INVALID_SELECTORS,
|
||||
"COOKIE2",
|
||||
"NO_NATS_ALLOWED",
|
||||
"AUTH_LIFETIME");
|
||||
ENUM_END(notify_type_names, AUTH_LIFETIME);
|
||||
ENUM_NEXT(notify_type_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, AUTH_LIFETIME,
|
||||
"EAP_ONLY_AUTHENTICATION");
|
||||
ENUM_END(notify_type_names, EAP_ONLY_AUTHENTICATION);
|
||||
|
||||
typedef struct private_notify_payload_t private_notify_payload_t;
|
||||
|
||||
|
||||
@@ -88,8 +88,10 @@ enum notify_type_t {
|
||||
NO_NATS_ALLOWED = 16402,
|
||||
/* repeated authentication extension, RFC4478 */
|
||||
AUTH_LIFETIME = 16403,
|
||||
/* draft-eronen-ipsec-ikev2-eap-auth, not assigned by IANA yet */
|
||||
EAP_ONLY_AUTHENTICATION = 40960,
|
||||
/* BEET mode, not even a draft yet. private use */
|
||||
USE_BEET_MODE = 40960,
|
||||
USE_BEET_MODE = 40961,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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("john@doe.xyz");
|
||||
method = module.constructor(EAP_SERVER, id, id);
|
||||
if (method == NULL)
|
||||
{
|
||||
method = module.constructor(EAP_PEER, id, id);
|
||||
}
|
||||
id->destroy(id);
|
||||
if (method == NULL)
|
||||
{
|
||||
DBG1(DBG_CFG, " unable to create instance of EAP method %s, skipped",
|
||||
entry->d_name);
|
||||
dlclose(module.handle);
|
||||
continue;
|
||||
}
|
||||
module.type = method->get_type(method);
|
||||
method->destroy(method);
|
||||
|
||||
DBG1(DBG_CFG, " loaded EAP method %N successfully from %s",
|
||||
eap_type_names, module.type, entry->d_name);
|
||||
|
||||
loaded_module = malloc_thing(module_entry_t);
|
||||
memcpy(loaded_module, &module, sizeof(module));
|
||||
modules->insert_last(modules, loaded_module);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
eap_method_t *eap_method_create(eap_type_t type, eap_role_t role,
|
||||
identification_t *server,
|
||||
identification_t *peer)
|
||||
{
|
||||
eap_method_t *method = NULL;
|
||||
iterator_t *iterator;
|
||||
module_entry_t *entry;
|
||||
|
||||
iterator = modules->create_iterator(modules, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&entry))
|
||||
{
|
||||
if (entry->type == type)
|
||||
{
|
||||
method = entry->constructor(role, server, peer);
|
||||
if (method)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
|
||||
if (method == NULL)
|
||||
{
|
||||
DBG1(DBG_CFG, "no EAP module found for %N %N",
|
||||
eap_type_names, type, eap_role_names, role);
|
||||
}
|
||||
return method;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -393,7 +393,7 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
|
||||
}
|
||||
|
||||
policy = policy_create(msg->add_conn.name, my_id, other_id,
|
||||
msg->add_conn.auth_method,
|
||||
msg->add_conn.auth_method, msg->add_conn.eap_type,
|
||||
msg->add_conn.rekey.ipsec_lifetime,
|
||||
msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
|
||||
msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
|
||||
|
||||
@@ -12,6 +12,7 @@ asn1/pem.c asn1/pem.h \
|
||||
asn1/ttodata.c asn1/ttodata.h \
|
||||
crypto/rsa/rsa_private_key.c crypto/rsa/rsa_private_key.h \
|
||||
crypto/rsa/rsa_public_key.h crypto/rsa/rsa_public_key.c \
|
||||
crypto/prfs/fips_prf.c crypto/prfs/fips_prf.h \
|
||||
crypto/prfs/hmac_prf.c crypto/prfs/hmac_prf.h \
|
||||
crypto/prfs/prf.c crypto/prfs/prf.h \
|
||||
crypto/signers/hmac_signer.c crypto/signers/hmac_signer.h \
|
||||
|
||||
+148
-36
@@ -35,13 +35,22 @@ chunk_t chunk_empty = { NULL, 0 };
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
chunk_t chunk_clone(chunk_t chunk)
|
||||
chunk_t chunk_create(u_char *ptr, size_t len)
|
||||
{
|
||||
chunk_t chunk = {ptr, len};
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk)
|
||||
{
|
||||
chunk_t clone = chunk_empty;
|
||||
|
||||
if (chunk.ptr && chunk.len > 0)
|
||||
{
|
||||
clone.ptr = malloc(chunk.len);
|
||||
clone.ptr = ptr;
|
||||
clone.len = chunk.len;
|
||||
memcpy(clone.ptr, chunk.ptr, chunk.len);
|
||||
}
|
||||
@@ -52,51 +61,151 @@ chunk_t chunk_clone(chunk_t chunk)
|
||||
/**
|
||||
* Decribed in header.
|
||||
*/
|
||||
chunk_t chunk_cat(const char* mode, ...)
|
||||
size_t chunk_length(const char* mode, ...)
|
||||
{
|
||||
chunk_t construct;
|
||||
va_list chunks;
|
||||
u_char *pos;
|
||||
int i;
|
||||
int count = strlen(mode);
|
||||
|
||||
/* sum up lengths of individual chunks */
|
||||
size_t length = 0;
|
||||
|
||||
va_start(chunks, mode);
|
||||
construct.len = 0;
|
||||
for (i = 0; i < count; i++)
|
||||
while (TRUE)
|
||||
{
|
||||
chunk_t ch = va_arg(chunks, chunk_t);
|
||||
construct.len += ch.len;
|
||||
}
|
||||
va_end(chunks);
|
||||
|
||||
/* allocate needed memory for construct */
|
||||
construct.ptr = malloc(construct.len);
|
||||
pos = construct.ptr;
|
||||
|
||||
/* copy or move the chunks */
|
||||
va_start(chunks, mode);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
chunk_t ch = va_arg(chunks, chunk_t);
|
||||
switch (*mode++)
|
||||
{
|
||||
case 'm':
|
||||
memcpy(pos, ch.ptr, ch.len);
|
||||
pos += ch.len;
|
||||
free(ch.ptr);
|
||||
break;
|
||||
case 'c':
|
||||
{
|
||||
chunk_t ch = va_arg(chunks, chunk_t);
|
||||
length += ch.len;
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
memcpy(pos, ch.ptr, ch.len);
|
||||
pos += ch.len;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
va_end(chunks);
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decribed in header.
|
||||
*/
|
||||
chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...)
|
||||
{
|
||||
va_list chunks;
|
||||
chunk_t construct = chunk_create(ptr, 0);
|
||||
|
||||
va_start(chunks, mode);
|
||||
while (TRUE)
|
||||
{
|
||||
bool free_chunk = FALSE;
|
||||
switch (*mode++)
|
||||
{
|
||||
case 'm':
|
||||
{
|
||||
free_chunk = TRUE;
|
||||
}
|
||||
case 'c':
|
||||
{
|
||||
chunk_t ch = va_arg(chunks, chunk_t);
|
||||
memcpy(ptr, ch.ptr, ch.len);
|
||||
ptr += ch.len;
|
||||
construct.len += ch.len;
|
||||
if (free_chunk)
|
||||
{
|
||||
free(ch.ptr);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
va_end(chunks);
|
||||
|
||||
return construct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decribed in header.
|
||||
*/
|
||||
void chunk_split(chunk_t chunk, const char *mode, ...)
|
||||
{
|
||||
va_list chunks;
|
||||
size_t len;
|
||||
chunk_t *ch;
|
||||
|
||||
va_start(chunks, mode);
|
||||
while (TRUE)
|
||||
{
|
||||
if (*mode == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
len = va_arg(chunks, size_t);
|
||||
ch = va_arg(chunks, chunk_t*);
|
||||
/* a null chunk means skip len bytes */
|
||||
if (ch == NULL)
|
||||
{
|
||||
chunk = chunk_skip(chunk, len);
|
||||
continue;
|
||||
}
|
||||
switch (*mode++)
|
||||
{
|
||||
case 'm':
|
||||
{
|
||||
ch->len = min(chunk.len, len);
|
||||
if (ch->len)
|
||||
{
|
||||
ch->ptr = chunk.ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
ch->ptr = NULL;
|
||||
}
|
||||
chunk = chunk_skip(chunk, ch->len);
|
||||
continue;
|
||||
}
|
||||
case 'a':
|
||||
{
|
||||
ch->len = min(chunk.len, len);
|
||||
if (ch->len)
|
||||
{
|
||||
ch->ptr = malloc(ch->len);
|
||||
memcpy(ch->ptr, chunk.ptr, ch->len);
|
||||
}
|
||||
else
|
||||
{
|
||||
ch->ptr = NULL;
|
||||
}
|
||||
chunk = chunk_skip(chunk, ch->len);
|
||||
continue;
|
||||
}
|
||||
case 'c':
|
||||
{
|
||||
ch->len = min(ch->len, chunk.len);
|
||||
ch->len = min(ch->len, len);
|
||||
if (ch->len)
|
||||
{
|
||||
memcpy(ch->ptr, chunk.ptr, ch->len);
|
||||
}
|
||||
else
|
||||
{
|
||||
ch->ptr = NULL;
|
||||
}
|
||||
chunk = chunk_skip(chunk, ch->len);
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
va_end(chunks);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
@@ -110,12 +219,15 @@ void chunk_free(chunk_t *chunk)
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
chunk_t chunk_alloc(size_t bytes)
|
||||
chunk_t chunk_skip(chunk_t chunk, size_t bytes)
|
||||
{
|
||||
chunk_t new_chunk;
|
||||
new_chunk.ptr = malloc(bytes);
|
||||
new_chunk.len = bytes;
|
||||
return new_chunk;
|
||||
if (chunk.len > bytes)
|
||||
{
|
||||
chunk.ptr += bytes;
|
||||
chunk.len -= bytes;
|
||||
return chunk;
|
||||
}
|
||||
return chunk_empty;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+60
-10
@@ -47,21 +47,36 @@ struct chunk_t {
|
||||
extern chunk_t chunk_empty;
|
||||
|
||||
/**
|
||||
* Initialize a chunk to point to a static(!) buffer
|
||||
* Create a new chunk pointing to "ptr" with length "len"
|
||||
*/
|
||||
#define chunk_from_buf(str) { str, sizeof(str) }
|
||||
chunk_t chunk_create(u_char *ptr, size_t len);
|
||||
|
||||
/**
|
||||
* Clone chunk contents in a newly allocated chunk
|
||||
* Create a clone of a chunk pointing to "ptr"
|
||||
*/
|
||||
chunk_t chunk_clone(chunk_t chunk);
|
||||
chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk);
|
||||
|
||||
/**
|
||||
* Allocate a chunk from concatenation of other chunks.
|
||||
* mode is a string 'm' and 'c, 'm' means move chunk,
|
||||
* 'c' means copy chunk.
|
||||
* Calculate length of multiple chunks
|
||||
*/
|
||||
chunk_t chunk_cat(const char* mode, ...);
|
||||
size_t chunk_length(const char *mode, ...);
|
||||
|
||||
/**
|
||||
* Concatenate chunks into a chunk pointing to "ptr",
|
||||
* "mode" is a string of "c" (copy) and "m" (move), which says
|
||||
* how to handle to chunks in "..."
|
||||
*/
|
||||
chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...);
|
||||
|
||||
/**
|
||||
* Split up a chunk into parts, "mode" is a string of "a" (alloc),
|
||||
* "c" (copy) and "m" (move). Each letter say for the corresponding chunk if
|
||||
* it should get allocated on heap, copied into existing chunk, or the chunk
|
||||
* should point into "chunk". The length of each part is an argument before
|
||||
* each target chunk. E.g.:
|
||||
* chunk_split(chunk, "mcac", 3, &a, 7, &b, 5, &c, d.len, &d);
|
||||
*/
|
||||
void chunk_split(chunk_t chunk, const char *mode, ...);
|
||||
|
||||
/**
|
||||
* Free contents of a chunk
|
||||
@@ -69,9 +84,44 @@ chunk_t chunk_cat(const char* mode, ...);
|
||||
void chunk_free(chunk_t *chunk);
|
||||
|
||||
/**
|
||||
* Allocate a chunk
|
||||
* Initialize a chunk to point to buffer inspectable by sizeof()
|
||||
*/
|
||||
chunk_t chunk_alloc(size_t bytes);
|
||||
#define chunk_from_buf(str) { str, sizeof(str) }
|
||||
|
||||
/**
|
||||
* Allocate a chunk on the heap
|
||||
*/
|
||||
#define chunk_alloc(bytes) chunk_create(malloc(bytes), bytes)
|
||||
|
||||
/**
|
||||
* Allocate a chunk on the stack
|
||||
*/
|
||||
#define chunk_alloca(bytes) chunk_create(alloca(bytes), bytes)
|
||||
|
||||
/**
|
||||
* Clone a chunk on heap
|
||||
*/
|
||||
#define chunk_clone(chunk) chunk_create_clone(malloc(chunk.len), chunk)
|
||||
|
||||
/**
|
||||
* Clone a chunk on stack
|
||||
*/
|
||||
#define chunk_clonea(chunk) chunk_create_clone(alloca(chunk.len), chunk)
|
||||
|
||||
/**
|
||||
* Concatenate chunks into a chunk on heap
|
||||
*/
|
||||
#define chunk_cat(mode, ...) chunk_create_cat(malloc(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Concatenate chunks into a chunk on stack
|
||||
*/
|
||||
#define chunk_cata(mode, ...) chunk_create_cat(alloca(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Skip n bytes in chunk (forward pointer, shorten length)
|
||||
*/
|
||||
chunk_t chunk_skip(chunk_t chunk, size_t bytes);
|
||||
|
||||
/**
|
||||
* Compare two chunks for equality,
|
||||
|
||||
@@ -122,10 +122,24 @@ struct hasher_t {
|
||||
*/
|
||||
void (*reset) (hasher_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the state of the hasher.
|
||||
*
|
||||
* A hasher stores internal state information. This state may be
|
||||
* manipulated to include a "seed" into the hashing operation. It used by
|
||||
* some exotic protocols (such as AKA).
|
||||
* The data pointed by chunk may be manipulated, but not replaced nor freed.
|
||||
* This is more a hack than a feature. The hasher's state may be byte
|
||||
* order dependant; use with care.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
chunk_t (*get_state) (hasher_t *this);
|
||||
|
||||
/**
|
||||
* @brief Destroys a hasher object.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*destroy) (hasher_t *this);
|
||||
};
|
||||
|
||||
@@ -363,6 +363,19 @@ static void reset(private_md5_hasher_t *this)
|
||||
this->count[1] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_state
|
||||
*/
|
||||
static chunk_t get_state(private_md5_hasher_t *this)
|
||||
{
|
||||
chunk_t chunk;
|
||||
|
||||
chunk.ptr = (u_char*)&this->state[0];
|
||||
chunk.len = sizeof(this->state);
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.destroy.
|
||||
*/
|
||||
@@ -382,6 +395,7 @@ md5_hasher_t *md5_hasher_create(void)
|
||||
this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash;
|
||||
this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size;
|
||||
this->public.hasher_interface.reset = (void (*) (hasher_t*))reset;
|
||||
this->public.hasher_interface.get_state = (chunk_t (*) (hasher_t*))get_state;
|
||||
this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy;
|
||||
|
||||
/* initialize */
|
||||
|
||||
@@ -223,7 +223,7 @@ static size_t get_hash_size(private_sha1_hasher_t *this)
|
||||
{
|
||||
return HASH_SIZE_SHA1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.reset.
|
||||
*/
|
||||
@@ -237,6 +237,20 @@ static void reset(private_sha1_hasher_t *this)
|
||||
this->count[0] = 0;
|
||||
this->count[1] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_state
|
||||
*/
|
||||
static chunk_t get_state(private_sha1_hasher_t *this)
|
||||
{
|
||||
chunk_t chunk;
|
||||
|
||||
chunk.ptr = (u_char*)&this->state[0];
|
||||
chunk.len = sizeof(this->state);
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.destroy.
|
||||
*/
|
||||
@@ -256,6 +270,7 @@ sha1_hasher_t *sha1_hasher_create(void)
|
||||
this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash;
|
||||
this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size;
|
||||
this->public.hasher_interface.reset = (void (*) (hasher_t*))reset;
|
||||
this->public.hasher_interface.get_state = (chunk_t (*) (hasher_t*))get_state;
|
||||
this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy;
|
||||
|
||||
/* initialize */
|
||||
|
||||
@@ -586,6 +586,38 @@ static void reset512(private_sha512_hasher_t *ctx)
|
||||
ctx->sha_bufCnt = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_state for SHA256
|
||||
*/
|
||||
static chunk_t get_state256(private_sha256_hasher_t *ctx)
|
||||
{
|
||||
chunk_t chunk;
|
||||
chunk.ptr = (u_char*)&ctx->sha_H[0];
|
||||
chunk.len = HASH_SIZE_SHA256;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.get_state for SHA384
|
||||
*/
|
||||
static chunk_t get_state384(private_sha512_hasher_t *ctx)
|
||||
{
|
||||
chunk_t chunk;
|
||||
chunk.ptr = (u_char*)&ctx->sha_H[0];
|
||||
chunk.len = HASH_SIZE_SHA384;
|
||||
return chunk;
|
||||
}
|
||||
/**
|
||||
* Implementation of hasher_t.get_state for SHA512
|
||||
*/
|
||||
static chunk_t get_state512(private_sha512_hasher_t *ctx)
|
||||
{
|
||||
chunk_t chunk;
|
||||
chunk.ptr = (u_char*)&ctx->sha_H[0];
|
||||
chunk.len = HASH_SIZE_SHA512;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hasher_t.destroy.
|
||||
*/
|
||||
@@ -606,6 +638,7 @@ sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm)
|
||||
case HASH_SHA256:
|
||||
this = (sha2_hasher_t*)malloc_thing(private_sha256_hasher_t);
|
||||
this->hasher_interface.reset = (void(*)(hasher_t*))reset256;
|
||||
this->hasher_interface.get_state = (chunk_t(*)(hasher_t*))get_state256;
|
||||
this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size256;
|
||||
this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash256;
|
||||
this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash256;
|
||||
@@ -614,6 +647,7 @@ sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm)
|
||||
/* uses SHA512 data structure */
|
||||
this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t);
|
||||
this->hasher_interface.reset = (void(*)(hasher_t*))reset384;
|
||||
this->hasher_interface.get_state = (chunk_t(*)(hasher_t*))get_state384;
|
||||
this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size384;
|
||||
this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash384;
|
||||
this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash384;
|
||||
@@ -621,6 +655,7 @@ sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm)
|
||||
case HASH_SHA512:
|
||||
this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t);
|
||||
this->hasher_interface.reset = (void(*)(hasher_t*))reset512;
|
||||
this->hasher_interface.get_state = (chunk_t(*)(hasher_t*))get_state512;
|
||||
this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size512;
|
||||
this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash512;
|
||||
this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash512;
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
/**
|
||||
* @file fips_prf.c
|
||||
*
|
||||
* @brief Implementation for fips_prf_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "fips_prf.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
typedef struct private_fips_prf_t private_fips_prf_t;
|
||||
|
||||
/**
|
||||
* Private data of a fips_prf_t object.
|
||||
*/
|
||||
struct private_fips_prf_t {
|
||||
/**
|
||||
* Public fips_prf_t interface.
|
||||
*/
|
||||
fips_prf_t public;
|
||||
|
||||
/**
|
||||
* key of prf function, "b" long
|
||||
*/
|
||||
u_int8_t *key;
|
||||
|
||||
/**
|
||||
* size of "b" in bytes
|
||||
*/
|
||||
size_t b;
|
||||
|
||||
/**
|
||||
* G function, either SHA1 or DES
|
||||
*/
|
||||
void (*g)(u_int8_t t[], chunk_t c, u_int8_t res[]);
|
||||
};
|
||||
|
||||
/**
|
||||
* t used in G(), equals to initial SHA1 value
|
||||
*/
|
||||
static u_int8_t t[] = {
|
||||
0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA,
|
||||
0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0,
|
||||
};
|
||||
|
||||
/**
|
||||
* sum = (a + b) mod 2 ^ (length * 8)
|
||||
*/
|
||||
static void add_mod(size_t length, u_int8_t a[], u_int8_t b[], u_int8_t sum[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = length - 1; i >= 0; i--)
|
||||
{
|
||||
u_int32_t tmp;
|
||||
int c = 0;
|
||||
|
||||
tmp = a[i] + b[i] + c;
|
||||
sum[i] = 0xff & tmp;
|
||||
c = tmp >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate "chunk mod 2^(length*8)" and save it into buffer
|
||||
*/
|
||||
static void chunk_mod(size_t length, chunk_t chunk, u_int8_t buffer[])
|
||||
{
|
||||
if (chunk.len < length)
|
||||
{
|
||||
/* apply seed as least significant bits, others are zero */
|
||||
memset(buffer, 0, length - chunk.len);
|
||||
memcpy(buffer + length - chunk.len, chunk.ptr, chunk.len);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* use least significant bytes from seed, as we use mod 2^b */
|
||||
memcpy(buffer, chunk.ptr + chunk.len - length, length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.get_bytes.
|
||||
*
|
||||
* Test vector:
|
||||
*
|
||||
* key:
|
||||
* 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
|
||||
* 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
|
||||
* 0xeb, 0x5a, 0x38, 0xb6
|
||||
*
|
||||
* seed:
|
||||
* 0x00
|
||||
*
|
||||
* result:
|
||||
* 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
|
||||
* 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
|
||||
* 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
|
||||
* 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
|
||||
* 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
|
||||
*/
|
||||
static void get_bytes(private_fips_prf_t *this, chunk_t seed, u_int8_t w[])
|
||||
{
|
||||
int i;
|
||||
u_int8_t xval[this->b];
|
||||
u_int8_t xseed[this->b];
|
||||
u_int8_t *xkey = this->key;
|
||||
u_int8_t one[this->b];
|
||||
chunk_t xval_chunk = chunk_from_buf(xval);
|
||||
|
||||
memset(one, 0, this->b);
|
||||
one[this->b - 1] = 0x01;
|
||||
|
||||
/* 3.1 */
|
||||
chunk_mod(this->b, seed, xseed);
|
||||
|
||||
/* 3.2 */
|
||||
for (i = 0; i < 2; i++) /* twice */
|
||||
{
|
||||
/* a. XVAL = (XKEY + XSEED j) mod 2^b */
|
||||
add_mod(this->b, xkey, xseed, xval);
|
||||
DBG3("XVAL %b", xval, this->b);
|
||||
/* b. wi = G(t, XVAL ) */
|
||||
this->g(t, xval_chunk, &w[i * this->b]);
|
||||
DBG3("w[%d] %b", i, &w[i * this->b], this->b);
|
||||
/* c. XKEY = (1 + XKEY + wi) mod 2b */
|
||||
add_mod(this->b, xkey, one, xkey);
|
||||
add_mod(this->b, xkey, &w[i * this->b], xkey);
|
||||
DBG3("XKEY %b", xkey, this->b);
|
||||
}
|
||||
|
||||
/* 3.3 done already, mod q not used */
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.get_block_size.
|
||||
*/
|
||||
static size_t get_block_size(private_fips_prf_t *this)
|
||||
{
|
||||
return 2 * this->b;
|
||||
}
|
||||
/**
|
||||
* Implementation of prf_t.allocate_bytes.
|
||||
*/
|
||||
static void allocate_bytes(private_fips_prf_t *this, chunk_t seed, chunk_t *chunk)
|
||||
{
|
||||
*chunk = chunk_alloc(get_block_size(this));
|
||||
get_bytes(this, seed, chunk->ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.get_key_size.
|
||||
*/
|
||||
static size_t get_key_size(private_fips_prf_t *this)
|
||||
{
|
||||
return this->b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.set_key.
|
||||
*/
|
||||
static void set_key(private_fips_prf_t *this, chunk_t key)
|
||||
{
|
||||
/* save key as "key mod 2^b" */
|
||||
chunk_mod(this->b, key, this->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of the G() function based on SHA1
|
||||
*/
|
||||
void g_sha1(u_int8_t t[], chunk_t c, u_int8_t res[])
|
||||
{
|
||||
hasher_t *hasher;
|
||||
u_int8_t buf[64];
|
||||
chunk_t state_chunk;
|
||||
u_int32_t *state, *iv, *hash;
|
||||
|
||||
if (c.len < sizeof(buf))
|
||||
{
|
||||
/* pad c with zeros */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memcpy(buf, c.ptr, c.len);
|
||||
c.ptr = buf;
|
||||
c.len = sizeof(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not more than 512 bits can be G()-ed */
|
||||
c.len = sizeof(buf);
|
||||
}
|
||||
|
||||
/* our SHA1 hasher's state is 32-Bit integers in host order. We must
|
||||
* convert them */
|
||||
hasher = hasher_create(HASH_SHA1);
|
||||
state_chunk = hasher->get_state(hasher);
|
||||
state = (u_int32_t*)state_chunk.ptr;
|
||||
iv = (u_int32_t*)t;
|
||||
hash = (u_int32_t*)res;
|
||||
state[0] = htonl(iv[0]);
|
||||
state[1] = htonl(iv[1]);
|
||||
state[2] = htonl(iv[2]);
|
||||
state[3] = htonl(iv[3]);
|
||||
hasher->get_hash(hasher, c, NULL);
|
||||
hash[0] = htonl(state[0]);
|
||||
hash[1] = htonl(state[1]);
|
||||
hash[2] = htonl(state[2]);
|
||||
hash[3] = htonl(state[3]);
|
||||
hash[4] = htonl(state[4]);
|
||||
hasher->destroy(hasher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of prf_t.destroy.
|
||||
*/
|
||||
static void destroy(private_fips_prf_t *this)
|
||||
{
|
||||
free(this->key);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
fips_prf_t *fips_prf_create(size_t b, void(*g)(u_int8_t[],chunk_t,u_int8_t[]))
|
||||
{
|
||||
private_fips_prf_t *this = malloc_thing(private_fips_prf_t);
|
||||
|
||||
this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes;
|
||||
this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes;
|
||||
this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size;
|
||||
this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size;
|
||||
this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key;
|
||||
this->public.prf_interface.destroy = (void (*) (prf_t *))destroy;
|
||||
|
||||
this->g = g;
|
||||
this->b = b;
|
||||
this->key = malloc(b);
|
||||
|
||||
return &(this->public);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @file fips_prf.h
|
||||
*
|
||||
* @brief Interface of fips_prf_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef FIPS_PRF_H_
|
||||
#define FIPS_PRF_H_
|
||||
|
||||
typedef struct fips_prf_t fips_prf_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <crypto/prfs/prf.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
|
||||
/**
|
||||
* @brief Implementation of prf_t using the FIPS 186-2-change1 standard.
|
||||
*
|
||||
* FIPS defines a "General Purpose Random Number Generator" (Revised
|
||||
* Algorithm for Computing m values of x (Appendix 3.1 of FIPS 186-2)). This
|
||||
* implementation is not intended for private key generation and therefore does
|
||||
* not include the "mod q" operation (see FIPS 186-2-change1 p74).
|
||||
* The FIPS PRF is stateful; the key changes every time when bytes are acquired.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - fips_prf_create()
|
||||
* - prf_create() using one of the FIPS algorithms
|
||||
*
|
||||
* @ingroup prfs
|
||||
*/
|
||||
struct fips_prf_t {
|
||||
|
||||
/**
|
||||
* Generic prf_t interface for this fips_prf_t class.
|
||||
*/
|
||||
prf_t prf_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a new fips_prf_t object.
|
||||
*
|
||||
* FIPS 186-2 defines G() functions used in the PRF function. It can
|
||||
* be implemented either based on SHA1 or DES.
|
||||
*
|
||||
* @param b size of b (in bytes, not bits)
|
||||
* @param g G() function to use (e.g. g_sha1)
|
||||
* @return
|
||||
* - fips_prf_t object
|
||||
* - NULL if b invalid not supported
|
||||
*
|
||||
* @ingroup prfs
|
||||
*/
|
||||
fips_prf_t *fips_prf_create(size_t b, void(*g)(u_int8_t[],chunk_t,u_int8_t[]));
|
||||
|
||||
/**
|
||||
* @brief Implementation of the G() function based on SHA1.
|
||||
*
|
||||
* @param t initialization vector for SHA1 hasher, 20 bytes long
|
||||
* @param c value to hash, not longer than 512 bit
|
||||
* @param res result of G(), requries 20 bytes
|
||||
*/
|
||||
void g_sha1(u_int8_t t[], chunk_t c, u_int8_t res[]);
|
||||
|
||||
#endif /* FIPS_PRF_H_ */
|
||||
@@ -26,10 +26,13 @@
|
||||
|
||||
#include <crypto/hashers/hasher.h>
|
||||
#include <crypto/prfs/hmac_prf.h>
|
||||
#include <crypto/prfs/fips_prf.h>
|
||||
|
||||
ENUM_BEGIN(pseudo_random_function_names, PRF_UNDEFINED, PRF_UNDEFINED,
|
||||
"PRF_UNDEFINED");
|
||||
ENUM_NEXT(pseudo_random_function_names, PRF_HMAC_MD5, PRF_AES128_CBC, PRF_UNDEFINED,
|
||||
ENUM_BEGIN(pseudo_random_function_names, PRF_UNDEFINED, PRF_FIPS_DES,
|
||||
"PRF_UNDEFINED",
|
||||
"PRF_FIPS_SHA1_160",
|
||||
"PRF_FIPS_DES");
|
||||
ENUM_NEXT(pseudo_random_function_names, PRF_HMAC_MD5, PRF_AES128_CBC, PRF_FIPS_DES,
|
||||
"PRF_HMAC_MD5",
|
||||
"PRF_HMAC_SHA1",
|
||||
"PRF_HMAC_TIGER",
|
||||
@@ -44,13 +47,12 @@ prf_t *prf_create(pseudo_random_function_t pseudo_random_function)
|
||||
switch (pseudo_random_function)
|
||||
{
|
||||
case PRF_HMAC_SHA1:
|
||||
{
|
||||
return (prf_t*)hmac_prf_create(HASH_SHA1);
|
||||
}
|
||||
case PRF_HMAC_MD5:
|
||||
{
|
||||
return (prf_t*)hmac_prf_create(HASH_MD5);
|
||||
}
|
||||
case PRF_FIPS_SHA1_160:
|
||||
return (prf_t*)fips_prf_create(20, g_sha1);
|
||||
case PRF_FIPS_DES:
|
||||
case PRF_HMAC_TIGER:
|
||||
case PRF_AES128_CBC:
|
||||
default:
|
||||
|
||||
@@ -31,11 +31,10 @@ typedef struct prf_t prf_t;
|
||||
|
||||
/**
|
||||
* @brief Pseudo random function, as in IKEv2 RFC 3.3.2.
|
||||
*
|
||||
* Currently only the following algorithms are implemented:
|
||||
* - PRF_HMAC_MD5
|
||||
* - PRF_HMAC_SHA1
|
||||
*
|
||||
*
|
||||
* PRF algorithms not defined in IKEv2 are allocated in "private use"
|
||||
* space.
|
||||
*
|
||||
* @ingroup prfs
|
||||
*/
|
||||
enum pseudo_random_function_t {
|
||||
@@ -46,6 +45,10 @@ enum pseudo_random_function_t {
|
||||
PRF_HMAC_SHA1 = 2,
|
||||
PRF_HMAC_TIGER = 3,
|
||||
PRF_AES128_CBC = 4,
|
||||
/** Implemented via fips_prf_t, other output sizes would be possible */
|
||||
PRF_FIPS_SHA1_160 = 1025,
|
||||
/** Could be implemented via fips_prf_t, uses fixed output size of 160bit */
|
||||
PRF_FIPS_DES = 1026,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -93,6 +96,9 @@ struct prf_t {
|
||||
|
||||
/**
|
||||
* @brief Get the key size of this prf_t object.
|
||||
*
|
||||
* This is a suggestion only, all implemented PRFs accept variable key
|
||||
* length.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return key size in bytes
|
||||
|
||||
@@ -27,11 +27,6 @@
|
||||
|
||||
#include <crypto/prfs/hmac_prf.h>
|
||||
|
||||
/**
|
||||
* This class represents a hmac signer with 12 byte (96 bit) output.
|
||||
*/
|
||||
#define BLOCK_SIZE 12
|
||||
|
||||
typedef struct private_hmac_signer_t private_hmac_signer_t;
|
||||
|
||||
/**
|
||||
@@ -43,10 +38,15 @@ struct private_hmac_signer_t {
|
||||
*/
|
||||
hmac_signer_t public;
|
||||
|
||||
/*
|
||||
/**
|
||||
* Assigned hmac function.
|
||||
*/
|
||||
prf_t *hmac_prf;
|
||||
|
||||
/**
|
||||
* Block size (truncation of HMAC Hash)
|
||||
*/
|
||||
size_t block_size;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -56,10 +56,10 @@ static void get_signature (private_hmac_signer_t *this, chunk_t data, u_int8_t *
|
||||
{
|
||||
u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)];
|
||||
|
||||
this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac);
|
||||
this->hmac_prf->get_bytes(this->hmac_prf, data, full_mac);
|
||||
|
||||
/* copy mac aka signature :-) */
|
||||
memcpy(buffer,full_mac,BLOCK_SIZE);
|
||||
/* copy MAC depending on truncation */
|
||||
memcpy(buffer, full_mac, this->block_size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,11 +72,11 @@ static void allocate_signature (private_hmac_signer_t *this, chunk_t data, chunk
|
||||
|
||||
this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac);
|
||||
|
||||
signature.ptr = malloc(BLOCK_SIZE);
|
||||
signature.len = BLOCK_SIZE;
|
||||
signature.ptr = malloc(this->block_size);
|
||||
signature.len = this->block_size;
|
||||
|
||||
/* copy signature */
|
||||
memcpy(signature.ptr,full_mac,BLOCK_SIZE);
|
||||
memcpy(signature.ptr, full_mac, this->block_size);
|
||||
|
||||
*chunk = signature;
|
||||
}
|
||||
@@ -84,19 +84,19 @@ static void allocate_signature (private_hmac_signer_t *this, chunk_t data, chunk
|
||||
/**
|
||||
* Implementation of signer_t.verify_signature.
|
||||
*/
|
||||
static bool verify_signature (private_hmac_signer_t *this, chunk_t data, chunk_t signature)
|
||||
static bool verify_signature(private_hmac_signer_t *this, chunk_t data, chunk_t signature)
|
||||
{
|
||||
u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)];
|
||||
|
||||
this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac);
|
||||
this->hmac_prf->get_bytes(this->hmac_prf, data, full_mac);
|
||||
|
||||
if (signature.len != BLOCK_SIZE)
|
||||
if (signature.len != this->block_size)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* compare mac aka signature :-) */
|
||||
if (memcmp(signature.ptr,full_mac,BLOCK_SIZE) == 0)
|
||||
if (memcmp(signature.ptr, full_mac, this->block_size) == 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
@@ -109,7 +109,7 @@ static bool verify_signature (private_hmac_signer_t *this, chunk_t data, chunk_t
|
||||
/**
|
||||
* Implementation of signer_t.get_key_size.
|
||||
*/
|
||||
static size_t get_key_size (private_hmac_signer_t *this)
|
||||
static size_t get_key_size(private_hmac_signer_t *this)
|
||||
{
|
||||
/* for HMAC signer, IKEv2 uses block size as key size */
|
||||
return this->hmac_prf->get_block_size(this->hmac_prf);
|
||||
@@ -118,17 +118,17 @@ static size_t get_key_size (private_hmac_signer_t *this)
|
||||
/**
|
||||
* Implementation of signer_t.get_block_size.
|
||||
*/
|
||||
static size_t get_block_size (private_hmac_signer_t *this)
|
||||
static size_t get_block_size(private_hmac_signer_t *this)
|
||||
{
|
||||
return BLOCK_SIZE;
|
||||
return this->block_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of signer_t.set_key.
|
||||
*/
|
||||
static void set_key (private_hmac_signer_t *this, chunk_t key)
|
||||
static void set_key(private_hmac_signer_t *this, chunk_t key)
|
||||
{
|
||||
this->hmac_prf->set_key(this->hmac_prf,key);
|
||||
this->hmac_prf->set_key(this->hmac_prf, key);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,12 +144,12 @@ static status_t destroy(private_hmac_signer_t *this)
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm)
|
||||
hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm, size_t block_size)
|
||||
{
|
||||
size_t hmac_block_size;
|
||||
private_hmac_signer_t *this = malloc_thing(private_hmac_signer_t);
|
||||
|
||||
this->hmac_prf = (prf_t *) hmac_prf_create(hash_algoritm);
|
||||
|
||||
if (this->hmac_prf == NULL)
|
||||
{
|
||||
/* algorithm not supported */
|
||||
@@ -157,6 +157,10 @@ hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* prevent invalid truncation */
|
||||
hmac_block_size = this->hmac_prf->get_block_size(this->hmac_prf);
|
||||
this->block_size = min(block_size, hmac_block_size);
|
||||
|
||||
/* interface functions */
|
||||
this->public.signer_interface.get_signature = (void (*) (signer_t*, chunk_t, u_int8_t*))get_signature;
|
||||
this->public.signer_interface.allocate_signature = (void (*) (signer_t*, chunk_t, chunk_t*))allocate_signature;
|
||||
|
||||
@@ -30,9 +30,11 @@ typedef struct hmac_signer_t hmac_signer_t;
|
||||
#include <crypto/hashers/hasher.h>
|
||||
|
||||
/**
|
||||
* @brief Implementation of signer_t interface using the
|
||||
* HMAC algorithm in combination with either MD5 or SHA1.
|
||||
*
|
||||
* @brief Implementation of signer_t interface using HMAC.
|
||||
*
|
||||
* HMAC uses a standard hash function implemented in a hasher_t to build
|
||||
* a MAC.
|
||||
*
|
||||
* @ingroup signers
|
||||
*/
|
||||
struct hmac_signer_t {
|
||||
@@ -45,15 +47,22 @@ struct hmac_signer_t {
|
||||
|
||||
/**
|
||||
* @brief Creates a new hmac_signer_t.
|
||||
*
|
||||
*
|
||||
* HMAC signatures are often truncated to shorten them to a more usable, but
|
||||
* still secure enough length.
|
||||
* Block size must be equal or smaller then the hash algorithms
|
||||
* hash.
|
||||
*
|
||||
* @param hash_algoritm Hash algorithm to use with signer
|
||||
* @param block_size Size of resulting signature (truncated to block_size)
|
||||
* @return
|
||||
* - hmac_signer_t
|
||||
* - NULL if hash algorithm not supported
|
||||
*
|
||||
* @ingroup signers
|
||||
*/
|
||||
hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm);
|
||||
hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm,
|
||||
size_t block_size);
|
||||
|
||||
|
||||
#endif /*HMAC_SIGNER_H_*/
|
||||
|
||||
@@ -25,9 +25,10 @@
|
||||
|
||||
#include <crypto/signers/hmac_signer.h>
|
||||
|
||||
ENUM_BEGIN(integrity_algorithm_names, AUTH_UNDEFINED, AUTH_UNDEFINED,
|
||||
"UNDEFINED");
|
||||
ENUM_NEXT(integrity_algorithm_names, AUTH_HMAC_MD5_96, AUTH_AES_XCBC_96, AUTH_UNDEFINED,
|
||||
ENUM_BEGIN(integrity_algorithm_names, AUTH_UNDEFINED, AUTH_HMAC_SHA1_128,
|
||||
"UNDEFINED",
|
||||
"AUTH_HMAC_SHA1_128");
|
||||
ENUM_NEXT(integrity_algorithm_names, AUTH_HMAC_MD5_96, AUTH_AES_XCBC_96, AUTH_HMAC_SHA1_128,
|
||||
"HMAC_MD5_96",
|
||||
"HMAC_SHA1_96",
|
||||
"DES_MAC",
|
||||
@@ -43,13 +44,11 @@ signer_t *signer_create(integrity_algorithm_t integrity_algorithm)
|
||||
switch(integrity_algorithm)
|
||||
{
|
||||
case AUTH_HMAC_SHA1_96:
|
||||
{
|
||||
return ((signer_t *) hmac_signer_create(HASH_SHA1));
|
||||
}
|
||||
return (signer_t *)hmac_signer_create(HASH_SHA1, 12);
|
||||
case AUTH_HMAC_SHA1_128:
|
||||
return (signer_t *)hmac_signer_create(HASH_SHA1, 16);
|
||||
case AUTH_HMAC_MD5_96:
|
||||
{
|
||||
return ((signer_t *) hmac_signer_create(HASH_MD5));
|
||||
}
|
||||
return (signer_t *)hmac_signer_create(HASH_MD5, 12);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -31,11 +31,9 @@ typedef struct signer_t signer_t;
|
||||
|
||||
/**
|
||||
* @brief Integrity algorithm, as in IKEv2 RFC 3.3.2.
|
||||
*
|
||||
* Currently only the following algorithms are implemented and therefore supported:
|
||||
* - AUTH_HMAC_MD5_96
|
||||
* - AUTH_HMAC_SHA1_96
|
||||
*
|
||||
*
|
||||
* Algorithms not specified in IKEv2 are allocated in private use space.
|
||||
*
|
||||
* @ingroup signers
|
||||
*/
|
||||
enum integrity_algorithm_t {
|
||||
@@ -46,7 +44,9 @@ enum integrity_algorithm_t {
|
||||
AUTH_HMAC_SHA1_96 = 2,
|
||||
AUTH_DES_MAC = 3,
|
||||
AUTH_KPDK_MD5 = 4,
|
||||
AUTH_AES_XCBC_96 = 5
|
||||
AUTH_AES_XCBC_96 = 5,
|
||||
/** Implemented via hmac_signer_t */
|
||||
AUTH_HMAC_SHA1_128 = 1025,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,6 +43,7 @@ ENUM(status_names, SUCCESS, DESTROY_ME,
|
||||
"VERIFY_ERROR",
|
||||
"INVALID_STATE",
|
||||
"DESTROY_ME",
|
||||
"NEED_MORE",
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -58,6 +59,18 @@ void *clalloc(void * pointer, size_t size)
|
||||
return (data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
void memxor(u_int8_t dest[], u_int8_t src[], size_t n)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
dest[i] ^= src[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We use a single mutex for all refcount variables. This
|
||||
* is not optimal for performance, but the critical section
|
||||
|
||||
@@ -226,6 +226,11 @@ enum status_t {
|
||||
* Destroy object which called method belongs to.
|
||||
*/
|
||||
DESTROY_ME,
|
||||
|
||||
/**
|
||||
* Another call to the method is required.
|
||||
*/
|
||||
NEED_MORE,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -259,6 +264,11 @@ typedef struct sockaddr sockaddr_t;
|
||||
*/
|
||||
void *clalloc(void *pointer, size_t size);
|
||||
|
||||
/**
|
||||
* Same as memcpy, but XORs src into dst instead of copy
|
||||
*/
|
||||
void memxor(u_int8_t dest[], u_int8_t src[], size_t n);
|
||||
|
||||
/**
|
||||
* Special type to count references
|
||||
*/
|
||||
|
||||
@@ -186,6 +186,7 @@ whitelist_t whitelist[] = {
|
||||
{getservbyport, 311},
|
||||
{register_printf_function, 159},
|
||||
{syslog, 45},
|
||||
{dlopen, 109},
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,7 @@ keywords.c files.h keywords.h cmp.c starter.c cmp.h exec.c invokecharon.c \
|
||||
exec.h invokecharon.h lex.yy.c
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/pluto -I$(top_srcdir)/src/whack -I$(top_srcdir)/src/stroke
|
||||
AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DDEBUG
|
||||
AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_EAPDIR=\"${eapdir}\" -DDEBUG
|
||||
starter_LDADD = loglite.o defs.o $(top_srcdir)/src/libfreeswan/libfreeswan.a
|
||||
EXTRA_DIST = parser.l parser.y keywords.txt ipsec.conf
|
||||
dist_man_MANS = ipsec.conf.5
|
||||
|
||||
@@ -165,6 +165,7 @@ static const token_info_t token_info[] =
|
||||
{ ARG_ENUM, offsetof(starter_config_t, setup.nat_traversal), LST_bool },
|
||||
{ ARG_TIME, offsetof(starter_config_t, setup.keep_alive), NULL },
|
||||
{ ARG_STR, offsetof(starter_config_t, setup.virtual_private), NULL },
|
||||
{ ARG_STR, offsetof(starter_config_t, setup.eapdir), NULL },
|
||||
{ ARG_STR, offsetof(starter_config_t, setup.pkcs11module), NULL },
|
||||
{ ARG_ENUM, offsetof(starter_config_t, setup.pkcs11keepstate), LST_bool },
|
||||
{ ARG_ENUM, offsetof(starter_config_t, setup.pkcs11proxy), LST_bool },
|
||||
@@ -184,6 +185,7 @@ static const token_info_t token_info[] =
|
||||
{ ARG_MISC, 0, NULL /* KW_COMPRESS */ },
|
||||
{ ARG_MISC, 0, NULL /* KW_AUTH */ },
|
||||
{ ARG_MISC, 0, NULL /* KW_AUTHBY */ },
|
||||
{ ARG_MISC, 0, NULL /* KW_EAP */ },
|
||||
{ ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL },
|
||||
{ ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL },
|
||||
{ ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL },
|
||||
|
||||
+16
-1
@@ -63,6 +63,7 @@ static void default_values(starter_config_t *cfg)
|
||||
cfg->setup.interfaces = new_list("%defaultroute");
|
||||
cfg->setup.charonstart = TRUE;
|
||||
cfg->setup.plutostart = TRUE;
|
||||
cfg->setup.eapdir = IPSEC_EAPDIR;
|
||||
|
||||
cfg->conn_default.seen = LEMPTY;
|
||||
cfg->conn_default.startup = STARTUP_NO;
|
||||
@@ -414,7 +415,7 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg)
|
||||
case KW_AUTHBY:
|
||||
conn->policy &= ~(POLICY_ID_AUTH_MASK | POLICY_ENCRYPT);
|
||||
|
||||
if (strcmp(kw->value, "never") != 0)
|
||||
if (!(streq(kw->value, "never") || streq(kw->value, "eap")))
|
||||
{
|
||||
char *value = kw->value;
|
||||
char *second = strchr(kw->value, '|');
|
||||
@@ -446,6 +447,20 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KW_EAP:
|
||||
/* TODO: a gperf function for all EAP types */
|
||||
if (streq(kw->value, "aka"))
|
||||
conn->eap = 23;
|
||||
else
|
||||
{
|
||||
conn->eap = atoi(kw->value);
|
||||
if (conn->eap == 0)
|
||||
{
|
||||
plog("# unknown EAP type: %s=%s", kw->entry->name, kw->value);
|
||||
cfg->err++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KW_REKEY:
|
||||
KW_POLICY_FLAG("no", "yes", POLICY_DONT_REKEY)
|
||||
break;
|
||||
|
||||
@@ -95,6 +95,7 @@ struct starter_conn {
|
||||
starter_state_t state;
|
||||
|
||||
keyexchange_t keyexchange;
|
||||
int eap;
|
||||
lset_t policy;
|
||||
time_t sa_ike_life_seconds;
|
||||
time_t sa_ipsec_life_seconds;
|
||||
@@ -167,6 +168,7 @@ struct starter_config {
|
||||
bool nat_traversal;
|
||||
u_int keep_alive;
|
||||
char *virtual_private;
|
||||
char *eapdir;
|
||||
char *pkcs11module;
|
||||
bool pkcs11keepstate;
|
||||
bool pkcs11proxy;
|
||||
|
||||
@@ -116,6 +116,8 @@ starter_start_charon (starter_config_t *cfg, bool debug)
|
||||
{
|
||||
arg[argc++] = "--strictcrlpolicy";
|
||||
}
|
||||
arg[argc++] = "--eapdir";
|
||||
arg[argc++] = cfg->setup.eapdir;
|
||||
|
||||
{ /* parse debug string */
|
||||
char *pos, *level, *buf_pos, type[4], buffer[512];
|
||||
|
||||
@@ -39,6 +39,7 @@ typedef enum {
|
||||
KW_NAT_TRAVERSAL,
|
||||
KW_KEEP_ALIVE,
|
||||
KW_VIRTUAL_PRIVATE,
|
||||
KW_EAPDIR,
|
||||
KW_PKCS11MODULE,
|
||||
KW_PKCS11KEEPSTATE,
|
||||
KW_PKCS11PROXY,
|
||||
@@ -67,6 +68,7 @@ typedef enum {
|
||||
KW_COMPRESS,
|
||||
KW_AUTH,
|
||||
KW_AUTHBY,
|
||||
KW_EAP,
|
||||
KW_IKELIFETIME,
|
||||
KW_KEYLIFE,
|
||||
KW_REKEYMARGIN,
|
||||
|
||||
@@ -47,6 +47,8 @@ nocrsend, KW_NOCRSEND
|
||||
nat_traversal, KW_NAT_TRAVERSAL
|
||||
keep_alive, KW_KEEP_ALIVE
|
||||
virtual_private, KW_VIRTUAL_PRIVATE
|
||||
eap, KW_EAP
|
||||
eapdir, KW_EAPDIR
|
||||
pkcs11module, KW_PKCS11MODULE
|
||||
pkcs11keepstate, KW_PKCS11KEEPSTATE
|
||||
pkcs11proxy, KW_PKCS11PROXY
|
||||
|
||||
+21
-23
@@ -37,29 +37,13 @@
|
||||
#include "files.h"
|
||||
|
||||
/**
|
||||
* AUTH Method to use.
|
||||
*
|
||||
* @ingroup config
|
||||
* Authentication mehtods, must be the same values as in charon
|
||||
*/
|
||||
enum auth_method_t {
|
||||
/**
|
||||
* Computed as specified in section 2.15 of RFC using
|
||||
* an RSA private key over a PKCS#1 padded hash.
|
||||
*/
|
||||
RSA_DIGITAL_SIGNATURE = 1,
|
||||
|
||||
/**
|
||||
* Computed as specified in section 2.15 of RFC using the
|
||||
* shared key associated with the identity in the ID payload
|
||||
* and the negotiated prf function
|
||||
*/
|
||||
SHARED_KEY_MESSAGE_INTEGRITY_CODE = 2,
|
||||
|
||||
/**
|
||||
* Computed as specified in section 2.15 of RFC using a
|
||||
* DSS private key over a SHA-1 hash.
|
||||
*/
|
||||
DSS_DIGITAL_SIGNATURE = 3,
|
||||
AUTH_RSA = 1,
|
||||
AUTH_PSK = 2,
|
||||
AUTH_DSS = 3,
|
||||
AUTH_EAP = 201,
|
||||
};
|
||||
|
||||
static char* push_string(stroke_msg_t *msg, char *string)
|
||||
@@ -192,8 +176,22 @@ int starter_stroke_add_conn(starter_conn_t *conn)
|
||||
msg.length = offsetof(stroke_msg_t, buffer);
|
||||
msg.add_conn.ikev2 = conn->keyexchange == KEY_EXCHANGE_IKEV2;
|
||||
msg.add_conn.name = push_string(&msg, connection_name(conn));
|
||||
msg.add_conn.auth_method = (conn->policy & POLICY_PSK)?
|
||||
SHARED_KEY_MESSAGE_INTEGRITY_CODE : RSA_DIGITAL_SIGNATURE;
|
||||
|
||||
/* RSA is preferred before PSK and EAP */
|
||||
if (conn->policy & POLICY_RSASIG)
|
||||
{
|
||||
msg.add_conn.auth_method = AUTH_RSA;
|
||||
}
|
||||
else if (conn->policy & POLICY_PSK)
|
||||
{
|
||||
msg.add_conn.auth_method = AUTH_PSK;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.add_conn.auth_method = AUTH_EAP;
|
||||
}
|
||||
msg.add_conn.eap_type = conn->eap;
|
||||
|
||||
if (conn->policy & POLICY_TUNNEL)
|
||||
{
|
||||
msg.add_conn.mode = 1; /* XFRM_MODE_TRANSPORT */
|
||||
|
||||
@@ -106,6 +106,8 @@ static int add_connection(char *name,
|
||||
|
||||
msg.add_conn.name = push_string(&msg, name);
|
||||
msg.add_conn.ikev2 = 1;
|
||||
msg.add_conn.auth_method = 2;
|
||||
msg.add_conn.eap_type = 0;
|
||||
msg.add_conn.mode = 1;
|
||||
|
||||
msg.add_conn.rekey.reauth = 0;
|
||||
|
||||
@@ -137,6 +137,7 @@ struct stroke_msg_t {
|
||||
char *name;
|
||||
int ikev2;
|
||||
int auth_method;
|
||||
int eap_type;
|
||||
int mode;
|
||||
struct {
|
||||
char *ike;
|
||||
|
||||
@@ -47,6 +47,10 @@ case $UMLSTARTMODE in
|
||||
cecho "Start the uml instances (scripts/kstart-umls)"
|
||||
$DIR/scripts/kstart-umls $HOSTS
|
||||
;;
|
||||
gnome-terminal)
|
||||
cecho "Start the uml instances (scripts/gstart-umls)"
|
||||
$DIR/scripts/gstart-umls $HOSTS
|
||||
;;
|
||||
xterm)
|
||||
cecho "Start the uml instances (scripts/xstart-umls)"
|
||||
$DIR/scripts/xstart-umls $HOSTS
|
||||
|
||||
+10
-10
@@ -17,7 +17,7 @@
|
||||
# RCSID $Id: testing.conf,v 1.52 2006/04/24 16:58:03 as Exp $
|
||||
|
||||
# Root directory of testing
|
||||
UMLTESTDIR=~/strongswan-testing
|
||||
UMLTESTDIR=/home/strongswan-testing
|
||||
|
||||
# Bzipped kernel sources
|
||||
# (file extension .tar.bz2 required)
|
||||
@@ -49,13 +49,13 @@ ROOTFSSIZE=544
|
||||
# Amount of Memory to use per UML [MB].
|
||||
# If "auto" is stated 1/12 of total host ram will be used.
|
||||
# Examples: MEM=64, MEM="128", MEM="auto"
|
||||
MEM=64
|
||||
MEM=96
|
||||
|
||||
# Directory where the UML kernels and file system will be built
|
||||
BUILDDIR=$UMLTESTDIR/umlbuild
|
||||
|
||||
# Filename of the built UML Kernel
|
||||
UMLKERNEL=$BUILDDIR/linux-uml-$KERNELVERSION
|
||||
UMLKERNEL=$UMLTESTDIR/linux
|
||||
|
||||
# Directory where test results will be stored
|
||||
TESTRESULTSDIR=$UMLTESTDIR/testresults
|
||||
@@ -63,7 +63,7 @@ TESTRESULTSDIR=$UMLTESTDIR/testresults
|
||||
# Path to a full strongswan tree on the host system, which is
|
||||
# mounted into /root/strongswan-shared. This gives us an easy
|
||||
# way to apply and test changes instantly.
|
||||
#SHAREDTREE=/home/mwilli/strongswan/trunk
|
||||
SHAREDTREE=/home/martin/strongswan/trunk
|
||||
|
||||
# Timezone for the UMLs, look in /usr/share/zoneinfo!
|
||||
TZUML="Europe/Zurich"
|
||||
@@ -72,22 +72,22 @@ TZUML="Europe/Zurich"
|
||||
# Enable particular steps in the make-testing and
|
||||
# start-testing scripts
|
||||
#
|
||||
ENABLE_BUILD_UMLKERNEL="yes"
|
||||
ENABLE_BUILD_UMLKERNEL="no"
|
||||
ENABLE_BUILD_SSHKEYS="yes"
|
||||
ENABLE_BUILD_HOSTCONFIG="yes"
|
||||
ENABLE_BUILD_UMLROOTFS="yes"
|
||||
ENABLE_BUILD_UMLHOSTFS="yes"
|
||||
ENABLE_START_TESTING="yes"
|
||||
ENABLE_DO_TESTS="yes"
|
||||
ENABLE_START_TESTING="no"
|
||||
ENABLE_DO_TESTS="no"
|
||||
ENABLE_STOP_TESTING="no"
|
||||
|
||||
##############################################################
|
||||
# How to start the UMLs?
|
||||
#
|
||||
# Start the UML instance in KDE konsole (requires KDE)
|
||||
UMLSTARTMODE="konsole"
|
||||
#UMLSTARTMODE="gnome-terminal"
|
||||
# Start the UML instance in an xterm (requires X11R6)
|
||||
# UMLSTARTMODE="xterm"
|
||||
UMLSTARTMODE="xterm"
|
||||
# Start the UML instance without a terminal window
|
||||
# but screen -r <host> can open a window anytime
|
||||
# UMLSTARTMODE="screen"
|
||||
@@ -100,7 +100,7 @@ SELECTEDTESTSONLY="no"
|
||||
|
||||
# Tests to do if $SELECTEDTESTSONLY is set "yes".
|
||||
#
|
||||
SELECTEDTESTS="net2net-cert"
|
||||
SELECTEDTESTS="ikev2-net2net ikev2-rw"
|
||||
|
||||
##############################################################
|
||||
# hostname and corresponding IPv4 and IPv6 addresses
|
||||
|
||||
Reference in New Issue
Block a user