Separated libcharon/sa directory with ikev1 and ikev2 subfolders
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "hybrid_authenticator.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
typedef struct private_hybrid_authenticator_t private_hybrid_authenticator_t;
|
||||
|
||||
/**
|
||||
* Private data of an hybrid_authenticator_t object.
|
||||
*/
|
||||
struct private_hybrid_authenticator_t {
|
||||
|
||||
/**
|
||||
* Public authenticator_t interface.
|
||||
*/
|
||||
hybrid_authenticator_t public;
|
||||
|
||||
/**
|
||||
* Public key authenticator
|
||||
*/
|
||||
authenticator_t *sig;
|
||||
|
||||
/**
|
||||
* HASH payload authenticator without credentials
|
||||
*/
|
||||
authenticator_t *hash;
|
||||
};
|
||||
|
||||
METHOD(authenticator_t, build_i, status_t,
|
||||
private_hybrid_authenticator_t *this, message_t *message)
|
||||
{
|
||||
return this->hash->build(this->hash, message);
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, process_r, status_t,
|
||||
private_hybrid_authenticator_t *this, message_t *message)
|
||||
{
|
||||
return this->hash->process(this->hash, message);
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, build_r, status_t,
|
||||
private_hybrid_authenticator_t *this, message_t *message)
|
||||
{
|
||||
return this->sig->build(this->sig, message);
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, process_i, status_t,
|
||||
private_hybrid_authenticator_t *this, message_t *message)
|
||||
{
|
||||
return this->sig->process(this->sig, message);
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, destroy, void,
|
||||
private_hybrid_authenticator_t *this)
|
||||
{
|
||||
DESTROY_IF(this->hash);
|
||||
DESTROY_IF(this->sig);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
hybrid_authenticator_t *hybrid_authenticator_create(ike_sa_t *ike_sa,
|
||||
bool initiator, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload)
|
||||
{
|
||||
private_hybrid_authenticator_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.authenticator = {
|
||||
.is_mutual = (void*)return_false,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.sig = authenticator_create_v1(ike_sa, initiator, AUTH_RSA, dh,
|
||||
dh_value, sa_payload, id_payload),
|
||||
.hash = authenticator_create_v1(ike_sa, initiator, AUTH_PSK,
|
||||
dh, dh_value, sa_payload, chunk_clone(id_payload)),
|
||||
);
|
||||
if (!this->sig || !this->hash)
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
if (initiator)
|
||||
{
|
||||
this->public.authenticator.build = _build_i;
|
||||
this->public.authenticator.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.authenticator.build = _build_r;
|
||||
this->public.authenticator.process = _process_r;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup hybrid_authenticator hybrid_authenticator
|
||||
* @{ @ingroup authenticators
|
||||
*/
|
||||
|
||||
#ifndef HYBRID_AUTHENTICATOR_H_
|
||||
#define HYBRID_AUTHENTICATOR_H_
|
||||
|
||||
typedef struct hybrid_authenticator_t hybrid_authenticator_t;
|
||||
|
||||
#include <sa/authenticator.h>
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t using IKEv1 hybrid authentication.
|
||||
*/
|
||||
struct hybrid_authenticator_t {
|
||||
|
||||
/**
|
||||
* Implemented authenticator_t interface.
|
||||
*/
|
||||
authenticator_t authenticator;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an authenticator to build hybrid signatures.
|
||||
*
|
||||
* @param ike_sa associated IKE_SA
|
||||
* @param initiator TRUE if we are the IKE_SA initiator
|
||||
* @param dh diffie hellman key exchange
|
||||
* @param dh_value others public diffie hellman value
|
||||
* @param sa_payload generated SA payload data, without payload header
|
||||
* @param id_payload encoded ID payload of peer to authenticate or verify
|
||||
* without payload header (gets owned)
|
||||
* @return hybrid authenticator
|
||||
*/
|
||||
hybrid_authenticator_t *hybrid_authenticator_create(ike_sa_t *ike_sa,
|
||||
bool initiator, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload);
|
||||
|
||||
#endif /** HYBRID_AUTHENTICATOR_H_ @}*/
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "psk_v1_authenticator.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev1/keymat_v1.h>
|
||||
#include <encoding/payloads/hash_payload.h>
|
||||
|
||||
typedef struct private_psk_v1_authenticator_t private_psk_v1_authenticator_t;
|
||||
|
||||
/**
|
||||
* Private data of an psk_v1_authenticator_t object.
|
||||
*/
|
||||
struct private_psk_v1_authenticator_t {
|
||||
|
||||
/**
|
||||
* Public authenticator_t interface.
|
||||
*/
|
||||
psk_v1_authenticator_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* TRUE if we are initiator
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* DH key exchange
|
||||
*/
|
||||
diffie_hellman_t *dh;
|
||||
|
||||
/**
|
||||
* Others DH public value
|
||||
*/
|
||||
chunk_t dh_value;
|
||||
|
||||
/**
|
||||
* Encoded SA payload, without fixed header
|
||||
*/
|
||||
chunk_t sa_payload;
|
||||
|
||||
/**
|
||||
* Encoded ID payload, without fixed header
|
||||
*/
|
||||
chunk_t id_payload;
|
||||
};
|
||||
|
||||
METHOD(authenticator_t, build, status_t,
|
||||
private_psk_v1_authenticator_t *this, message_t *message)
|
||||
{
|
||||
hash_payload_t *hash_payload;
|
||||
keymat_v1_t *keymat;
|
||||
chunk_t hash, dh;
|
||||
|
||||
this->dh->get_my_public_value(this->dh, &dh);
|
||||
keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
hash = keymat->get_hash(keymat, this->initiator, dh, this->dh_value,
|
||||
this->ike_sa->get_id(this->ike_sa), this->sa_payload,
|
||||
this->id_payload);
|
||||
free(dh.ptr);
|
||||
|
||||
hash_payload = hash_payload_create(HASH_V1);
|
||||
hash_payload->set_hash(hash_payload, hash);
|
||||
message->add_payload(message, &hash_payload->payload_interface);
|
||||
free(hash.ptr);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, process, status_t,
|
||||
private_psk_v1_authenticator_t *this, message_t *message)
|
||||
{
|
||||
hash_payload_t *hash_payload;
|
||||
keymat_v1_t *keymat;
|
||||
chunk_t hash, dh;
|
||||
|
||||
hash_payload = (hash_payload_t*)message->get_payload(message, HASH_V1);
|
||||
if (!hash_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "HASH payload missing in message");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
this->dh->get_my_public_value(this->dh, &dh);
|
||||
keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
hash = keymat->get_hash(keymat, !this->initiator, this->dh_value, dh,
|
||||
this->ike_sa->get_id(this->ike_sa), this->sa_payload,
|
||||
this->id_payload);
|
||||
free(dh.ptr);
|
||||
if (chunk_equals(hash, hash_payload->get_hash(hash_payload)))
|
||||
{
|
||||
free(hash.ptr);
|
||||
return SUCCESS;
|
||||
}
|
||||
free(hash.ptr);
|
||||
DBG1(DBG_IKE, "calculated HASH does not match HASH payload");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, destroy, void,
|
||||
private_psk_v1_authenticator_t *this)
|
||||
{
|
||||
chunk_free(&this->id_payload);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa,
|
||||
bool initiator, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload)
|
||||
{
|
||||
private_psk_v1_authenticator_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.authenticator = {
|
||||
.build = _build,
|
||||
.process = _process,
|
||||
.is_mutual = (void*)return_false,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.initiator = initiator,
|
||||
.dh = dh,
|
||||
.dh_value = dh_value,
|
||||
.sa_payload = sa_payload,
|
||||
.id_payload = id_payload,
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup psk_v1_authenticator psk_v1_authenticator
|
||||
* @{ @ingroup authenticators
|
||||
*/
|
||||
|
||||
#ifndef PSK_V1_AUTHENTICATOR_H_
|
||||
#define PSK_V1_AUTHENTICATOR_H_
|
||||
|
||||
typedef struct psk_v1_authenticator_t psk_v1_authenticator_t;
|
||||
|
||||
#include <sa/authenticator.h>
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t using pre-shared keys for IKEv1.
|
||||
*/
|
||||
struct psk_v1_authenticator_t {
|
||||
|
||||
/**
|
||||
* Implemented authenticator_t interface.
|
||||
*/
|
||||
authenticator_t authenticator;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an authenticator to build PSK signatures.
|
||||
*
|
||||
* @param ike_sa associated IKE_SA
|
||||
* @param initiator TRUE if we are the IKE_SA initiator
|
||||
* @param dh diffie hellman key exchange
|
||||
* @param dh_value others public diffie hellman value
|
||||
* @param sa_payload generated SA payload data, without payload header
|
||||
* @param id_payload encoded ID payload of peer to authenticate or verify
|
||||
* without payload header (gets owned)
|
||||
* @return PSK authenticator
|
||||
*/
|
||||
psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa,
|
||||
bool initiator, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload);
|
||||
|
||||
#endif /** PSK_V1_AUTHENTICATOR_H_ @}*/
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "pubkey_v1_authenticator.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev1/keymat_v1.h>
|
||||
#include <encoding/payloads/hash_payload.h>
|
||||
|
||||
typedef struct private_pubkey_v1_authenticator_t private_pubkey_v1_authenticator_t;
|
||||
|
||||
/**
|
||||
* Private data of an pubkey_v1_authenticator_t object.
|
||||
*/
|
||||
struct private_pubkey_v1_authenticator_t {
|
||||
|
||||
/**
|
||||
* Public authenticator_t interface.
|
||||
*/
|
||||
pubkey_v1_authenticator_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* TRUE if we are initiator
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* DH key exchange
|
||||
*/
|
||||
diffie_hellman_t *dh;
|
||||
|
||||
/**
|
||||
* Others DH public value
|
||||
*/
|
||||
chunk_t dh_value;
|
||||
|
||||
/**
|
||||
* Encoded SA payload, without fixed header
|
||||
*/
|
||||
chunk_t sa_payload;
|
||||
|
||||
/**
|
||||
* Encoded ID payload, without fixed header
|
||||
*/
|
||||
chunk_t id_payload;
|
||||
};
|
||||
|
||||
METHOD(authenticator_t, build, status_t,
|
||||
private_pubkey_v1_authenticator_t *this, message_t *message)
|
||||
{
|
||||
hash_payload_t *sig_payload;
|
||||
chunk_t hash, sig, dh;
|
||||
keymat_v1_t *keymat;
|
||||
status_t status;
|
||||
private_key_t *private;
|
||||
identification_t *id;
|
||||
auth_cfg_t *auth;
|
||||
key_type_t type;
|
||||
signature_scheme_t scheme;
|
||||
|
||||
/* TODO-IKEv1: other key types */
|
||||
type = KEY_RSA;
|
||||
scheme = SIGN_RSA_EMSA_PKCS1_NULL;
|
||||
|
||||
id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
|
||||
private = lib->credmgr->get_private(lib->credmgr, type, id, auth);
|
||||
if (!private)
|
||||
{
|
||||
DBG1(DBG_IKE, "no private key found for '%Y'", id);
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
this->dh->get_my_public_value(this->dh, &dh);
|
||||
keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
hash = keymat->get_hash(keymat, this->initiator, dh, this->dh_value,
|
||||
this->ike_sa->get_id(this->ike_sa), this->sa_payload,
|
||||
this->id_payload);
|
||||
free(dh.ptr);
|
||||
|
||||
if (private->sign(private, scheme, hash, &sig))
|
||||
{
|
||||
sig_payload = hash_payload_create(SIGNATURE_V1);
|
||||
sig_payload->set_hash(sig_payload, sig);
|
||||
free(sig.ptr);
|
||||
message->add_payload(message, &sig_payload->payload_interface);
|
||||
status = SUCCESS;
|
||||
DBG1(DBG_IKE, "authentication of '%Y' (myself) successful", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "authentication of '%Y' (myself) failed", id);
|
||||
status = FAILED;
|
||||
}
|
||||
private->destroy(private);
|
||||
free(hash.ptr);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, process, status_t,
|
||||
private_pubkey_v1_authenticator_t *this, message_t *message)
|
||||
{
|
||||
chunk_t hash, sig, dh;
|
||||
keymat_v1_t *keymat;
|
||||
public_key_t *public;
|
||||
hash_payload_t *sig_payload;
|
||||
auth_cfg_t *auth, *current_auth;
|
||||
enumerator_t *enumerator;
|
||||
status_t status = NOT_FOUND;
|
||||
key_type_t type;
|
||||
signature_scheme_t scheme;
|
||||
identification_t *id;
|
||||
|
||||
/* TODO-IKEv1: currently RSA only */
|
||||
type = KEY_RSA;
|
||||
scheme = SIGN_RSA_EMSA_PKCS1_NULL;
|
||||
|
||||
sig_payload = (hash_payload_t*)message->get_payload(message, SIGNATURE_V1);
|
||||
if (!sig_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "SIG payload missing in message");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
this->dh->get_my_public_value(this->dh, &dh);
|
||||
keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa);
|
||||
hash = keymat->get_hash(keymat, !this->initiator, this->dh_value, dh,
|
||||
this->ike_sa->get_id(this->ike_sa), this->sa_payload,
|
||||
this->id_payload);
|
||||
free(dh.ptr);
|
||||
|
||||
sig = sig_payload->get_hash(sig_payload);
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
|
||||
enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, type,
|
||||
id, auth);
|
||||
while (enumerator->enumerate(enumerator, &public, ¤t_auth))
|
||||
{
|
||||
if (public->verify(public, scheme, hash, sig))
|
||||
{
|
||||
DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
|
||||
id, key_type_names, type);
|
||||
status = SUCCESS;
|
||||
auth->merge(auth, current_auth, FALSE);
|
||||
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "signature validation failed, looking for another key");
|
||||
status = FAILED;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
free(hash.ptr);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "no trusted %N public key found for '%Y'",
|
||||
key_type_names, type, id);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
METHOD(authenticator_t, destroy, void,
|
||||
private_pubkey_v1_authenticator_t *this)
|
||||
{
|
||||
chunk_free(&this->id_payload);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa,
|
||||
bool initiator, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload)
|
||||
{
|
||||
private_pubkey_v1_authenticator_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.authenticator = {
|
||||
.build = _build,
|
||||
.process = _process,
|
||||
.is_mutual = (void*)return_false,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.initiator = initiator,
|
||||
.dh = dh,
|
||||
.dh_value = dh_value,
|
||||
.sa_payload = sa_payload,
|
||||
.id_payload = id_payload,
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup pubkey_v1_authenticator pubkey_v1_authenticator
|
||||
* @{ @ingroup authenticators
|
||||
*/
|
||||
|
||||
#ifndef PUBKEY_V1_AUTHENTICATOR_H_
|
||||
#define PUBKEY_V1_AUTHENTICATOR_H_
|
||||
|
||||
typedef struct pubkey_v1_authenticator_t pubkey_v1_authenticator_t;
|
||||
|
||||
#include <sa/authenticator.h>
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t using public keys for IKEv1.
|
||||
*/
|
||||
struct pubkey_v1_authenticator_t {
|
||||
|
||||
/**
|
||||
* Implemented authenticator_t interface.
|
||||
*/
|
||||
authenticator_t authenticator;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an authenticator to build and verify public key signatures.
|
||||
*
|
||||
* @param ike_sa associated IKE_SA
|
||||
* @param initiator TRUE if we are IKE_SA initiator
|
||||
* @param dh diffie hellman key exchange
|
||||
* @param dh_value others public diffie hellman value
|
||||
* @param sa_payload generated SA payload data, without payload header
|
||||
* @param id_payload encoded ID payload of peer to authenticate or verify
|
||||
* without payload header (gets owned)
|
||||
* @return pubkey authenticator
|
||||
*/
|
||||
pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa,
|
||||
bool initiator, diffie_hellman_t *dh,
|
||||
chunk_t dh_value, chunk_t sa_payload,
|
||||
chunk_t id_payload);
|
||||
|
||||
#endif /** PUBKEY_V1_AUTHENTICATOR_H_ @}*/
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "xauth_manager.h"
|
||||
|
||||
#include <utils/linked_list.h>
|
||||
#include <threading/rwlock.h>
|
||||
|
||||
typedef struct private_xauth_manager_t private_xauth_manager_t;
|
||||
typedef struct xauth_entry_t xauth_entry_t;
|
||||
|
||||
/**
|
||||
* XAuth constructor entry
|
||||
*/
|
||||
struct xauth_entry_t {
|
||||
|
||||
/**
|
||||
* Xauth backend name
|
||||
*/
|
||||
char *name;
|
||||
|
||||
/**
|
||||
* Role of the method, XAUTH_SERVER or XAUTH_PEER
|
||||
*/
|
||||
xauth_role_t role;
|
||||
|
||||
/**
|
||||
* constructor function to create instance
|
||||
*/
|
||||
xauth_constructor_t constructor;
|
||||
};
|
||||
|
||||
/**
|
||||
* private data of xauth_manager
|
||||
*/
|
||||
struct private_xauth_manager_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
xauth_manager_t public;
|
||||
|
||||
/**
|
||||
* list of eap_entry_t's
|
||||
*/
|
||||
linked_list_t *methods;
|
||||
|
||||
/**
|
||||
* rwlock to lock methods
|
||||
*/
|
||||
rwlock_t *lock;
|
||||
};
|
||||
|
||||
METHOD(xauth_manager_t, add_method, void,
|
||||
private_xauth_manager_t *this, char *name, xauth_role_t role,
|
||||
xauth_constructor_t constructor)
|
||||
{
|
||||
xauth_entry_t *entry;
|
||||
|
||||
INIT(entry,
|
||||
.name = name,
|
||||
.role = role,
|
||||
.constructor = constructor,
|
||||
);
|
||||
|
||||
this->lock->write_lock(this->lock);
|
||||
this->methods->insert_last(this->methods, entry);
|
||||
this->lock->unlock(this->lock);
|
||||
}
|
||||
|
||||
METHOD(xauth_manager_t, remove_method, void,
|
||||
private_xauth_manager_t *this, xauth_constructor_t constructor)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
xauth_entry_t *entry;
|
||||
|
||||
this->lock->write_lock(this->lock);
|
||||
enumerator = this->methods->create_enumerator(this->methods);
|
||||
while (enumerator->enumerate(enumerator, &entry))
|
||||
{
|
||||
if (constructor == entry->constructor)
|
||||
{
|
||||
this->methods->remove_at(this->methods, enumerator);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
this->lock->unlock(this->lock);
|
||||
}
|
||||
|
||||
METHOD(xauth_manager_t, create_instance, xauth_method_t*,
|
||||
private_xauth_manager_t *this, char *name, xauth_role_t role,
|
||||
identification_t *server, identification_t *peer)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
xauth_entry_t *entry;
|
||||
xauth_method_t *method = NULL;
|
||||
|
||||
this->lock->read_lock(this->lock);
|
||||
enumerator = this->methods->create_enumerator(this->methods);
|
||||
while (enumerator->enumerate(enumerator, &entry))
|
||||
{
|
||||
if (role == entry->role &&
|
||||
(!name || streq(name, entry->name)))
|
||||
{
|
||||
method = entry->constructor(server, peer);
|
||||
if (method)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
this->lock->unlock(this->lock);
|
||||
return method;
|
||||
}
|
||||
|
||||
METHOD(xauth_manager_t, destroy, void,
|
||||
private_xauth_manager_t *this)
|
||||
{
|
||||
this->methods->destroy_function(this->methods, free);
|
||||
this->lock->destroy(this->lock);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* See header
|
||||
*/
|
||||
xauth_manager_t *xauth_manager_create()
|
||||
{
|
||||
private_xauth_manager_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.add_method = _add_method,
|
||||
.remove_method = _remove_method,
|
||||
.create_instance = _create_instance,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.methods = linked_list_create(),
|
||||
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup xauth_manager xauth_manager
|
||||
* @{ @ingroup xauth
|
||||
*/
|
||||
|
||||
#ifndef XAUTH_MANAGER_H_
|
||||
#define XAUTH_MANAGER_H_
|
||||
|
||||
#include <sa/ikev1/authenticators/xauth/xauth_method.h>
|
||||
|
||||
typedef struct xauth_manager_t xauth_manager_t;
|
||||
|
||||
/**
|
||||
* The XAuth manager manages all XAuth implementations and creates instances.
|
||||
*
|
||||
* A plugin registers it's implemented XAuth method at the manager by
|
||||
* providing type and a contructor function. The manager then instanciates
|
||||
* xauth_method_t instances through the provided constructor to handle
|
||||
* XAuth authentication.
|
||||
*/
|
||||
struct xauth_manager_t {
|
||||
|
||||
/**
|
||||
* Register a XAuth method implementation.
|
||||
*
|
||||
* @param name backend name to register
|
||||
* @param role XAUTH_SERVER or XAUTH_PEER
|
||||
* @param constructor constructor function, returns an xauth_method_t
|
||||
*/
|
||||
void (*add_method)(xauth_manager_t *this, char *name,
|
||||
xauth_role_t role, xauth_constructor_t constructor);
|
||||
|
||||
/**
|
||||
* Unregister a XAuth method implementation using it's constructor.
|
||||
*
|
||||
* @param constructor constructor function, as added in add_method
|
||||
*/
|
||||
void (*remove_method)(xauth_manager_t *this, xauth_constructor_t constructor);
|
||||
|
||||
/**
|
||||
* Create a new XAuth method instance.
|
||||
*
|
||||
* @param name backend name, as it was registered with
|
||||
* @param role XAUTH_SERVER or XAUTH_PEER
|
||||
* @param server identity of the server
|
||||
* @param peer identity of the peer (client)
|
||||
* @return XAUTH method instance, NULL if no constructor found
|
||||
*/
|
||||
xauth_method_t* (*create_instance)(xauth_manager_t *this,
|
||||
char *name, xauth_role_t role,
|
||||
identification_t *server, identification_t *peer);
|
||||
|
||||
/**
|
||||
* Destroy a eap_manager instance.
|
||||
*/
|
||||
void (*destroy)(xauth_manager_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a eap_manager instance.
|
||||
*/
|
||||
xauth_manager_t *xauth_manager_create();
|
||||
|
||||
#endif /** XAUTH_MANAGER_H_ @}*/
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 "xauth_method.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
ENUM(xauth_role_names, XAUTH_SERVER, XAUTH_PEER,
|
||||
"XAUTH_SERVER",
|
||||
"XAUTH_PEER",
|
||||
);
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
bool xauth_method_register(plugin_t *plugin, plugin_feature_t *feature,
|
||||
bool reg, void *data)
|
||||
{
|
||||
if (reg)
|
||||
{
|
||||
charon->xauth->add_method(charon->xauth, feature->arg.xauth,
|
||||
feature->type == FEATURE_XAUTH_SERVER ? XAUTH_SERVER : XAUTH_PEER,
|
||||
(xauth_constructor_t)data);
|
||||
}
|
||||
else
|
||||
{
|
||||
charon->xauth->remove_method(charon->xauth, (xauth_constructor_t)data);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup xauth_method xauth_method
|
||||
* @{ @ingroup xauth
|
||||
*/
|
||||
|
||||
#ifndef XAUTH_METHOD_H_
|
||||
#define XAUTH_METHOD_H_
|
||||
|
||||
typedef struct xauth_method_t xauth_method_t;
|
||||
typedef enum xauth_role_t xauth_role_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <plugins/plugin.h>
|
||||
#include <utils/identification.h>
|
||||
#include <encoding/payloads/cp_payload.h>
|
||||
|
||||
/**
|
||||
* Role of an xauth_method, SERVER or PEER (client)
|
||||
*/
|
||||
enum xauth_role_t {
|
||||
XAUTH_SERVER,
|
||||
XAUTH_PEER,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum names for xauth_role_t.
|
||||
*/
|
||||
extern enum_name_t *xauth_role_names;
|
||||
|
||||
/**
|
||||
* Interface of an XAuth method for server and client side.
|
||||
*
|
||||
* An XAuth method initiates an XAuth exchange and processes requests and
|
||||
* responses. An XAuth method may need multiple exchanges before succeeding.
|
||||
* Sending of XAUTH(STATUS) message is done by the framework, not a method.
|
||||
*/
|
||||
struct xauth_method_t {
|
||||
|
||||
/**
|
||||
* Initiate the XAuth exchange.
|
||||
*
|
||||
* initiate() is only useable for server implementations, as clients only
|
||||
* reply to server requests.
|
||||
* A cp_payload is created in "out" if result is NEED_MORE.
|
||||
*
|
||||
* @param out cp_payload to send to the client
|
||||
* @return
|
||||
* - NEED_MORE, if an other exchange is required
|
||||
* - FAILED, if unable to create XAuth request payload
|
||||
*/
|
||||
status_t (*initiate) (xauth_method_t *this, cp_payload_t **out);
|
||||
|
||||
/**
|
||||
* Process a received XAuth message.
|
||||
*
|
||||
* A cp_payload is created in "out" if result is NEED_MORE.
|
||||
*
|
||||
* @param in cp_payload response received
|
||||
* @param out created cp_payload to send
|
||||
* @return
|
||||
* - NEED_MORE, if an other exchange is required
|
||||
* - FAILED, if XAuth method failed
|
||||
* - SUCCESS, if XAuth method succeeded
|
||||
*/
|
||||
status_t (*process) (xauth_method_t *this, cp_payload_t *in,
|
||||
cp_payload_t **out);
|
||||
|
||||
/**
|
||||
* Get the XAuth username received as XAuth initiator.
|
||||
*
|
||||
* @return used XAuth username, pointer to internal data
|
||||
*/
|
||||
identification_t* (*get_identity)(xauth_method_t *this);
|
||||
|
||||
/**
|
||||
* Destroys a eap_method_t object.
|
||||
*/
|
||||
void (*destroy) (xauth_method_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor definition for a pluggable XAuth method.
|
||||
*
|
||||
* Each XAuth module must define a constructor function which will return
|
||||
* an initialized object with the methods defined in xauth_method_t.
|
||||
* Constructors for server and peers are identical, to support both roles
|
||||
* of a XAuth method, a plugin needs register two constructors in the
|
||||
* xauth_manager_t.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
typedef xauth_method_t *(*xauth_constructor_t)(identification_t *server,
|
||||
identification_t *peer);
|
||||
|
||||
/**
|
||||
* Helper function to (un-)register XAuth methods from plugin features.
|
||||
*
|
||||
* This function is a plugin_feature_callback_t and can be used with the
|
||||
* PLUGIN_CALLBACK macro to register a XAuth method constructor.
|
||||
*
|
||||
* @param plugin plugin registering the XAuth method constructor
|
||||
* @param feature associated plugin feature
|
||||
* @param reg TRUE to register, FALSE to unregister.
|
||||
* @param data data passed to callback, an xauth_constructor_t
|
||||
*/
|
||||
bool xauth_method_register(plugin_t *plugin, plugin_feature_t *feature,
|
||||
bool reg, void *data);
|
||||
|
||||
#endif /** XAUTH_METHOD_H_ @}*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Tobias Brunner
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup keymat_v1 keymat_v1
|
||||
* @{ @ingroup sa
|
||||
*/
|
||||
|
||||
#ifndef KEYMAT_V1_H_
|
||||
#define KEYMAT_V1_H_
|
||||
|
||||
#include <sa/keymat.h>
|
||||
#include <sa/authenticator.h>
|
||||
|
||||
typedef struct keymat_v1_t keymat_v1_t;
|
||||
|
||||
/**
|
||||
* Derivation and management of sensitive keying material, IKEv1 variant.
|
||||
*/
|
||||
struct keymat_v1_t {
|
||||
|
||||
/**
|
||||
* Implements keymat_t.
|
||||
*/
|
||||
keymat_t keymat;
|
||||
|
||||
/**
|
||||
* Derive keys for the IKE_SA.
|
||||
*
|
||||
* These keys are not handed out, but are used by the associated signers,
|
||||
* crypters and authentication functions.
|
||||
*
|
||||
* @param proposal selected algorithms
|
||||
* @param dh diffie hellman key allocated by create_dh()
|
||||
* @param dh_other public DH value from other peer
|
||||
* @param nonce_i initiators nonce value
|
||||
* @param nonce_r responders nonce value
|
||||
* @param id IKE_SA identifier
|
||||
* @param auth authentication method
|
||||
* @param shared_key PSK in case of AUTH_CLASS_PSK, NULL otherwise
|
||||
* @return TRUE on success
|
||||
*/
|
||||
bool (*derive_ike_keys)(keymat_v1_t *this, proposal_t *proposal,
|
||||
diffie_hellman_t *dh, chunk_t dh_other,
|
||||
chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id,
|
||||
auth_method_t auth, shared_key_t *shared_key);
|
||||
|
||||
/**
|
||||
* Derive keys for the CHILD_SA.
|
||||
*
|
||||
* @param proposal selected algorithms
|
||||
* @param dh diffie hellman key, NULL if none used
|
||||
* @param spi_i SPI chosen by initiatior
|
||||
* @param spi_r SPI chosen by responder
|
||||
* @param nonce_i quick mode initiator nonce
|
||||
* @param nonce_r quick mode responder nonce
|
||||
* @param encr_i allocated initiators encryption key
|
||||
* @param integ_i allocated initiators integrity key
|
||||
* @param encr_r allocated responders encryption key
|
||||
* @param integ_r allocated responders integrity key
|
||||
*/
|
||||
bool (*derive_child_keys)(keymat_v1_t *this, proposal_t *proposal,
|
||||
diffie_hellman_t *dh, u_int32_t spi_i, u_int32_t spi_r,
|
||||
chunk_t nonce_i, chunk_t nonce_r,
|
||||
chunk_t *encr_i, chunk_t *integ_i,
|
||||
chunk_t *encr_r, chunk_t *integ_r);
|
||||
|
||||
/**
|
||||
* Create the negotiated hasher.
|
||||
*
|
||||
* @param proposal selected algorithms
|
||||
* @return TRUE, if creation was successful
|
||||
*/
|
||||
bool (*create_hasher)(keymat_v1_t *this, proposal_t *proposal);
|
||||
|
||||
/**
|
||||
* Get the negotiated hasher.
|
||||
*
|
||||
* @return allocated hasher or NULL
|
||||
*/
|
||||
hasher_t *(*get_hasher)(keymat_v1_t *this);
|
||||
|
||||
/**
|
||||
* Get HASH data for authentication.
|
||||
*
|
||||
* @param initiatior TRUE to create HASH_I, FALSE for HASH_R
|
||||
* @param dh public DH value of peer to create HASH for
|
||||
* @param dh_other others public DH value
|
||||
* @param ike_sa_id IKE_SA identifier
|
||||
* @param sa_i encoded SA payload of initiator
|
||||
* @param id encoded IDii payload for HASH_I (IDir for HASH_R)
|
||||
* @return allocated HASH data
|
||||
*/
|
||||
chunk_t (*get_hash)(keymat_v1_t *this, bool initiator,
|
||||
chunk_t dh, chunk_t dh_other, ike_sa_id_t *ike_sa_id,
|
||||
chunk_t sa_i, chunk_t id);
|
||||
|
||||
/**
|
||||
* Get HASH data for integrity/authentication in Phase 2 exchanges.
|
||||
*
|
||||
* @param message message to generate the HASH data for
|
||||
* @return allocated HASH data
|
||||
*/
|
||||
chunk_t (*get_hash_phase2)(keymat_v1_t *this, message_t *message);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the IV for a message with the given message ID.
|
||||
*
|
||||
* @param mid message ID
|
||||
* @return IV (needs to be freed)
|
||||
*/
|
||||
chunk_t (*get_iv)(keymat_v1_t *this, u_int32_t mid);
|
||||
|
||||
/**
|
||||
* Updates the IV for the next message with the given message ID.
|
||||
*
|
||||
* A call of confirm_iv() is required in order to actually make the IV
|
||||
* available. This is needed for the inbound case where we store the last
|
||||
* block of the encrypted message but want to update the IV only after
|
||||
* verification of the decrypted message.
|
||||
*
|
||||
* @param mid message ID
|
||||
* @param last_block last block of encrypted message (gets cloned)
|
||||
*/
|
||||
void (*update_iv)(keymat_v1_t *this, u_int32_t mid, chunk_t last_block);
|
||||
|
||||
/**
|
||||
* Confirms the updated IV for the given message ID.
|
||||
*
|
||||
* To actually make the new IV available via get_iv this method has to
|
||||
* be called after update_iv.
|
||||
*
|
||||
* @param mid message ID
|
||||
*/
|
||||
void (*confirm_iv)(keymat_v1_t *this, u_int32_t mid);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a keymat instance.
|
||||
*
|
||||
* @param initiator TRUE if we are the initiator
|
||||
* @return keymat instance
|
||||
*/
|
||||
keymat_v1_t *keymat_v1_create(bool initiator);
|
||||
|
||||
#endif /** KEYMAT_V1_H_ @}*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup task_manager_v1 task_manager_v1
|
||||
* @{ @ingroup sa
|
||||
*/
|
||||
|
||||
#ifndef TASK_MANAGER_V1_H_
|
||||
#define TASK_MANAGER_V1_H_
|
||||
|
||||
typedef struct task_manager_v1_t task_manager_v1_t;
|
||||
|
||||
#include <sa/task_manager.h>
|
||||
|
||||
/**
|
||||
* Task manager, IKEv1 variant.
|
||||
*/
|
||||
struct task_manager_v1_t {
|
||||
|
||||
/**
|
||||
* Implements task_manager_t.
|
||||
*/
|
||||
task_manager_t task_manager;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an instance of the task manager.
|
||||
*
|
||||
* @param ike_sa IKE_SA to manage.
|
||||
*/
|
||||
task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa);
|
||||
|
||||
#endif /** TASK_MANAGER_V1_H_ @}*/
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "informational.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev1/tasks/isakmp_delete.h>
|
||||
#include <sa/ikev1/tasks/quick_delete.h>
|
||||
#include <encoding/payloads/delete_payload.h>
|
||||
|
||||
typedef struct private_informational_t private_informational_t;
|
||||
|
||||
/**
|
||||
* Private members of a informational_t task.
|
||||
*/
|
||||
struct private_informational_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
informational_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Notify payload to send
|
||||
*/
|
||||
notify_payload_t *notify;
|
||||
|
||||
/**
|
||||
* Delete subtask
|
||||
*/
|
||||
task_t *del;
|
||||
};
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_informational_t *this, message_t *message)
|
||||
{
|
||||
message->add_payload(message, &this->notify->payload_interface);
|
||||
this->notify = NULL;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_informational_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
delete_payload_t *delete;
|
||||
notify_payload_t *notify;
|
||||
notify_type_t type;
|
||||
payload_t *payload;
|
||||
status_t status = SUCCESS;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case NOTIFY_V1:
|
||||
notify = (notify_payload_t*)payload;
|
||||
type = notify->get_notify_type(notify);
|
||||
|
||||
if (type == INITIAL_CONTACT_IKEV1)
|
||||
{
|
||||
this->ike_sa->set_condition(this->ike_sa,
|
||||
COND_INIT_CONTACT_SEEN, TRUE);
|
||||
}
|
||||
else if (type < 16384)
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N error notify",
|
||||
notify_type_names, notify->get_notify_type(notify));
|
||||
if (this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING)
|
||||
{ /* only critical during main mode */
|
||||
status = FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N notify",
|
||||
notify_type_names, notify->get_notify_type(notify));
|
||||
}
|
||||
continue;
|
||||
case DELETE_V1:
|
||||
if (!this->del)
|
||||
{
|
||||
delete = (delete_payload_t*)payload;
|
||||
if (delete->get_protocol_id(delete) == PROTO_IKE)
|
||||
{
|
||||
this->del = (task_t*)isakmp_delete_create(this->ike_sa,
|
||||
FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->del = (task_t*)quick_delete_create(this->ike_sa,
|
||||
PROTO_NONE, 0, FALSE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (this->del && status == SUCCESS)
|
||||
{
|
||||
return this->del->process(this->del, message);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_informational_t *this, message_t *message)
|
||||
{
|
||||
if (this->del)
|
||||
{
|
||||
return this->del->build(this->del, message);
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_informational_t *this, message_t *message)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_informational_t *this)
|
||||
{
|
||||
return TASK_INFORMATIONAL;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_informational_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_informational_t *this)
|
||||
{
|
||||
DESTROY_IF(this->notify);
|
||||
DESTROY_IF(this->del);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify)
|
||||
{
|
||||
private_informational_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.notify = notify,
|
||||
);
|
||||
|
||||
if (notify)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup informational informational
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef INFORMATIONAL_H_
|
||||
#define informational_H_
|
||||
|
||||
typedef struct informational_t informational_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
|
||||
/**
|
||||
* IKEv1 informational exchange, negotiates errors.
|
||||
*/
|
||||
struct informational_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new informational task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param notify notify to send as initiator, NULL if responder
|
||||
* @return task to handle by the task_manager
|
||||
*/
|
||||
informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify);
|
||||
|
||||
#endif /** INFORMATIONAL_H_ @}*/
|
||||
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "isakmp_cert_post.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <encoding/payloads/cert_payload.h>
|
||||
#include <encoding/payloads/certreq_payload.h>
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <credentials/certificates/x509.h>
|
||||
|
||||
|
||||
typedef struct private_isakmp_cert_post_t private_isakmp_cert_post_t;
|
||||
|
||||
/**
|
||||
* Private members of a isakmp_cert_post_t task.
|
||||
*/
|
||||
struct private_isakmp_cert_post_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
isakmp_cert_post_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* States of ike cert pre
|
||||
*/
|
||||
enum {
|
||||
CR_SA,
|
||||
CR_KE,
|
||||
CR_AUTH,
|
||||
} state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if we actually use certificates for authentication
|
||||
*/
|
||||
static bool use_certs(private_isakmp_cert_post_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
bool use = FALSE;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1)
|
||||
{
|
||||
sa_payload_t *sa_payload = (sa_payload_t*)payload;
|
||||
|
||||
switch (sa_payload->get_auth_method(sa_payload))
|
||||
{
|
||||
case AUTH_RSA:
|
||||
case AUTH_XAUTH_INIT_RSA:
|
||||
case AUTH_XAUTH_RESP_RSA:
|
||||
case AUTH_HYBRID_INIT_RSA:
|
||||
case AUTH_HYBRID_RESP_RSA:
|
||||
use = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
return use;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add certificates to message
|
||||
*/
|
||||
static void build_certs(private_isakmp_cert_post_t *this, message_t *message)
|
||||
{
|
||||
peer_cfg_t *peer_cfg;
|
||||
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
if (!peer_cfg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (peer_cfg->get_cert_policy(peer_cfg))
|
||||
{
|
||||
case CERT_NEVER_SEND:
|
||||
break;
|
||||
case CERT_SEND_IF_ASKED:
|
||||
if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN))
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* FALL */
|
||||
case CERT_ALWAYS_SEND:
|
||||
{
|
||||
cert_payload_t *payload;
|
||||
enumerator_t *enumerator;
|
||||
certificate_t *cert;
|
||||
auth_rule_t type;
|
||||
auth_cfg_t *auth;
|
||||
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
|
||||
cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
|
||||
if (!cert)
|
||||
{
|
||||
break;
|
||||
}
|
||||
payload = cert_payload_create_from_cert(CERTIFICATE_V1, cert);
|
||||
if (!payload)
|
||||
{
|
||||
break;
|
||||
}
|
||||
DBG1(DBG_IKE, "sending end entity cert \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
message->add_payload(message, (payload_t*)payload);
|
||||
|
||||
enumerator = auth->create_enumerator(auth);
|
||||
while (enumerator->enumerate(enumerator, &type, &cert))
|
||||
{
|
||||
if (type == AUTH_RULE_IM_CERT)
|
||||
{
|
||||
payload = cert_payload_create_from_cert(CERTIFICATE_V1, cert);
|
||||
if (payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "sending issuer cert \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
message->add_payload(message, (payload_t*)payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_isakmp_cert_post_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
if (this->state == CR_AUTH)
|
||||
{
|
||||
build_certs(this, message);
|
||||
return SUCCESS;
|
||||
}
|
||||
return NEED_MORE;
|
||||
case AGGRESSIVE:
|
||||
if (this->state == CR_AUTH)
|
||||
{
|
||||
build_certs(this, message);
|
||||
return SUCCESS;
|
||||
}
|
||||
return NEED_MORE;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_isakmp_cert_post_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
return NEED_MORE;
|
||||
case CR_KE:
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
return NEED_MORE;
|
||||
}
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
return SUCCESS;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_isakmp_cert_post_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
this->state = CR_KE;
|
||||
return NEED_MORE;
|
||||
case CR_KE:
|
||||
this->state = CR_AUTH;
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
build_certs(this, message);
|
||||
return SUCCESS;
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
build_certs(this, message);
|
||||
this->state = CR_AUTH;
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
return SUCCESS;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_isakmp_cert_post_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
this->state = CR_KE;
|
||||
return NEED_MORE;
|
||||
case CR_KE:
|
||||
this->state = CR_AUTH;
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
return SUCCESS;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
{
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_isakmp_cert_post_t *this)
|
||||
{
|
||||
return TASK_ISAKMP_CERT_POST;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_isakmp_cert_post_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_isakmp_cert_post_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
isakmp_cert_post_t *isakmp_cert_post_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_isakmp_cert_post_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.initiator = initiator,
|
||||
.state = CR_SA,
|
||||
);
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.process = _process_i;
|
||||
this->public.task.build = _build_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.process = _process_r;
|
||||
this->public.task.build = _build_r;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup isakmp_cert_post isakmp_cert_post
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef ISAKMP_CERT_POST_H_
|
||||
#define ISAKMP_CERT_POST_H_
|
||||
|
||||
typedef struct isakmp_cert_post_t isakmp_cert_post_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* ISAKMP_CERT_POST, IKEv1 certificate processing after authentication.
|
||||
*/
|
||||
struct isakmp_cert_post_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new isakmp_cert_post task.
|
||||
*
|
||||
* The initiator parameter means the original initiator, not the initiator
|
||||
* of the certificate request.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if task is the original initiator
|
||||
* @return isakmp_cert_post task to handle by the task_manager
|
||||
*/
|
||||
isakmp_cert_post_t *isakmp_cert_post_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** ISAKMP_CERT_POST_H_ @}*/
|
||||
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "isakmp_cert_pre.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <encoding/payloads/cert_payload.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/certreq_payload.h>
|
||||
#include <credentials/certificates/x509.h>
|
||||
|
||||
|
||||
typedef struct private_isakmp_cert_pre_t private_isakmp_cert_pre_t;
|
||||
|
||||
/**
|
||||
* Private members of a isakmp_cert_pre_t task.
|
||||
*/
|
||||
struct private_isakmp_cert_pre_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
isakmp_cert_pre_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* Send certificate requests?
|
||||
*/
|
||||
bool send_req;
|
||||
|
||||
/** next message we expect */
|
||||
enum {
|
||||
CR_SA,
|
||||
CR_KE,
|
||||
CR_AUTH,
|
||||
} state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the CA certificate for a given certreq payload
|
||||
*/
|
||||
static certificate_t* find_certificate(private_isakmp_cert_pre_t *this,
|
||||
certreq_payload_t *certreq)
|
||||
{
|
||||
identification_t *id;
|
||||
certificate_t *cert;
|
||||
|
||||
if (certreq->get_cert_type(certreq) != CERT_X509)
|
||||
{
|
||||
DBG1(DBG_IKE, "%N CERTREQ not supported - ignored",
|
||||
certificate_type_names, certreq->get_cert_type(certreq));
|
||||
return NULL;
|
||||
}
|
||||
id = certreq->get_dn(certreq);
|
||||
if (!id)
|
||||
{
|
||||
DBG1(DBG_IKE, "ignoring certificate request without data",
|
||||
certificate_type_names, certreq->get_cert_type(certreq));
|
||||
return NULL;
|
||||
}
|
||||
cert = lib->credmgr->get_cert(lib->credmgr, CERT_X509, KEY_ANY, id, TRUE);
|
||||
if (cert)
|
||||
{
|
||||
DBG1(DBG_IKE, "received cert request for '%Y'",
|
||||
cert->get_subject(cert));
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "received cert request for unknown ca '%Y'", id);
|
||||
}
|
||||
id->destroy(id);
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
/**
|
||||
* read certificate requests
|
||||
*/
|
||||
static void process_certreqs(private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
auth_cfg_t *auth;
|
||||
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
switch (payload->get_type(payload))
|
||||
{
|
||||
case CERTIFICATE_REQUEST_V1:
|
||||
{
|
||||
certificate_t *cert;
|
||||
|
||||
this->ike_sa->set_condition(this->ike_sa,
|
||||
COND_CERTREQ_SEEN, TRUE);
|
||||
cert = find_certificate(this, (certreq_payload_t*)payload);
|
||||
if (cert)
|
||||
{
|
||||
auth->add(auth, AUTH_RULE_CA_CERT, cert);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import receuved certificates
|
||||
*/
|
||||
static void process_certs(private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
auth_cfg_t *auth;
|
||||
bool first = TRUE;
|
||||
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == CERTIFICATE_V1)
|
||||
{
|
||||
cert_payload_t *cert_payload;
|
||||
cert_encoding_t encoding;
|
||||
certificate_t *cert;
|
||||
|
||||
cert_payload = (cert_payload_t*)payload;
|
||||
encoding = cert_payload->get_cert_encoding(cert_payload);
|
||||
|
||||
switch (encoding)
|
||||
{
|
||||
case ENC_X509_SIGNATURE:
|
||||
{
|
||||
cert = cert_payload->get_cert(cert_payload);
|
||||
if (cert)
|
||||
{
|
||||
if (first)
|
||||
{ /* the first is an end entity certificate */
|
||||
DBG1(DBG_IKE, "received end entity cert \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert);
|
||||
first = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "received issuer cert \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
auth->add(auth, AUTH_HELPER_IM_CERT, cert);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ENC_CRL:
|
||||
cert = cert_payload->get_cert(cert_payload);
|
||||
if (cert)
|
||||
{
|
||||
DBG1(DBG_IKE, "received CRL \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert);
|
||||
}
|
||||
break;
|
||||
case ENC_PKCS7_WRAPPED_X509:
|
||||
case ENC_PGP:
|
||||
case ENC_DNS_SIGNED_KEY:
|
||||
case ENC_KERBEROS_TOKEN:
|
||||
case ENC_ARL:
|
||||
case ENC_SPKI:
|
||||
case ENC_X509_ATTRIBUTE:
|
||||
case ENC_RAW_RSA_KEY:
|
||||
case ENC_X509_HASH_AND_URL_BUNDLE:
|
||||
case ENC_OCSP_CONTENT:
|
||||
default:
|
||||
DBG1(DBG_ENC, "certificate encoding %N not supported",
|
||||
cert_encoding_names, encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the subject of a CA certificate a message
|
||||
*/
|
||||
static void add_certreq(private_isakmp_cert_pre_t *this, message_t *message,
|
||||
certificate_t *cert)
|
||||
{
|
||||
if (cert->get_type(cert) == CERT_X509)
|
||||
{
|
||||
x509_t *x509 = (x509_t*)cert;
|
||||
|
||||
if (x509->get_flags(x509) & X509_CA)
|
||||
{
|
||||
DBG1(DBG_IKE, "sending cert request for \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
message->add_payload(message, (payload_t*)
|
||||
certreq_payload_create_dn(cert->get_subject(cert)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add auth_cfg's CA certificates to the certificate request
|
||||
*/
|
||||
static void add_certreqs(private_isakmp_cert_pre_t *this,
|
||||
auth_cfg_t *auth, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
auth_rule_t type;
|
||||
void *value;
|
||||
|
||||
enumerator = auth->create_enumerator(auth);
|
||||
while (enumerator->enumerate(enumerator, &type, &value))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case AUTH_RULE_CA_CERT:
|
||||
add_certreq(this, message, (certificate_t*)value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build certificate requests
|
||||
*/
|
||||
static void build_certreqs(private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
ike_cfg_t *ike_cfg;
|
||||
peer_cfg_t *peer_cfg;
|
||||
certificate_t *cert;
|
||||
auth_cfg_t *auth;
|
||||
|
||||
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
if (!ike_cfg->send_certreq(ike_cfg))
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* check if we require a specific CA for that peer */
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
if (peer_cfg)
|
||||
{
|
||||
enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
|
||||
if (enumerator->enumerate(enumerator, &auth))
|
||||
{
|
||||
add_certreqs(this, auth, message);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
if (!message->get_payload(message, CERTIFICATE_REQUEST_V1))
|
||||
{
|
||||
/* otherwise add all trusted CA certificates */
|
||||
enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
|
||||
CERT_ANY, KEY_ANY, NULL, TRUE);
|
||||
while (enumerator->enumerate(enumerator, &cert))
|
||||
{
|
||||
add_certreq(this, message, cert);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we actually use certificates for authentication
|
||||
*/
|
||||
static bool use_certs(private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
bool use = FALSE;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1)
|
||||
{
|
||||
sa_payload_t *sa_payload = (sa_payload_t*)payload;
|
||||
|
||||
switch (sa_payload->get_auth_method(sa_payload))
|
||||
{
|
||||
case AUTH_HYBRID_INIT_RSA:
|
||||
case AUTH_HYBRID_RESP_RSA:
|
||||
if (!this->initiator)
|
||||
{
|
||||
this->send_req = FALSE;
|
||||
}
|
||||
/* FALL */
|
||||
case AUTH_RSA:
|
||||
case AUTH_XAUTH_INIT_RSA:
|
||||
case AUTH_XAUTH_RESP_RSA:
|
||||
use = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
return use;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
if (this->state == CR_AUTH)
|
||||
{
|
||||
build_certreqs(this, message);
|
||||
}
|
||||
return NEED_MORE;
|
||||
case AGGRESSIVE:
|
||||
if (this->state == CR_SA)
|
||||
{
|
||||
build_certreqs(this, message);
|
||||
}
|
||||
return NEED_MORE;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
return NEED_MORE;
|
||||
case CR_KE:
|
||||
process_certreqs(this, message);
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
process_certreqs(this, message);
|
||||
process_certs(this, message);
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
process_certreqs(this, message);
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
process_certs(this, message);
|
||||
return SUCCESS;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
this->state = CR_KE;
|
||||
return NEED_MORE;
|
||||
case CR_KE:
|
||||
if (this->send_req)
|
||||
{
|
||||
build_certreqs(this, message);
|
||||
}
|
||||
this->state = CR_AUTH;
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
return NEED_MORE;
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
this->state = CR_AUTH;
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
return SUCCESS;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_isakmp_cert_pre_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case CR_SA:
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
this->state = CR_KE;
|
||||
return NEED_MORE;
|
||||
case CR_KE:
|
||||
process_certreqs(this, message);
|
||||
this->state = CR_AUTH;
|
||||
return NEED_MORE;
|
||||
case CR_AUTH:
|
||||
process_certs(this, message);
|
||||
return SUCCESS;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
{
|
||||
if (!use_certs(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
process_certreqs(this, message);
|
||||
process_certs(this, message);
|
||||
return SUCCESS;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_isakmp_cert_pre_t *this)
|
||||
{
|
||||
return TASK_ISAKMP_CERT_PRE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_isakmp_cert_pre_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_isakmp_cert_pre_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
isakmp_cert_pre_t *isakmp_cert_pre_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_isakmp_cert_pre_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.initiator = initiator,
|
||||
.state = CR_SA,
|
||||
.send_req = TRUE,
|
||||
);
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup isakmp_cert_pre isakmp_cert_pre
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef ISAKMP_CERT_PRE_H_
|
||||
#define ISAKMP_CERT_PRE_H_
|
||||
|
||||
typedef struct isakmp_cert_pre_t isakmp_cert_pre_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* ISAKMP_CERT_PRE task, IKEv1 certificate processing before authentication.
|
||||
*/
|
||||
struct isakmp_cert_pre_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new ISAKMP_CERT_PRE task.
|
||||
*
|
||||
* The initiator parameter means the original initiator, not the initiator
|
||||
* of the certificate request.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if task is the original initiator
|
||||
* @return isakmp_cert_pre task to handle by the task_manager
|
||||
*/
|
||||
isakmp_cert_pre_t *isakmp_cert_pre_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** ISAKMP_CERT_PRE_H_ @}*/
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "isakmp_delete.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/delete_payload.h>
|
||||
|
||||
typedef struct private_isakmp_delete_t private_isakmp_delete_t;
|
||||
|
||||
/**
|
||||
* Private members of a isakmp_delete_t task.
|
||||
*/
|
||||
struct private_isakmp_delete_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
isakmp_delete_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
};
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_isakmp_delete_t *this, message_t *message)
|
||||
{
|
||||
delete_payload_t *delete_payload;
|
||||
ike_sa_id_t *id;
|
||||
|
||||
DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa),
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
|
||||
delete_payload = delete_payload_create(DELETE_V1, PROTO_IKE);
|
||||
id = this->ike_sa->get_id(this->ike_sa);
|
||||
delete_payload->set_ike_spi(delete_payload, id->get_initiator_spi(id),
|
||||
id->get_responder_spi(id));
|
||||
message->add_payload(message, (payload_t*)delete_payload);
|
||||
|
||||
DBG1(DBG_IKE, "sending DELETE for IKE_SA %s[%d]",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa));
|
||||
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
|
||||
charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_isakmp_delete_t *this, message_t *message)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_isakmp_delete_t *this, message_t *message)
|
||||
{
|
||||
DBG1(DBG_IKE, "received DELETE for IKE_SA %s[%d]",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa));
|
||||
DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa),
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
|
||||
charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_isakmp_delete_t *this, message_t *message)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_isakmp_delete_t *this)
|
||||
{
|
||||
return TASK_ISAKMP_DELETE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_isakmp_delete_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_isakmp_delete_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
isakmp_delete_t *isakmp_delete_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_isakmp_delete_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
);
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup isakmp_delete isakmp_delete
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef ISAKMP_DELETE_H_
|
||||
#define ISAKMP_DELETE_H_
|
||||
|
||||
typedef struct isakmp_delete_t isakmp_delete_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type ISAKMP_DELETE, delete an IKEv1 IKE_SA.
|
||||
*/
|
||||
struct isakmp_delete_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new isakmp_delete task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if we initiate the delete
|
||||
* @return isakmp_delete task to handle by the task_manager
|
||||
*/
|
||||
isakmp_delete_t *isakmp_delete_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** ISAKMP_DELETE_H_ @}*/
|
||||
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2011 Tobias Brunner,
|
||||
* Copyright (C) 2006-2007 Martin Willi
|
||||
* Copyright (C) 2006 Daniel Roethlisberger
|
||||
* 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 "isakmp_natd.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <hydra.h>
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev1/keymat_v1.h>
|
||||
#include <config/peer_cfg.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
#include <encoding/payloads/hash_payload.h>
|
||||
|
||||
typedef struct private_isakmp_natd_t private_isakmp_natd_t;
|
||||
|
||||
/**
|
||||
* Private members of a ike_natt_t task.
|
||||
*/
|
||||
struct private_isakmp_natd_t {
|
||||
|
||||
/**
|
||||
* Public interface.
|
||||
*/
|
||||
isakmp_natd_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* Keymat derivation (from SA)
|
||||
*/
|
||||
keymat_v1_t *keymat;
|
||||
|
||||
/**
|
||||
* Did we process any NAT detection payloads for a source address?
|
||||
*/
|
||||
bool src_seen;
|
||||
|
||||
/**
|
||||
* Did we process any NAT detection payloads for a destination address?
|
||||
*/
|
||||
bool dst_seen;
|
||||
|
||||
/**
|
||||
* Have we found a matching source address NAT hash?
|
||||
*/
|
||||
bool src_matched;
|
||||
|
||||
/**
|
||||
* Have we found a matching destination address NAT hash?
|
||||
*/
|
||||
bool dst_matched;
|
||||
};
|
||||
|
||||
/**
|
||||
* Build NAT detection hash for a host.
|
||||
*/
|
||||
static chunk_t generate_natd_hash(private_isakmp_natd_t *this,
|
||||
ike_sa_id_t *ike_sa_id, host_t *host)
|
||||
{
|
||||
hasher_t *hasher;
|
||||
chunk_t natd_chunk, natd_hash;
|
||||
u_int64_t spi_i, spi_r;
|
||||
u_int16_t port;
|
||||
|
||||
hasher = this->keymat->get_hasher(this->keymat);
|
||||
if (!hasher)
|
||||
{
|
||||
DBG1(DBG_IKE, "no hasher available to build NAT-D payload");
|
||||
return chunk_empty;
|
||||
}
|
||||
|
||||
spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
|
||||
spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
|
||||
port = htons(host->get_port(host));
|
||||
|
||||
/* natd_hash = HASH(CKY-I | CKY-R | IP | Port) */
|
||||
natd_chunk = chunk_cata("cccc", chunk_from_thing(spi_i),
|
||||
chunk_from_thing(spi_r), host->get_address(host),
|
||||
chunk_from_thing(port));
|
||||
hasher->allocate_hash(hasher, natd_chunk, &natd_hash);
|
||||
DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk);
|
||||
DBG3(DBG_IKE, "natd_hash %B", &natd_hash);
|
||||
|
||||
return natd_hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a faked NAT-D payload to enforce UDP encapsulation.
|
||||
*/
|
||||
static chunk_t generate_natd_hash_faked(private_isakmp_natd_t *this)
|
||||
{
|
||||
hasher_t *hasher;
|
||||
chunk_t chunk;
|
||||
rng_t *rng;
|
||||
|
||||
hasher = this->keymat->get_hasher(this->keymat);
|
||||
if (!hasher)
|
||||
{
|
||||
DBG1(DBG_IKE, "no hasher available to build NAT-D payload");
|
||||
return chunk_empty;
|
||||
}
|
||||
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||
if (!rng)
|
||||
{
|
||||
DBG1(DBG_IKE, "unable to get random bytes for NAT-D fake");
|
||||
return chunk_empty;
|
||||
}
|
||||
rng->allocate_bytes(rng, hasher->get_hash_size(hasher), &chunk);
|
||||
rng->destroy(rng);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a NAT-D payload.
|
||||
*/
|
||||
static hash_payload_t *build_natd_payload(private_isakmp_natd_t *this, bool src,
|
||||
host_t *host)
|
||||
{
|
||||
hash_payload_t *payload;
|
||||
ike_cfg_t *config;
|
||||
chunk_t hash;
|
||||
|
||||
config = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
if (src && config->force_encap(config))
|
||||
{
|
||||
hash = generate_natd_hash_faked(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
ike_sa_id_t *ike_sa_id = this->ike_sa->get_id(this->ike_sa);
|
||||
hash = generate_natd_hash(this, ike_sa_id, host);
|
||||
}
|
||||
payload = hash_payload_create(NAT_D_V1);
|
||||
payload->set_hash(payload, hash);
|
||||
chunk_free(&hash);
|
||||
return payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add NAT-D payloads to the message.
|
||||
*/
|
||||
static void add_natd_payloads(private_isakmp_natd_t *this, message_t *message)
|
||||
{
|
||||
hash_payload_t *payload;
|
||||
host_t *host;
|
||||
|
||||
/* destination has to be added first */
|
||||
host = message->get_destination(message);
|
||||
payload = build_natd_payload(this, FALSE, host);
|
||||
message->add_payload(message, (payload_t*)payload);
|
||||
|
||||
/* source is added second, compared with IKEv2 we always know the source,
|
||||
* as these payloads are added in the second Phase 1 exchange or the
|
||||
* response to the first */
|
||||
host = message->get_source(message);
|
||||
payload = build_natd_payload(this, TRUE, host);
|
||||
message->add_payload(message, (payload_t*)payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read NAT-D payloads from message and evaluate them.
|
||||
*/
|
||||
static void process_payloads(private_isakmp_natd_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
hash_payload_t *hash_payload;
|
||||
chunk_t hash, src_hash, dst_hash;
|
||||
ike_sa_id_t *ike_sa_id;
|
||||
host_t *me, *other;
|
||||
ike_cfg_t *config;
|
||||
|
||||
/* precompute hashes for incoming NAT-D comparison */
|
||||
ike_sa_id = message->get_ike_sa_id(message);
|
||||
me = message->get_destination(message);
|
||||
other = message->get_source(message);
|
||||
dst_hash = generate_natd_hash(this, ike_sa_id, me);
|
||||
src_hash = generate_natd_hash(this, ike_sa_id, other);
|
||||
|
||||
DBG3(DBG_IKE, "precalculated src_hash %B", &src_hash);
|
||||
DBG3(DBG_IKE, "precalculated dst_hash %B", &dst_hash);
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) != NAT_D_V1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
hash_payload = (hash_payload_t*)payload;
|
||||
if (!this->dst_seen)
|
||||
{ /* the first NAT-D payload contains the destination hash */
|
||||
this->dst_seen = TRUE;
|
||||
hash = hash_payload->get_hash(hash_payload);
|
||||
DBG3(DBG_IKE, "received dst_hash %B", &hash);
|
||||
if (chunk_equals(hash, dst_hash))
|
||||
{
|
||||
this->dst_matched = TRUE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* the other NAT-D payloads contain source hashes */
|
||||
this->src_seen = TRUE;
|
||||
if (!this->src_matched)
|
||||
{
|
||||
hash = hash_payload->get_hash(hash_payload);
|
||||
DBG3(DBG_IKE, "received src_hash %B", &hash);
|
||||
if (chunk_equals(hash, src_hash))
|
||||
{
|
||||
this->src_matched = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
chunk_free(&src_hash);
|
||||
chunk_free(&dst_hash);
|
||||
|
||||
if (this->src_seen && this->dst_seen)
|
||||
{
|
||||
this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE,
|
||||
!this->dst_matched);
|
||||
this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE,
|
||||
!this->src_matched);
|
||||
config = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
if (this->dst_matched && this->src_matched &&
|
||||
config->force_encap(config))
|
||||
{
|
||||
this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_isakmp_natd_t *this, message_t *message)
|
||||
{
|
||||
status_t result = NEED_MORE;
|
||||
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case AGGRESSIVE:
|
||||
{ /* add NAT-D payloads to the second request, already processed
|
||||
* those by the responder contained in the first response */
|
||||
result = SUCCESS;
|
||||
/* fall */
|
||||
}
|
||||
case ID_PROT:
|
||||
{ /* add NAT-D payloads to the second request, need to process
|
||||
* those by the responder contained in the second response */
|
||||
if (message->get_payload(message, SECURITY_ASSOCIATION_V1))
|
||||
{ /* wait for the second exchange */
|
||||
return NEED_MORE;
|
||||
}
|
||||
add_natd_payloads(this, message);
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_isakmp_natd_t *this, message_t *message)
|
||||
{
|
||||
status_t result = NEED_MORE;
|
||||
|
||||
if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))
|
||||
{ /* we didn't receive VIDs inidcating support for NAT-T */
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
{ /* process NAT-D payloads in the second response, added them in the
|
||||
* second request already, so we're done afterwards */
|
||||
if (message->get_payload(message, SECURITY_ASSOCIATION_V1))
|
||||
{ /* wait for the second exchange */
|
||||
return NEED_MORE;
|
||||
}
|
||||
result = SUCCESS;
|
||||
/* fall */
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
{ /* process NAT-D payloads in the first response, add them in the
|
||||
* following second request */
|
||||
process_payloads(this, message);
|
||||
|
||||
if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
|
||||
{
|
||||
this->ike_sa->float_ports(this->ike_sa);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_isakmp_natd_t *this, message_t *message)
|
||||
{
|
||||
status_t result = NEED_MORE;
|
||||
|
||||
if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))
|
||||
{ /* we didn't receive VIDs indicating NAT-T support */
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case AGGRESSIVE:
|
||||
{ /* proccess NAT-D payloads in the second request, already added ours
|
||||
* in the first response */
|
||||
result = SUCCESS;
|
||||
/* fall */
|
||||
}
|
||||
case ID_PROT:
|
||||
{ /* process NAT-D payloads in the second request, need to add ours
|
||||
* to the second response */
|
||||
if (message->get_payload(message, SECURITY_ASSOCIATION_V1))
|
||||
{ /* wait for the second exchange */
|
||||
return NEED_MORE;
|
||||
}
|
||||
process_payloads(this, message);
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_isakmp_natd_t *this, message_t *message)
|
||||
{
|
||||
switch (message->get_exchange_type(message))
|
||||
{
|
||||
case ID_PROT:
|
||||
{ /* add NAT-D payloads to second response, already processed those
|
||||
* contained in the second request */
|
||||
if (message->get_payload(message, SECURITY_ASSOCIATION_V1))
|
||||
{ /* wait for the second exchange */
|
||||
return NEED_MORE;
|
||||
}
|
||||
add_natd_payloads(this, message);
|
||||
return SUCCESS;
|
||||
}
|
||||
case AGGRESSIVE:
|
||||
{ /* add NAT-D payloads to the first response, process those contained
|
||||
* in the following second request */
|
||||
add_natd_payloads(this, message);
|
||||
return NEED_MORE;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_isakmp_natd_t *this)
|
||||
{
|
||||
return TASK_ISAKMP_NATD;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_isakmp_natd_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
this->src_seen = FALSE;
|
||||
this->dst_seen = FALSE;
|
||||
this->src_matched = FALSE;
|
||||
this->dst_matched = FALSE;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_isakmp_natd_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
isakmp_natd_t *isakmp_natd_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_isakmp_natd_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
|
||||
.initiator = initiator,
|
||||
);
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Tobias Brunner
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup isakmp_natd isakmp_natd
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef ISAKMP_NATD_H_
|
||||
#define ISAKMP_NATD_H_
|
||||
|
||||
typedef struct isakmp_natd_t isakmp_natd_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type ISAKMP_NATD, detects NAT situation in IKEv1 Phase 1.
|
||||
*/
|
||||
struct isakmp_natd_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new ISAKMP_NATD task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if task is the original initiator
|
||||
* @return isakmp_natd task to handle by the task_manager
|
||||
*/
|
||||
isakmp_natd_t *isakmp_natd_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** ISAKMP_NATD_H_ @}*/
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "isakmp_vendor.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/vendor_id_payload.h>
|
||||
|
||||
typedef struct private_isakmp_vendor_t private_isakmp_vendor_t;
|
||||
|
||||
/**
|
||||
* Private data of an isakmp_vendor_t object.
|
||||
*/
|
||||
struct private_isakmp_vendor_t {
|
||||
|
||||
/**
|
||||
* Public isakmp_vendor_t interface.
|
||||
*/
|
||||
isakmp_vendor_t public;
|
||||
|
||||
/**
|
||||
* Associated IKE_SA
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the inititator of this task
|
||||
*/
|
||||
bool initiator;
|
||||
};
|
||||
|
||||
/**
|
||||
* IKEv1 Vendor ID database
|
||||
*/
|
||||
static struct {
|
||||
/* Description */
|
||||
char *desc;
|
||||
/* extension flag negotiated with vendor ID, if any */
|
||||
ike_extension_t extension;
|
||||
/* send yourself? */
|
||||
bool send;
|
||||
/* length of vendor ID string */
|
||||
int len;
|
||||
/* vendor ID string */
|
||||
char *id;
|
||||
} vendor_ids[] = {
|
||||
|
||||
/* strongSwan MD5("strongSwan") */
|
||||
{ "strongSwan", EXT_STRONGSWAN, FALSE, 16,
|
||||
"\x88\x2f\xe5\x6d\x6f\xd2\x0d\xbc\x22\x51\x61\x3b\x2e\xbe\x5b\xeb"},
|
||||
|
||||
/* XAuth, MD5("draft-ietf-ipsra-isakmp-xauth-06.txt") */
|
||||
{ "XAuth", EXT_XAUTH, TRUE, 8,
|
||||
"\x09\x00\x26\x89\xdf\xd6\xb7\x12"},
|
||||
|
||||
/* NAT-Traversal, MD5("RFC 3947") */
|
||||
{ "NAT-T (RFC 3947)", EXT_NATT, TRUE, 16,
|
||||
"\x4a\x13\x1c\x81\x07\x03\x58\x45\x5c\x57\x28\xf2\x0e\x95\x45\x2f"},
|
||||
|
||||
/* draft-ietf-ipsec-dpd-00 */
|
||||
{ "DPD", 0, FALSE, 16,
|
||||
"\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00"},
|
||||
|
||||
{ "draft-stenberg-ipsec-nat-traversal-01", 0, FALSE, 16,
|
||||
"\x27\xba\xb5\xdc\x01\xea\x07\x60\xea\x4e\x31\x90\xac\x27\xc0\xd0"},
|
||||
|
||||
{ "draft-stenberg-ipsec-nat-traversal-02", 0, FALSE, 16,
|
||||
"\x61\x05\xc4\x22\xe7\x68\x47\xe4\x3f\x96\x84\x80\x12\x92\xae\xcd"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike-00", 0, FALSE, 16,
|
||||
"\x44\x85\x15\x2d\x18\xb6\xbb\xcd\x0b\xe8\xa8\x46\x95\x79\xdd\xcc"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike-02", 0, FALSE, 16,
|
||||
"\xcd\x60\x46\x43\x35\xdf\x21\xf8\x7c\xfd\xb2\xfc\x68\xb6\xa4\x48"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike-02", 0, FALSE, 16,
|
||||
"\x90\xcb\x80\x91\x3e\xbb\x69\x6e\x08\x63\x81\xb5\xec\x42\x7b\x1f"},
|
||||
|
||||
{ "draft-ietf-ipsec-nat-t-ike-03", 0, FALSE, 16,
|
||||
"\x7d\x94\x19\xa6\x53\x10\xca\x6f\x2c\x17\x9d\x92\x15\x52\x9d\x56"},
|
||||
|
||||
{ "Cisco Unity", 0, FALSE, 16,
|
||||
"\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00"},
|
||||
};
|
||||
|
||||
METHOD(task_t, build, status_t,
|
||||
private_isakmp_vendor_t *this, message_t *message)
|
||||
{
|
||||
vendor_id_payload_t *vid_payload;
|
||||
bool strongswan;
|
||||
int i;
|
||||
|
||||
strongswan = lib->settings->get_bool(lib->settings,
|
||||
"charon.send_vendor_id", FALSE);
|
||||
for (i = 0; i < countof(vendor_ids); i++)
|
||||
{
|
||||
if (vendor_ids[i].send ||
|
||||
(vendor_ids[i].extension == EXT_STRONGSWAN && strongswan))
|
||||
{
|
||||
vid_payload = vendor_id_payload_create_data(VENDOR_ID_V1,
|
||||
chunk_clone(chunk_create(vendor_ids[i].id, vendor_ids[i].len)));
|
||||
message->add_payload(message, &vid_payload->payload_interface);
|
||||
}
|
||||
}
|
||||
return this->initiator ? NEED_MORE : SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process, status_t,
|
||||
private_isakmp_vendor_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
int i;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == VENDOR_ID_V1)
|
||||
{
|
||||
vendor_id_payload_t *vid;
|
||||
bool found = FALSE;
|
||||
chunk_t data;
|
||||
|
||||
vid = (vendor_id_payload_t*)payload;
|
||||
data = vid->get_data(vid);
|
||||
|
||||
for (i = 0; i < countof(vendor_ids); i++)
|
||||
{
|
||||
if (chunk_equals(data, chunk_create(vendor_ids[i].id,
|
||||
vendor_ids[i].len)))
|
||||
{
|
||||
DBG1(DBG_IKE, "received %s vendor id", vendor_ids[i].desc);
|
||||
if (vendor_ids[i].extension)
|
||||
{
|
||||
this->ike_sa->enable_extension(this->ike_sa,
|
||||
vendor_ids[i].extension);
|
||||
}
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
DBG1(DBG_ENC, "received unknown vendor id: %#B", &data);
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
return this->initiator ? SUCCESS : NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_isakmp_vendor_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_isakmp_vendor_t *this)
|
||||
{
|
||||
return TASK_ISAKMP_VENDOR;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_isakmp_vendor_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
isakmp_vendor_t *isakmp_vendor_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_isakmp_vendor_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.build = _build,
|
||||
.process = _process,
|
||||
.migrate = _migrate,
|
||||
.get_type = _get_type,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.initiator = initiator,
|
||||
.ike_sa = ike_sa,
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup isakmp_vendor isakmp_vendor
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef ISAKMP_VENDOR_H_
|
||||
#define ISAKMP_VENDOR_H_
|
||||
|
||||
typedef struct isakmp_vendor_t isakmp_vendor_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Vendor ID processing task for IKEv1.
|
||||
*/
|
||||
struct isakmp_vendor_t {
|
||||
|
||||
/**
|
||||
* Implements task interface.
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a isakmp_vendor instance.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if task is the original initiator
|
||||
*/
|
||||
isakmp_vendor_t *isakmp_vendor_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** ISAKMP_VENDOR_H_ @}*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup main_mode main_mode
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef MAIN_MODE_H_
|
||||
#define MAIN_MODE_H_
|
||||
|
||||
typedef struct main_mode_t main_mode_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* IKEv1 main mode, establishes a mainmode including authentication.
|
||||
*/
|
||||
struct main_mode_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new main_mode task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE if task initiated locally
|
||||
* @return task to handle by the task_manager
|
||||
*/
|
||||
main_mode_t *main_mode_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** MAIN_MODE_H_ @}*/
|
||||
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "mode_config.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <hydra.h>
|
||||
#include <encoding/payloads/cp_payload.h>
|
||||
|
||||
typedef struct private_mode_config_t private_mode_config_t;
|
||||
|
||||
/**
|
||||
* Private members of a mode_config_t task.
|
||||
*/
|
||||
struct private_mode_config_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
mode_config_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* virtual ip
|
||||
*/
|
||||
host_t *virtual_ip;
|
||||
|
||||
/**
|
||||
* list of attributes requested and its handler, entry_t
|
||||
*/
|
||||
linked_list_t *requested;
|
||||
};
|
||||
|
||||
/**
|
||||
* Entry for a requested attribute and the requesting handler
|
||||
*/
|
||||
typedef struct {
|
||||
/** attribute requested */
|
||||
configuration_attribute_type_t type;
|
||||
/** handler requesting this attribute */
|
||||
attribute_handler_t *handler;
|
||||
} entry_t;
|
||||
|
||||
/**
|
||||
* build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip
|
||||
*/
|
||||
static configuration_attribute_t *build_vip(host_t *vip)
|
||||
{
|
||||
configuration_attribute_type_t type;
|
||||
chunk_t chunk, prefix;
|
||||
|
||||
if (vip->get_family(vip) == AF_INET)
|
||||
{
|
||||
type = INTERNAL_IP4_ADDRESS;
|
||||
if (vip->is_anyaddr(vip))
|
||||
{
|
||||
chunk = chunk_empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
chunk = vip->get_address(vip);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
type = INTERNAL_IP6_ADDRESS;
|
||||
if (vip->is_anyaddr(vip))
|
||||
{
|
||||
chunk = chunk_empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix = chunk_alloca(1);
|
||||
*prefix.ptr = 64;
|
||||
chunk = vip->get_address(vip);
|
||||
chunk = chunk_cata("cc", chunk, prefix);
|
||||
}
|
||||
}
|
||||
return configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1,
|
||||
type, chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a received attribute as initiator
|
||||
*/
|
||||
static void handle_attribute(private_mode_config_t *this,
|
||||
configuration_attribute_t *ca)
|
||||
{
|
||||
attribute_handler_t *handler = NULL;
|
||||
enumerator_t *enumerator;
|
||||
entry_t *entry;
|
||||
|
||||
/* find the handler which requested this attribute */
|
||||
enumerator = this->requested->create_enumerator(this->requested);
|
||||
while (enumerator->enumerate(enumerator, &entry))
|
||||
{
|
||||
if (entry->type == ca->get_type(ca))
|
||||
{
|
||||
handler = entry->handler;
|
||||
this->requested->remove_at(this->requested, enumerator);
|
||||
free(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
/* and pass it to the handle function */
|
||||
handler = hydra->attributes->handle(hydra->attributes,
|
||||
this->ike_sa->get_other_id(this->ike_sa), handler,
|
||||
ca->get_type(ca), ca->get_chunk(ca));
|
||||
if (handler)
|
||||
{
|
||||
this->ike_sa->add_configuration_attribute(this->ike_sa,
|
||||
handler, ca->get_type(ca), ca->get_chunk(ca));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* process a single configuration attribute
|
||||
*/
|
||||
static void process_attribute(private_mode_config_t *this,
|
||||
configuration_attribute_t *ca)
|
||||
{
|
||||
host_t *ip;
|
||||
chunk_t addr;
|
||||
int family = AF_INET6;
|
||||
|
||||
switch (ca->get_type(ca))
|
||||
{
|
||||
case INTERNAL_IP4_ADDRESS:
|
||||
family = AF_INET;
|
||||
/* fall */
|
||||
case INTERNAL_IP6_ADDRESS:
|
||||
{
|
||||
addr = ca->get_chunk(ca);
|
||||
if (addr.len == 0)
|
||||
{
|
||||
ip = host_create_any(family);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* skip prefix byte in IPv6 payload*/
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
addr.len--;
|
||||
}
|
||||
ip = host_create_from_chunk(family, addr, 0);
|
||||
}
|
||||
if (ip)
|
||||
{
|
||||
DESTROY_IF(this->virtual_ip);
|
||||
this->virtual_ip = ip;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (this->initiator)
|
||||
{
|
||||
handle_attribute(this, ca);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan for configuration payloads and attributes
|
||||
*/
|
||||
static void process_payloads(private_mode_config_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator, *attributes;
|
||||
payload_t *payload;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == CONFIGURATION_V1)
|
||||
{
|
||||
cp_payload_t *cp = (cp_payload_t*)payload;
|
||||
configuration_attribute_t *ca;
|
||||
|
||||
switch (cp->get_type(cp))
|
||||
{
|
||||
case CFG_REQUEST:
|
||||
case CFG_REPLY:
|
||||
attributes = cp->create_attribute_enumerator(cp);
|
||||
while (attributes->enumerate(attributes, &ca))
|
||||
{
|
||||
DBG2(DBG_IKE, "processing %N attribute",
|
||||
configuration_attribute_type_names, ca->get_type(ca));
|
||||
process_attribute(this, ca);
|
||||
}
|
||||
attributes->destroy(attributes);
|
||||
break;
|
||||
default:
|
||||
DBG1(DBG_IKE, "ignoring %N config payload",
|
||||
config_type_names, cp->get_type(cp));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_mode_config_t *this, message_t *message)
|
||||
{
|
||||
cp_payload_t *cp = NULL;
|
||||
enumerator_t *enumerator;
|
||||
attribute_handler_t *handler;
|
||||
peer_cfg_t *config;
|
||||
configuration_attribute_type_t type;
|
||||
chunk_t data;
|
||||
host_t *vip;
|
||||
|
||||
/* reuse virtual IP if we already have one */
|
||||
vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
|
||||
if (!vip)
|
||||
{
|
||||
config = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
vip = config->get_virtual_ip(config);
|
||||
}
|
||||
if (vip)
|
||||
{
|
||||
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST);
|
||||
cp->add_attribute(cp, build_vip(vip));
|
||||
}
|
||||
|
||||
enumerator = hydra->attributes->create_initiator_enumerator(hydra->attributes,
|
||||
this->ike_sa->get_other_id(this->ike_sa), vip);
|
||||
while (enumerator->enumerate(enumerator, &handler, &type, &data))
|
||||
{
|
||||
configuration_attribute_t *ca;
|
||||
entry_t *entry;
|
||||
|
||||
DBG2(DBG_IKE, "building %N attribute",
|
||||
configuration_attribute_type_names, type);
|
||||
ca = configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1,
|
||||
type, data);
|
||||
if (!cp)
|
||||
{
|
||||
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST);
|
||||
}
|
||||
cp->add_attribute(cp, ca);
|
||||
|
||||
INIT(entry,
|
||||
.type = type,
|
||||
.handler = handler,
|
||||
);
|
||||
this->requested->insert_last(this->requested, entry);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (cp)
|
||||
{
|
||||
message->add_payload(message, (payload_t*)cp);
|
||||
}
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_mode_config_t *this, message_t *message)
|
||||
{
|
||||
process_payloads(this, message);
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_mode_config_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
configuration_attribute_type_t type;
|
||||
chunk_t value;
|
||||
host_t *vip = NULL;
|
||||
cp_payload_t *cp = NULL;
|
||||
peer_cfg_t *config;
|
||||
identification_t *id;
|
||||
|
||||
id = this->ike_sa->get_other_eap_id(this->ike_sa);
|
||||
|
||||
config = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
if (this->virtual_ip)
|
||||
{
|
||||
DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
|
||||
if (config->get_pool(config))
|
||||
{
|
||||
vip = hydra->attributes->acquire_address(hydra->attributes,
|
||||
config->get_pool(config), id, this->virtual_ip);
|
||||
}
|
||||
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
|
||||
if (vip)
|
||||
{
|
||||
DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", vip, id);
|
||||
this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip);
|
||||
cp->add_attribute(cp, build_vip(vip));
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "no virtual IP found, sending empty config payload");
|
||||
}
|
||||
}
|
||||
/* query registered providers for additional attributes to include */
|
||||
enumerator = hydra->attributes->create_responder_enumerator(
|
||||
hydra->attributes, config->get_pool(config), id, vip);
|
||||
while (enumerator->enumerate(enumerator, &type, &value))
|
||||
{
|
||||
if (!cp)
|
||||
{
|
||||
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
|
||||
}
|
||||
DBG2(DBG_IKE, "building %N attribute",
|
||||
configuration_attribute_type_names, type);
|
||||
cp->add_attribute(cp,
|
||||
configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1,
|
||||
type, value));
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (cp)
|
||||
{
|
||||
message->add_payload(message, (payload_t*)cp);
|
||||
}
|
||||
DESTROY_IF(vip);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_mode_config_t *this, message_t *message)
|
||||
{
|
||||
process_payloads(this, message);
|
||||
|
||||
if (this->virtual_ip)
|
||||
{
|
||||
this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_mode_config_t *this)
|
||||
{
|
||||
return TASK_MODE_CONFIG;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_mode_config_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
DESTROY_IF(this->virtual_ip);
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->virtual_ip = NULL;
|
||||
this->requested->destroy_function(this->requested, free);
|
||||
this->requested = linked_list_create();
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_mode_config_t *this)
|
||||
{
|
||||
DESTROY_IF(this->virtual_ip);
|
||||
this->requested->destroy_function(this->requested, free);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_mode_config_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.initiator = initiator,
|
||||
.ike_sa = ike_sa,
|
||||
.requested = linked_list_create(),
|
||||
);
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup mode_config mode_config
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef MODE_CONFIG_H_
|
||||
#define MODE_CONFIG_H_
|
||||
|
||||
typedef struct mode_config_t mode_config_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type TASK_MODE_COFNIG, IKEv1 configuration attribute exchange.
|
||||
*/
|
||||
struct mode_config_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new mode_config task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE for initiator
|
||||
* @return mode_config task to handle by the task_manager
|
||||
*/
|
||||
mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** MODE_CONFIG_H_ @}*/
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "quick_delete.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/delete_payload.h>
|
||||
|
||||
typedef struct private_quick_delete_t private_quick_delete_t;
|
||||
|
||||
/**
|
||||
* Private members of a quick_delete_t task.
|
||||
*/
|
||||
struct private_quick_delete_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
quick_delete_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* Protocol of CHILD_SA to delete
|
||||
*/
|
||||
protocol_id_t protocol;
|
||||
|
||||
/**
|
||||
* Inbound SPI of CHILD_SA to delete
|
||||
*/
|
||||
u_int32_t spi;
|
||||
|
||||
/**
|
||||
* Send delete even if SA does not exist
|
||||
*/
|
||||
bool force;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete the specified CHILD_SA, if found
|
||||
*/
|
||||
static bool delete_child(private_quick_delete_t *this,
|
||||
protocol_id_t protocol, u_int32_t spi)
|
||||
{
|
||||
u_int64_t bytes_in, bytes_out;
|
||||
child_sa_t *child_sa;
|
||||
|
||||
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, TRUE);
|
||||
if (!child_sa)
|
||||
{ /* fallback and check for outbound SA */
|
||||
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, FALSE);
|
||||
if (!child_sa)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
this->spi = spi = child_sa->get_spi(child_sa, TRUE);
|
||||
}
|
||||
|
||||
child_sa->set_state(child_sa, CHILD_DELETING);
|
||||
|
||||
child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in);
|
||||
child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out);
|
||||
|
||||
DBG0(DBG_IKE, "closing CHILD_SA %s{%d} "
|
||||
"with SPIs %.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R",
|
||||
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
|
||||
ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
|
||||
ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
|
||||
child_sa->get_traffic_selectors(child_sa, TRUE),
|
||||
child_sa->get_traffic_selectors(child_sa, FALSE));
|
||||
|
||||
charon->bus->child_updown(charon->bus, child_sa, FALSE);
|
||||
|
||||
this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
|
||||
|
||||
/* TODO-IKEv1: handle close action? */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_quick_delete_t *this, message_t *message)
|
||||
{
|
||||
if (delete_child(this, this->protocol, this->spi) || this->force)
|
||||
{
|
||||
delete_payload_t *delete_payload;
|
||||
|
||||
DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
|
||||
protocol_id_names, this->protocol, ntohl(this->spi));
|
||||
|
||||
delete_payload = delete_payload_create(DELETE_V1, PROTO_ESP);
|
||||
delete_payload->add_spi(delete_payload, this->spi);
|
||||
message->add_payload(message, &delete_payload->payload_interface);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_quick_delete_t *this, message_t *message)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_quick_delete_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *payloads, *spis;
|
||||
payload_t *payload;
|
||||
delete_payload_t *delete_payload;
|
||||
protocol_id_t protocol;
|
||||
u_int32_t spi;
|
||||
|
||||
payloads = message->create_payload_enumerator(message);
|
||||
while (payloads->enumerate(payloads, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == DELETE_V1)
|
||||
{
|
||||
delete_payload = (delete_payload_t*)payload;
|
||||
protocol = delete_payload->get_protocol_id(delete_payload);
|
||||
if (protocol != PROTO_ESP && protocol != PROTO_AH)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
spis = delete_payload->create_spi_enumerator(delete_payload);
|
||||
while (spis->enumerate(spis, &spi))
|
||||
{
|
||||
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
|
||||
protocol_id_names, protocol, ntohl(spi));
|
||||
if (!delete_child(this, protocol, spi))
|
||||
{
|
||||
DBG1(DBG_IKE, "CHILD_SA not found, ignored");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
spis->destroy(spis);
|
||||
}
|
||||
}
|
||||
payloads->destroy(payloads);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_quick_delete_t *this, message_t *message)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_quick_delete_t *this)
|
||||
{
|
||||
return TASK_QUICK_DELETE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_quick_delete_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_quick_delete_t *this)
|
||||
{
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
|
||||
u_int32_t spi, bool force)
|
||||
{
|
||||
private_quick_delete_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.protocol = protocol,
|
||||
.spi = spi,
|
||||
.force = force,
|
||||
);
|
||||
|
||||
if (protocol != PROTO_NONE)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup quick_delete quick_delete
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef QUICK_DELETE_H_
|
||||
#define QUICK_DELETE_H_
|
||||
|
||||
typedef struct quick_delete_t quick_delete_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
#include <sa/child_sa.h>
|
||||
|
||||
/**
|
||||
* Task of type QUICK_DELETE, delete an IKEv1 quick mode SA.
|
||||
*/
|
||||
struct quick_delete_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new quick_delete task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param protocol protocol of CHILD_SA to delete, PROTO_NONE as responder
|
||||
* @param spi inbound SPI of CHILD_SA to delete
|
||||
* @param force send delete even if SA does not exist
|
||||
* @return quick_delete task to handle by the task_manager
|
||||
*/
|
||||
quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
|
||||
u_int32_t spi, bool force);
|
||||
|
||||
#endif /** QUICK_DELETE_H_ @}*/
|
||||
@@ -0,0 +1,947 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "quick_mode.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <daemon.h>
|
||||
#include <sa/ikev1/keymat_v1.h>
|
||||
#include <encoding/payloads/sa_payload.h>
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <encoding/payloads/ke_payload.h>
|
||||
#include <encoding/payloads/id_payload.h>
|
||||
#include <encoding/payloads/payload.h>
|
||||
#include <sa/ikev1/tasks/informational.h>
|
||||
#include <sa/ikev1/tasks/quick_delete.h>
|
||||
|
||||
typedef struct private_quick_mode_t private_quick_mode_t;
|
||||
|
||||
/**
|
||||
* Private members of a quick_mode_t task.
|
||||
*/
|
||||
struct private_quick_mode_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
quick_mode_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* TRUE if we are initiating quick mode
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* Traffic selector of initiator
|
||||
*/
|
||||
traffic_selector_t *tsi;
|
||||
|
||||
/**
|
||||
* Traffic selector of responder
|
||||
*/
|
||||
traffic_selector_t *tsr;
|
||||
|
||||
/**
|
||||
* Initiators nonce
|
||||
*/
|
||||
chunk_t nonce_i;
|
||||
|
||||
/**
|
||||
* Responder nonce
|
||||
*/
|
||||
chunk_t nonce_r;
|
||||
|
||||
/**
|
||||
* Initiators ESP SPI
|
||||
*/
|
||||
u_int32_t spi_i;
|
||||
|
||||
/**
|
||||
* Responder ESP SPI
|
||||
*/
|
||||
u_int32_t spi_r;
|
||||
|
||||
/**
|
||||
* selected CHILD_SA proposal
|
||||
*/
|
||||
proposal_t *proposal;
|
||||
|
||||
/**
|
||||
* Config of CHILD_SA to establish
|
||||
*/
|
||||
child_cfg_t *config;
|
||||
|
||||
/**
|
||||
* CHILD_SA we are about to establish
|
||||
*/
|
||||
child_sa_t *child_sa;
|
||||
|
||||
/**
|
||||
* IKEv1 keymat
|
||||
*/
|
||||
keymat_v1_t *keymat;
|
||||
|
||||
/**
|
||||
* DH exchange, when PFS is in use
|
||||
*/
|
||||
diffie_hellman_t *dh;
|
||||
|
||||
/**
|
||||
* Negotiated lifetime of new SA
|
||||
*/
|
||||
u_int32_t lifetime;
|
||||
|
||||
/**
|
||||
* Negotaited lifebytes of new SA
|
||||
*/
|
||||
u_int64_t lifebytes;
|
||||
|
||||
/**
|
||||
* Notify type in case of error
|
||||
*/
|
||||
notify_type_t notify_type;
|
||||
|
||||
/** states of quick mode */
|
||||
enum {
|
||||
QM_INIT,
|
||||
QM_NEGOTIATED,
|
||||
} state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Install negotiated CHILD_SA
|
||||
*/
|
||||
static bool install(private_quick_mode_t *this)
|
||||
{
|
||||
status_t status, status_i, status_o;
|
||||
chunk_t encr_i, encr_r, integ_i, integ_r;
|
||||
linked_list_t *tsi, *tsr;
|
||||
|
||||
this->child_sa->set_proposal(this->child_sa, this->proposal);
|
||||
this->child_sa->set_state(this->child_sa, CHILD_INSTALLING);
|
||||
this->child_sa->set_mode(this->child_sa, MODE_TUNNEL);
|
||||
this->child_sa->set_protocol(this->child_sa,
|
||||
this->proposal->get_protocol(this->proposal));
|
||||
|
||||
status_i = status_o = FAILED;
|
||||
encr_i = encr_r = integ_i = integ_r = chunk_empty;
|
||||
tsi = linked_list_create();
|
||||
tsr = linked_list_create();
|
||||
tsi->insert_last(tsi, this->tsi);
|
||||
tsr->insert_last(tsr, this->tsr);
|
||||
if (this->keymat->derive_child_keys(this->keymat, this->proposal, this->dh,
|
||||
this->spi_i, this->spi_r, this->nonce_i, this->nonce_r,
|
||||
&encr_i, &integ_i, &encr_r, &integ_r))
|
||||
{
|
||||
if (this->initiator)
|
||||
{
|
||||
status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
|
||||
this->spi_i, 0, TRUE, FALSE, tsi, tsr);
|
||||
status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
|
||||
this->spi_r, 0, FALSE, FALSE, tsi, tsr);
|
||||
}
|
||||
else
|
||||
{
|
||||
status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
|
||||
this->spi_r, 0, TRUE, FALSE, tsr, tsi);
|
||||
status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
|
||||
this->spi_i, 0, FALSE, FALSE, tsr, tsi);
|
||||
}
|
||||
}
|
||||
chunk_clear(&integ_i);
|
||||
chunk_clear(&integ_r);
|
||||
chunk_clear(&encr_i);
|
||||
chunk_clear(&encr_r);
|
||||
|
||||
if (status_i != SUCCESS || status_o != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel",
|
||||
(status_i != SUCCESS) ? "inbound " : "",
|
||||
(status_i != SUCCESS && status_o != SUCCESS) ? "and ": "",
|
||||
(status_o != SUCCESS) ? "outbound " : "");
|
||||
tsi->destroy(tsi);
|
||||
tsr->destroy(tsr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
status = this->child_sa->add_policies(this->child_sa, tsi, tsr);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = this->child_sa->add_policies(this->child_sa, tsr, tsi);
|
||||
}
|
||||
tsi->destroy(tsi);
|
||||
tsr->destroy(tsr);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
|
||||
this->dh, this->nonce_i, this->nonce_r);
|
||||
|
||||
/* add to IKE_SA, and remove from task */
|
||||
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
|
||||
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
|
||||
|
||||
DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
|
||||
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
|
||||
this->child_sa->get_name(this->child_sa),
|
||||
this->child_sa->get_reqid(this->child_sa),
|
||||
ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
|
||||
ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
|
||||
this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
|
||||
this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
|
||||
|
||||
charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
|
||||
|
||||
this->child_sa = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and add NONCE
|
||||
*/
|
||||
static bool add_nonce(private_quick_mode_t *this, chunk_t *nonce,
|
||||
message_t *message)
|
||||
{
|
||||
nonce_payload_t *nonce_payload;
|
||||
rng_t *rng;
|
||||
|
||||
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||
if (!rng)
|
||||
{
|
||||
DBG1(DBG_IKE, "no RNG found to create nonce");
|
||||
return FALSE;
|
||||
}
|
||||
rng->allocate_bytes(rng, NONCE_SIZE, nonce);
|
||||
rng->destroy(rng);
|
||||
|
||||
nonce_payload = nonce_payload_create(NONCE_V1);
|
||||
nonce_payload->set_nonce(nonce_payload, *nonce);
|
||||
message->add_payload(message, &nonce_payload->payload_interface);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract nonce from NONCE payload
|
||||
*/
|
||||
static bool get_nonce(private_quick_mode_t *this, chunk_t *nonce,
|
||||
message_t *message)
|
||||
{
|
||||
nonce_payload_t *nonce_payload;
|
||||
|
||||
nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1);
|
||||
if (!nonce_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "NONCE payload missing in message");
|
||||
return FALSE;
|
||||
}
|
||||
*nonce = nonce_payload->get_nonce(nonce_payload);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add KE payload to message
|
||||
*/
|
||||
static void add_ke(private_quick_mode_t *this, message_t *message)
|
||||
{
|
||||
ke_payload_t *ke_payload;
|
||||
|
||||
ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1, this->dh);
|
||||
message->add_payload(message, &ke_payload->payload_interface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DH value from a KE payload
|
||||
*/
|
||||
static bool get_ke(private_quick_mode_t *this, message_t *message)
|
||||
{
|
||||
ke_payload_t *ke_payload;
|
||||
|
||||
ke_payload = (ke_payload_t*)message->get_payload(message, KEY_EXCHANGE_V1);
|
||||
if (!ke_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "KE payload missing");
|
||||
return FALSE;
|
||||
}
|
||||
this->dh->set_other_public_value(this->dh,
|
||||
ke_payload->get_key_exchange_data(ke_payload));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a traffic selector from configuration
|
||||
*/
|
||||
static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local,
|
||||
linked_list_t *supplied)
|
||||
{
|
||||
traffic_selector_t *ts;
|
||||
linked_list_t *list;
|
||||
host_t *host;
|
||||
|
||||
host = this->ike_sa->get_virtual_ip(this->ike_sa, local);
|
||||
if (!host)
|
||||
{
|
||||
if (local)
|
||||
{
|
||||
host = this->ike_sa->get_my_host(this->ike_sa);
|
||||
}
|
||||
else
|
||||
{
|
||||
host = this->ike_sa->get_other_host(this->ike_sa);
|
||||
}
|
||||
}
|
||||
list = this->config->get_traffic_selectors(this->config, local,
|
||||
supplied, host);
|
||||
if (list->get_first(list, (void**)&ts) == SUCCESS)
|
||||
{
|
||||
if (list->get_count(list) > 1)
|
||||
{
|
||||
DBG1(DBG_IKE, "configuration has more than one %s traffic selector,"
|
||||
" using first only", local ? "local" : "remote");
|
||||
}
|
||||
ts = ts->clone(ts);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "%s traffic selector missing in configuration",
|
||||
local ? "local" : "local");
|
||||
ts = NULL;
|
||||
}
|
||||
list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
|
||||
return ts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add selected traffic selectors to message
|
||||
*/
|
||||
static void add_ts(private_quick_mode_t *this, message_t *message)
|
||||
{
|
||||
id_payload_t *id_payload;
|
||||
host_t *hsi, *hsr;
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
hsi = this->ike_sa->get_my_host(this->ike_sa);
|
||||
hsr = this->ike_sa->get_other_host(this->ike_sa);
|
||||
}
|
||||
else
|
||||
{
|
||||
hsr = this->ike_sa->get_my_host(this->ike_sa);
|
||||
hsi = this->ike_sa->get_other_host(this->ike_sa);
|
||||
}
|
||||
/* add ID payload only if negotiating non host2host tunnels */
|
||||
if (!this->tsi->is_host(this->tsi, hsi) ||
|
||||
!this->tsr->is_host(this->tsr, hsr) ||
|
||||
this->tsi->get_protocol(this->tsi) ||
|
||||
this->tsr->get_protocol(this->tsr) ||
|
||||
this->tsi->get_from_port(this->tsi) ||
|
||||
this->tsr->get_from_port(this->tsr) ||
|
||||
this->tsi->get_to_port(this->tsi) != 65535 ||
|
||||
this->tsr->get_to_port(this->tsr) != 65535)
|
||||
{
|
||||
id_payload = id_payload_create_from_ts(this->tsi);
|
||||
message->add_payload(message, &id_payload->payload_interface);
|
||||
id_payload = id_payload_create_from_ts(this->tsr);
|
||||
message->add_payload(message, &id_payload->payload_interface);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get traffic selectors from received message
|
||||
*/
|
||||
static bool get_ts(private_quick_mode_t *this, message_t *message)
|
||||
{
|
||||
traffic_selector_t *tsi = NULL, *tsr = NULL;
|
||||
enumerator_t *enumerator;
|
||||
id_payload_t *id_payload;
|
||||
payload_t *payload;
|
||||
host_t *hsi, *hsr;
|
||||
bool first = TRUE;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == ID_V1)
|
||||
{
|
||||
id_payload = (id_payload_t*)payload;
|
||||
|
||||
if (first)
|
||||
{
|
||||
tsi = id_payload->get_ts(id_payload);
|
||||
first = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
tsr = id_payload->get_ts(id_payload);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
/* create host2host selectors if ID payloads missing */
|
||||
if (this->initiator)
|
||||
{
|
||||
hsi = this->ike_sa->get_my_host(this->ike_sa);
|
||||
hsr = this->ike_sa->get_other_host(this->ike_sa);
|
||||
}
|
||||
else
|
||||
{
|
||||
hsr = this->ike_sa->get_my_host(this->ike_sa);
|
||||
hsi = this->ike_sa->get_other_host(this->ike_sa);
|
||||
}
|
||||
if (!tsi)
|
||||
{
|
||||
tsi = traffic_selector_create_from_subnet(hsi->clone(hsi),
|
||||
hsi->get_family(hsi) == AF_INET ? 32 : 128, 0, 0);
|
||||
}
|
||||
if (!tsr)
|
||||
{
|
||||
tsr = traffic_selector_create_from_subnet(hsr->clone(hsr),
|
||||
hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0);
|
||||
}
|
||||
if (this->initiator)
|
||||
{
|
||||
/* check if peer selection valid */
|
||||
if (!tsr->is_contained_in(tsr, this->tsr) ||
|
||||
!tsi->is_contained_in(tsi, this->tsi))
|
||||
{
|
||||
DBG1(DBG_IKE, "peer selected invalid traffic selectors: ",
|
||||
"%R for %R, %R for %R", tsi, this->tsi, tsr, this->tsr);
|
||||
tsi->destroy(tsi);
|
||||
tsr->destroy(tsr);
|
||||
return FALSE;
|
||||
}
|
||||
this->tsi->destroy(this->tsi);
|
||||
this->tsr->destroy(this->tsr);
|
||||
this->tsi = tsi;
|
||||
this->tsr = tsr;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->tsi = tsi;
|
||||
this->tsr = tsr;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add NAT-OA payloads
|
||||
*/
|
||||
static void add_nat_oa_payloads(private_quick_mode_t *this, message_t *message)
|
||||
{
|
||||
identification_t *id;
|
||||
id_payload_t *nat_oa;
|
||||
host_t *src, *dst;
|
||||
|
||||
src = message->get_source(message);
|
||||
dst = message->get_destination(message);
|
||||
|
||||
src = this->initiator ? src : dst;
|
||||
dst = this->initiator ? dst : src;
|
||||
|
||||
/* first NAT-OA is the initiator's address */
|
||||
id = identification_create_from_sockaddr(src->get_sockaddr(src));
|
||||
nat_oa = id_payload_create_from_identification(NAT_OA_V1, id);
|
||||
message->add_payload(message, (payload_t*)nat_oa);
|
||||
id->destroy(id);
|
||||
|
||||
/* second NAT-OA is that of the responder */
|
||||
id = identification_create_from_sockaddr(dst->get_sockaddr(dst));
|
||||
nat_oa = id_payload_create_from_identification(NAT_OA_V1, id);
|
||||
message->add_payload(message, (payload_t*)nat_oa);
|
||||
id->destroy(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up lifetimes
|
||||
*/
|
||||
static void get_lifetimes(private_quick_mode_t *this)
|
||||
{
|
||||
lifetime_cfg_t *lft;
|
||||
|
||||
lft = this->config->get_lifetime(this->config);
|
||||
if (lft->time.life)
|
||||
{
|
||||
this->lifetime = lft->time.life;
|
||||
}
|
||||
else if (lft->bytes.life)
|
||||
{
|
||||
this->lifebytes = lft->bytes.life;
|
||||
}
|
||||
free(lft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and apply lifetimes
|
||||
*/
|
||||
static void apply_lifetimes(private_quick_mode_t *this, sa_payload_t *sa_payload)
|
||||
{
|
||||
u_int32_t lifetime;
|
||||
u_int64_t lifebytes;
|
||||
|
||||
lifetime = sa_payload->get_lifetime(sa_payload);
|
||||
lifebytes = sa_payload->get_lifebytes(sa_payload);
|
||||
if (this->lifetime != lifetime)
|
||||
{
|
||||
DBG1(DBG_IKE, "received %us lifetime, configured %us, using lower",
|
||||
lifetime, this->lifetime);
|
||||
this->lifetime = min(this->lifetime, lifetime);
|
||||
}
|
||||
if (this->lifebytes != lifebytes)
|
||||
{
|
||||
DBG1(DBG_IKE, "received %llu lifebytes, configured %llu, using lower",
|
||||
lifebytes, this->lifebytes);
|
||||
this->lifebytes = min(this->lifebytes, lifebytes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the task ready to build notify error message
|
||||
*/
|
||||
static status_t send_notify(private_quick_mode_t *this, notify_type_t type)
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
|
||||
notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1,
|
||||
PROTO_ESP, type);
|
||||
notify->set_spi(notify, this->spi_i);
|
||||
|
||||
this->ike_sa->queue_task(this->ike_sa,
|
||||
(task_t*)informational_create(this->ike_sa, notify));
|
||||
/* cancel all active/passive tasks in favour of informational */
|
||||
return ALREADY_DONE;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_quick_mode_t *this, message_t *message)
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case QM_INIT:
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
sa_payload_t *sa_payload;
|
||||
linked_list_t *list;
|
||||
proposal_t *proposal;
|
||||
ipsec_mode_t mode;
|
||||
diffie_hellman_group_t group;
|
||||
bool udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
|
||||
|
||||
this->child_sa = child_sa_create(
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->config, 0, udp);
|
||||
|
||||
list = this->config->get_proposals(this->config, FALSE);
|
||||
|
||||
this->spi_i = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
|
||||
if (!this->spi_i)
|
||||
{
|
||||
DBG1(DBG_IKE, "allocating SPI from kernel failed");
|
||||
return FAILED;
|
||||
}
|
||||
enumerator = list->create_enumerator(list);
|
||||
while (enumerator->enumerate(enumerator, &proposal))
|
||||
{
|
||||
proposal->set_spi(proposal, this->spi_i);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
mode = this->config->get_mode(this->config);
|
||||
if (udp && mode == MODE_TRANSPORT)
|
||||
{
|
||||
/* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
|
||||
add_nat_oa_payloads(this, message);
|
||||
}
|
||||
|
||||
get_lifetimes(this);
|
||||
sa_payload = sa_payload_create_from_proposals_v1(list,
|
||||
this->lifetime, this->lifebytes, AUTH_NONE,
|
||||
mode, udp);
|
||||
list->destroy_offset(list, offsetof(proposal_t, destroy));
|
||||
message->add_payload(message, &sa_payload->payload_interface);
|
||||
|
||||
if (!add_nonce(this, &this->nonce_i, message))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
group = this->config->get_dh_group(this->config);
|
||||
if (group != MODP_NONE)
|
||||
{
|
||||
this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
|
||||
group);
|
||||
if (!this->dh)
|
||||
{
|
||||
DBG1(DBG_IKE, "configured DH group %N not supported",
|
||||
diffie_hellman_group_names, group);
|
||||
return FAILED;
|
||||
}
|
||||
add_ke(this, message);
|
||||
}
|
||||
this->tsi = select_ts(this, TRUE, NULL);
|
||||
this->tsr = select_ts(this, FALSE, NULL);
|
||||
if (!this->tsi || !this->tsr)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
add_ts(this, message);
|
||||
return NEED_MORE;
|
||||
}
|
||||
case QM_NEGOTIATED:
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for notify errors, return TRUE if error found
|
||||
*/
|
||||
static bool has_notify_errors(private_quick_mode_t *this, message_t *message)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
bool err = FALSE;
|
||||
|
||||
enumerator = message->create_payload_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
if (payload->get_type(payload) == NOTIFY_V1)
|
||||
{
|
||||
notify_payload_t *notify;
|
||||
notify_type_t type;
|
||||
|
||||
notify = (notify_payload_t*)payload;
|
||||
type = notify->get_notify_type(notify);
|
||||
if (type < 16384)
|
||||
{
|
||||
|
||||
DBG1(DBG_IKE, "received %N error notify",
|
||||
notify_type_names, type);
|
||||
err = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "received %N notify", notify_type_names, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_quick_mode_t *this, message_t *message)
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case QM_INIT:
|
||||
{
|
||||
sa_payload_t *sa_payload;
|
||||
linked_list_t *tsi, *tsr, *list;
|
||||
peer_cfg_t *peer_cfg;
|
||||
host_t *me, *other;
|
||||
u_int16_t group;
|
||||
bool udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
|
||||
|
||||
if (!get_ts(this, message))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
|
||||
if (!me)
|
||||
{
|
||||
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||
}
|
||||
other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
|
||||
if (!other)
|
||||
{
|
||||
other = this->ike_sa->get_other_host(this->ike_sa);
|
||||
}
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
tsi = linked_list_create();
|
||||
tsr = linked_list_create();
|
||||
tsi->insert_last(tsi, this->tsi);
|
||||
tsr->insert_last(tsr, this->tsr);
|
||||
this->tsi = this->tsr = NULL;
|
||||
this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi,
|
||||
me, other);
|
||||
this->tsi = select_ts(this, FALSE, tsi);
|
||||
this->tsr = select_ts(this, TRUE, tsr);
|
||||
tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
|
||||
tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
|
||||
if (!this->config)
|
||||
{
|
||||
DBG1(DBG_IKE, "no child config found");
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
|
||||
sa_payload = (sa_payload_t*)message->get_payload(message,
|
||||
SECURITY_ASSOCIATION_V1);
|
||||
if (!sa_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "sa payload missing");
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
list = sa_payload->get_proposals(sa_payload);
|
||||
this->proposal = this->config->select_proposal(this->config,
|
||||
list, FALSE, FALSE);
|
||||
list->destroy_offset(list, offsetof(proposal_t, destroy));
|
||||
|
||||
get_lifetimes(this);
|
||||
apply_lifetimes(this, sa_payload);
|
||||
|
||||
if (!this->proposal)
|
||||
{
|
||||
DBG1(DBG_IKE, "no matching proposal found, sending %N",
|
||||
notify_type_names, NO_PROPOSAL_CHOSEN);
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
this->spi_i = this->proposal->get_spi(this->proposal);
|
||||
|
||||
if (!get_nonce(this, &this->nonce_i, message))
|
||||
{
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
|
||||
if (this->proposal->get_algorithm(this->proposal,
|
||||
DIFFIE_HELLMAN_GROUP, &group, NULL))
|
||||
{
|
||||
this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
|
||||
group);
|
||||
if (!this->dh)
|
||||
{
|
||||
DBG1(DBG_IKE, "negotiated DH group %N not supported",
|
||||
diffie_hellman_group_names, group);
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
if (!get_ke(this, message))
|
||||
{
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
this->child_sa = child_sa_create(
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->config, 0, udp);
|
||||
return NEED_MORE;
|
||||
}
|
||||
case QM_NEGOTIATED:
|
||||
{
|
||||
if (has_notify_errors(this, message))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
if (!install(this))
|
||||
{
|
||||
this->ike_sa->queue_task(this->ike_sa,
|
||||
(task_t*)quick_delete_create(this->ike_sa,
|
||||
this->proposal->get_protocol(this->proposal),
|
||||
this->spi_i, TRUE));
|
||||
return ALREADY_DONE;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_quick_mode_t *this, message_t *message)
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case QM_INIT:
|
||||
{
|
||||
sa_payload_t *sa_payload;
|
||||
ipsec_mode_t mode;
|
||||
bool udp = this->child_sa->has_encap(this->child_sa);
|
||||
|
||||
this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
|
||||
if (!this->spi_r)
|
||||
{
|
||||
DBG1(DBG_IKE, "allocating SPI from kernel failed");
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
this->proposal->set_spi(this->proposal, this->spi_r);
|
||||
|
||||
mode = this->config->get_mode(this->config);
|
||||
if (udp && mode == MODE_TRANSPORT)
|
||||
{
|
||||
/* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
|
||||
add_nat_oa_payloads(this, message);
|
||||
}
|
||||
|
||||
sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
|
||||
this->lifetime, this->lifebytes, AUTH_NONE,
|
||||
mode, udp);
|
||||
message->add_payload(message, &sa_payload->payload_interface);
|
||||
|
||||
if (!add_nonce(this, &this->nonce_r, message))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
if (this->dh)
|
||||
{
|
||||
add_ke(this, message);
|
||||
}
|
||||
|
||||
add_ts(this, message);
|
||||
|
||||
this->state = QM_NEGOTIATED;
|
||||
return NEED_MORE;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_quick_mode_t *this, message_t *message)
|
||||
{
|
||||
switch (this->state)
|
||||
{
|
||||
case QM_INIT:
|
||||
{
|
||||
sa_payload_t *sa_payload;
|
||||
linked_list_t *list;
|
||||
|
||||
sa_payload = (sa_payload_t*)message->get_payload(message,
|
||||
SECURITY_ASSOCIATION_V1);
|
||||
if (!sa_payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "sa payload missing");
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
list = sa_payload->get_proposals(sa_payload);
|
||||
this->proposal = this->config->select_proposal(this->config,
|
||||
list, FALSE, FALSE);
|
||||
list->destroy_offset(list, offsetof(proposal_t, destroy));
|
||||
if (!this->proposal)
|
||||
{
|
||||
DBG1(DBG_IKE, "no matching proposal found");
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
this->spi_r = this->proposal->get_spi(this->proposal);
|
||||
|
||||
apply_lifetimes(this, sa_payload);
|
||||
|
||||
if (!get_nonce(this, &this->nonce_r, message))
|
||||
{
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
if (this->dh && !get_ke(this, message))
|
||||
{
|
||||
return send_notify(this, INVALID_KEY_INFORMATION);
|
||||
}
|
||||
if (!get_ts(this, message))
|
||||
{
|
||||
return send_notify(this, INVALID_PAYLOAD_TYPE);
|
||||
}
|
||||
if (!install(this))
|
||||
{
|
||||
return send_notify(this, NO_PROPOSAL_CHOSEN);
|
||||
}
|
||||
this->state = QM_NEGOTIATED;
|
||||
return NEED_MORE;
|
||||
}
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_quick_mode_t *this)
|
||||
{
|
||||
return TASK_QUICK_MODE;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_quick_mode_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_quick_mode_t *this)
|
||||
{
|
||||
chunk_free(&this->nonce_i);
|
||||
chunk_free(&this->nonce_r);
|
||||
DESTROY_IF(this->tsi);
|
||||
DESTROY_IF(this->tsr);
|
||||
DESTROY_IF(this->proposal);
|
||||
DESTROY_IF(this->child_sa);
|
||||
DESTROY_IF(this->config);
|
||||
DESTROY_IF(this->dh);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
|
||||
traffic_selector_t *tsi, traffic_selector_t *tsr)
|
||||
{
|
||||
private_quick_mode_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.initiator = config != NULL,
|
||||
.config = config,
|
||||
.keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
|
||||
.state = QM_INIT,
|
||||
);
|
||||
|
||||
if (config)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup quick_mode quick_mode
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef QUICK_MODE_H_
|
||||
#define QUICK_MODE_H_
|
||||
|
||||
typedef struct quick_mode_t quick_mode_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* IKEv1 quick mode, establishes a CHILD_SA in IKEv1.
|
||||
*/
|
||||
struct quick_mode_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new quick_mode task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param config child_cfg if task initiator, NULL if responder
|
||||
* @param tsi source of triggering packet, or NULL
|
||||
* @param tsr destination of triggering packet, or NULL
|
||||
* @return task to handle by the task_manager
|
||||
*/
|
||||
quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
|
||||
traffic_selector_t *tsi, traffic_selector_t *tsr);
|
||||
|
||||
#endif /** QUICK_MODE_H_ @}*/
|
||||
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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 "xauth.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <hydra.h>
|
||||
#include <encoding/payloads/cp_payload.h>
|
||||
|
||||
typedef struct private_xauth_t private_xauth_t;
|
||||
|
||||
/**
|
||||
* Status types exchanged
|
||||
*/
|
||||
typedef enum {
|
||||
XAUTH_FAILED = 0,
|
||||
XAUTH_OK = 1,
|
||||
} xauth_status_t;
|
||||
|
||||
/**
|
||||
* Private members of a xauth_t task.
|
||||
*/
|
||||
struct private_xauth_t {
|
||||
|
||||
/**
|
||||
* Public methods and task_t interface.
|
||||
*/
|
||||
xauth_t public;
|
||||
|
||||
/**
|
||||
* Assigned IKE_SA.
|
||||
*/
|
||||
ike_sa_t *ike_sa;
|
||||
|
||||
/**
|
||||
* Are we the XAUTH initiator?
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* XAuth backend to use
|
||||
*/
|
||||
xauth_method_t *xauth;
|
||||
|
||||
/**
|
||||
* XAuth username
|
||||
*/
|
||||
identification_t *user;
|
||||
|
||||
/**
|
||||
* Generated configuration payload
|
||||
*/
|
||||
cp_payload_t *cp;
|
||||
|
||||
/**
|
||||
* status of Xauth exchange
|
||||
*/
|
||||
xauth_status_t status;
|
||||
};
|
||||
|
||||
/**
|
||||
* Load XAuth backend
|
||||
*/
|
||||
static xauth_method_t *load_method(private_xauth_t* this)
|
||||
{
|
||||
identification_t *server, *peer;
|
||||
enumerator_t *enumerator;
|
||||
xauth_method_t *xauth;
|
||||
xauth_role_t role;
|
||||
peer_cfg_t *peer_cfg;
|
||||
auth_cfg_t *auth;
|
||||
char *name;
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
server = this->ike_sa->get_my_id(this->ike_sa);
|
||||
peer = this->ike_sa->get_other_id(this->ike_sa);
|
||||
role = XAUTH_SERVER;
|
||||
}
|
||||
else
|
||||
{
|
||||
peer = this->ike_sa->get_my_id(this->ike_sa);
|
||||
server = this->ike_sa->get_other_id(this->ike_sa);
|
||||
role = XAUTH_PEER;
|
||||
}
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !this->initiator);
|
||||
if (!enumerator->enumerate(enumerator, &auth) ||
|
||||
(uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
|
||||
{
|
||||
if (!enumerator->enumerate(enumerator, &auth) ||
|
||||
(uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
|
||||
{
|
||||
DBG1(DBG_CFG, "no XAuth authentication round found");
|
||||
enumerator->destroy(enumerator);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND);
|
||||
this->user = auth->get(auth, AUTH_RULE_XAUTH_IDENTITY);
|
||||
if (!this->initiator && this->user)
|
||||
{ /* use XAUTH username, if configured */
|
||||
peer = this->user;
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
xauth = charon->xauth->create_instance(charon->xauth, name, role,
|
||||
server, peer);
|
||||
if (!xauth)
|
||||
{
|
||||
if (name)
|
||||
{
|
||||
DBG1(DBG_CFG, "no XAuth method found named '%s'");
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, "no XAuth method found");
|
||||
}
|
||||
}
|
||||
return xauth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set IKE_SA to established state
|
||||
*/
|
||||
static void establish(private_xauth_t *this)
|
||||
{
|
||||
DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
|
||||
this->ike_sa->get_name(this->ike_sa),
|
||||
this->ike_sa->get_unique_id(this->ike_sa),
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_my_id(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa),
|
||||
this->ike_sa->get_other_id(this->ike_sa));
|
||||
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
|
||||
charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i_status, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
cp_payload_t *cp;
|
||||
|
||||
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET);
|
||||
cp->add_attribute(cp,
|
||||
configuration_attribute_create_value(XAUTH_STATUS, this->status));
|
||||
|
||||
message->add_payload(message, (payload_t *)cp);
|
||||
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
if (!this->xauth)
|
||||
{
|
||||
cp_payload_t *cp;
|
||||
|
||||
this->xauth = load_method(this);
|
||||
if (!this->xauth)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
if (this->xauth->initiate(this->xauth, &cp) != NEED_MORE)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
message->add_payload(message, (payload_t *)cp);
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
if (this->cp)
|
||||
{ /* send previously generated payload */
|
||||
message->add_payload(message, (payload_t *)this->cp);
|
||||
this->cp = NULL;
|
||||
return NEED_MORE;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r_ack, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
cp_payload_t *cp;
|
||||
|
||||
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_ACK);
|
||||
cp->add_attribute(cp,
|
||||
configuration_attribute_create_chunk(
|
||||
CONFIGURATION_ATTRIBUTE_V1, XAUTH_STATUS, chunk_empty));
|
||||
|
||||
message->add_payload(message, (payload_t *)cp);
|
||||
|
||||
if (this->status == XAUTH_OK)
|
||||
{
|
||||
establish(this);
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_r, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
cp_payload_t *cp;
|
||||
|
||||
if (!this->xauth)
|
||||
{
|
||||
this->xauth = load_method(this);
|
||||
if (!this->xauth)
|
||||
{ /* send empty reply */
|
||||
return NEED_MORE;
|
||||
}
|
||||
}
|
||||
cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
|
||||
if (!cp)
|
||||
{
|
||||
DBG1(DBG_IKE, "configuration payload missing in XAuth request");
|
||||
return FAILED;
|
||||
}
|
||||
if (cp->get_type(cp) == CFG_REQUEST)
|
||||
{
|
||||
switch (this->xauth->process(this->xauth, cp, &this->cp))
|
||||
{
|
||||
case NEED_MORE:
|
||||
return NEED_MORE;
|
||||
case SUCCESS:
|
||||
case FAILED:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this->cp = NULL;
|
||||
return NEED_MORE;
|
||||
}
|
||||
if (cp->get_type(cp) == CFG_SET)
|
||||
{
|
||||
configuration_attribute_t *attribute;
|
||||
enumerator_t *enumerator;
|
||||
|
||||
enumerator = cp->create_attribute_enumerator(cp);
|
||||
while (enumerator->enumerate(enumerator, &attribute))
|
||||
{
|
||||
if (attribute->get_type(attribute) == XAUTH_STATUS)
|
||||
{
|
||||
this->status = attribute->get_value(attribute);
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
if (this->status == XAUTH_OK)
|
||||
{
|
||||
DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) successful",
|
||||
this->xauth->get_identity(this->xauth));
|
||||
establish(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) failed",
|
||||
this->xauth->get_identity(this->xauth));
|
||||
}
|
||||
}
|
||||
this->public.task.build = _build_r_ack;
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, build_r, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
if (!this->cp)
|
||||
{ /* send empty reply if building data failed */
|
||||
this->cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
|
||||
}
|
||||
message->add_payload(message, (payload_t *)this->cp);
|
||||
this->cp = NULL;
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i_status, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
cp_payload_t *cp;
|
||||
|
||||
cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
|
||||
if (!cp || cp->get_type(cp) != CFG_ACK)
|
||||
{
|
||||
DBG1(DBG_IKE, "received invalid XAUTH status response");
|
||||
return FAILED;
|
||||
}
|
||||
if (this->status != XAUTH_OK)
|
||||
{
|
||||
DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication");
|
||||
return FAILED;
|
||||
}
|
||||
establish(this);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_t, process_i, status_t,
|
||||
private_xauth_t *this, message_t *message)
|
||||
{
|
||||
identification_t *id;
|
||||
cp_payload_t *cp;
|
||||
|
||||
cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
|
||||
if (!cp)
|
||||
{
|
||||
DBG1(DBG_IKE, "configuration payload missing in XAuth response");
|
||||
return FAILED;
|
||||
}
|
||||
switch (this->xauth->process(this->xauth, cp, &this->cp))
|
||||
{
|
||||
case NEED_MORE:
|
||||
return NEED_MORE;
|
||||
case SUCCESS:
|
||||
id = this->xauth->get_identity(this->xauth);
|
||||
if (this->user && !id->matches(id, this->user))
|
||||
{
|
||||
DBG1(DBG_IKE, "XAuth username '%Y' does not match to "
|
||||
"configured username '%Y'", id, this->user);
|
||||
break;
|
||||
}
|
||||
DBG1(DBG_IKE, "XAuth authentication of '%Y' successful", id);
|
||||
this->status = XAUTH_OK;
|
||||
break;
|
||||
case FAILED:
|
||||
DBG1(DBG_IKE, "XAuth authentication of '%Y' failed",
|
||||
this->xauth->get_identity(this->xauth));
|
||||
break;
|
||||
default:
|
||||
return FAILED;
|
||||
}
|
||||
this->public.task.build = _build_i_status;
|
||||
this->public.task.process = _process_i_status;
|
||||
return NEED_MORE;
|
||||
}
|
||||
|
||||
METHOD(task_t, get_type, task_type_t,
|
||||
private_xauth_t *this)
|
||||
{
|
||||
return TASK_XAUTH;
|
||||
}
|
||||
|
||||
METHOD(task_t, migrate, void,
|
||||
private_xauth_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
this->ike_sa = ike_sa;
|
||||
}
|
||||
|
||||
METHOD(task_t, destroy, void,
|
||||
private_xauth_t *this)
|
||||
{
|
||||
DESTROY_IF(this->xauth);
|
||||
DESTROY_IF(this->cp);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator)
|
||||
{
|
||||
private_xauth_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.task = {
|
||||
.get_type = _get_type,
|
||||
.migrate = _migrate,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.initiator = initiator,
|
||||
.ike_sa = ike_sa,
|
||||
.status = XAUTH_FAILED,
|
||||
);
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->public.task.build = _build_i;
|
||||
this->public.task.process = _process_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.task.build = _build_r;
|
||||
this->public.task.process = _process_r;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Martin Willi
|
||||
* Copyright (C) 2011 revosec AG
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup xauth xauth
|
||||
* @{ @ingroup tasks
|
||||
*/
|
||||
|
||||
#ifndef XAUTH_H_
|
||||
#define XAUTH_H_
|
||||
|
||||
typedef struct xauth_t xauth_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <sa/ike_sa.h>
|
||||
#include <sa/task.h>
|
||||
|
||||
/**
|
||||
* Task of type TASK_XAUTH, additional authentication after main/aggressive mode.
|
||||
*/
|
||||
struct xauth_t {
|
||||
|
||||
/**
|
||||
* Implements the task_t interface
|
||||
*/
|
||||
task_t task;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new xauth task.
|
||||
*
|
||||
* @param ike_sa IKE_SA this task works for
|
||||
* @param initiator TRUE for initiator
|
||||
* @return xauth task to handle by the task_manager
|
||||
*/
|
||||
xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator);
|
||||
|
||||
#endif /** XAUTH_H_ @}*/
|
||||
Reference in New Issue
Block a user