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:
Martin Willi
2008-10-28 16:07:06 +00:00
parent 3c8234d408
commit 6a4ff35cc4
13 changed files with 749 additions and 586 deletions
+1
View File
@@ -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 \
+10 -6
View File
@@ -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, &current_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
View File
@@ -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
View File
@@ -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
+469
View File
@@ -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;
}
+145
View File
@@ -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_ @}*/
+4 -2
View File
@@ -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,
+35 -61
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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
*