From: Martin Willi Date: Thu, 8 Oct 2009 11:01:49 +0000 (+0200) Subject: Ported AKA functions to 3gpp2 plugin X-Git-Tag: 4.3.5rc1~59 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0030880c6b83498def8268225bf6a5e9953e9de0;p=thirdparty%2Fstrongswan.git Ported AKA functions to 3gpp2 plugin --- diff --git a/src/charon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.c b/src/charon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.c index b7213891d5..17f522abdc 100644 --- a/src/charon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.c +++ b/src/charon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.c @@ -15,6 +15,11 @@ #include "eap_aka_3gpp2_functions.h" +#include +#include + +#include + typedef struct private_eap_aka_3gpp2_functions_t private_eap_aka_3gpp2_functions_t; /** @@ -26,13 +31,335 @@ struct private_eap_aka_3gpp2_functions_t { * Public eap_aka_3gpp2_functions_t interface. */ eap_aka_3gpp2_functions_t public; + + /** + * Used keyed SHA1 function, as PRF + */ + prf_t *prf; +}; + +#define PAYLOAD_LENGTH 64 + +#define F1 0x42 +#define F1STAR 0x43 +#define F2 0x44 +#define F3 0x45 +#define F4 0x46 +#define F5 0x47 +#define F5STAR 0x48 + +/** Family key, as proposed in S.S0055 */ +static chunk_t fmk = chunk_from_chars(0x41, 0x48, 0x41, 0x47); + +/** + * Binary represnation of the polynom T^160 + T^5 + T^3 + T^2 + 1 + */ +static u_int8_t g[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2d +}; + +/** + * Predefined random bits from the RAND Corporation book + */ +static u_int8_t a[] = { + 0x9d, 0xe9, 0xc9, 0xc8, 0xef, 0xd5, 0x78, 0x11, + 0x48, 0x23, 0x14, 0x01, 0x90, 0x1f, 0x2d, 0x49, + 0x3f, 0x4c, 0x63, 0x65 +}; + +/** + * Predefined random bits from the RAND Corporation book + */ +static u_int8_t b[] = { + 0x75, 0xef, 0xd1, 0x5c, 0x4b, 0x8f, 0x8f, 0x51, + 0x4e, 0xf3, 0xbc, 0xc3, 0x79, 0x4a, 0x76, 0x5e, + 0x7e, 0xec, 0x45, 0xe0 }; +/** + * Multiplicate two mpz_t with bits interpreted as polynoms. + */ +static void mpz_mul_poly(mpz_t r, mpz_t a, mpz_t b) +{ + mpz_t bm, rm; + int current = 0, shifted = 0, shift; + + mpz_init_set(bm, b); + mpz_init_set_ui(rm, 0); + /* scan through a, for each found bit: */ + while ((current = mpz_scan1(a, current)) != ULONG_MAX) + { + /* XOR shifted b into r */ + shift = current - shifted; + mpz_mul_2exp(bm, bm, shift); + shifted += shift; + mpz_xor(rm, rm, bm); + current++; + } + + mpz_swap(r, rm); + mpz_clear(rm); + mpz_clear(bm); +} + +/** + * Calculate the sum of a + b interpreted as polynoms. + */ +static void mpz_add_poly(mpz_t res, mpz_t a, mpz_t b) +{ + /* addition of polynominals is just the XOR */ + mpz_xor(res, a, b); +} + +/** + * Calculate the remainder of a/b interpreted as polynoms. + */ +static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b) +{ + /* Example: + * a = 10001010 + * b = 00000101 + */ + int a_bit, b_bit, diff; + mpz_t bm, am; + + mpz_init_set(am, a); + mpz_init(bm); + + a_bit = mpz_sizeinbase(a, 2); + b_bit = mpz_sizeinbase(b, 2); + + /* don't do anything if b > a */ + if (a_bit >= b_bit) + { + /* shift b left to align up most signaficant "1" to a: + * a = 10001010 + * b = 10100000 + */ + mpz_mul_2exp(bm, b, a_bit - b_bit); + do + { + /* XOR b into a, this kills the most significant "1": + * a = 00101010 + */ + mpz_xor(am, am, bm); + /* find the next most significant "1" in a, and align up b: + * a = 00101010 + * b = 00101000 + */ + diff = a_bit - mpz_sizeinbase(am, 2); + mpz_div_2exp(bm, bm, diff); + a_bit -= diff; + } + while (b_bit <= mpz_sizeinbase(bm, 2)); + /* While b is not shifted to its original value */ + } + /* after another iteration: + * a = 00000010 + * which is the polynomial modulo + */ + + mpz_swap(r, am); + mpz_clear(am); + mpz_clear(bm); +} + +/** + * Step 3 of the various fx() functions: + * XOR the key into the SHA1 IV + */ +static void step3(prf_t *prf, u_char k[K_LENGTH], u_char payload[PAYLOAD_LENGTH], + u_int8_t h[HASH_SIZE_SHA1]) +{ + /* use the keyed hasher to build the hash */ + prf->set_key(prf, chunk_create(k, sizeof(k))); + prf->get_bytes(prf, chunk_create(payload, sizeof(payload)), h); +} + +/** + * Step 4 of the various fx() functions: + * Polynomial whiten calculations + */ +static void step4(u_char x[HASH_SIZE_SHA1]) +{ + mpz_t xm, am, bm, gm; + + mpz_init(xm); + mpz_init(am); + mpz_init(bm); + mpz_init(gm); + + mpz_import(xm, sizeof(x), 1, 1, 1, 0, x); + mpz_import(am, sizeof(a), 1, 1, 1, 0, a); + mpz_import(bm, sizeof(b), 1, 1, 1, 0, b); + mpz_import(gm, sizeof(g), 1, 1, 1, 0, g); + + mpz_mul_poly(xm, am, xm); + mpz_add_poly(xm, bm, xm); + mpz_mod_poly(xm, xm, gm); + + mpz_export(x, NULL, 1, sizeof(x), 1, 0, xm); + + mpz_clear(xm); + mpz_clear(am); + mpz_clear(bm); + mpz_clear(gm); +} + +/** + * Calculation function for f2(), f3(), f4() + */ +static void fx(prf_t *prf, u_char f, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char out[MAC_LENGTH]) +{ + u_char payload[PAYLOAD_LENGTH]; + u_char h[HASH_SIZE_SHA1]; + u_char i; + + for (i = 0; i < 2; i++) + { + memset(payload, 0x5c, sizeof(payload)); + payload[11] ^= f; + memxor(payload + 12, fmk.ptr, fmk.len); + memxor(payload + 24, rand, sizeof(rand)); + + payload[3] ^= i; + payload[19] ^= i; + payload[35] ^= i; + payload[51] ^= i; + + step3(prf, k, payload, h); + step4(h); + memcpy(out + i * 8, h, 8); + } +} + +/** + * Calculation function of f1() and f1star() + */ +static void f1x(prf_t *prf, u_int8_t f, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH], + u_char amf[AMF_LENGTH], u_char mac[MAC_LENGTH]) +{ + /* generate MAC = f1(FMK, SQN, RAND, AMF) + * K is loaded into hashers IV; FMK, RAND, SQN, AMF are XORed in a 512-bit + * payload which gets hashed + */ + u_char payload[PAYLOAD_LENGTH]; + u_char h[HASH_SIZE_SHA1]; + + memset(payload, 0x5c, sizeof(payload)); + payload[11] ^= f; + memxor(payload + 12, fmk.ptr, fmk.len); + memxor(payload + 16, rand, sizeof(rand)); + memxor(payload + 34, sqn, sizeof(sqn)); + memxor(payload + 42, amf, sizeof(amf)); + + step3(prf, k, payload, h); + step4(h); + memcpy(mac, h, sizeof(mac)); +} + +/** + * Calculation function of f5() and f5star() + */ +static void f5x(prf_t *prf, u_char f, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char ak[AK_LENGTH]) +{ + u_char payload[PAYLOAD_LENGTH]; + u_char h[HASH_SIZE_SHA1]; + + memset(payload, 0x5c, sizeof(payload)); + payload[11] ^= f; + memxor(payload + 12, fmk.ptr, fmk.len); + memxor(payload + 16, rand, sizeof(rand)); + + step3(prf, k, payload, h); + step4(h); + memcpy(ak, h, sizeof(ak)); +} + +/** + * Calculate MAC from RAND, SQN, AMF using K + */ +static void f1(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH], + u_char amf[AMF_LENGTH], u_char mac[MAC_LENGTH]) +{ + f1x(this->prf, F1, k, rand, sqn, amf, mac); + DBG3(DBG_IKE, "MAC %b", mac, sizeof(mac)); +} + +/** + * Calculate MACS from RAND, SQN, AMF using K + */ +static void f1star(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH], + u_char amf[AMF_LENGTH], u_char macs[MAC_LENGTH]) +{ + f1x(this->prf, F1STAR, k, rand, sqn, amf, macs); + DBG3(DBG_IKE, "MACS %b", macs, sizeof(macs)); +} + +/** + * Calculate RES from RAND using K + */ +static void f2(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char res[RES_LENGTH]) +{ + fx(this->prf, F2, k, rand, res); + DBG3(DBG_IKE, "RES %b", res, sizeof(res)); +} + +/** + * Calculate CK from RAND using K + */ +static void f3(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char ck[CK_LENGTH]) +{ + fx(this->prf, F3, k, rand, ck); + DBG3(DBG_IKE, "CK %b", ck, sizeof(ck)); +} + +/** + * Calculate IK from RAND using K + */ +static void f4(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char ik[IK_LENGTH]) +{ + fx(this->prf, F4, k, rand, ik); + DBG3(DBG_IKE, "IK %b", ik, sizeof(ik)); +} + +/** + * Calculate AK from a RAND using K + */ +static void f5(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char ak[AK_LENGTH]) +{ + f5x(this->prf, F5, k, rand, ak); + DBG3(DBG_IKE, "AK %b", ak, sizeof(ak)); +} + +/** + * Calculate AKS from a RAND using K + */ +static void f5star(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char aks[AK_LENGTH]) +{ + f5x(this->prf, F5STAR, k, rand, aks); + DBG3(DBG_IKE, "AKS %b", aks, sizeof(aks)); +} + + /** * Implementation of eap_aka_3gpp2_functions_t.destroy. */ static void destroy(private_eap_aka_3gpp2_functions_t *this) { + this->prf->destroy(this->prf); free(this); } @@ -41,10 +368,27 @@ static void destroy(private_eap_aka_3gpp2_functions_t *this) */ eap_aka_3gpp2_functions_t *eap_aka_3gpp2_functions_create() { - private_eap_aka_3gpp2_functions_t *this = malloc_thing(private_eap_aka_3gpp2_functions_t); + private_eap_aka_3gpp2_functions_t *this; + + this = malloc_thing(private_eap_aka_3gpp2_functions_t); + this->public.f1 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH], u_char amf[AMF_LENGTH], u_char mac[MAC_LENGTH]))f1; + this->public.f1star = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH], u_char amf[AMF_LENGTH], u_char macs[MAC_LENGTH]))f1star; + this->public.f2 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char res[RES_LENGTH]))f2; + this->public.f3 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char ck[CK_LENGTH]))f3; + this->public.f4 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char ik[IK_LENGTH]))f4; + this->public.f5 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char ak[AK_LENGTH]))f5; + this->public.f5star = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char aks[AK_LENGTH]))f5star; this->public.destroy = (void(*)(eap_aka_3gpp2_functions_t*))destroy; + this->prf = lib->crypto->create_prf(lib->crypto, PRF_KEYED_SHA1); + if (!this->prf) + { + DBG1(DBG_CFG, "%N not supported, unable to use 3GPP2 algorithm", + pseudo_random_function_names, PRF_KEYED_SHA1); + free(this); + return NULL; + } return &this->public; } diff --git a/src/charon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.h b/src/charon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.h index a836ccceb6..e870e1e35a 100644 --- a/src/charon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.h +++ b/src/charon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.h @@ -24,6 +24,19 @@ #include #include +#define RAND_LENGTH 16 +#define RES_LENGTH 16 +#define SQN_LENGTH 6 +#define K_LENGTH 16 +#define MAC_LENGTH 8 +#define CK_LENGTH 16 +#define IK_LENGTH 16 +#define AK_LENGTH 6 +#define AMF_LENGTH 2 +#define FMK_LENGTH 4 +#define AUTN_LENGTH (SQN_LENGTH + AMF_LENGTH + MAC_LENGTH) +#define AUTS_LENGTH (SQN_LENGTH + MAC_LENGTH) + typedef struct eap_aka_3gpp2_functions_t eap_aka_3gpp2_functions_t; /** @@ -31,6 +44,78 @@ typedef struct eap_aka_3gpp2_functions_t eap_aka_3gpp2_functions_t; */ struct eap_aka_3gpp2_functions_t { + /** + * Calculate MAC from RAND, SQN, AMF using K. + * + * @param k secret key K + * @param rand random value rand + * @param sqn sequence number + * @param amf authentication management field + * @param mac buffer receiving mac MAC + */ + void (*f1)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH], + u_char amf[AMF_LENGTH], u_char mac[MAC_LENGTH]); + + /** + * Calculate MACS from RAND, SQN, AMF using K + * + * @param k secret key K + * @param rand random value RAND + * @param sqn sequence number + * @param amf authentication management field + * @param macs buffer receiving resynchronization mac MACS + */ + void (*f1star)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH], + u_char amf[AMF_LENGTH], u_char macs[MAC_LENGTH]); + + /** + * Calculate RES from RAND using K + * + * @param k secret key K + * @param rand random value RAND + * @param macs buffer receiving result RES + */ + void (*f2)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char res[RES_LENGTH]); + /** + * Calculate CK from RAND using K + * + * @param k secret key K + * @param rand random value RAND + * @param macs buffer receiving encryption key CK + */ + void (*f3)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char ck[CK_LENGTH]); + /** + * Calculate IK from RAND using K + * + * @param k secret key K + * @param rand random value RAND + * @param macs buffer receiving integrity key IK + */ + void (*f4)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char ik[IK_LENGTH]); + /** + * Calculate AK from a RAND using K + * + * @param k secret key K + * @param rand random value RAND + * @param macs buffer receiving anonymity key AK + */ + void (*f5)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char ak[AK_LENGTH]); + /** + * Calculate AKS from a RAND using K + * + * @param k secret key K + * @param rand random value RAND + * @param macs buffer receiving resynchronization anonymity key AKS + */ + void (*f5star)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], + u_char rand[RAND_LENGTH], u_char aks[AK_LENGTH]); + /** * Destroy a eap_aka_3gpp2_functions_t. */ @@ -39,6 +124,8 @@ struct eap_aka_3gpp2_functions_t { /** * Create a eap_aka_3gpp2_functions instance. + * + * @return function set, NULL on error */ eap_aka_3gpp2_functions_t *eap_aka_3gpp2_functions_create(); diff --git a/src/charon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_plugin.c b/src/charon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_plugin.c index b4df96d8dc..7055f2554c 100644 --- a/src/charon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_plugin.c +++ b/src/charon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_plugin.c @@ -71,6 +71,11 @@ plugin_t *plugin_create() this->public.plugin.destroy = (void(*)(plugin_t*))destroy; this->functions = eap_aka_3gpp2_functions_create(); + if (!this->functions) + { + free(this); + return NULL; + } this->card = eap_aka_3gpp2_card_create(this->functions); this->provider = eap_aka_3gpp2_provider_create(this->functions);