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 \
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;
}
}
fprintf(out, "\n");
-
+
if (ike_proposal)
{
char buf[BUF_LEN];
fprintf(out, "%12s[%d]: IKE proposal: %s\n",
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
buf+4);
- }
+ }
}
}
/*
- * 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
*/
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);
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);
/*
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
#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;
};
/**
- * 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.
*/
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);
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);
/*
* 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
*
};
/**
- * 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.
*/
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)
{
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;
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;
}
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))
{
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);
/*
* 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
*
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
}
/**
+ * 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
*/
static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip)
{
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);
}
/**
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)
{
}
/**
- * 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.
*/
static ike_sa_id_t* get_id(private_ike_sa_t *this)
}
/**
- * 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.
*/
static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa)
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)
{
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;
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);
/*
* 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
*
#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>
* was sent.
*/
void (*send_keepalive) (ike_sa_t *this);
-
- /**
- * Derive all keys and create the transforms for IKE communication.
- *
- * 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
- */
- 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
+ * Get the keying material of this IKE_SA.
*
- * @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
+ * @return per IKE_SA keymat instance
*/
- 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
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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_ @}*/
/*
* 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
*
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)
{
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,
/*
* 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
*
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
*/
chunk_t my_nonce;
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)
{
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 */
*/
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)
}
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;
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);
*/
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;
}
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);
- }
- 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);
+ old_keymat = this->old_sa->get_keymat(this->old_sa);
}
- 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;
}
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);
}
/**
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);
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;
/*
- * 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
/*
- * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*