Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HA: add support for PPK #2071

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/libcharon/bus/bus.c
Expand Up @@ -637,6 +637,33 @@ METHOD(bus_t, ike_derived_keys, void,
this->mutex->unlock(this->mutex);
}

METHOD(bus_t, ike_ppk, void,
private_bus_t *this, ike_sa_t *ike_sa, identification_t *ppk_id)
{
enumerator_t *enumerator;
entry_t *entry;
bool keep;

this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->calling || !entry->listener->ike_ppk)
{
continue;
}
entry->calling++;
keep = entry->listener->ike_ppk(entry->listener, ike_sa, ppk_id);
entry->calling--;
if (!keep)
{
unregister_listener(this, entry, enumerator);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}

METHOD(bus_t, child_keys, void,
private_bus_t *this, child_sa_t *child_sa, bool initiator,
key_exchange_t *dh, chunk_t nonce_i, chunk_t nonce_r)
Expand Down Expand Up @@ -1144,6 +1171,7 @@ bus_t *bus_create()
.message = _message,
.ike_keys = _ike_keys,
.ike_derived_keys = _ike_derived_keys,
.ike_ppk = _ike_ppk,
.child_keys = _child_keys,
.child_derived_keys = _child_derived_keys,
.ike_updown = _ike_updown,
Expand Down
8 changes: 8 additions & 0 deletions src/libcharon/bus/bus.h
Expand Up @@ -376,6 +376,14 @@ struct bus_t {
chunk_t sk_ar, chunk_t sk_ei, chunk_t sk_er,
chunk_t sk_pi, chunk_t sk_pr);

/**
* IKE_SA apply PPK hook
*
* @param ike_sa IKE_SA the PPK was applied to
* @param ppk_id the id of the applied PPK
*/
void (*ike_ppk)(bus_t *this, ike_sa_t *ike_sa, identification_t *ppk_id);

/**
* CHILD_SA keymat hook.
*
Expand Down
10 changes: 10 additions & 0 deletions src/libcharon/bus/listeners/listener.h
Expand Up @@ -113,6 +113,16 @@ struct listener_t {
chunk_t sk_ai, chunk_t sk_ar, chunk_t sk_ei,
chunk_t sk_er, chunk_t sk_pi, chunk_t sk_pr);

/**
* Hook called with applied PPK id.
*
* @param ike_sa IKE_SA the PPK was applied to
* @param ppk_id the id of the applied PPK
*/

bool (*ike_ppk)(listener_t *this, ike_sa_t *ike_sa,
identification_t *ppk_id);

/**
* Hook called with CHILD_SA key material.
*
Expand Down
17 changes: 17 additions & 0 deletions src/libcharon/plugins/ha/ha_cache.c
Expand Up @@ -72,6 +72,8 @@ typedef struct {
u_int segment;
/* ADD message */
ha_message_t *add;
/* PPK message */
ha_message_t *ppk;
/* list of updates UPDATE message */
linked_list_t *updates;
/* last initiator mid */
Expand Down Expand Up @@ -104,6 +106,7 @@ static void entry_destroy(entry_t *entry)
entry->updates->destroy_offset(entry->updates,
offsetof(ha_message_t, destroy));
entry->add->destroy(entry->add);
DESTROY_IF(entry->ppk);
DESTROY_IF(entry->midi);
DESTROY_IF(entry->midr);
DESTROY_IF(entry->iv);
Expand All @@ -126,6 +129,16 @@ METHOD(ha_cache_t, cache, void,
entry_destroy(entry);
}
break;
case HA_IKE_PPK:
entry = this->cache->get(this->cache, ike_sa);
if (entry)
{
DESTROY_IF(entry->ppk);
entry->ppk = message;
break;
}
message->destroy(message);
break;
case HA_IKE_UPDATE:
entry = this->cache->get(this->cache, ike_sa);
if (entry)
Expand Down Expand Up @@ -319,6 +332,10 @@ METHOD(ha_cache_t, resync, void,
if (entry->segment == segment)
{
this->socket->push(this->socket, entry->add);
if (entry->ppk)
{
this->socket->push(this->socket, entry->ppk);
}
updates = entry->updates->create_enumerator(entry->updates);
while (updates->enumerate(updates, &message))
{
Expand Down
79 changes: 79 additions & 0 deletions src/libcharon/plugins/ha/ha_dispatcher.c
Expand Up @@ -297,6 +297,82 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
DESTROY_IF(message);
}

/**
* Process messages of type IKE_PPK
*/
static void process_ike_ppk(private_ha_dispatcher_t *this, ha_message_t *message)
{
ha_message_attribute_t attribute;
ha_message_value_t value;
enumerator_t *enumerator;
ike_sa_t *ike_sa = NULL;
identification_t *ppk_id = NULL;
keymat_v2_t *keymat;
shared_key_t *key;
chunk_t ppk;

enumerator = message->create_attribute_enumerator(message);
while (enumerator->enumerate(enumerator, &attribute, &value))
{
if (attribute != HA_IKE_ID && ike_sa == NULL)
{
/* must be first attribute */
break;
}
switch (attribute)
{
case HA_IKE_ID:
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
value.ike_sa_id);
break;
case HA_PPK_ID:
ppk_id = value.id->clone(value.id);
default:
break;
}
}
enumerator->destroy(enumerator);

if (ike_sa)
{
key = lib->credmgr->get_shared(lib->credmgr, SHARED_PPK, ppk_id, NULL);
if (!key)
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
ike_sa);
DBG1(DBG_CFG, "HA is missing PPK for '%Y' while passive", ppk_id);
}
else
{
ppk = chunk_clone(key->get_key(key));
key->destroy(key);
keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
if (!keymat->derive_ike_keys_ppk(keymat, ppk))
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
ike_sa);
DBG1(DBG_IKE, "HA keymat PPK derivation failed");
chunk_clear(&ppk);
}
else
{
chunk_clear(&ppk);
ike_sa->set_condition(ike_sa, COND_PPK, TRUE);
this->cache->cache(this->cache, ike_sa, message);
message = NULL;
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
}
}
else
{
DBG1(DBG_CFG, "passive HA IKE_SA to update not found");
}

DESTROY_IF(ppk_id);
message->destroy(message);
}

/**
* Apply all set conditions to the IKE_SA
*/
Expand Down Expand Up @@ -1034,6 +1110,9 @@ static job_requeue_t dispatch(private_ha_dispatcher_t *this)
case HA_IKE_ADD:
process_ike_add(this, message);
break;
case HA_IKE_PPK:
process_ike_ppk(this, message);
break;
case HA_IKE_UPDATE:
process_ike_update(this, message);
break;
Expand Down
25 changes: 25 additions & 0 deletions src/libcharon/plugins/ha/ha_ike.c
Expand Up @@ -165,6 +165,30 @@ METHOD(listener_t, ike_keys, bool,
return TRUE;
}

METHOD(listener_t, ike_ppk, bool,
private_ha_ike_t *this, ike_sa_t *ike_sa, identification_t *ppk_id)
{
ha_message_t *m;

if (ike_sa->get_state(ike_sa) == IKE_PASSIVE)
{ /* only sync active IKE_SAs */
return TRUE;
}
if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
{ /* do not sync SA between nodes */
return TRUE;
}

m = ha_message_create(HA_IKE_PPK);
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
m->add_attribute(m, HA_PPK_ID, ppk_id);

this->socket->push(this->socket, m);
this->cache->cache(this->cache, ike_sa, m);

return TRUE;
}

METHOD(listener_t, ike_updown, bool,
private_ha_ike_t *this, ike_sa_t *ike_sa, bool up)
{
Expand Down Expand Up @@ -402,6 +426,7 @@ ha_ike_t *ha_ike_create(ha_socket_t *socket, ha_tunnel_t *tunnel,
.listener = {
.alert = _alert,
.ike_keys = _ike_keys,
.ike_ppk = _ike_ppk,
.ike_updown = _ike_updown,
.ike_rekey = _ike_rekey,
.ike_state_change = _ike_state_change,
Expand Down
5 changes: 4 additions & 1 deletion src/libcharon/plugins/ha/ha_message.c
Expand Up @@ -47,7 +47,7 @@ struct private_ha_message_t {
chunk_t buf;
};

ENUM(ha_message_type_names, HA_IKE_ADD, HA_IKE_IV,
ENUM(ha_message_type_names, HA_IKE_ADD, HA_IKE_PPK,
"IKE_ADD",
"IKE_UPDATE",
"IKE_MID_INITIATOR",
Expand All @@ -60,6 +60,7 @@ ENUM(ha_message_type_names, HA_IKE_ADD, HA_IKE_IV,
"STATUS",
"RESYNC",
"IKE_IV",
"IKE_PPK",
);

typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t;
Expand Down Expand Up @@ -168,6 +169,7 @@ METHOD(ha_message_t, add_attribute, void,
case HA_LOCAL_ID:
case HA_REMOTE_ID:
case HA_REMOTE_EAP_ID:
case HA_PPK_ID:
{
identification_encoding_t *enc;
identification_t *id;
Expand Down Expand Up @@ -377,6 +379,7 @@ METHOD(enumerator_t, attribute_enumerate, bool,
case HA_LOCAL_ID:
case HA_REMOTE_ID:
case HA_REMOTE_EAP_ID:
case HA_PPK_ID:
{
identification_encoding_t *enc;

Expand Down
4 changes: 4 additions & 0 deletions src/libcharon/plugins/ha/ha_message.h
Expand Up @@ -66,6 +66,8 @@ enum ha_message_type_t {
HA_RESYNC,
/** IV synchronization for IKEv1 Main/Aggressive mode */
HA_IKE_IV,
/** update an existing IKE_SA with PPK */
HA_IKE_PPK,
};

/**
Expand Down Expand Up @@ -159,6 +161,8 @@ enum ha_message_attribute_t {
HA_IV,
/** uint16_t, auth_method_t for IKEv1 key derivation */
HA_AUTH_METHOD,
/** identification_t*, PPK id */
HA_PPK_ID,
};

/**
Expand Down
1 change: 1 addition & 0 deletions src/libcharon/sa/ikev2/tasks/ike_auth.c
Expand Up @@ -964,6 +964,7 @@ static bool apply_ppk(private_ike_auth_t *this)
}
DBG1(DBG_CFG, "using PPK for PPK_ID '%Y'", this->ppk_id);
this->ike_sa->set_condition(this->ike_sa, COND_PPK, TRUE);
charon->bus->ike_ppk(charon->bus, this->ike_sa, this->ppk_id);
}
clear_ppk(this);
return TRUE;
Expand Down