diff options
| author | René Mayrhofer <rene@mayrhofer.eu.org> | 2011-05-19 13:37:29 +0200 |
|---|---|---|
| committer | René Mayrhofer <rene@mayrhofer.eu.org> | 2011-05-19 13:37:29 +0200 |
| commit | 0a9d51a49042a68daa15b0c74a2b7f152f52606b (patch) | |
| tree | 451888dcb17d00e52114f734e846821373fbbd44 /src/libcharon/sa/authenticators | |
| parent | 568905f488e63e28778f87ac0e38d845f45bae79 (diff) | |
| download | vyos-strongswan-0a9d51a49042a68daa15b0c74a2b7f152f52606b.tar.gz vyos-strongswan-0a9d51a49042a68daa15b0c74a2b7f152f52606b.zip | |
Imported Upstream version 4.5.2
Diffstat (limited to 'src/libcharon/sa/authenticators')
| -rw-r--r-- | src/libcharon/sa/authenticators/eap/eap_method.h | 21 | ||||
| -rw-r--r-- | src/libcharon/sa/authenticators/eap/sim_card.h | 125 | ||||
| -rw-r--r-- | src/libcharon/sa/authenticators/eap/sim_hooks.h | 53 | ||||
| -rw-r--r-- | src/libcharon/sa/authenticators/eap/sim_manager.c | 298 | ||||
| -rw-r--r-- | src/libcharon/sa/authenticators/eap/sim_manager.h | 229 | ||||
| -rw-r--r-- | src/libcharon/sa/authenticators/eap/sim_provider.h | 124 | ||||
| -rw-r--r-- | src/libcharon/sa/authenticators/eap_authenticator.c | 16 |
7 files changed, 481 insertions, 385 deletions
diff --git a/src/libcharon/sa/authenticators/eap/eap_method.h b/src/libcharon/sa/authenticators/eap/eap_method.h index 9961039ff..0eab2b5ff 100644 --- a/src/libcharon/sa/authenticators/eap/eap_method.h +++ b/src/libcharon/sa/authenticators/eap/eap_method.h @@ -113,14 +113,29 @@ struct eap_method_t { * Not all EAP methods establish a shared secret. For implementations of * the EAP-Identity method, get_msk() returns the received identity. * - * @param msk chunk receiving internal stored MSK + * @param msk chunk receiving internal stored MSK * @return - * - SUCCESS, or - * - FAILED, if MSK not established (yet) + * - SUCCESS, or + * - FAILED, if MSK not established (yet) */ status_t (*get_msk) (eap_method_t *this, chunk_t *msk); /** + * Get the current EAP identifier. + * + * @return current EAP identifier + */ + u_int8_t (*get_identifier) (eap_method_t *this); + + /** + * Set the EAP identifier to a deterministic value, overwriting + * the randomly initialized default value. + * + * @param identifier current EAP identifier + */ + void (*set_identifier) (eap_method_t *this, u_int8_t identifier); + + /** * Destroys a eap_method_t object. */ void (*destroy) (eap_method_t *this); diff --git a/src/libcharon/sa/authenticators/eap/sim_card.h b/src/libcharon/sa/authenticators/eap/sim_card.h new file mode 100644 index 000000000..5f5dc580b --- /dev/null +++ b/src/libcharon/sa/authenticators/eap/sim_card.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2008-2009 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. + */ + +/** + * @defgroup sim_card sim_card + * @{ @ingroup eap + */ + +#ifndef SIM_CARD_H_ +#define SIM_CARD_H_ + +typedef struct sim_card_t sim_card_t; + +/** + * Interface for a (U)SIM card (used as EAP client). + * + * The SIM card completes triplets/quintuplets requested in a challenge + * received from the server. + * An implementation supporting only one of SIM/AKA authentication may + * implement the other methods with return_false()/return NOT_SUPPORTED/NULL. + */ +struct sim_card_t { + + /** + * Calculate SRES/KC from a RAND for SIM authentication. + * + * @param id permanent identity to get a triplet for + * @param rand RAND input buffer, fixed size 16 bytes + * @param sres SRES output buffer, fixed size 4 byte + * @param kc KC output buffer, fixed size 8 bytes + * @return TRUE if SRES/KC calculated, FALSE on error/wrong identity + */ + bool (*get_triplet)(sim_card_t *this, identification_t *id, + char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], + char kc[SIM_KC_LEN]); + + /** + * Calculate CK/IK/RES from RAND/AUTN for AKA authentication. + * + * If the received sequence number (in autn) is out of sync, INVALID_STATE + * is returned. + * The RES value is the only one with variable length. Pass a buffer + * of at least AKA_RES_MAX, the actual number of bytes is written to the + * res_len value. While the standard would allow any bit length between + * 32 and 128 bits, we support only full bytes for now. + * + * @param id permanent identity to request quintuplet for + * @param rand random value rand + * @param autn authentication token autn + * @param ck buffer receiving encryption key ck + * @param ik buffer receiving integrity key ik + * @param res buffer receiving authentication result res + * @param res_len nubmer of bytes written to res buffer + * @return SUCCESS, FAILED, or INVALID_STATE if out of sync + */ + status_t (*get_quintuplet)(sim_card_t *this, identification_t *id, + char rand[AKA_RAND_LEN], char autn[AKA_AUTN_LEN], + char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], + char res[AKA_RES_MAX], int *res_len); + + /** + * Calculate AUTS from RAND for AKA resynchronization. + * + * @param id permanent identity to request quintuplet for + * @param rand random value rand + * @param auts resynchronization parameter auts + * @return TRUE if parameter generated successfully + */ + bool (*resync)(sim_card_t *this, identification_t *id, + char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]); + + /** + * Set the pseudonym to use for next authentication. + * + * @param id permanent identity of the peer + * @param pseudonym pseudonym identity received from the server + */ + void (*set_pseudonym)(sim_card_t *this, identification_t *id, + identification_t *pseudonym); + + /** + * Get the pseudonym previously stored via set_pseudonym(). + * + * @param id permanent identity of the peer + * @return associated pseudonym identity, NULL if none stored + */ + identification_t* (*get_pseudonym)(sim_card_t *this, identification_t *id); + + /** + * Store parameters to use for the next fast reauthentication. + * + * @param id permanent identity of the peer + * @param next next fast reauthentication identity to use + * @param mk master key MK to store for reauthentication + * @param counter counter value to store, host order + */ + void (*set_reauth)(sim_card_t *this, identification_t *id, + identification_t *next, char mk[HASH_SIZE_SHA1], + u_int16_t counter); + + /** + * Retrieve parameters for fast reauthentication stored via set_reauth(). + * + * @param id permanent identity of the peer + * @param mk buffer receiving master key MK + * @param counter pointer receiving counter value, in host order + * @return fast reauthentication identity, NULL if not found + */ + identification_t* (*get_reauth)(sim_card_t *this, identification_t *id, + char mk[HASH_SIZE_SHA1], u_int16_t *counter); +}; + +#endif /** SIM_CARD_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/eap/sim_hooks.h b/src/libcharon/sa/authenticators/eap/sim_hooks.h new file mode 100644 index 000000000..0a675e4ab --- /dev/null +++ b/src/libcharon/sa/authenticators/eap/sim_hooks.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2008-2009 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. + */ + +/** + * @defgroup sim_hooks sim_hooks + * @{ @ingroup eap + */ + +#ifndef SIM_HOOKS_H_ +#define SIM_HOOKS_H_ + +typedef struct sim_hooks_t sim_hooks_t; + +/** + * Additional hooks invoked during EAP-SIM/AKA message processing. + */ +struct sim_hooks_t { + + /** + * SIM/AKA message parsing. + * + * As a SIM/AKA optionally contains encrypted attributes, the hook + * might get invoked twice, once before and once after decryption. + * + * @param message SIM/AKA message + * @param inbound TRUE for incoming messages, FALSE for outgoing + * @param decrypted TRUE if AT_ENCR_DATA has been decrypted + */ + void (*message)(sim_hooks_t *this, simaka_message_t *message, + bool inbound, bool decrypted); + + /** + * SIM/AKA encryption/authentication key hooks. + * + * @param k_encr derived SIM/AKA encryption key k_encr + * @param k_auth derived SIM/AKA authentication key k_auth + */ + void (*keys)(sim_hooks_t *this, chunk_t k_encr, chunk_t k_auth); +}; + +#endif /** SIM_HOOKS_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/eap/sim_manager.c b/src/libcharon/sa/authenticators/eap/sim_manager.c index 157865083..9ccaf5298 100644 --- a/src/libcharon/sa/authenticators/eap/sim_manager.c +++ b/src/libcharon/sa/authenticators/eap/sim_manager.c @@ -17,6 +17,7 @@ #include <daemon.h> #include <utils/linked_list.h> +#include <threading/rwlock.h> typedef struct private_sim_manager_t private_sim_manager_t; @@ -44,65 +45,67 @@ struct private_sim_manager_t { * list of added hooks */ linked_list_t *hooks; + + /** + * lock for lists above + */ + rwlock_t *lock; }; -/** - * Implementation of sim_manager_t.add_card - */ -static void add_card(private_sim_manager_t *this, sim_card_t *card) +METHOD(sim_manager_t, add_card, void, + private_sim_manager_t *this, sim_card_t *card) { + this->lock->write_lock(this->lock); this->cards->insert_last(this->cards, card); + this->lock->unlock(this->lock); } -/** - * Implementation of sim_manager_t.remove_card - */ -static void remove_card(private_sim_manager_t *this, sim_card_t *card) +METHOD(sim_manager_t, remove_card, void, + private_sim_manager_t *this, sim_card_t *card) { + this->lock->write_lock(this->lock); this->cards->remove(this->cards, card, NULL); + this->lock->unlock(this->lock); } -/** - * Implementation of sim_manager_t.card_get_triplet - */ -static bool card_get_triplet(private_sim_manager_t *this, identification_t *id, - char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], - char kc[SIM_KC_LEN]) +METHOD(sim_manager_t, card_get_triplet, bool, + private_sim_manager_t *this, identification_t *id, + char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN]) { enumerator_t *enumerator; sim_card_t *card; int tried = 0; + this->lock->read_lock(this->lock); enumerator = this->cards->create_enumerator(this->cards); while (enumerator->enumerate(enumerator, &card)) { if (card->get_triplet(card, id, rand, sres, kc)) { enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return TRUE; } tried++; } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); DBG1(DBG_IKE, "tried %d SIM cards, but none has triplets for '%Y'", tried, id); return FALSE; } -/** - * Implementation of sim_manager_t.card_get_quintuplet - */ -static status_t card_get_quintuplet(private_sim_manager_t *this, - identification_t *id, char rand[AKA_RAND_LEN], - char autn[AKA_AUTN_LEN], char ck[AKA_CK_LEN], - char ik[AKA_IK_LEN], char res[AKA_RES_MAX], - int *res_len) +METHOD(sim_manager_t, card_get_quintuplet, status_t, + private_sim_manager_t *this, identification_t *id, char rand[AKA_RAND_LEN], + char autn[AKA_AUTN_LEN], char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], + char res[AKA_RES_MAX], int *res_len) { enumerator_t *enumerator; sim_card_t *card; status_t status = NOT_FOUND; int tried = 0; + this->lock->read_lock(this->lock); enumerator = this->cards->create_enumerator(this->cards); while (enumerator->enumerate(enumerator, &card)) { @@ -112,6 +115,7 @@ static status_t card_get_quintuplet(private_sim_manager_t *this, case SUCCESS: case INVALID_STATE: enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return status; case NOT_SUPPORTED: case FAILED: @@ -121,62 +125,62 @@ static status_t card_get_quintuplet(private_sim_manager_t *this, } } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); DBG1(DBG_IKE, "tried %d SIM cards, but none has quintuplets for '%Y'", tried, id); return status; } -/** - * Implementation of sim_manager_t.card_resync - */ -static bool card_resync(private_sim_manager_t *this, identification_t *id, - char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]) +METHOD(sim_manager_t, card_resync, bool, + private_sim_manager_t *this, identification_t *id, + char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]) { enumerator_t *enumerator; sim_card_t *card; + this->lock->read_lock(this->lock); enumerator = this->cards->create_enumerator(this->cards); while (enumerator->enumerate(enumerator, &card)) { if (card->resync(card, id, rand, auts)) { enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return TRUE; } } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return FALSE; } -/** - * Implementation of sim_manager_t.card_set_pseudonym - */ -static void card_set_pseudonym(private_sim_manager_t *this, - identification_t *id, identification_t *pseudonym) +METHOD(sim_manager_t, card_set_pseudonym, void, + private_sim_manager_t *this, identification_t *id, + identification_t *pseudonym) { enumerator_t *enumerator; sim_card_t *card; DBG1(DBG_IKE, "storing pseudonym '%Y' for '%Y'", pseudonym, id); + this->lock->read_lock(this->lock); enumerator = this->cards->create_enumerator(this->cards); while (enumerator->enumerate(enumerator, &card)) { card->set_pseudonym(card, id, pseudonym); } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); } -/** - * Implementation of sim_manager_t.card_get_pseudonym - */ -static identification_t* card_get_pseudonym(private_sim_manager_t *this, - identification_t *id) +METHOD(sim_manager_t, card_get_pseudonym, identification_t*, + private_sim_manager_t *this, identification_t *id) { enumerator_t *enumerator; sim_card_t *card; identification_t *pseudonym = NULL; + this->lock->read_lock(this->lock); enumerator = this->cards->create_enumerator(this->cards); while (enumerator->enumerate(enumerator, &card)) { @@ -189,15 +193,13 @@ static identification_t* card_get_pseudonym(private_sim_manager_t *this, } } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return pseudonym; } -/** - * Implementation of sim_manager_t.card_set_reauth - */ -static void card_set_reauth(private_sim_manager_t *this, identification_t *id, - identification_t *next, char mk[HASH_SIZE_SHA1], - u_int16_t counter) +METHOD(sim_manager_t, card_set_reauth, void, + private_sim_manager_t *this, identification_t *id, identification_t *next, + char mk[HASH_SIZE_SHA1], u_int16_t counter) { enumerator_t *enumerator; sim_card_t *card; @@ -205,25 +207,25 @@ static void card_set_reauth(private_sim_manager_t *this, identification_t *id, DBG1(DBG_IKE, "storing next reauthentication identity '%Y' for '%Y'", next, id); + this->lock->read_lock(this->lock); enumerator = this->cards->create_enumerator(this->cards); while (enumerator->enumerate(enumerator, &card)) { card->set_reauth(card, id, next, mk, counter); } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); } -/** - * Implementation of sim_manager_t.card_get_reauth - */ -static identification_t* card_get_reauth(private_sim_manager_t *this, - identification_t *id, char mk[HASH_SIZE_SHA1], - u_int16_t *counter) +METHOD(sim_manager_t, card_get_reauth, identification_t*, + private_sim_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1], + u_int16_t *counter) { enumerator_t *enumerator; sim_card_t *card; identification_t *reauth = NULL; + this->lock->read_lock(this->lock); enumerator = this->cards->create_enumerator(this->cards); while (enumerator->enumerate(enumerator, &card)) { @@ -236,66 +238,63 @@ static identification_t* card_get_reauth(private_sim_manager_t *this, } } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return reauth; } -/** - * Implementation of sim_manager_t.add_provider - */ -static void add_provider(private_sim_manager_t *this, sim_provider_t *provider) +METHOD(sim_manager_t, add_provider, void, + private_sim_manager_t *this, sim_provider_t *provider) { + this->lock->write_lock(this->lock); this->providers->insert_last(this->providers, provider); + this->lock->unlock(this->lock); } -/** - * Implementation of sim_manager_t.remove_provider - */ -static void remove_provider(private_sim_manager_t *this, - sim_provider_t *provider) +METHOD(sim_manager_t, remove_provider, void, + private_sim_manager_t *this, sim_provider_t *provider) { + this->lock->write_lock(this->lock); this->providers->remove(this->providers, provider, NULL); + this->lock->unlock(this->lock); } -/** - * Implementation of sim_manager_t.provider_get_triplet - */ -static bool provider_get_triplet(private_sim_manager_t *this, - identification_t *id, char rand[SIM_RAND_LEN], - char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN]) +METHOD(sim_manager_t, provider_get_triplet, bool, + private_sim_manager_t *this, identification_t *id, char rand[SIM_RAND_LEN], + char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN]) { enumerator_t *enumerator; sim_provider_t *provider; int tried = 0; + this->lock->read_lock(this->lock); enumerator = this->providers->create_enumerator(this->providers); while (enumerator->enumerate(enumerator, &provider)) { if (provider->get_triplet(provider, id, rand, sres, kc)) { enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return TRUE; } tried++; } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); DBG1(DBG_IKE, "tried %d SIM providers, but none had a triplet for '%Y'", tried, id); return FALSE; } -/** - * Implementation of sim_manager_t.provider_get_quintuplet - */ -static bool provider_get_quintuplet(private_sim_manager_t *this, - identification_t *id, char rand[AKA_RAND_LEN], - char xres[AKA_RES_MAX], int *xres_len, - char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], - char autn[AKA_AUTN_LEN]) +METHOD(sim_manager_t, provider_get_quintuplet, bool, + private_sim_manager_t *this, identification_t *id, char rand[AKA_RAND_LEN], + char xres[AKA_RES_MAX], int *xres_len, char ck[AKA_CK_LEN], + char ik[AKA_IK_LEN], char autn[AKA_AUTN_LEN]) { enumerator_t *enumerator; sim_provider_t *provider; int tried = 0; + this->lock->read_lock(this->lock); enumerator = this->providers->create_enumerator(this->providers); while (enumerator->enumerate(enumerator, &provider)) { @@ -303,47 +302,48 @@ static bool provider_get_quintuplet(private_sim_manager_t *this, ck, ik, autn)) { enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return TRUE; } } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); DBG1(DBG_IKE, "tried %d SIM providers, but none had a quintuplet for '%Y'", tried, id); return FALSE; } -/** - * Implementation of sim_manager_t.provider_resync - */ -static bool provider_resync(private_sim_manager_t *this, identification_t *id, - char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]) +METHOD(sim_manager_t, provider_resync, bool, + private_sim_manager_t *this, identification_t *id, + char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]) { enumerator_t *enumerator; sim_provider_t *provider; + this->lock->read_lock(this->lock); enumerator = this->providers->create_enumerator(this->providers); while (enumerator->enumerate(enumerator, &provider)) { if (provider->resync(provider, id, rand, auts)) { enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return TRUE; } } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return FALSE; } -/** - * Implementation of sim_manager_t.provider_is_pseudonym - */ -static identification_t* provider_is_pseudonym(private_sim_manager_t *this, - identification_t *id) +METHOD(sim_manager_t, provider_is_pseudonym, identification_t*, + private_sim_manager_t *this, identification_t *id) { enumerator_t *enumerator; sim_provider_t *provider; identification_t *permanent = NULL; + this->lock->read_lock(this->lock); enumerator = this->providers->create_enumerator(this->providers); while (enumerator->enumerate(enumerator, &provider)) { @@ -356,19 +356,18 @@ static identification_t* provider_is_pseudonym(private_sim_manager_t *this, } } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return permanent; } -/** - * Implementation of sim_manager_t.provider_gen_pseudonym - */ -static identification_t* provider_gen_pseudonym(private_sim_manager_t *this, - identification_t *id) +METHOD(sim_manager_t, provider_gen_pseudonym, identification_t*, + private_sim_manager_t *this, identification_t *id) { enumerator_t *enumerator; sim_provider_t *provider; identification_t *pseudonym = NULL; + this->lock->read_lock(this->lock); enumerator = this->providers->create_enumerator(this->providers); while (enumerator->enumerate(enumerator, &provider)) { @@ -380,20 +379,19 @@ static identification_t* provider_gen_pseudonym(private_sim_manager_t *this, } } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return pseudonym; } -/** - * Implementation of sim_manager_t.provider_is_reauth - */ -static identification_t* provider_is_reauth(private_sim_manager_t *this, - identification_t *id, char mk[HASH_SIZE_SHA1], - u_int16_t *counter) +METHOD(sim_manager_t, provider_is_reauth, identification_t*, + private_sim_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1], + u_int16_t *counter) { enumerator_t *enumerator; sim_provider_t *provider; identification_t *permanent = NULL; + this->lock->read_lock(this->lock); enumerator = this->providers->create_enumerator(this->providers); while (enumerator->enumerate(enumerator, &provider)) { @@ -406,19 +404,18 @@ static identification_t* provider_is_reauth(private_sim_manager_t *this, } } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return permanent; } -/** - * Implementation of sim_manager_t.provider_gen_reauth - */ -static identification_t* provider_gen_reauth(private_sim_manager_t *this, - identification_t *id, char mk[HASH_SIZE_SHA1]) +METHOD(sim_manager_t, provider_gen_reauth, identification_t*, + private_sim_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1]) { enumerator_t *enumerator; sim_provider_t *provider; identification_t *reauth = NULL; + this->lock->read_lock(this->lock); enumerator = this->providers->create_enumerator(this->providers); while (enumerator->enumerate(enumerator, &provider)) { @@ -430,67 +427,66 @@ static identification_t* provider_gen_reauth(private_sim_manager_t *this, } } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); return reauth; } -/** - * Implementation of sim_manager_t.add_hooks - */ -static void add_hooks(private_sim_manager_t *this, sim_hooks_t *hooks) +METHOD(sim_manager_t, add_hooks, void, + private_sim_manager_t *this, sim_hooks_t *hooks) { + this->lock->write_lock(this->lock); this->hooks->insert_last(this->hooks, hooks); + this->lock->unlock(this->lock); } -/** - * Implementation of sim_manager_t.remove_hooks - */ -static void remove_hooks(private_sim_manager_t *this, sim_hooks_t *hooks) +METHOD(sim_manager_t, remove_hooks, void, + private_sim_manager_t *this, sim_hooks_t *hooks) { + this->lock->write_lock(this->lock); this->hooks->remove(this->hooks, hooks, NULL); + this->lock->unlock(this->lock); } -/** - * Implementation of sim_manager_t.message_hook - */ -static void message_hook(private_sim_manager_t *this, - simaka_message_t *message, bool inbound, bool decrypted) +METHOD(sim_manager_t, message_hook, void, + private_sim_manager_t *this, simaka_message_t *message, + bool inbound, bool decrypted) { enumerator_t *enumerator; sim_hooks_t *hooks; + this->lock->read_lock(this->lock); enumerator = this->hooks->create_enumerator(this->hooks); while (enumerator->enumerate(enumerator, &hooks)) { hooks->message(hooks, message, inbound, decrypted); } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); } -/** - * Implementation of sim_manager_t.key_hook - */ -static void key_hook(private_sim_manager_t *this, - chunk_t k_encr, chunk_t k_auth) +METHOD(sim_manager_t, key_hook, void, + private_sim_manager_t *this, chunk_t k_encr, chunk_t k_auth) { enumerator_t *enumerator; sim_hooks_t *hooks; + this->lock->read_lock(this->lock); enumerator = this->hooks->create_enumerator(this->hooks); while (enumerator->enumerate(enumerator, &hooks)) { hooks->keys(hooks, k_encr, k_auth); } enumerator->destroy(enumerator); + this->lock->unlock(this->lock); } -/** - * Implementation of sim_manager_t.destroy. - */ -static void destroy(private_sim_manager_t *this) +METHOD(sim_manager_t, destroy, void, + private_sim_manager_t *this) { this->cards->destroy(this->cards); this->providers->destroy(this->providers); this->hooks->destroy(this->hooks); + this->lock->destroy(this->lock); free(this); } @@ -499,35 +495,39 @@ static void destroy(private_sim_manager_t *this) */ sim_manager_t *sim_manager_create() { - private_sim_manager_t *this = malloc_thing(private_sim_manager_t); - - this->public.add_card = (void(*)(sim_manager_t*, sim_card_t *card))add_card; - this->public.remove_card = (void(*)(sim_manager_t*, sim_card_t *card))remove_card; - this->public.card_get_triplet = (bool(*)(sim_manager_t*, identification_t *id, char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN]))card_get_triplet; - this->public.card_get_quintuplet = (status_t(*)(sim_manager_t*, identification_t *id, char rand[AKA_RAND_LEN], char autn[AKA_AUTN_LEN], char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], char res[AKA_RES_MAX], int *res_len))card_get_quintuplet; - this->public.card_resync = (bool(*)(sim_manager_t*, identification_t *id, char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]))card_resync; - this->public.card_set_pseudonym = (void(*)(sim_manager_t*, identification_t *id, identification_t *pseudonym))card_set_pseudonym; - this->public.card_get_pseudonym = (identification_t*(*)(sim_manager_t*, identification_t *id))card_get_pseudonym; - this->public.card_set_reauth = (void(*)(sim_manager_t*, identification_t *id, identification_t *next, char mk[HASH_SIZE_SHA1], u_int16_t counter))card_set_reauth; - this->public.card_get_reauth = (identification_t*(*)(sim_manager_t*, identification_t *id, char mk[HASH_SIZE_SHA1], u_int16_t *counter))card_get_reauth; - this->public.add_provider = (void(*)(sim_manager_t*, sim_provider_t *provider))add_provider; - this->public.remove_provider = (void(*)(sim_manager_t*, sim_provider_t *provider))remove_provider; - this->public.provider_get_triplet = (bool(*)(sim_manager_t*, identification_t *id, char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN]))provider_get_triplet; - this->public.provider_get_quintuplet = (bool(*)(sim_manager_t*, identification_t *id, char rand[AKA_RAND_LEN], char xres[AKA_RES_MAX], int *xres_len, char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], char autn[AKA_AUTN_LEN]))provider_get_quintuplet; - this->public.provider_resync = (bool(*)(sim_manager_t*, identification_t *id, char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]))provider_resync; - this->public.provider_is_pseudonym = (identification_t*(*)(sim_manager_t*, identification_t *id))provider_is_pseudonym; - this->public.provider_gen_pseudonym = (identification_t*(*)(sim_manager_t*, identification_t *id))provider_gen_pseudonym; - this->public.provider_is_reauth = (identification_t*(*)(sim_manager_t*, identification_t *id, char mk[HASH_SIZE_SHA1], u_int16_t *counter))provider_is_reauth; - this->public.provider_gen_reauth = (identification_t*(*)(sim_manager_t*, identification_t *id, char mk[HASH_SIZE_SHA1]))provider_gen_reauth; - this->public.add_hooks = (void(*)(sim_manager_t*, sim_hooks_t *hooks))add_hooks; - this->public.remove_hooks = (void(*)(sim_manager_t*, sim_hooks_t *hooks))remove_hooks; - this->public.message_hook = (void(*)(sim_manager_t*, simaka_message_t *message, bool inbound, bool decrypted))message_hook; - this->public.key_hook = (void(*)(sim_manager_t*, chunk_t k_encr, chunk_t k_auth))key_hook; - this->public.destroy = (void(*)(sim_manager_t*))destroy; - - this->cards = linked_list_create(); - this->providers = linked_list_create(); - this->hooks = linked_list_create(); + private_sim_manager_t *this; + + INIT(this, + .public = { + .add_card = _add_card, + .remove_card = _remove_card, + .card_get_triplet = _card_get_triplet, + .card_get_quintuplet = _card_get_quintuplet, + .card_resync = _card_resync, + .card_set_pseudonym = _card_set_pseudonym, + .card_get_pseudonym = _card_get_pseudonym, + .card_set_reauth = _card_set_reauth, + .card_get_reauth = _card_get_reauth, + .add_provider = _add_provider, + .remove_provider = _remove_provider, + .provider_get_triplet = _provider_get_triplet, + .provider_get_quintuplet = _provider_get_quintuplet, + .provider_resync = _provider_resync, + .provider_is_pseudonym = _provider_is_pseudonym, + .provider_gen_pseudonym = _provider_gen_pseudonym, + .provider_is_reauth = _provider_is_reauth, + .provider_gen_reauth = _provider_gen_reauth, + .add_hooks = _add_hooks, + .remove_hooks = _remove_hooks, + .message_hook = _message_hook, + .key_hook = _key_hook, + .destroy = _destroy, + }, + .cards = linked_list_create(), + .providers = linked_list_create(), + .hooks = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); return &this->public; } diff --git a/src/libcharon/sa/authenticators/eap/sim_manager.h b/src/libcharon/sa/authenticators/eap/sim_manager.h index 9aa661ac8..db4a65011 100644 --- a/src/libcharon/sa/authenticators/eap/sim_manager.h +++ b/src/libcharon/sa/authenticators/eap/sim_manager.h @@ -27,9 +27,6 @@ #include <sa/authenticators/eap/eap_method.h> typedef struct sim_manager_t sim_manager_t; -typedef struct sim_card_t sim_card_t; -typedef struct sim_provider_t sim_provider_t; -typedef struct sim_hooks_t sim_hooks_t; /** implemented in libsimaka, but we need it for the message hook */ typedef struct simaka_message_t simaka_message_t; @@ -45,229 +42,9 @@ typedef struct simaka_message_t simaka_message_t; #define AKA_AUTN_LEN 16 #define AKA_AUTS_LEN 14 -/** - * Interface for a (U)SIM card (used as EAP client). - * - * The SIM card completes triplets/quintuplets requested in a challenge - * received from the server. - * An implementation supporting only one of SIM/AKA authentication may - * implement the other methods with return_false()/return NOT_SUPPORTED/NULL. - */ -struct sim_card_t { - - /** - * Calculate SRES/KC from a RAND for SIM authentication. - * - * @param id permanent identity to get a triplet for - * @param rand RAND input buffer, fixed size 16 bytes - * @param sres SRES output buffer, fixed size 4 byte - * @param kc KC output buffer, fixed size 8 bytes - * @return TRUE if SRES/KC calculated, FALSE on error/wrong identity - */ - bool (*get_triplet)(sim_card_t *this, identification_t *id, - char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], - char kc[SIM_KC_LEN]); - - /** - * Calculate CK/IK/RES from RAND/AUTN for AKA authentication. - * - * If the received sequence number (in autn) is out of sync, INVALID_STATE - * is returned. - * The RES value is the only one with variable length. Pass a buffer - * of at least AKA_RES_MAX, the actual number of bytes is written to the - * res_len value. While the standard would allow any bit length between - * 32 and 128 bits, we support only full bytes for now. - * - * @param id permanent identity to request quintuplet for - * @param rand random value rand - * @param autn authentication token autn - * @param ck buffer receiving encryption key ck - * @param ik buffer receiving integrity key ik - * @param res buffer receiving authentication result res - * @param res_len nubmer of bytes written to res buffer - * @return SUCCESS, FAILED, or INVALID_STATE if out of sync - */ - status_t (*get_quintuplet)(sim_card_t *this, identification_t *id, - char rand[AKA_RAND_LEN], char autn[AKA_AUTN_LEN], - char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], - char res[AKA_RES_MAX], int *res_len); - - /** - * Calculate AUTS from RAND for AKA resynchronization. - * - * @param id permanent identity to request quintuplet for - * @param rand random value rand - * @param auts resynchronization parameter auts - * @return TRUE if parameter generated successfully - */ - bool (*resync)(sim_card_t *this, identification_t *id, - char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]); - - /** - * Set the pseudonym to use for next authentication. - * - * @param id permanent identity of the peer - * @param pseudonym pseudonym identity received from the server - */ - void (*set_pseudonym)(sim_card_t *this, identification_t *id, - identification_t *pseudonym); - - /** - * Get the pseudonym previously stored via set_pseudonym(). - * - * @param id permanent identity of the peer - * @return associated pseudonym identity, NULL if none stored - */ - identification_t* (*get_pseudonym)(sim_card_t *this, identification_t *id); - - /** - * Store parameters to use for the next fast reauthentication. - * - * @param id permanent identity of the peer - * @param next next fast reauthentication identity to use - * @param mk master key MK to store for reauthentication - * @param counter counter value to store, host order - */ - void (*set_reauth)(sim_card_t *this, identification_t *id, - identification_t *next, char mk[HASH_SIZE_SHA1], - u_int16_t counter); - - /** - * Retrieve parameters for fast reauthentication stored via set_reauth(). - * - * @param id permanent identity of the peer - * @param mk buffer receiving master key MK - * @param counter pointer receiving counter value, in host order - * @return fast reauthentication identity, NULL if not found - */ - identification_t* (*get_reauth)(sim_card_t *this, identification_t *id, - char mk[HASH_SIZE_SHA1], u_int16_t *counter); -}; - -/** - * Interface for a triplet/quintuplet provider (used as EAP server). - * - * A SIM provider hands out triplets for SIM authentication and quintuplets - * for AKA authentication. Multiple SIM provider instances can serve as - * authentication backend to authenticate clients using SIM/AKA. - * An implementation supporting only one of SIM/AKA authentication may - * implement the other methods with return_false(). - */ -struct sim_provider_t { - - /** - * Create a challenge for SIM authentication. - * - * @param id permanent identity of peer to gen triplet for - * @param rand RAND output buffer, fixed size 16 bytes - * @param sres SRES output buffer, fixed size 4 byte - * @param kc KC output buffer, fixed size 8 bytes - * @return TRUE if triplet received, FALSE otherwise - */ - bool (*get_triplet)(sim_provider_t *this, identification_t *id, - char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], - char kc[SIM_KC_LEN]); - - /** - * Create a challenge for AKA authentication. - * - * The XRES value is the only one with variable length. Pass a buffer - * of at least AKA_RES_MAX, the actual number of bytes is written to the - * xres_len value. While the standard would allow any bit length between - * 32 and 128 bits, we support only full bytes for now. - * - * @param id permanent identity of peer to create challenge for - * @param rand buffer receiving random value rand - * @param xres buffer receiving expected authentication result xres - * @param xres_len nubmer of bytes written to xres buffer - * @param ck buffer receiving encryption key ck - * @param ik buffer receiving integrity key ik - * @param autn authentication token autn - * @return TRUE if quintuplet generated successfully - */ - bool (*get_quintuplet)(sim_provider_t *this, identification_t *id, - char rand[AKA_RAND_LEN], - char xres[AKA_RES_MAX], int *xres_len, - char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], - char autn[AKA_AUTN_LEN]); - - /** - * Process AKA resynchroniusation request of a peer. - * - * @param id permanent identity of peer requesting resynchronisation - * @param rand random value rand - * @param auts synchronization parameter auts - * @return TRUE if resynchronized successfully - */ - bool (*resync)(sim_provider_t *this, identification_t *id, - char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]); - - /** - * Check if peer uses a pseudonym, get permanent identity. - * - * @param id pseudonym identity candidate - * @return permanent identity, NULL if id not a pseudonym - */ - identification_t* (*is_pseudonym)(sim_provider_t *this, - identification_t *id); - - /** - * Generate a pseudonym identitiy for a given peer identity. - * - * @param id permanent identity to generate a pseudonym for - * @return generated pseudonym, NULL to not use a pseudonym identity - */ - identification_t* (*gen_pseudonym)(sim_provider_t *this, - identification_t *id); - - /** - * Check if peer uses reauthentication, retrieve reauth parameters. - * - * @param id reauthentication identity (candidate) - * @param mk buffer receiving master key MK - * @param counter pointer receiving current counter value, host order - * @return permanent identity, NULL if id not a reauth identity - */ - identification_t* (*is_reauth)(sim_provider_t *this, identification_t *id, - char mk[HASH_SIZE_SHA1], u_int16_t *counter); - - /** - * Generate a fast reauthentication identity, associated to a master key. - * - * @param id permanent peer identity - * @param mk master key to store along with generated identity - * @return fast reauthentication identity, NULL to not use reauth - */ - identification_t* (*gen_reauth)(sim_provider_t *this, identification_t *id, - char mk[HASH_SIZE_SHA1]); -}; - -/** - * Additional hooks invoked during EAP-SIM/AKA message processing. - */ -struct sim_hooks_t { - - /** - * SIM/AKA message parsing. - * - * As a SIM/AKA optionally contains encrypted attributes, the hook - * might get invoked twice, once before and once after decryption. - * - * @param message SIM/AKA message - * @param inbound TRUE for incoming messages, FALSE for outgoing - * @param decrypted TRUE if AT_ENCR_DATA has been decrypted - */ - void (*message)(sim_hooks_t *this, simaka_message_t *message, - bool inbound, bool decrypted); - - /** - * SIM/AKA encryption/authentication key hooks. - * - * @param k_encr derived SIM/AKA encryption key k_encr - * @param k_auth derived SIM/AKA authentication key k_auth - */ - void (*keys)(sim_hooks_t *this, chunk_t k_encr, chunk_t k_auth); -}; +#include <sa/authenticators/eap/sim_card.h> +#include <sa/authenticators/eap/sim_provider.h> +#include <sa/authenticators/eap/sim_hooks.h> /** * The SIM manager handles multiple (U)SIM cards/providers and hooks. diff --git a/src/libcharon/sa/authenticators/eap/sim_provider.h b/src/libcharon/sa/authenticators/eap/sim_provider.h new file mode 100644 index 000000000..191e094db --- /dev/null +++ b/src/libcharon/sa/authenticators/eap/sim_provider.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2008-2009 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. + */ + +/** + * @defgroup sim_provider sim_provider + * @{ @ingroup eap + */ + +#ifndef SIM_PROVIDER_H_ +#define SIM_PROVIDER_H_ + +typedef struct sim_provider_t sim_provider_t; + +/** + * Interface for a triplet/quintuplet provider (used as EAP server). + * + * A SIM provider hands out triplets for SIM authentication and quintuplets + * for AKA authentication. Multiple SIM provider instances can serve as + * authentication backend to authenticate clients using SIM/AKA. + * An implementation supporting only one of SIM/AKA authentication may + * implement the other methods with return_false(). + */ +struct sim_provider_t { + + /** + * Create a challenge for SIM authentication. + * + * @param id permanent identity of peer to gen triplet for + * @param rand RAND output buffer, fixed size 16 bytes + * @param sres SRES output buffer, fixed size 4 byte + * @param kc KC output buffer, fixed size 8 bytes + * @return TRUE if triplet received, FALSE otherwise + */ + bool (*get_triplet)(sim_provider_t *this, identification_t *id, + char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], + char kc[SIM_KC_LEN]); + + /** + * Create a challenge for AKA authentication. + * + * The XRES value is the only one with variable length. Pass a buffer + * of at least AKA_RES_MAX, the actual number of bytes is written to the + * xres_len value. While the standard would allow any bit length between + * 32 and 128 bits, we support only full bytes for now. + * + * @param id permanent identity of peer to create challenge for + * @param rand buffer receiving random value rand + * @param xres buffer receiving expected authentication result xres + * @param xres_len nubmer of bytes written to xres buffer + * @param ck buffer receiving encryption key ck + * @param ik buffer receiving integrity key ik + * @param autn authentication token autn + * @return TRUE if quintuplet generated successfully + */ + bool (*get_quintuplet)(sim_provider_t *this, identification_t *id, + char rand[AKA_RAND_LEN], + char xres[AKA_RES_MAX], int *xres_len, + char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], + char autn[AKA_AUTN_LEN]); + + /** + * Process AKA resynchroniusation request of a peer. + * + * @param id permanent identity of peer requesting resynchronisation + * @param rand random value rand + * @param auts synchronization parameter auts + * @return TRUE if resynchronized successfully + */ + bool (*resync)(sim_provider_t *this, identification_t *id, + char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]); + + /** + * Check if peer uses a pseudonym, get permanent identity. + * + * @param id pseudonym identity candidate + * @return permanent identity, NULL if id not a pseudonym + */ + identification_t* (*is_pseudonym)(sim_provider_t *this, + identification_t *id); + + /** + * Generate a pseudonym identitiy for a given peer identity. + * + * @param id permanent identity to generate a pseudonym for + * @return generated pseudonym, NULL to not use a pseudonym identity + */ + identification_t* (*gen_pseudonym)(sim_provider_t *this, + identification_t *id); + + /** + * Check if peer uses reauthentication, retrieve reauth parameters. + * + * @param id reauthentication identity (candidate) + * @param mk buffer receiving master key MK + * @param counter pointer receiving current counter value, host order + * @return permanent identity, NULL if id not a reauth identity + */ + identification_t* (*is_reauth)(sim_provider_t *this, identification_t *id, + char mk[HASH_SIZE_SHA1], u_int16_t *counter); + + /** + * Generate a fast reauthentication identity, associated to a master key. + * + * @param id permanent peer identity + * @param mk master key to store along with generated identity + * @return fast reauthentication identity, NULL to not use reauth + */ + identification_t* (*gen_reauth)(sim_provider_t *this, identification_t *id, + char mk[HASH_SIZE_SHA1]); +}; + +#endif /** SIM_CARD_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/eap_authenticator.c b/src/libcharon/sa/authenticators/eap_authenticator.c index dea02755d..d442acb00 100644 --- a/src/libcharon/sa/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/authenticators/eap_authenticator.c @@ -183,16 +183,18 @@ static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this, if (this->method) { action = "initiating"; + type = this->method->get_type(this->method, &vendor); if (this->method->initiate(this->method, &out) == NEED_MORE) { if (vendor) { - DBG1(DBG_IKE, "initiating EAP vendor type %d-%d method", - type, vendor); + DBG1(DBG_IKE, "initiating EAP vendor type %d-%d method (id 0x%02X)", + type, vendor, out->get_identifier(out)); } else { - DBG1(DBG_IKE, "initiating %N method", eap_type_names, type); + DBG1(DBG_IKE, "initiating %N method (id 0x%02X)", eap_type_names, + type, out->get_identifier(out)); } return out; } @@ -371,13 +373,13 @@ static eap_payload_t* client_process_eap(private_eap_authenticator_t *this, { if (vendor) { - DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d", - type, vendor); + DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d ", + "(id 0x%02X)", type, vendor, in->get_identifier(in)); } else { - DBG1(DBG_IKE, "server requested %N authentication", - eap_type_names, type); + DBG1(DBG_IKE, "server requested %N authentication (id 0x%02X)", + eap_type_names, type, in->get_identifier(in)); } this->method = load_method(this, type, vendor, EAP_PEER); if (!this->method) |
