moved key derivation and management into keymat object
allows secured implementation of key management (e.g. in kernel or HW) only IKE keys for now
This commit is contained in:
@@ -74,6 +74,7 @@ sa/ike_sa.c sa/ike_sa.h \
|
||||
sa/ike_sa_id.c sa/ike_sa_id.h \
|
||||
sa/ike_sa_manager.c sa/ike_sa_manager.h \
|
||||
sa/task_manager.c sa/task_manager.h \
|
||||
sa/keymat.c sa/keymat.h \
|
||||
sa/tasks/child_create.c sa/tasks/child_create.h \
|
||||
sa/tasks/child_delete.c sa/tasks/child_delete.h \
|
||||
sa/tasks/child_rekey.c sa/tasks/child_rekey.h \
|
||||
|
||||
@@ -79,14 +79,18 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
|
||||
|
||||
if (all)
|
||||
{
|
||||
proposal_t *ike_proposal = ike_sa->get_proposal(ike_sa);
|
||||
|
||||
keymat_t *keymat;
|
||||
proposal_t *ike_proposal;
|
||||
|
||||
keymat = ike_sa->get_keymat(ike_sa);
|
||||
ike_proposal = keymat->get_proposal(keymat);
|
||||
|
||||
fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s",
|
||||
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
|
||||
id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "",
|
||||
id->get_responder_spi(id), id->is_initiator(id) ? "" : "*");
|
||||
|
||||
|
||||
|
||||
|
||||
if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
|
||||
{
|
||||
u_int32_t rekey, reauth, now;
|
||||
@@ -112,7 +116,7 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
|
||||
}
|
||||
}
|
||||
fprintf(out, "\n");
|
||||
|
||||
|
||||
if (ike_proposal)
|
||||
{
|
||||
char buf[BUF_LEN];
|
||||
@@ -121,7 +125,7 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
|
||||
fprintf(out, "%12s[%d]: IKE proposal: %s\n",
|
||||
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
|
||||
buf+4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Copyright (C) 2006-2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -70,36 +70,24 @@ struct private_eap_authenticator_t {
|
||||
*/
|
||||
u_int32_t vendor;
|
||||
};
|
||||
|
||||
/**
|
||||
* reuse shared key signature function from PSK authenticator
|
||||
*/
|
||||
extern chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce,
|
||||
chunk_t secret, identification_t *id,
|
||||
chunk_t skp, prf_t *prf);
|
||||
/**
|
||||
* Implementation of authenticator_t.verify.
|
||||
*/
|
||||
static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init,
|
||||
chunk_t my_nonce, auth_payload_t *auth_payload)
|
||||
{
|
||||
chunk_t auth_data, recv_auth_data, secret;
|
||||
identification_t *other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
chunk_t auth_data, recv_auth_data;
|
||||
identification_t *other_id;
|
||||
keymat_t *keymat;
|
||||
|
||||
if (this->msk.len)
|
||||
{ /* use MSK if EAP method established one... */
|
||||
secret = this->msk;
|
||||
}
|
||||
else
|
||||
{ /* ... or use SKp if not */
|
||||
secret = this->ike_sa->get_skp_verify(this->ike_sa);
|
||||
}
|
||||
auth_data = build_shared_key_signature(ike_sa_init, my_nonce, secret,
|
||||
other_id, this->ike_sa->get_skp_verify(this->ike_sa),
|
||||
this->ike_sa->get_prf(this->ike_sa));
|
||||
other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
keymat = this->ike_sa->get_keymat(this->ike_sa);
|
||||
|
||||
auth_data = keymat->get_psk_sig(keymat, TRUE, ike_sa_init, my_nonce,
|
||||
this->msk, other_id);
|
||||
|
||||
recv_auth_data = auth_payload->get_data(auth_payload);
|
||||
if (!chunk_equals(auth_data, recv_auth_data))
|
||||
if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data))
|
||||
{
|
||||
DBG1(DBG_IKE, "verification of AUTH payload created from EAP MSK failed");
|
||||
chunk_free(&auth_data);
|
||||
@@ -118,23 +106,18 @@ static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init,
|
||||
static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init,
|
||||
chunk_t other_nonce, auth_payload_t **auth_payload)
|
||||
{
|
||||
chunk_t auth_data, secret;
|
||||
identification_t *my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
identification_t *my_id;
|
||||
chunk_t auth_data;
|
||||
keymat_t *keymat;
|
||||
|
||||
my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
keymat = this->ike_sa->get_keymat(this->ike_sa);
|
||||
|
||||
DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
|
||||
my_id, auth_class_names, AUTH_CLASS_EAP);
|
||||
|
||||
if (this->msk.len)
|
||||
{ /* use MSK if EAP method established one... */
|
||||
secret = this->msk;
|
||||
}
|
||||
else
|
||||
{ /* ... or use SKp if not */
|
||||
secret = this->ike_sa->get_skp_build(this->ike_sa);
|
||||
}
|
||||
auth_data = build_shared_key_signature(ike_sa_init, other_nonce, secret,
|
||||
my_id, this->ike_sa->get_skp_build(this->ike_sa),
|
||||
this->ike_sa->get_prf(this->ike_sa));
|
||||
|
||||
auth_data = keymat->get_psk_sig(keymat, FALSE, ike_sa_init, other_nonce,
|
||||
this->msk, my_id);
|
||||
|
||||
*auth_payload = auth_payload_create();
|
||||
(*auth_payload)->set_auth_method(*auth_payload, AUTH_PSK);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -23,12 +23,6 @@
|
||||
#include <daemon.h>
|
||||
#include <credentials/auth_info.h>
|
||||
|
||||
/**
|
||||
* Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
|
||||
*/
|
||||
#define IKEV2_KEY_PAD "Key Pad for IKEv2"
|
||||
#define IKEV2_KEY_PAD_LENGTH 17
|
||||
|
||||
|
||||
typedef struct private_psk_authenticator_t private_psk_authenticator_t;
|
||||
|
||||
@@ -48,55 +42,6 @@ struct private_psk_authenticator_t {
|
||||
ike_sa_t *ike_sa;
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds the octets to be signed as described in section 2.15 of RFC 4306
|
||||
*/
|
||||
chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce,
|
||||
identification_t *id, prf_t *prf)
|
||||
{
|
||||
u_int8_t id_header_buf[] = {0x00, 0x00, 0x00, 0x00};
|
||||
chunk_t id_header = chunk_from_buf(id_header_buf);
|
||||
chunk_t id_with_header, id_prfd, id_encoding;
|
||||
|
||||
id_header_buf[0] = id->get_type(id);
|
||||
id_encoding = id->get_encoding(id);
|
||||
|
||||
id_with_header = chunk_cat("cc", id_header, id_encoding);
|
||||
prf->allocate_bytes(prf, id_with_header, &id_prfd);
|
||||
chunk_free(&id_with_header);
|
||||
|
||||
return chunk_cat("ccm", ike_sa_init, nonce, id_prfd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the AUTH data using auth method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
|
||||
*/
|
||||
chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce,
|
||||
chunk_t secret, identification_t *id,
|
||||
chunk_t skp, prf_t *prf)
|
||||
{
|
||||
chunk_t key_pad, key, auth_data, octets;
|
||||
|
||||
prf->set_key(prf, skp);
|
||||
octets = build_tbs_octets(ike_sa_init, nonce, id, prf);
|
||||
/* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */
|
||||
key_pad.ptr = IKEV2_KEY_PAD;
|
||||
key_pad.len = IKEV2_KEY_PAD_LENGTH;
|
||||
prf->set_key(prf, secret);
|
||||
prf->allocate_bytes(prf, key_pad, &key);
|
||||
prf->set_key(prf, key);
|
||||
prf->allocate_bytes(prf, octets, &auth_data);
|
||||
DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", &octets);
|
||||
DBG3(DBG_IKE, "secret %B", &secret);
|
||||
DBG3(DBG_IKE, "keypad %B", &key_pad);
|
||||
DBG3(DBG_IKE, "prf(secret, keypad) %B", &key);
|
||||
DBG3(DBG_IKE, "AUTH = prf(prf(secret, keypad), octets) %B", &auth_data);
|
||||
chunk_free(&octets);
|
||||
chunk_free(&key);
|
||||
|
||||
return auth_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t.verify.
|
||||
*/
|
||||
@@ -105,25 +50,25 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init,
|
||||
{
|
||||
chunk_t auth_data, recv_auth_data;
|
||||
identification_t *my_id, *other_id;
|
||||
shared_key_t *shared_key;
|
||||
shared_key_t *key;
|
||||
enumerator_t *enumerator;
|
||||
bool authenticated = FALSE;
|
||||
int keys_found = 0;
|
||||
keymat_t *keymat;
|
||||
|
||||
keymat = this->ike_sa->get_keymat(this->ike_sa);
|
||||
recv_auth_data = auth_payload->get_data(auth_payload);
|
||||
my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
enumerator = charon->credentials->create_shared_enumerator(
|
||||
charon->credentials, SHARED_IKE, my_id, other_id);
|
||||
while (!authenticated && enumerator->enumerate(enumerator, &shared_key, NULL, NULL))
|
||||
while (!authenticated && enumerator->enumerate(enumerator, &key, NULL, NULL))
|
||||
{
|
||||
keys_found++;
|
||||
auth_data = build_shared_key_signature(ike_sa_init, my_nonce,
|
||||
shared_key->get_key(shared_key), other_id,
|
||||
this->ike_sa->get_skp_verify(this->ike_sa),
|
||||
this->ike_sa->get_prf(this->ike_sa));
|
||||
recv_auth_data = auth_payload->get_data(auth_payload);
|
||||
if (auth_data.len == recv_auth_data.len &&
|
||||
memeq(auth_data.ptr, recv_auth_data.ptr, auth_data.len))
|
||||
|
||||
auth_data = keymat->get_psk_sig(keymat, TRUE, ike_sa_init, my_nonce,
|
||||
key->get_key(key), other_id);
|
||||
if (auth_data.len && chunk_equals(auth_data, recv_auth_data))
|
||||
{
|
||||
DBG1(DBG_IKE, "authentication of '%D' with %N successful",
|
||||
other_id, auth_method_names, AUTH_PSK);
|
||||
@@ -153,26 +98,26 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init,
|
||||
static status_t build(private_psk_authenticator_t *this, chunk_t ike_sa_init,
|
||||
chunk_t other_nonce, auth_payload_t **auth_payload)
|
||||
{
|
||||
shared_key_t *shared_key;
|
||||
chunk_t auth_data;
|
||||
identification_t *my_id, *other_id;
|
||||
shared_key_t *key;
|
||||
chunk_t auth_data;
|
||||
keymat_t *keymat;
|
||||
|
||||
keymat = this->ike_sa->get_keymat(this->ike_sa);
|
||||
my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
|
||||
my_id, auth_method_names, AUTH_PSK);
|
||||
shared_key = charon->credentials->get_shared(charon->credentials, SHARED_IKE,
|
||||
my_id, other_id);
|
||||
if (shared_key == NULL)
|
||||
key = charon->credentials->get_shared(charon->credentials, SHARED_IKE,
|
||||
my_id, other_id);
|
||||
if (key == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id);
|
||||
return NOT_FOUND;
|
||||
}
|
||||
auth_data = build_shared_key_signature(ike_sa_init, other_nonce,
|
||||
shared_key->get_key(shared_key), my_id,
|
||||
this->ike_sa->get_skp_build(this->ike_sa),
|
||||
this->ike_sa->get_prf(this->ike_sa));
|
||||
shared_key->destroy(shared_key);
|
||||
auth_data = keymat->get_psk_sig(keymat, FALSE, ike_sa_init, other_nonce,
|
||||
key->get_key(key), my_id);
|
||||
key->destroy(key);
|
||||
DBG2(DBG_IKE, "successfully created shared key MAC");
|
||||
*auth_payload = auth_payload_create();
|
||||
(*auth_payload)->set_auth_method(*auth_payload, AUTH_PSK);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Tobias Brunner
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -43,12 +43,6 @@ struct private_pubkey_authenticator_t {
|
||||
ike_sa_t *ike_sa;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function implemented in psk_authenticator.c
|
||||
*/
|
||||
extern chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce,
|
||||
identification_t *id, prf_t *prf);
|
||||
|
||||
/**
|
||||
* Implementation of authenticator_t.verify.
|
||||
*/
|
||||
@@ -58,15 +52,15 @@ static status_t verify(private_pubkey_authenticator_t *this, chunk_t ike_sa_init
|
||||
public_key_t *public;
|
||||
auth_method_t auth_method;
|
||||
chunk_t auth_data, octets;
|
||||
identification_t *other_id;
|
||||
prf_t *prf;
|
||||
identification_t *id;
|
||||
auth_info_t *auth, *current_auth;
|
||||
enumerator_t *enumerator;
|
||||
key_type_t key_type = KEY_ECDSA;
|
||||
signature_scheme_t scheme;
|
||||
status_t status = FAILED;
|
||||
keymat_t *keymat;
|
||||
|
||||
other_id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
id = this->ike_sa->get_other_id(this->ike_sa);
|
||||
auth_method = auth_payload->get_auth_method(auth_payload);
|
||||
switch (auth_method)
|
||||
{
|
||||
@@ -89,19 +83,17 @@ static status_t verify(private_pubkey_authenticator_t *this, chunk_t ike_sa_init
|
||||
return INVALID_ARG;
|
||||
}
|
||||
auth_data = auth_payload->get_data(auth_payload);
|
||||
prf = this->ike_sa->get_prf(this->ike_sa);
|
||||
prf->set_key(prf, this->ike_sa->get_skp_verify(this->ike_sa));
|
||||
octets = build_tbs_octets(ike_sa_init, my_nonce, other_id, prf);
|
||||
|
||||
keymat = this->ike_sa->get_keymat(this->ike_sa);
|
||||
octets = keymat->get_auth_octets(keymat, TRUE, ike_sa_init, my_nonce, id);
|
||||
auth = this->ike_sa->get_other_auth(this->ike_sa);
|
||||
enumerator = charon->credentials->create_public_enumerator(
|
||||
charon->credentials, key_type, other_id, auth);
|
||||
charon->credentials, key_type, id, auth);
|
||||
while (enumerator->enumerate(enumerator, &public, ¤t_auth))
|
||||
{
|
||||
if (public->verify(public, scheme, octets, auth_data))
|
||||
{
|
||||
DBG1(DBG_IKE, "authentication of '%D' with %N successful",
|
||||
other_id, auth_method_names, auth_method);
|
||||
id, auth_method_names, auth_method);
|
||||
status = SUCCESS;
|
||||
auth->merge(auth, current_auth);
|
||||
break;
|
||||
@@ -125,19 +117,19 @@ static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
|
||||
chunk_t octets, auth_data;
|
||||
status_t status = FAILED;
|
||||
private_key_t *private;
|
||||
identification_t *my_id;
|
||||
prf_t *prf;
|
||||
identification_t *id;
|
||||
auth_info_t *auth;
|
||||
auth_method_t auth_method;
|
||||
signature_scheme_t scheme;
|
||||
keymat_t *keymat;
|
||||
|
||||
my_id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
id = this->ike_sa->get_my_id(this->ike_sa);
|
||||
auth = this->ike_sa->get_my_auth(this->ike_sa);
|
||||
private = charon->credentials->get_private(charon->credentials, KEY_ANY,
|
||||
my_id, auth);
|
||||
id, auth);
|
||||
if (private == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "no private key found for '%D'", my_id);
|
||||
DBG1(DBG_IKE, "no private key found for '%D'", id);
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -176,9 +168,8 @@ static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
|
||||
key_type_names, private->get_type(private));
|
||||
return status;
|
||||
}
|
||||
prf = this->ike_sa->get_prf(this->ike_sa);
|
||||
prf->set_key(prf, this->ike_sa->get_skp_build(this->ike_sa));
|
||||
octets = build_tbs_octets(ike_sa_init, other_nonce, my_id, prf);
|
||||
keymat = this->ike_sa->get_keymat(this->ike_sa);
|
||||
octets = keymat->get_auth_octets(keymat, FALSE, ike_sa_init, other_nonce, id);
|
||||
|
||||
if (private->sign(private, scheme, octets, &auth_data))
|
||||
{
|
||||
@@ -189,9 +180,9 @@ static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
|
||||
chunk_free(&auth_data);
|
||||
status = SUCCESS;
|
||||
}
|
||||
DBG1(DBG_IKE, "authentication of '%D' (myself) with %N %s", my_id,
|
||||
auth_method_names, auth_method,
|
||||
(status == SUCCESS)? "successful":"failed");
|
||||
DBG1(DBG_IKE, "authentication of '%D' (myself) with %N %s", id,
|
||||
auth_method_names, auth_method,
|
||||
(status == SUCCESS)? "successful":"failed");
|
||||
chunk_free(&octets);
|
||||
private->destroy(private);
|
||||
|
||||
|
||||
+20
-320
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2008 Tobias Brunner
|
||||
* Copyright (C) 2006 Daniel Roethlisberger
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -191,49 +191,9 @@ struct private_ike_sa_t {
|
||||
linked_list_t *child_sas;
|
||||
|
||||
/**
|
||||
* Selected IKE proposal
|
||||
* keymat of this IKE_SA
|
||||
*/
|
||||
proposal_t *selected_proposal;
|
||||
|
||||
/**
|
||||
* crypter for inbound traffic
|
||||
*/
|
||||
crypter_t *crypter_in;
|
||||
|
||||
/**
|
||||
* crypter for outbound traffic
|
||||
*/
|
||||
crypter_t *crypter_out;
|
||||
|
||||
/**
|
||||
* Signer for inbound traffic
|
||||
*/
|
||||
signer_t *signer_in;
|
||||
|
||||
/**
|
||||
* Signer for outbound traffic
|
||||
*/
|
||||
signer_t *signer_out;
|
||||
|
||||
/**
|
||||
* Multi purpose prf, set key, use it, forget it
|
||||
*/
|
||||
prf_t *prf;
|
||||
|
||||
/**
|
||||
* Prf function for derivating keymat child SAs
|
||||
*/
|
||||
prf_t *child_prf;
|
||||
|
||||
/**
|
||||
* Key to build outging authentication data (SKp)
|
||||
*/
|
||||
chunk_t skp_build;
|
||||
|
||||
/**
|
||||
* Key to verify incoming authentication data (SKp)
|
||||
*/
|
||||
chunk_t skp_verify;
|
||||
keymat_t *keymat;
|
||||
|
||||
/**
|
||||
* Virtual IP on local host, if any
|
||||
@@ -742,6 +702,14 @@ static void reset(private_ike_sa_t *this)
|
||||
this->task_manager->reset(this->task_manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.get_keymat
|
||||
*/
|
||||
static keymat_t* get_keymat(private_ike_sa_t *this)
|
||||
{
|
||||
return this->keymat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.set_virtual_ip
|
||||
*/
|
||||
@@ -912,7 +880,9 @@ static status_t generate_message(private_ike_sa_t *this, message_t *message,
|
||||
{
|
||||
this->stats[STAT_OUTBOUND] = time(NULL);
|
||||
message->set_ike_sa_id(message, this->ike_sa_id);
|
||||
return message->generate(message, this->crypter_out, this->signer_out, packet);
|
||||
return message->generate(message,
|
||||
this->keymat->get_crypter(this->keymat, FALSE),
|
||||
this->keymat->get_signer(this->keymat, FALSE), packet);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1335,7 +1305,9 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
|
||||
|
||||
is_request = message->get_request(message);
|
||||
|
||||
status = message->parse_body(message, this->crypter_in, this->signer_in);
|
||||
status = message->parse_body(message,
|
||||
this->keymat->get_crypter(this->keymat, TRUE),
|
||||
this->keymat->get_signer(this->keymat, TRUE));
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
|
||||
@@ -1472,38 +1444,6 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.get_prf.
|
||||
*/
|
||||
static prf_t *get_prf(private_ike_sa_t *this)
|
||||
{
|
||||
return this->prf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.get_prf.
|
||||
*/
|
||||
static prf_t *get_child_prf(private_ike_sa_t *this)
|
||||
{
|
||||
return this->child_prf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.get_skp_bild
|
||||
*/
|
||||
static chunk_t get_skp_build(private_ike_sa_t *this)
|
||||
{
|
||||
return this->skp_build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.get_skp_verify
|
||||
*/
|
||||
static chunk_t get_skp_verify(private_ike_sa_t *this)
|
||||
{
|
||||
return this->skp_verify;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.get_id.
|
||||
*/
|
||||
@@ -1563,224 +1503,6 @@ static void set_eap_identity(private_ike_sa_t *this, identification_t *id)
|
||||
this->eap_identity = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.derive_keys.
|
||||
*/
|
||||
static status_t derive_keys(private_ike_sa_t *this,
|
||||
proposal_t *proposal, chunk_t secret,
|
||||
chunk_t nonce_i, chunk_t nonce_r,
|
||||
bool initiator, prf_t *child_prf, prf_t *old_prf)
|
||||
{
|
||||
prf_plus_t *prf_plus;
|
||||
chunk_t skeyseed, key, full_nonce, fixed_nonce, prf_plus_seed;
|
||||
u_int16_t alg, key_size;
|
||||
crypter_t *crypter_i, *crypter_r;
|
||||
signer_t *signer_i, *signer_r;
|
||||
u_int8_t spi_i_buf[sizeof(u_int64_t)], spi_r_buf[sizeof(u_int64_t)];
|
||||
chunk_t spi_i = chunk_from_buf(spi_i_buf);
|
||||
chunk_t spi_r = chunk_from_buf(spi_r_buf);
|
||||
|
||||
/* Create SAs general purpose PRF first, we may use it here */
|
||||
if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
|
||||
{
|
||||
DBG1(DBG_IKE, "no %N selected",
|
||||
transform_type_names, PSEUDO_RANDOM_FUNCTION);
|
||||
return FAILED;
|
||||
}
|
||||
this->prf = lib->crypto->create_prf(lib->crypto, alg);
|
||||
if (this->prf == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "%N %N not supported!",
|
||||
transform_type_names, PSEUDO_RANDOM_FUNCTION,
|
||||
pseudo_random_function_names, alg);
|
||||
return FAILED;
|
||||
}
|
||||
DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret);
|
||||
/* full nonce is used as seed for PRF+ ... */
|
||||
full_nonce = chunk_cat("cc", nonce_i, nonce_r);
|
||||
/* but the PRF may need a fixed key which only uses the first bytes of
|
||||
* the nonces. */
|
||||
switch (alg)
|
||||
{
|
||||
case PRF_AES128_XCBC:
|
||||
/* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does
|
||||
* not and therefore fixed key semantics apply to XCBC for key
|
||||
* derivation. */
|
||||
nonce_i.len = min(nonce_i.len, this->prf->get_key_size(this->prf)/2);
|
||||
nonce_r.len = min(nonce_r.len, this->prf->get_key_size(this->prf)/2);
|
||||
break;
|
||||
default:
|
||||
/* all other algorithms use variable key length, full nonce */
|
||||
break;
|
||||
}
|
||||
fixed_nonce = chunk_cat("cc", nonce_i, nonce_r);
|
||||
*((u_int64_t*)spi_i.ptr) = this->ike_sa_id->get_initiator_spi(this->ike_sa_id);
|
||||
*((u_int64_t*)spi_r.ptr) = this->ike_sa_id->get_responder_spi(this->ike_sa_id);
|
||||
prf_plus_seed = chunk_cat("ccc", full_nonce, spi_i, spi_r);
|
||||
|
||||
/* KEYMAT = prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr)
|
||||
*
|
||||
* if we are rekeying, SKEYSEED is built on another way
|
||||
*/
|
||||
if (child_prf == NULL) /* not rekeying */
|
||||
{
|
||||
/* SKEYSEED = prf(Ni | Nr, g^ir) */
|
||||
this->prf->set_key(this->prf, fixed_nonce);
|
||||
this->prf->allocate_bytes(this->prf, secret, &skeyseed);
|
||||
DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
|
||||
this->prf->set_key(this->prf, skeyseed);
|
||||
chunk_clear(&skeyseed);
|
||||
chunk_clear(&secret);
|
||||
prf_plus = prf_plus_create(this->prf, prf_plus_seed);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* SKEYSEED = prf(SK_d (old), [g^ir (new)] | Ni | Nr)
|
||||
* use OLD SAs PRF functions for both prf_plus and prf */
|
||||
secret = chunk_cat("mc", secret, full_nonce);
|
||||
child_prf->allocate_bytes(child_prf, secret, &skeyseed);
|
||||
DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
|
||||
old_prf->set_key(old_prf, skeyseed);
|
||||
chunk_clear(&skeyseed);
|
||||
chunk_clear(&secret);
|
||||
prf_plus = prf_plus_create(old_prf, prf_plus_seed);
|
||||
}
|
||||
chunk_free(&full_nonce);
|
||||
chunk_free(&fixed_nonce);
|
||||
chunk_clear(&prf_plus_seed);
|
||||
|
||||
/* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */
|
||||
|
||||
/* SK_d is used for generating CHILD_SA key mat => child_prf */
|
||||
proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL);
|
||||
this->child_prf = lib->crypto->create_prf(lib->crypto, alg);
|
||||
key_size = this->child_prf->get_key_size(this->child_prf);
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_d secret %B", &key);
|
||||
this->child_prf->set_key(this->child_prf, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
/* SK_ai/SK_ar used for integrity protection => signer_in/signer_out */
|
||||
if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
|
||||
{
|
||||
DBG1(DBG_IKE, "no %N selected",
|
||||
transform_type_names, INTEGRITY_ALGORITHM);
|
||||
return FAILED;
|
||||
}
|
||||
signer_i = lib->crypto->create_signer(lib->crypto, alg);
|
||||
signer_r = lib->crypto->create_signer(lib->crypto, alg);
|
||||
if (signer_i == NULL || signer_r == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "%N %N not supported!",
|
||||
transform_type_names, INTEGRITY_ALGORITHM,
|
||||
integrity_algorithm_names ,alg);
|
||||
prf_plus->destroy(prf_plus);
|
||||
return FAILED;
|
||||
}
|
||||
key_size = signer_i->get_key_size(signer_i);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_ai secret %B", &key);
|
||||
signer_i->set_key(signer_i, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_ar secret %B", &key);
|
||||
signer_r->set_key(signer_r, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->signer_in = signer_r;
|
||||
this->signer_out = signer_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->signer_in = signer_i;
|
||||
this->signer_out = signer_r;
|
||||
}
|
||||
|
||||
/* SK_ei/SK_er used for encryption => crypter_in/crypter_out */
|
||||
if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size))
|
||||
{
|
||||
DBG1(DBG_IKE, "no %N selected",
|
||||
transform_type_names, ENCRYPTION_ALGORITHM);
|
||||
prf_plus->destroy(prf_plus);
|
||||
return FAILED;
|
||||
}
|
||||
crypter_i = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
|
||||
crypter_r = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
|
||||
if (crypter_i == NULL || crypter_r == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
|
||||
transform_type_names, ENCRYPTION_ALGORITHM,
|
||||
encryption_algorithm_names, alg, key_size);
|
||||
prf_plus->destroy(prf_plus);
|
||||
return FAILED;
|
||||
}
|
||||
key_size = crypter_i->get_key_size(crypter_i);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_ei secret %B", &key);
|
||||
crypter_i->set_key(crypter_i, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_er secret %B", &key);
|
||||
crypter_r->set_key(crypter_r, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
this->crypter_in = crypter_r;
|
||||
this->crypter_out = crypter_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->crypter_in = crypter_i;
|
||||
this->crypter_out = crypter_r;
|
||||
}
|
||||
|
||||
/* SK_pi/SK_pr used for authentication => stored for later */
|
||||
key_size = this->prf->get_key_size(this->prf);
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_pi secret %B", &key);
|
||||
if (initiator)
|
||||
{
|
||||
this->skp_build = key;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->skp_verify = key;
|
||||
}
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_pr secret %B", &key);
|
||||
if (initiator)
|
||||
{
|
||||
this->skp_verify = key;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->skp_build = key;
|
||||
}
|
||||
|
||||
/* all done, prf_plus not needed anymore */
|
||||
prf_plus->destroy(prf_plus);
|
||||
|
||||
/* save selected proposal */
|
||||
this->selected_proposal = proposal->clone(proposal);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.get_proposal.
|
||||
*/
|
||||
static proposal_t* get_proposal(private_ike_sa_t *this)
|
||||
{
|
||||
return this->selected_proposal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of ike_sa_t.add_child_sa.
|
||||
*/
|
||||
@@ -2452,16 +2174,7 @@ static void destroy(private_ike_sa_t *this)
|
||||
charon->bus->set_sa(charon->bus, NULL);
|
||||
|
||||
this->task_manager->destroy(this->task_manager);
|
||||
|
||||
DESTROY_IF(this->crypter_in);
|
||||
DESTROY_IF(this->crypter_out);
|
||||
DESTROY_IF(this->signer_in);
|
||||
DESTROY_IF(this->signer_out);
|
||||
DESTROY_IF(this->prf);
|
||||
DESTROY_IF(this->child_prf);
|
||||
chunk_free(&this->skp_verify);
|
||||
chunk_free(&this->skp_build);
|
||||
DESTROY_IF(this->selected_proposal);
|
||||
this->keymat->destroy(this->keymat);
|
||||
|
||||
if (this->my_virtual_ip)
|
||||
{
|
||||
@@ -2561,12 +2274,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
|
||||
this->public.destroy = (void (*)(ike_sa_t*))destroy;
|
||||
this->public.send_dpd = (status_t (*)(ike_sa_t*)) send_dpd;
|
||||
this->public.send_keepalive = (void (*)(ike_sa_t*)) send_keepalive;
|
||||
this->public.get_prf = (prf_t* (*)(ike_sa_t*)) get_prf;
|
||||
this->public.get_child_prf = (prf_t* (*)(ike_sa_t *)) get_child_prf;
|
||||
this->public.get_skp_verify = (chunk_t (*)(ike_sa_t *)) get_skp_verify;
|
||||
this->public.get_skp_build = (chunk_t (*)(ike_sa_t *)) get_skp_build;
|
||||
this->public.derive_keys = (status_t (*)(ike_sa_t *,proposal_t*,chunk_t,chunk_t,chunk_t,bool,prf_t*,prf_t*)) derive_keys;
|
||||
this->public.get_proposal = (proposal_t* (*)(ike_sa_t*)) get_proposal;
|
||||
this->public.get_keymat = (keymat_t*(*)(ike_sa_t*))get_keymat;
|
||||
this->public.add_child_sa = (void (*)(ike_sa_t*,child_sa_t*)) add_child_sa;
|
||||
this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,protocol_id_t,u_int32_t,bool)) get_child_sa;
|
||||
this->public.create_child_sa_iterator = (iterator_t* (*)(ike_sa_t*)) create_child_sa_iterator;
|
||||
@@ -2607,15 +2315,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
|
||||
this->eap_identity = NULL;
|
||||
this->extensions = 0;
|
||||
this->conditions = 0;
|
||||
this->selected_proposal = NULL;
|
||||
this->crypter_in = NULL;
|
||||
this->crypter_out = NULL;
|
||||
this->signer_in = NULL;
|
||||
this->signer_out = NULL;
|
||||
this->prf = NULL;
|
||||
this->skp_verify = chunk_empty;
|
||||
this->skp_build = chunk_empty;
|
||||
this->child_prf = NULL;
|
||||
this->keymat = keymat_create(ike_sa_id->is_initiator(ike_sa_id));
|
||||
this->state = IKE_CREATED;
|
||||
this->keepalive_interval = lib->settings->get_time(lib->settings,
|
||||
"charon.keep_alive", KEEPALIVE_INTERVAL);
|
||||
|
||||
+6
-57
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2008 Tobias Brunner
|
||||
* Copyright (C) 2006 Daniel Roethlisberger
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -38,9 +38,7 @@ typedef struct ike_sa_t ike_sa_t;
|
||||
#include <sa/ike_sa_id.h>
|
||||
#include <sa/child_sa.h>
|
||||
#include <sa/tasks/task.h>
|
||||
#include <crypto/prfs/prf.h>
|
||||
#include <crypto/crypters/crypter.h>
|
||||
#include <crypto/signers/signer.h>
|
||||
#include <sa/keymat.h>
|
||||
#include <config/peer_cfg.h>
|
||||
#include <config/ike_cfg.h>
|
||||
#include <credentials/auth_info.h>
|
||||
@@ -714,62 +712,13 @@ struct ike_sa_t {
|
||||
* was sent.
|
||||
*/
|
||||
void (*send_keepalive) (ike_sa_t *this);
|
||||
|
||||
|
||||
/**
|
||||
* Derive all keys and create the transforms for IKE communication.
|
||||
* Get the keying material of this IKE_SA.
|
||||
*
|
||||
* Keys are derived using the diffie hellman secret, nonces and internal
|
||||
* stored SPIs.
|
||||
* Key derivation differs when an IKE_SA is set up to replace an
|
||||
* existing IKE_SA (rekeying). The SK_d key from the old IKE_SA
|
||||
* is included in the derivation process.
|
||||
*
|
||||
* @param proposal proposal which contains algorithms to use
|
||||
* @param secret secret derived from DH exchange, gets freed
|
||||
* @param nonce_i initiators nonce
|
||||
* @param nonce_r responders nonce
|
||||
* @param initiator TRUE if initiator, FALSE otherwise
|
||||
* @param child_prf PRF with SK_d key when rekeying, NULL otherwise
|
||||
* @param old_prf general purpose PRF of old SA when rekeying
|
||||
* @return per IKE_SA keymat instance
|
||||
*/
|
||||
status_t (*derive_keys)(ike_sa_t *this, proposal_t* proposal, chunk_t secret,
|
||||
chunk_t nonce_i, chunk_t nonce_r,
|
||||
bool initiator, prf_t *child_prf, prf_t *old_prf);
|
||||
|
||||
/**
|
||||
* Get the selected IKE proposal
|
||||
*
|
||||
* @return selected IKE proposal
|
||||
*/
|
||||
proposal_t* (*get_proposal)(ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* Get a multi purpose prf for the negotiated PRF function.
|
||||
*
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
prf_t *(*get_prf) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* Get the prf-object, which is used to derive keys for child SAs.
|
||||
*
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
prf_t *(*get_child_prf) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* Get the key to build outgoing authentication data.
|
||||
*
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
chunk_t (*get_skp_build) (ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* Get the key to verify incoming authentication data.
|
||||
*
|
||||
* @return pointer to prf_t object
|
||||
*/
|
||||
chunk_t (*get_skp_verify) (ike_sa_t *this);
|
||||
keymat_t* (*get_keymat)(ike_sa_t *this);
|
||||
|
||||
/**
|
||||
* Associates a child SA to this IKE SA
|
||||
|
||||
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "keymat.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <crypto/prf_plus.h>
|
||||
|
||||
typedef struct private_keymat_t private_keymat_t;
|
||||
|
||||
/**
|
||||
* Private data of an keymat_t object.
|
||||
*/
|
||||
struct private_keymat_t {
|
||||
|
||||
/**
|
||||
* Public keymat_t interface.
|
||||
*/
|
||||
keymat_t public;
|
||||
|
||||
/**
|
||||
* IKE_SA Role, initiator or responder
|
||||
*/
|
||||
bool initiator;
|
||||
|
||||
/**
|
||||
* diffie hellman key exchange
|
||||
*/
|
||||
diffie_hellman_t *dh;
|
||||
|
||||
/**
|
||||
* inbound signer (verify)
|
||||
*/
|
||||
signer_t *signer_in;
|
||||
|
||||
/**
|
||||
* outbound signer (sign)
|
||||
*/
|
||||
signer_t *signer_out;
|
||||
|
||||
/**
|
||||
* inbound crypter (decrypt)
|
||||
*/
|
||||
crypter_t *crypter_in;
|
||||
|
||||
/**
|
||||
* outbound crypter (encrypt)
|
||||
*/
|
||||
crypter_t *crypter_out;
|
||||
|
||||
/**
|
||||
* General purpose PRF
|
||||
*/
|
||||
prf_t *prf;
|
||||
|
||||
/**
|
||||
* PRF for CHILD_SA keymat
|
||||
*/
|
||||
prf_t *child_prf;
|
||||
|
||||
/**
|
||||
* Key to build outging authentication data (SKp)
|
||||
*/
|
||||
chunk_t skp_build;
|
||||
|
||||
/**
|
||||
* Key to verify incoming authentication data (SKp)
|
||||
*/
|
||||
chunk_t skp_verify;
|
||||
|
||||
/**
|
||||
* Negotiated IKE proposal
|
||||
*/
|
||||
proposal_t *proposal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of keymat_t.set_dh_group
|
||||
*/
|
||||
static bool set_dh_group(private_keymat_t *this, diffie_hellman_group_t group)
|
||||
{
|
||||
DESTROY_IF(this->dh);
|
||||
this->dh = lib->crypto->create_dh(lib->crypto, group);
|
||||
return this->dh != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of keymat_t.get_dh
|
||||
*/
|
||||
static diffie_hellman_t* get_dh(private_keymat_t *this)
|
||||
{
|
||||
return this->dh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of keymat_t.derive_keys
|
||||
*/
|
||||
static bool derive_keys(private_keymat_t *this, proposal_t *proposal,
|
||||
chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id,
|
||||
private_keymat_t *rekey)
|
||||
{
|
||||
chunk_t skeyseed, key, secret, full_nonce, fixed_nonce, prf_plus_seed;
|
||||
chunk_t spi_i, spi_r;
|
||||
crypter_t *crypter_i, *crypter_r;
|
||||
signer_t *signer_i, *signer_r;
|
||||
prf_plus_t *prf_plus;
|
||||
u_int16_t alg, key_size;
|
||||
|
||||
spi_i = chunk_alloca(sizeof(u_int64_t));
|
||||
spi_r = chunk_alloca(sizeof(u_int64_t));
|
||||
|
||||
if (!this->dh || this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Create SAs general purpose PRF first, we may use it here */
|
||||
if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
|
||||
{
|
||||
DBG1(DBG_IKE, "no %N selected",
|
||||
transform_type_names, PSEUDO_RANDOM_FUNCTION);
|
||||
return FALSE;
|
||||
}
|
||||
this->prf = lib->crypto->create_prf(lib->crypto, alg);
|
||||
if (this->prf == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "%N %N not supported!",
|
||||
transform_type_names, PSEUDO_RANDOM_FUNCTION,
|
||||
pseudo_random_function_names, alg);
|
||||
return FALSE;
|
||||
}
|
||||
DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret);
|
||||
/* full nonce is used as seed for PRF+ ... */
|
||||
full_nonce = chunk_cat("cc", nonce_i, nonce_r);
|
||||
/* but the PRF may need a fixed key which only uses the first bytes of
|
||||
* the nonces. */
|
||||
switch (alg)
|
||||
{
|
||||
case PRF_AES128_XCBC:
|
||||
/* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does
|
||||
* not and therefore fixed key semantics apply to XCBC for key
|
||||
* derivation. */
|
||||
nonce_i.len = min(nonce_i.len, this->prf->get_key_size(this->prf)/2);
|
||||
nonce_r.len = min(nonce_r.len, this->prf->get_key_size(this->prf)/2);
|
||||
break;
|
||||
default:
|
||||
/* all other algorithms use variable key length, full nonce */
|
||||
break;
|
||||
}
|
||||
fixed_nonce = chunk_cat("cc", nonce_i, nonce_r);
|
||||
*((u_int64_t*)spi_i.ptr) = id->get_initiator_spi(id);
|
||||
*((u_int64_t*)spi_r.ptr) = id->get_responder_spi(id);
|
||||
prf_plus_seed = chunk_cat("ccc", full_nonce, spi_i, spi_r);
|
||||
|
||||
/* KEYMAT = prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr)
|
||||
*
|
||||
* if we are rekeying, SKEYSEED is built on another way
|
||||
*/
|
||||
if (rekey == NULL) /* not rekeying */
|
||||
{
|
||||
/* SKEYSEED = prf(Ni | Nr, g^ir) */
|
||||
this->prf->set_key(this->prf, fixed_nonce);
|
||||
this->prf->allocate_bytes(this->prf, secret, &skeyseed);
|
||||
DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
|
||||
this->prf->set_key(this->prf, skeyseed);
|
||||
chunk_clear(&skeyseed);
|
||||
chunk_clear(&secret);
|
||||
prf_plus = prf_plus_create(this->prf, prf_plus_seed);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* SKEYSEED = prf(SK_d (old), [g^ir (new)] | Ni | Nr)
|
||||
* use OLD SAs PRF functions for both prf_plus and prf */
|
||||
secret = chunk_cat("mc", secret, full_nonce);
|
||||
rekey->child_prf->allocate_bytes(rekey->child_prf, secret, &skeyseed);
|
||||
DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
|
||||
rekey->prf->set_key(rekey->prf, skeyseed);
|
||||
chunk_clear(&skeyseed);
|
||||
chunk_clear(&secret);
|
||||
prf_plus = prf_plus_create(rekey->prf, prf_plus_seed);
|
||||
}
|
||||
chunk_free(&full_nonce);
|
||||
chunk_free(&fixed_nonce);
|
||||
chunk_clear(&prf_plus_seed);
|
||||
|
||||
/* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */
|
||||
|
||||
/* SK_d is used for generating CHILD_SA key mat => child_prf */
|
||||
proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL);
|
||||
this->child_prf = lib->crypto->create_prf(lib->crypto, alg);
|
||||
key_size = this->child_prf->get_key_size(this->child_prf);
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_d secret %B", &key);
|
||||
this->child_prf->set_key(this->child_prf, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
/* SK_ai/SK_ar used for integrity protection => signer_in/signer_out */
|
||||
if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
|
||||
{
|
||||
DBG1(DBG_IKE, "no %N selected",
|
||||
transform_type_names, INTEGRITY_ALGORITHM);
|
||||
return FALSE;
|
||||
}
|
||||
signer_i = lib->crypto->create_signer(lib->crypto, alg);
|
||||
signer_r = lib->crypto->create_signer(lib->crypto, alg);
|
||||
if (signer_i == NULL || signer_r == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "%N %N not supported!",
|
||||
transform_type_names, INTEGRITY_ALGORITHM,
|
||||
integrity_algorithm_names ,alg);
|
||||
prf_plus->destroy(prf_plus);
|
||||
return FALSE;
|
||||
}
|
||||
key_size = signer_i->get_key_size(signer_i);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_ai secret %B", &key);
|
||||
signer_i->set_key(signer_i, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_ar secret %B", &key);
|
||||
signer_r->set_key(signer_r, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
this->signer_in = signer_r;
|
||||
this->signer_out = signer_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->signer_in = signer_i;
|
||||
this->signer_out = signer_r;
|
||||
}
|
||||
|
||||
/* SK_ei/SK_er used for encryption => crypter_in/crypter_out */
|
||||
if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size))
|
||||
{
|
||||
DBG1(DBG_IKE, "no %N selected",
|
||||
transform_type_names, ENCRYPTION_ALGORITHM);
|
||||
prf_plus->destroy(prf_plus);
|
||||
return FALSE;
|
||||
}
|
||||
crypter_i = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
|
||||
crypter_r = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
|
||||
if (crypter_i == NULL || crypter_r == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
|
||||
transform_type_names, ENCRYPTION_ALGORITHM,
|
||||
encryption_algorithm_names, alg, key_size);
|
||||
prf_plus->destroy(prf_plus);
|
||||
return FALSE;
|
||||
}
|
||||
key_size = crypter_i->get_key_size(crypter_i);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_ei secret %B", &key);
|
||||
crypter_i->set_key(crypter_i, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_er secret %B", &key);
|
||||
crypter_r->set_key(crypter_r, key);
|
||||
chunk_clear(&key);
|
||||
|
||||
if (this->initiator)
|
||||
{
|
||||
this->crypter_in = crypter_r;
|
||||
this->crypter_out = crypter_i;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->crypter_in = crypter_i;
|
||||
this->crypter_out = crypter_r;
|
||||
}
|
||||
|
||||
/* SK_pi/SK_pr used for authentication => stored for later */
|
||||
key_size = this->prf->get_key_size(this->prf);
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_pi secret %B", &key);
|
||||
if (this->initiator)
|
||||
{
|
||||
this->skp_build = key;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->skp_verify = key;
|
||||
}
|
||||
prf_plus->allocate_bytes(prf_plus, key_size, &key);
|
||||
DBG4(DBG_IKE, "Sk_pr secret %B", &key);
|
||||
if (this->initiator)
|
||||
{
|
||||
this->skp_verify = key;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->skp_build = key;
|
||||
}
|
||||
|
||||
/* all done, prf_plus not needed anymore */
|
||||
prf_plus->destroy(prf_plus);
|
||||
|
||||
/* save selected proposal */
|
||||
this->proposal = proposal->clone(proposal);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of keymat_t.get_proposal
|
||||
*/
|
||||
static proposal_t* get_proposal(private_keymat_t *this)
|
||||
{
|
||||
return this->proposal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of keymat_t.get_signer
|
||||
*/
|
||||
static signer_t* get_signer(private_keymat_t *this, bool in)
|
||||
{
|
||||
return in ? this->signer_in : this->signer_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of keymat_t.get_crypter
|
||||
*/
|
||||
static crypter_t* get_crypter(private_keymat_t *this, bool in)
|
||||
{
|
||||
return in ? this->crypter_in : this->crypter_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of keymat_t.get_child_prf
|
||||
*/
|
||||
static prf_t* get_child_prf(private_keymat_t *this)
|
||||
{
|
||||
return this->child_prf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of keymat_t.get_auth_octets
|
||||
*/
|
||||
static chunk_t get_auth_octets(private_keymat_t *this, bool verify,
|
||||
chunk_t ike_sa_init, chunk_t nonce,
|
||||
identification_t *id)
|
||||
{
|
||||
chunk_t chunk, idx, octets;
|
||||
chunk_t skp;
|
||||
|
||||
skp = verify ? this->skp_verify : this->skp_build;
|
||||
|
||||
chunk = chunk_alloca(4);
|
||||
memset(chunk.ptr, 0, chunk.len);
|
||||
chunk.ptr[0] = id->get_type(id);
|
||||
idx = chunk_cata("cc", chunk, id->get_encoding(id));
|
||||
|
||||
DBG3(DBG_IKE, "IDx' %B", &idx);
|
||||
DBG3(DBG_IKE, "SK_p %B", &skp);
|
||||
this->prf->set_key(this->prf, skp);
|
||||
this->prf->allocate_bytes(this->prf, idx, &chunk);
|
||||
|
||||
octets = chunk_cat("ccm", ike_sa_init, nonce, chunk);
|
||||
DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", &octets);
|
||||
return octets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
|
||||
*/
|
||||
#define IKEV2_KEY_PAD "Key Pad for IKEv2"
|
||||
#define IKEV2_KEY_PAD_LENGTH 17
|
||||
|
||||
/**
|
||||
* Implementation of keymat_t.get_psk_sig
|
||||
*/
|
||||
static chunk_t get_psk_sig(private_keymat_t *this, bool verify,
|
||||
chunk_t ike_sa_init, chunk_t nonce, chunk_t secret,
|
||||
identification_t *id)
|
||||
{
|
||||
chunk_t key_pad, key, sig, octets;
|
||||
|
||||
if (!secret.len)
|
||||
{ /* EAP uses SK_p if no MSK has been established */
|
||||
secret = verify ? this->skp_verify : this->skp_build;
|
||||
}
|
||||
octets = get_auth_octets(this, verify, ike_sa_init, nonce, id);
|
||||
/* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */
|
||||
key_pad = chunk_create(IKEV2_KEY_PAD, IKEV2_KEY_PAD_LENGTH);
|
||||
this->prf->set_key(this->prf, secret);
|
||||
this->prf->allocate_bytes(this->prf, key_pad, &key);
|
||||
this->prf->set_key(this->prf, key);
|
||||
this->prf->allocate_bytes(this->prf, octets, &sig);
|
||||
DBG4(DBG_IKE, "secret %B", &secret);
|
||||
DBG4(DBG_IKE, "prf(secret, keypad) %B", &key);
|
||||
DBG3(DBG_IKE, "AUTH = prf(prf(secret, keypad), octets) %B", &sig);
|
||||
chunk_free(&octets);
|
||||
chunk_free(&key);
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of keymat_t.destroy.
|
||||
*/
|
||||
static void destroy(private_keymat_t *this)
|
||||
{
|
||||
DESTROY_IF(this->dh);
|
||||
DESTROY_IF(this->signer_in);
|
||||
DESTROY_IF(this->signer_out);
|
||||
DESTROY_IF(this->crypter_in);
|
||||
DESTROY_IF(this->crypter_out);
|
||||
DESTROY_IF(this->prf);
|
||||
DESTROY_IF(this->child_prf);
|
||||
DESTROY_IF(this->proposal);
|
||||
chunk_clear(&this->skp_verify);
|
||||
chunk_clear(&this->skp_build);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
keymat_t *keymat_create(bool initiator)
|
||||
{
|
||||
private_keymat_t *this = malloc_thing(private_keymat_t);
|
||||
|
||||
this->public.set_dh_group = (bool(*)(keymat_t*, diffie_hellman_group_t group))set_dh_group;
|
||||
this->public.get_dh = (diffie_hellman_t*(*)(keymat_t*))get_dh;
|
||||
this->public.derive_keys = (bool(*)(keymat_t*, proposal_t *proposal, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, keymat_t *rekey))derive_keys;
|
||||
this->public.get_proposal = (proposal_t*(*)(keymat_t*))get_proposal;
|
||||
this->public.get_signer = (signer_t*(*)(keymat_t*, bool in))get_signer;
|
||||
this->public.get_crypter = (crypter_t*(*)(keymat_t*, bool in))get_crypter;
|
||||
this->public.get_child_prf = (prf_t*(*)(keymat_t*))get_child_prf;
|
||||
this->public.get_auth_octets = (chunk_t(*)(keymat_t *, bool verify, chunk_t ike_sa_init, chunk_t nonce, identification_t *id))get_auth_octets;
|
||||
this->public.get_psk_sig = (chunk_t(*)(keymat_t*, bool verify, chunk_t ike_sa_init, chunk_t nonce, chunk_t secret, identification_t *id))get_psk_sig;
|
||||
this->public.destroy = (void(*)(keymat_t*))destroy;
|
||||
|
||||
this->initiator = initiator;
|
||||
|
||||
this->dh = NULL;
|
||||
this->signer_in = NULL;
|
||||
this->signer_out = NULL;
|
||||
this->crypter_in = NULL;
|
||||
this->crypter_out = NULL;
|
||||
this->prf = NULL;
|
||||
this->child_prf = NULL;
|
||||
this->proposal = NULL;
|
||||
this->skp_verify = chunk_empty;
|
||||
this->skp_build = chunk_empty;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup keymat keymat
|
||||
* @{ @ingroup sa
|
||||
*/
|
||||
|
||||
#ifndef KEYMAT_H_
|
||||
#define KEYMAT_H_
|
||||
|
||||
#include <library.h>
|
||||
#include <utils/identification.h>
|
||||
#include <crypto/prfs/prf.h>
|
||||
#include <crypto/crypters/crypter.h>
|
||||
#include <crypto/signers/signer.h>
|
||||
#include <config/proposal.h>
|
||||
#include <sa/ike_sa_id.h>
|
||||
|
||||
typedef struct keymat_t keymat_t;
|
||||
|
||||
/**
|
||||
* Derivation an management of sensitive keying material.
|
||||
*/
|
||||
struct keymat_t {
|
||||
|
||||
/**
|
||||
* Set the diffie hellman group to use.
|
||||
*
|
||||
* @param group diffie hellman group to use
|
||||
* @return TRUE if group supported
|
||||
*/
|
||||
bool (*set_dh_group)(keymat_t *this, diffie_hellman_group_t group);
|
||||
|
||||
/**
|
||||
* Get the diffie hellman key agreement interface.
|
||||
*
|
||||
* Call set_dh_group() before acquiring this interface.
|
||||
*
|
||||
* @return key agreement interface
|
||||
*/
|
||||
diffie_hellman_t* (*get_dh)(keymat_t *this);
|
||||
|
||||
/**
|
||||
* Derive keys from the shared secret.
|
||||
*
|
||||
* @param proposal selected algorithms
|
||||
* @param nonce_i initiators nonce value
|
||||
* @param nonce_r responders nonce value
|
||||
* @param id IKE_SA identifier
|
||||
* @param rekey keymat of old SA if we are rekeying
|
||||
* @return TRUE on success
|
||||
*/
|
||||
bool (*derive_keys)(keymat_t *this, proposal_t *proposal, chunk_t nonce_i,
|
||||
chunk_t nonce_r, ike_sa_id_t *id, keymat_t *rekey);
|
||||
/**
|
||||
* Get a signer to sign/verify IKE messages.
|
||||
*
|
||||
* @param in TRUE for inbound (verify), FALSE for outbound (sign)
|
||||
* @return signer
|
||||
*/
|
||||
signer_t* (*get_signer)(keymat_t *this, bool in);
|
||||
|
||||
/*
|
||||
* Get a crypter to en-/decrypt IKE messages.
|
||||
*
|
||||
* @param in TRUE for inbound (decrypt), FALSE for outbound (encrypt)
|
||||
* @return crypter
|
||||
*/
|
||||
crypter_t* (*get_crypter)(keymat_t *this, bool in);
|
||||
|
||||
/**
|
||||
* Get a keyed PRF to derive keymat for children.
|
||||
*
|
||||
* @return PRF to derive CHILD_SA keymat from
|
||||
*/
|
||||
prf_t* (*get_child_prf)(keymat_t *this);
|
||||
|
||||
/**
|
||||
* Get the selected proposal passed to derive_keys().
|
||||
*
|
||||
* @return selected proposal
|
||||
*/
|
||||
proposal_t* (*get_proposal)(keymat_t *this);
|
||||
|
||||
/**
|
||||
* Generate octets to use for authentication procedure (RFC4306 2.15).
|
||||
*
|
||||
* This method creates the plain octets and is usually signed by a private
|
||||
* key. PSK and EAP authentication include a secret into the data, use
|
||||
* the get_psk_sig() method instead.
|
||||
*
|
||||
* @param verify TRUE to create for verfification, FALSE to sign
|
||||
* @param ike_sa_init encoded ike_sa_init message
|
||||
* @param nonce nonce value
|
||||
* @param id identity
|
||||
* @return authentication octets
|
||||
*/
|
||||
chunk_t (*get_auth_octets)(keymat_t *this, bool verify, chunk_t ike_sa_init,
|
||||
chunk_t nonce, identification_t *id);
|
||||
/**
|
||||
* Build the shared secret signature used for PSK and EAP authentication.
|
||||
*
|
||||
* This method wraps the get_auth_octets() method and additionally
|
||||
* includes the secret into the signature. If no secret is given, SK_p is
|
||||
* used as secret (used for EAP methods without MSK).
|
||||
*
|
||||
* @param verify TRUE to create for verfification, FALSE to sign
|
||||
* @param ike_sa_init encoded ike_sa_init message
|
||||
* @param nonce nonce value
|
||||
* @param secret optional secret to include into signature
|
||||
* @param id identity
|
||||
* @return signature octets
|
||||
*/
|
||||
chunk_t (*get_psk_sig)(keymat_t *this, bool verify, chunk_t ike_sa_init,
|
||||
chunk_t nonce, chunk_t secret, identification_t *id);
|
||||
/**
|
||||
* Destroy a keymat_t.
|
||||
*/
|
||||
void (*destroy)(keymat_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a keymat instance.
|
||||
*
|
||||
* @param initiator TRUE if we are the initiator
|
||||
* @return keymat instance
|
||||
*/
|
||||
keymat_t *keymat_create(bool initiator);
|
||||
|
||||
#endif /* KEYMAT_ @}*/
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Tobias Brunner
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -196,6 +196,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
|
||||
chunk_t nonce_i, nonce_r, secret, seed;
|
||||
linked_list_t *my_ts, *other_ts;
|
||||
host_t *me, *other, *other_vip, *my_vip;
|
||||
keymat_t *keymat;
|
||||
|
||||
if (this->proposals == NULL)
|
||||
{
|
||||
@@ -351,7 +352,8 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
|
||||
keymat = this->ike_sa->get_keymat(this->ike_sa);
|
||||
prf_plus = prf_plus_create(keymat->get_child_prf(keymat), seed);
|
||||
if (this->initiator)
|
||||
{
|
||||
status = this->child_sa->update(this->child_sa, this->proposal,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Tobias Brunner
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -64,10 +64,15 @@ struct private_ike_init_t {
|
||||
diffie_hellman_group_t dh_group;
|
||||
|
||||
/**
|
||||
* Diffie hellman object used to generate public DH value.
|
||||
* diffie hellman key exchange
|
||||
*/
|
||||
diffie_hellman_t *dh;
|
||||
|
||||
/**
|
||||
* Keymat derivation (from IKE_SA)
|
||||
*/
|
||||
keymat_t *keymat;
|
||||
|
||||
/**
|
||||
* nonce chosen by us
|
||||
*/
|
||||
@@ -192,7 +197,10 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
|
||||
this->dh_group = ke_payload->get_dh_group_number(ke_payload);
|
||||
if (!this->initiator)
|
||||
{
|
||||
this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
|
||||
if (this->keymat->set_dh_group(this->keymat, this->dh_group))
|
||||
{
|
||||
this->dh = this->keymat->get_dh(this->keymat);
|
||||
}
|
||||
}
|
||||
if (this->dh)
|
||||
{
|
||||
@@ -241,18 +249,18 @@ static status_t build_i(private_ike_init_t *this, message_t *message)
|
||||
DBG1(DBG_IKE, "giving up after %d retries", MAX_RETRIES);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
|
||||
/* if the DH group is set via use_dh_group(), we already have a DH object */
|
||||
if (!this->dh)
|
||||
{
|
||||
this->dh_group = this->config->get_dh_group(this->config);
|
||||
this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
|
||||
if (this->dh == NULL)
|
||||
if (!this->keymat->set_dh_group(this->keymat, this->dh_group))
|
||||
{
|
||||
DBG1(DBG_IKE, "configured DH group %N not supported",
|
||||
diffie_hellman_group_names, this->dh_group);
|
||||
return FAILED;
|
||||
}
|
||||
this->dh = this->keymat->get_dh(this->keymat);
|
||||
}
|
||||
|
||||
/* generate nonce only when we are trying the first time */
|
||||
@@ -368,9 +376,9 @@ static status_t process_r(private_ike_init_t *this, message_t *message)
|
||||
*/
|
||||
static status_t build_r(private_ike_init_t *this, message_t *message)
|
||||
{
|
||||
chunk_t secret;
|
||||
status_t status;
|
||||
|
||||
keymat_t *old_keymat = NULL;
|
||||
ike_sa_id_t *id;
|
||||
|
||||
/* check if we have everything we need */
|
||||
if (this->proposal == NULL ||
|
||||
this->other_nonce.len == 0 || this->my_nonce.len == 0)
|
||||
@@ -381,8 +389,7 @@ static status_t build_r(private_ike_init_t *this, message_t *message)
|
||||
}
|
||||
|
||||
if (this->dh == NULL ||
|
||||
!this->proposal->has_dh_group(this->proposal, this->dh_group) ||
|
||||
this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
|
||||
!this->proposal->has_dh_group(this->proposal, this->dh_group))
|
||||
{
|
||||
u_int16_t group;
|
||||
|
||||
@@ -404,30 +411,14 @@ static status_t build_r(private_ike_init_t *this, message_t *message)
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
id = this->ike_sa->get_id(this->ike_sa);
|
||||
if (this->old_sa)
|
||||
{
|
||||
ike_sa_id_t *id;
|
||||
prf_t *prf, *child_prf;
|
||||
|
||||
/* Apply SPI if we are rekeying */
|
||||
id = this->ike_sa->get_id(this->ike_sa);
|
||||
{ /* rekeying: Apply SPI, include keymat from old SA in key derivation */
|
||||
id->set_initiator_spi(id, this->proposal->get_spi(this->proposal));
|
||||
|
||||
/* setup crypto keys for the rekeyed SA */
|
||||
prf = this->old_sa->get_prf(this->old_sa);
|
||||
child_prf = this->old_sa->get_child_prf(this->old_sa);
|
||||
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
|
||||
this->other_nonce, this->my_nonce,
|
||||
FALSE, child_prf, prf);
|
||||
old_keymat = this->old_sa->get_keymat(this->old_sa);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* setup crypto keys */
|
||||
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
|
||||
this->other_nonce, this->my_nonce,
|
||||
FALSE, NULL, NULL);
|
||||
}
|
||||
if (status != SUCCESS)
|
||||
if (!this->keymat->derive_keys(this->keymat, this->proposal, this->other_nonce,
|
||||
this->my_nonce, id, old_keymat))
|
||||
{
|
||||
DBG1(DBG_IKE, "key derivation failed");
|
||||
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
|
||||
@@ -443,8 +434,8 @@ static status_t build_r(private_ike_init_t *this, message_t *message)
|
||||
*/
|
||||
static status_t process_i(private_ike_init_t *this, message_t *message)
|
||||
{
|
||||
chunk_t secret;
|
||||
status_t status;
|
||||
keymat_t *old_keymat = NULL;
|
||||
ike_sa_id_t *id;
|
||||
iterator_t *iterator;
|
||||
payload_t *payload;
|
||||
|
||||
@@ -521,42 +512,25 @@ static status_t process_i(private_ike_init_t *this, message_t *message)
|
||||
}
|
||||
|
||||
if (this->dh == NULL ||
|
||||
!this->proposal->has_dh_group(this->proposal, this->dh_group) ||
|
||||
this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
|
||||
!this->proposal->has_dh_group(this->proposal, this->dh_group))
|
||||
{
|
||||
DBG1(DBG_IKE, "peer DH group selection invalid");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* Apply SPI if we are rekeying */
|
||||
id = this->ike_sa->get_id(this->ike_sa);
|
||||
if (this->old_sa)
|
||||
{
|
||||
ike_sa_id_t *id;
|
||||
prf_t *prf, *child_prf;
|
||||
|
||||
id = this->ike_sa->get_id(this->ike_sa);
|
||||
{ /* rekeying: Apply SPI, include keymat from old SA in key derivation */
|
||||
id->set_responder_spi(id, this->proposal->get_spi(this->proposal));
|
||||
|
||||
/* setup crypto keys for the rekeyed SA */
|
||||
prf = this->old_sa->get_prf(this->old_sa);
|
||||
child_prf = this->old_sa->get_child_prf(this->old_sa);
|
||||
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
|
||||
this->my_nonce, this->other_nonce,
|
||||
TRUE, child_prf, prf);
|
||||
old_keymat = this->old_sa->get_keymat(this->old_sa);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* setup crypto keys for a new SA */
|
||||
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
|
||||
this->my_nonce, this->other_nonce,
|
||||
TRUE, NULL, NULL);
|
||||
}
|
||||
if (status != SUCCESS)
|
||||
if (!this->keymat->derive_keys(this->keymat, this->proposal, this->my_nonce,
|
||||
this->other_nonce, id, old_keymat))
|
||||
{
|
||||
DBG1(DBG_IKE, "key derivation failed");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -590,12 +564,12 @@ static chunk_t get_lower_nonce(private_ike_init_t *this)
|
||||
static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
|
||||
{
|
||||
DESTROY_IF(this->proposal);
|
||||
DESTROY_IF(this->dh);
|
||||
chunk_free(&this->other_nonce);
|
||||
|
||||
this->ike_sa = ike_sa;
|
||||
this->proposal = NULL;
|
||||
this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
|
||||
this->keymat->set_dh_group(this->keymat, this->dh_group);
|
||||
this->dh = this->keymat->get_dh(this->keymat);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -604,7 +578,6 @@ static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
|
||||
static void destroy(private_ike_init_t *this)
|
||||
{
|
||||
DESTROY_IF(this->proposal);
|
||||
DESTROY_IF(this->dh);
|
||||
chunk_free(&this->my_nonce);
|
||||
chunk_free(&this->other_nonce);
|
||||
chunk_free(&this->cookie);
|
||||
@@ -637,6 +610,7 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
|
||||
this->initiator = initiator;
|
||||
this->dh_group = MODP_NONE;
|
||||
this->dh = NULL;
|
||||
this->keymat = ike_sa->get_keymat(ike_sa);
|
||||
this->my_nonce = chunk_empty;
|
||||
this->other_nonce = chunk_empty;
|
||||
this->cookie = chunk_empty;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2007 Martin Willi
|
||||
* Copyright (C) 2006-2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Martin Willi
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user