implemented reauthentication using the new reauth=yes|no parameter

This commit is contained in:
Martin Willi
2006-12-19 07:30:07 +00:00
parent 4986554f1a
commit 6fe03b0af0
20 changed files with 210 additions and 67 deletions
+17 -2
View File
@@ -109,6 +109,11 @@ struct private_connection_t {
*/
u_int32_t hard_lifetime;
/**
* Use full reauthentication instead of rekeying
*/
bool reauth;
/**
* Time, which specifies the range of a random value
* substracted from soft_lifetime.
@@ -306,13 +311,21 @@ static u_int32_t get_soft_lifetime(private_connection_t *this)
}
/**
* Implementation of connection_t.get_hard_lifetime
* Implementation of connection_t.get_hard_lifetime.
*/
static u_int32_t get_hard_lifetime(private_connection_t *this)
{
return this->hard_lifetime;
}
/**
* Implementation of connection_t.get_reauth.
*/
static bool get_reauth(private_connection_t *this)
{
return this->reauth;
}
/**
* Implementation of connection_t.get_ref.
*/
@@ -343,7 +356,7 @@ connection_t * connection_create(char *name, bool ikev2,
cert_policy_t cert_policy,
cert_policy_t certreq_policy,
host_t *my_host, host_t *other_host,
u_int32_t dpd_delay,
u_int32_t dpd_delay, bool reauth,
u_int32_t retrans_sequences,
u_int32_t hard_lifetime,
u_int32_t soft_lifetime, u_int32_t jitter)
@@ -361,6 +374,7 @@ connection_t * connection_create(char *name, bool ikev2,
this->public.select_proposal = (proposal_t*(*)(connection_t*,linked_list_t*))select_proposal;
this->public.add_proposal = (void(*)(connection_t*, proposal_t*)) add_proposal;
this->public.get_dpd_delay = (u_int32_t(*)(connection_t*)) get_dpd_delay;
this->public.get_reauth = (bool(*)(connection_t*)) get_reauth;
this->public.get_retrans_seq = (u_int32_t(*)(connection_t*)) get_retrans_seq;
this->public.get_dh_group = (diffie_hellman_group_t(*)(connection_t*)) get_dh_group;
this->public.check_dh_group = (bool(*)(connection_t*,diffie_hellman_group_t)) check_dh_group;
@@ -378,6 +392,7 @@ connection_t * connection_create(char *name, bool ikev2,
this->my_host = my_host;
this->other_host = other_host;
this->dpd_delay = dpd_delay;
this->reauth = reauth;
this->retrans_sequences = retrans_sequences;
this->hard_lifetime = hard_lifetime;
this->soft_lifetime = soft_lifetime;
+11 -1
View File
@@ -132,6 +132,14 @@ struct connection_t {
*/
u_int32_t (*get_dpd_delay) (connection_t *this);
/**
* @brief Should a full reauthentication be done instead of rekeying?
*
* @param this calling object
* @return TRUE to use full reauthentication
*/
bool (*get_reauth) (connection_t *this);
/**
* @brief Get the max number of retransmission sequences.
*
@@ -267,6 +275,7 @@ struct connection_t {
* @param my_host host_t representing local address
* @param other_host host_t representing remote address
* @param dpd_delay interval of DPD liveness checks
* @param reauth use full reauthentication instead of rekeying
* @param retrans_sequences number of retransmit sequences to use
* @param hard_lifetime lifetime before deleting an IKE_SA
* @param soft_lifetime lifetime before rekeying an IKE_SA
@@ -278,7 +287,8 @@ struct connection_t {
connection_t * connection_create(char *name, bool ikev2,
cert_policy_t cert_pol, cert_policy_t req_pol,
host_t *my_host, host_t *other_host,
u_int32_t dpd_delay, u_int32_t retrans_sequences,
u_int32_t dpd_delay, bool reauth,
u_int32_t retrans_sequences,
u_int32_t hard_lifetime, u_int32_t soft_lifetime,
u_int32_t jitter);
+25 -3
View File
@@ -40,6 +40,11 @@ struct private_rekey_ike_sa_job_t {
* ID of the IKE_SA to rekey
*/
ike_sa_id_t *ike_sa_id;
/**
* force reauthentication of the peer (full IKE_SA setup)
*/
bool reauth;
};
/**
@@ -56,6 +61,7 @@ static job_type_t get_type(private_rekey_ike_sa_job_t *this)
static status_t execute(private_rekey_ike_sa_job_t *this)
{
ike_sa_t *ike_sa;
status_t status;
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id);
@@ -64,9 +70,24 @@ static status_t execute(private_rekey_ike_sa_job_t *this)
DBG2(DBG_JOB, "IKE_SA %J to rekey not found", this->ike_sa_id);
return DESTROY_ME;
}
ike_sa->rekey(ike_sa);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
if (this->reauth)
{
status = ike_sa->reauth(ike_sa);
}
else
{
status = ike_sa->rekey(ike_sa);
}
if (status == DESTROY_ME)
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
}
else
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
return DESTROY_ME;
}
@@ -82,7 +103,7 @@ static void destroy(private_rekey_ike_sa_job_t *this)
/*
* Described in header
*/
rekey_ike_sa_job_t *rekey_ike_sa_job_create(ike_sa_id_t *ike_sa_id)
rekey_ike_sa_job_t *rekey_ike_sa_job_create(ike_sa_id_t *ike_sa_id, bool reauth)
{
private_rekey_ike_sa_job_t *this = malloc_thing(private_rekey_ike_sa_job_t);
@@ -93,6 +114,7 @@ rekey_ike_sa_job_t *rekey_ike_sa_job_create(ike_sa_id_t *ike_sa_id)
/* private variables */
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
this->reauth = reauth;
return &(this->public);
}
+2 -1
View File
@@ -50,10 +50,11 @@ struct rekey_ike_sa_job_t {
* @brief Creates a job of type REKEY_IKE_SA.
*
* @param ike_sa_id ID of the IKE_SA to rekey
* @param reauth TRUE to reauthenticate peer, FALSE for rekeying only
* @return rekey_ike_sa_job_t object
*
* @ingroup jobs
*/
rekey_ike_sa_job_t *rekey_ike_sa_job_create(ike_sa_id_t *ike_sa_id);
rekey_ike_sa_job_t *rekey_ike_sa_job_create(ike_sa_id_t *ike_sa_id, bool reauth);
#endif /* REKEY_IKE_SA_JOB_H_ */
+107 -55
View File
@@ -1730,7 +1730,7 @@ static status_t destroy_child_sa(private_ike_sa_t *this, protocol_id_t protocol,
/**
* Implementation of ike_sa_t.set_lifetimes.
*/
static void set_lifetimes(private_ike_sa_t *this,
static void set_lifetimes(private_ike_sa_t *this, bool reauth,
u_int32_t soft_lifetime, u_int32_t hard_lifetime)
{
job_t *job;
@@ -1738,7 +1738,7 @@ static void set_lifetimes(private_ike_sa_t *this,
if (soft_lifetime)
{
this->time.rekey = this->time.established + soft_lifetime;
job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id);
job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth);
charon->event_queue->add_relative(charon->event_queue, job,
soft_lifetime * 1000);
}
@@ -1752,58 +1752,6 @@ static void set_lifetimes(private_ike_sa_t *this,
}
}
/**
* Implementation of ike_sa_t.rekey.
*/
static status_t rekey(private_ike_sa_t *this)
{
rekey_ike_sa_t *rekey_ike_sa;
DBG1(DBG_IKE, "rekeying IKE_SA between %H[%D]..%H[%D]",
this->my_host, this->my_id, this->other_host, this->other_id);
if (this->state != IKE_ESTABLISHED)
{
SIG(IKE_REKEY_START, "rekeying IKE_SA");
SIG(IKE_REKEY_FAILED, "unable to rekey IKE_SA in state %N",
ike_sa_state_names, this->state);
return FAILED;
}
rekey_ike_sa = rekey_ike_sa_create(&this->public);
return queue_transaction(this, (transaction_t*)rekey_ike_sa, FALSE);
}
/**
* Implementation of ike_sa_t.get_rekeying_transaction.
*/
static transaction_t* get_rekeying_transaction(private_ike_sa_t *this)
{
return this->rekeying_transaction;
}
/**
* Implementation of ike_sa_t.set_rekeying_transaction.
*/
static void set_rekeying_transaction(private_ike_sa_t *this, transaction_t *rekey)
{
this->rekeying_transaction = rekey;
}
/**
* Implementation of ike_sa_t.adopt_children.
*/
static void adopt_children(private_ike_sa_t *this, private_ike_sa_t *other)
{
child_sa_t *child_sa;
while (other->child_sas->remove_last(other->child_sas,
(void**)&child_sa) == SUCCESS)
{
this->child_sas->insert_first(this->child_sas, (void*)child_sa);
}
}
/**
* Implementation of public_ike_sa_t.delete.
*/
@@ -1842,6 +1790,109 @@ static status_t delete_(private_ike_sa_t *this)
}
}
/**
* Implementation of ike_sa_t.rekey.
*/
static status_t rekey(private_ike_sa_t *this)
{
rekey_ike_sa_t *rekey_ike_sa;
DBG1(DBG_IKE, "rekeying IKE_SA between %H[%D]..%H[%D]",
this->my_host, this->my_id, this->other_host, this->other_id);
if (this->state != IKE_ESTABLISHED)
{
SIG(IKE_REKEY_START, "rekeying IKE_SA");
SIG(IKE_REKEY_FAILED, "unable to rekey IKE_SA in state %N",
ike_sa_state_names, this->state);
return FAILED;
}
rekey_ike_sa = rekey_ike_sa_create(&this->public);
return queue_transaction(this, (transaction_t*)rekey_ike_sa, FALSE);
}
/**
* Implementation of ike_sa_t.reauth.
*/
static status_t reauth(private_ike_sa_t *this)
{
connection_t *connection;
child_sa_t *child_sa;
iterator_t *iterator;
DBG1(DBG_IKE, "reauthenticating IKE_SA between %H[%D]..%H[%D]",
this->my_host, this->my_id, this->other_host, this->other_id);
/* get a connection to initiate */
connection = charon->connections->get_connection_by_hosts(charon->connections,
this->my_host, this->other_host);
if (connection == NULL)
{
DBG1(DBG_IKE, "no connection found to reauthenticate");
return FAILED;
}
/* queue CREATE_CHILD_SA transactions to set up all CHILD_SAs */
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
job_t *job;
policy_t *policy;
linked_list_t *my_ts, *other_ts;
my_ts = child_sa->get_my_traffic_selectors(child_sa);
other_ts = child_sa->get_other_traffic_selectors(child_sa);
policy = charon->policies->get_policy(charon->policies,
this->my_id, this->other_id, my_ts, other_ts,
this->my_host, this->other_host, NULL);
if (policy == NULL)
{
DBG1(DBG_IKE, "policy not found to recreate CHILD_SA, skipped");
continue;
}
connection->get_ref(connection);
job = (job_t*)initiate_job_create(connection, policy);
charon->job_queue->add(charon->job_queue, job);
}
iterator->destroy(iterator);
connection->destroy(connection);
/* delete the old IKE_SA
* TODO: we should delay the delete to avoid connectivity gaps?! */
return delete_(this);
}
/**
* Implementation of ike_sa_t.get_rekeying_transaction.
*/
static transaction_t* get_rekeying_transaction(private_ike_sa_t *this)
{
return this->rekeying_transaction;
}
/**
* Implementation of ike_sa_t.set_rekeying_transaction.
*/
static void set_rekeying_transaction(private_ike_sa_t *this, transaction_t *rekey)
{
this->rekeying_transaction = rekey;
}
/**
* Implementation of ike_sa_t.adopt_children.
*/
static void adopt_children(private_ike_sa_t *this, private_ike_sa_t *other)
{
child_sa_t *child_sa;
while (other->child_sas->remove_last(other->child_sas,
(void**)&child_sa) == SUCCESS)
{
this->child_sas->insert_first(this->child_sas, (void*)child_sa);
}
}
/**
* Implementation of ike_sa_t.get_next_message_id.
*/
@@ -1987,9 +2038,10 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa;
this->public.enable_natt = (void(*)(ike_sa_t*, bool)) enable_natt;
this->public.is_natt_enabled = (bool(*)(ike_sa_t*)) is_natt_enabled;
this->public.set_lifetimes = (void(*)(ike_sa_t*,u_int32_t,u_int32_t))set_lifetimes;
this->public.set_lifetimes = (void(*)(ike_sa_t*,bool,u_int32_t,u_int32_t))set_lifetimes;
this->public.apply_connection = (void(*)(ike_sa_t*,connection_t*))apply_connection;
this->public.rekey = (status_t(*)(ike_sa_t*))rekey;
this->public.reauth = (status_t(*)(ike_sa_t*))reauth;
this->public.get_rekeying_transaction = (transaction_t*(*)(ike_sa_t*))get_rekeying_transaction;
this->public.set_rekeying_transaction = (void(*)(ike_sa_t*,transaction_t*))set_rekeying_transaction;
this->public.adopt_children = (void(*)(ike_sa_t*,ike_sa_t*))adopt_children;
+13 -1
View File
@@ -545,10 +545,11 @@ struct ike_sa_t {
* hard_lifetime is only reached when rekeying at soft_lifetime fails.
*
* @param this calling object
* @param reauth use full reauthentication instead of rekeying.
* @param soft_lifetime soft_lifetime
* @param hard_lifetime hard_lifetime
*/
void (*set_lifetimes) (ike_sa_t *this,
void (*set_lifetimes) (ike_sa_t *this, bool reauth,
u_int32_t soft_lifetime, u_int32_t hard_lifetime);
/**
@@ -561,6 +562,17 @@ struct ike_sa_t {
*/
status_t (*rekey) (ike_sa_t *this);
/**
* @brief Reauthentication the IKE_SA.
*
* Create a completely new IKE_SA with authentication, recreates all children
* within the IKE_SA and shuts the old SA down.
*
* @param this calling object
* @return - SUCCESS, if IKE_SA rekeying initiated
*/
status_t (*reauth) (ike_sa_t *this);
/**
* @brief Get the transaction which rekeys this IKE_SA.
*
+6
View File
@@ -323,6 +323,12 @@ static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this,
continue;
}
if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING)
{
/* skip IKE_SA which are not useable */
continue;
}
found_my_id = entry->ike_sa->get_my_id(entry->ike_sa);
found_other_id = entry->ike_sa->get_other_id(entry->ike_sa);
found_my_host = entry->ike_sa->get_my_host(entry->ike_sa);
+2 -1
View File
@@ -72,7 +72,8 @@ struct ike_sa_manager_t {
* Allows the lookup of an IKE_SA by user IDs and hosts. It returns the
* first found occurence, if there are multiple candidates. Supplied IDs
* may contain wildcards, hosts may be %any.
* If no IKE_SA is found, a new one is created.
* If no IKE_SA is found, a new one is created. This is also the case when
* the found IKE_SA is in the DELETING state.
*
* @param this the manager object
* @param my_host address of our host
+3 -1
View File
@@ -790,7 +790,8 @@ static status_t get_response(private_ike_sa_init_t *this,
return DESTROY_ME;
}
this->ike_sa->set_lifetimes(this->ike_sa,
this->ike_sa->set_lifetimes(this->ike_sa,
this->connection->get_reauth(this->connection),
this->connection->get_soft_lifetime(this->connection),
this->connection->get_hard_lifetime(this->connection));
@@ -1030,6 +1031,7 @@ static status_t conclude(private_ike_sa_init_t *this, message_t *response,
}
this->ike_sa->set_lifetimes(this->ike_sa,
this->connection->get_reauth(this->connection),
this->connection->get_soft_lifetime(this->connection),
this->connection->get_hard_lifetime(this->connection));
@@ -366,6 +366,7 @@ static status_t switchto_new_sa(private_rekey_ike_sa_t* this, bool initiator)
this->new_sa->apply_connection(this->new_sa, this->connection);
this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
this->new_sa->set_lifetimes(this->new_sa,
this->connection->get_reauth(this->connection),
this->connection->get_soft_lifetime(this->connection),
this->connection->get_hard_lifetime(this->connection));
return SUCCESS;
+1
View File
@@ -347,6 +347,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
msg->add_conn.other.sendcert,
my_host, other_host,
msg->add_conn.dpd.delay,
msg->add_conn.rekey.reauth,
msg->add_conn.rekey.tries,
msg->add_conn.rekey.ike_lifetime,
msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin,
+1
View File
@@ -834,6 +834,7 @@ extern const char *prettypolicy(lset_t policy);
#define POLICY_XAUTH_PSK LELEM(18) /* do we support XAUTH????PreShared? */
#define POLICY_XAUTH_RSASIG LELEM(19) /* do we support XAUTH????RSA? */
#define POLICY_XAUTH_SERVER LELEM(20) /* are we an XAUTH server? */
#define POLICY_REAUTH LELEM(21) /* reauthenticate on rekeying, IKEv2 */
/* Any IPsec policy? If not, a connection description
* is only for ISAKMP SA, not IPSEC SA. (A pun, I admit.)
+1
View File
@@ -190,6 +190,7 @@ static const token_info_t token_info[] =
{ ARG_ULNG, offsetof(starter_conn_t, sa_keying_tries), NULL },
{ ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL },
{ ARG_MISC, 0, NULL /* KW_REKEY */ },
{ ARG_MISC, 0, NULL /* KW_REAUTH */ },
{ ARG_STR, offsetof(starter_conn_t, ike), NULL },
{ ARG_STR, offsetof(starter_conn_t, esp), NULL },
{ ARG_STR, offsetof(starter_conn_t, pfsgroup), LST_pfsgroup },
+5 -1
View File
@@ -67,7 +67,8 @@ static void default_values(starter_config_t *cfg)
cfg->conn_default.seen = LEMPTY;
cfg->conn_default.startup = STARTUP_NO;
cfg->conn_default.state = STATE_IGNORE;
cfg->conn_default.policy = POLICY_ENCRYPT | POLICY_TUNNEL | POLICY_RSASIG | POLICY_PFS;
cfg->conn_default.policy = POLICY_ENCRYPT | POLICY_TUNNEL | POLICY_RSASIG |
POLICY_PFS | POLICY_REAUTH;
cfg->conn_default.ike = clone_str(ike_defaults, "ike_defaults");
cfg->conn_default.esp = clone_str(esp_defaults, "esp_defaults");
@@ -447,6 +448,9 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg)
case KW_REKEY:
KW_POLICY_FLAG("no", "yes", POLICY_DONT_REKEY)
break;
case KW_REAUTH:
KW_POLICY_FLAG("yes", "no", POLICY_REAUTH)
break;
case KW_MODECONFIG:
KW_POLICY_FLAG("push", "pull", POLICY_MODECFG_PUSH)
break;
+10 -1
View File
@@ -733,12 +733,21 @@ and
The two ends need not agree,
but while a value of
.B no
prevents Pluto from requesting renegotiation,
prevents Pluto/Charon from requesting renegotiation,
it does not prevent responding to renegotiation requested from the other end,
so
.B no
will be largely ineffective unless both ends agree on it.
.TP
.B reauth
whether rekeying of an IKE_SA should also reauthenticate the peer. In IKEv1,
reauthentication is always done. In IKEv2, a value of
.B no
rekeys without uninstalling the IPsec SAs, a value of
.B yes
(the default) creates a new IKE_SA from scratch and tries to recreate
all IPsec SAs.
.TP
.B rekeyfuzz
maximum percentage by which
.B rekeymargin
+1
View File
@@ -73,6 +73,7 @@ typedef enum {
KW_KEYINGTRIES,
KW_REKEYFUZZ,
KW_REKEY,
KW_REAUTH,
KW_IKE,
KW_ESP,
KW_PFSGROUP,
+1
View File
@@ -62,6 +62,7 @@ ikelifetime, KW_IKELIFETIME
keyingtries, KW_KEYINGTRIES
rekeyfuzz, KW_REKEYFUZZ
rekey, KW_REKEY
reauth, KW_REAUTH
esp, KW_ESP
ike, KW_IKE
pfsgroup, KW_PFSGROUP
+1
View File
@@ -205,6 +205,7 @@ int starter_stroke_add_conn(starter_conn_t *conn)
}
else
{
msg.add_conn.rekey.reauth = (conn->policy & POLICY_REAUTH);
msg.add_conn.rekey.ipsec_lifetime = conn->sa_ipsec_life_seconds;
msg.add_conn.rekey.ike_lifetime = conn->sa_ike_life_seconds;
msg.add_conn.rekey.margin = conn->sa_rekey_margin;
+1
View File
@@ -107,6 +107,7 @@ static int add_connection(char *name,
msg.add_conn.name = push_string(&msg, name);
msg.add_conn.ikev2 = 1;
msg.add_conn.rekey.reauth = 0;
msg.add_conn.rekey.ipsec_lifetime = 0;
msg.add_conn.rekey.ike_lifetime = 0;
msg.add_conn.rekey.margin = 0;
+1
View File
@@ -142,6 +142,7 @@ struct stroke_msg_t {
char *esp;
} algorithms;
struct {
int reauth;
time_t ipsec_lifetime;
time_t ike_lifetime;
time_t margin;