Handle PRF failures in eap-aka-3gpp2

This commit is contained in:
Martin Willi
2012-07-16 14:55:08 +02:00
parent a564e4ca77
commit ff9e46772f
4 changed files with 124 additions and 57 deletions
@@ -74,13 +74,19 @@ METHOD(simaka_card_t, get_quintuplet, status_t,
mac = autn + AKA_SQN_LEN + AKA_AMF_LEN; mac = autn + AKA_SQN_LEN + AKA_AMF_LEN;
/* XOR anonymity key AK into SQN to decrypt it */ /* XOR anonymity key AK into SQN to decrypt it */
this->f->f5(this->f, k, rand, ak); if (!this->f->f5(this->f, k, rand, ak))
{
return FAILED;
}
DBG3(DBG_IKE, "using ak %b", ak, AKA_AK_LEN); DBG3(DBG_IKE, "using ak %b", ak, AKA_AK_LEN);
memxor(sqn, ak, AKA_SQN_LEN); memxor(sqn, ak, AKA_SQN_LEN);
DBG3(DBG_IKE, "using sqn %b", sqn, AKA_SQN_LEN); DBG3(DBG_IKE, "using sqn %b", sqn, AKA_SQN_LEN);
/* calculate expected MAC and compare against received one */ /* calculate expected MAC and compare against received one */
this->f->f1(this->f, k, rand, sqn, amf, xmac); if (!this->f->f1(this->f, k, rand, sqn, amf, xmac))
{
return FAILED;
}
if (!memeq(mac, xmac, AKA_MAC_LEN)) if (!memeq(mac, xmac, AKA_MAC_LEN))
{ {
DBG1(DBG_IKE, "received MAC does not match XMAC"); DBG1(DBG_IKE, "received MAC does not match XMAC");
@@ -98,11 +104,13 @@ METHOD(simaka_card_t, get_quintuplet, status_t,
/* update stored SQN to the received one */ /* update stored SQN to the received one */
memcpy(this->sqn, sqn, AKA_SQN_LEN); memcpy(this->sqn, sqn, AKA_SQN_LEN);
/* CK/IK */ /* CK/IK, calculate RES */
this->f->f3(this->f, k, rand, ck); if (!this->f->f3(this->f, k, rand, ck) ||
this->f->f4(this->f, k, rand, ik); !this->f->f4(this->f, k, rand, ik) ||
/* calculate RES */ !this->f->f2(this->f, k, rand, res))
this->f->f2(this->f, k, rand, res); {
return FAILED;
}
*res_len = AKA_RES_MAX; *res_len = AKA_RES_MAX;
return SUCCESS; return SUCCESS;
@@ -122,8 +130,11 @@ METHOD(simaka_card_t, resync, bool,
/* AMF is set to zero in resync */ /* AMF is set to zero in resync */
memset(amf, 0, AKA_AMF_LEN); memset(amf, 0, AKA_AMF_LEN);
this->f->f5star(this->f, k, rand, aks); if (!this->f->f5star(this->f, k, rand, aks) ||
this->f->f1star(this->f, k, rand, this->sqn, amf, macs); !this->f->f1star(this->f, k, rand, this->sqn, amf, macs))
{
return FALSE;
}
/* AUTS = SQN xor AKS | MACS */ /* AUTS = SQN xor AKS | MACS */
memcpy(auts, this->sqn, AKA_SQN_LEN); memcpy(auts, this->sqn, AKA_SQN_LEN);
memxor(auts, aks, AKA_AK_LEN); memxor(auts, aks, AKA_AK_LEN);
@@ -170,12 +170,12 @@ static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b)
* Step 3 of the various fx() functions: * Step 3 of the various fx() functions:
* XOR the key into the SHA1 IV * XOR the key into the SHA1 IV
*/ */
static void step3(prf_t *prf, u_char k[AKA_K_LEN], static bool step3(prf_t *prf, u_char k[AKA_K_LEN],
u_char payload[AKA_PAYLOAD_LEN], u_int8_t h[HASH_SIZE_SHA1]) u_char payload[AKA_PAYLOAD_LEN], u_int8_t h[HASH_SIZE_SHA1])
{ {
/* use the keyed hasher to build the hash */ /* use the keyed hasher to build the hash */
prf->set_key(prf, chunk_create(k, AKA_K_LEN)); return prf->set_key(prf, chunk_create(k, AKA_K_LEN)) &&
prf->get_bytes(prf, chunk_create(payload, AKA_PAYLOAD_LEN), h); prf->get_bytes(prf, chunk_create(payload, AKA_PAYLOAD_LEN), h);
} }
/** /**
@@ -211,7 +211,7 @@ static void step4(u_char x[HASH_SIZE_SHA1])
/** /**
* Calculation function for f2(), f3(), f4() * Calculation function for f2(), f3(), f4()
*/ */
static void fx(prf_t *prf, u_char f, u_char k[AKA_K_LEN], static bool fx(prf_t *prf, u_char f, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char out[AKA_MAC_LEN]) u_char rand[AKA_RAND_LEN], u_char out[AKA_MAC_LEN])
{ {
u_char payload[AKA_PAYLOAD_LEN]; u_char payload[AKA_PAYLOAD_LEN];
@@ -230,16 +230,20 @@ static void fx(prf_t *prf, u_char f, u_char k[AKA_K_LEN],
payload[35] ^= i; payload[35] ^= i;
payload[51] ^= i; payload[51] ^= i;
step3(prf, k, payload, h); if (!step3(prf, k, payload, h))
{
return FALSE;
}
step4(h); step4(h);
memcpy(out + i * 8, h, 8); memcpy(out + i * 8, h, 8);
} }
return TRUE;
} }
/** /**
* Calculation function of f1() and f1star() * Calculation function of f1() and f1star()
*/ */
static void f1x(prf_t *prf, u_int8_t f, u_char k[AKA_K_LEN], static bool f1x(prf_t *prf, u_int8_t f, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN], u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN]) u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN])
{ {
@@ -257,15 +261,19 @@ static void f1x(prf_t *prf, u_int8_t f, u_char k[AKA_K_LEN],
memxor(payload + 34, sqn, AKA_SQN_LEN); memxor(payload + 34, sqn, AKA_SQN_LEN);
memxor(payload + 42, amf, AKA_AMF_LEN); memxor(payload + 42, amf, AKA_AMF_LEN);
step3(prf, k, payload, h); if (!step3(prf, k, payload, h))
{
return FALSE;
}
step4(h); step4(h);
memcpy(mac, h, AKA_MAC_LEN); memcpy(mac, h, AKA_MAC_LEN);
return TRUE;
} }
/** /**
* Calculation function of f5() and f5star() * Calculation function of f5() and f5star()
*/ */
static void f5x(prf_t *prf, u_char f, u_char k[AKA_K_LEN], static bool f5x(prf_t *prf, u_char f, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN]) u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN])
{ {
u_char payload[AKA_PAYLOAD_LEN]; u_char payload[AKA_PAYLOAD_LEN];
@@ -276,88 +284,120 @@ static void f5x(prf_t *prf, u_char f, u_char k[AKA_K_LEN],
memxor(payload + 12, fmk.ptr, fmk.len); memxor(payload + 12, fmk.ptr, fmk.len);
memxor(payload + 16, rand, AKA_RAND_LEN); memxor(payload + 16, rand, AKA_RAND_LEN);
step3(prf, k, payload, h); if (!step3(prf, k, payload, h))
{
return FALSE;
}
step4(h); step4(h);
memcpy(ak, h, AKA_AK_LEN); memcpy(ak, h, AKA_AK_LEN);
return TRUE;
} }
/** /**
* Calculate MAC from RAND, SQN, AMF using K * Calculate MAC from RAND, SQN, AMF using K
*/ */
METHOD(eap_aka_3gpp2_functions_t, f1, void, METHOD(eap_aka_3gpp2_functions_t, f1, bool,
private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN], u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN]) u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN])
{ {
f1x(this->prf, F1, k, rand, sqn, amf, mac); if (f1x(this->prf, F1, k, rand, sqn, amf, mac))
DBG3(DBG_IKE, "MAC %b", mac, AKA_MAC_LEN); {
DBG3(DBG_IKE, "MAC %b", mac, AKA_MAC_LEN);
return TRUE;
}
return FALSE;
} }
/** /**
* Calculate MACS from RAND, SQN, AMF using K * Calculate MACS from RAND, SQN, AMF using K
*/ */
METHOD(eap_aka_3gpp2_functions_t, f1star, void, METHOD(eap_aka_3gpp2_functions_t, f1star, bool,
private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN], u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
u_char amf[AKA_AMF_LEN], u_char macs[AKA_MAC_LEN]) u_char amf[AKA_AMF_LEN], u_char macs[AKA_MAC_LEN])
{ {
f1x(this->prf, F1STAR, k, rand, sqn, amf, macs); if (f1x(this->prf, F1STAR, k, rand, sqn, amf, macs))
DBG3(DBG_IKE, "MACS %b", macs, AKA_MAC_LEN); {
DBG3(DBG_IKE, "MACS %b", macs, AKA_MAC_LEN);
return TRUE;
}
return FALSE;
} }
/** /**
* Calculate RES from RAND using K * Calculate RES from RAND using K
*/ */
METHOD(eap_aka_3gpp2_functions_t, f2, void, METHOD(eap_aka_3gpp2_functions_t, f2, bool,
private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char res[AKA_RES_MAX]) u_char rand[AKA_RAND_LEN], u_char res[AKA_RES_MAX])
{ {
fx(this->prf, F2, k, rand, res); if (fx(this->prf, F2, k, rand, res))
DBG3(DBG_IKE, "RES %b", res, AKA_RES_MAX); {
DBG3(DBG_IKE, "RES %b", res, AKA_RES_MAX);
return TRUE;
}
return FALSE;
} }
/** /**
* Calculate CK from RAND using K * Calculate CK from RAND using K
*/ */
METHOD(eap_aka_3gpp2_functions_t, f3, void, METHOD(eap_aka_3gpp2_functions_t, f3, bool,
private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char ck[AKA_CK_LEN]) u_char rand[AKA_RAND_LEN], u_char ck[AKA_CK_LEN])
{ {
fx(this->prf, F3, k, rand, ck); if (fx(this->prf, F3, k, rand, ck))
DBG3(DBG_IKE, "CK %b", ck, AKA_CK_LEN); {
DBG3(DBG_IKE, "CK %b", ck, AKA_CK_LEN);
return TRUE;
}
return FALSE;
} }
/** /**
* Calculate IK from RAND using K * Calculate IK from RAND using K
*/ */
METHOD(eap_aka_3gpp2_functions_t, f4, void, METHOD(eap_aka_3gpp2_functions_t, f4, bool,
private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char ik[AKA_IK_LEN]) u_char rand[AKA_RAND_LEN], u_char ik[AKA_IK_LEN])
{ {
fx(this->prf, F4, k, rand, ik); if (fx(this->prf, F4, k, rand, ik))
DBG3(DBG_IKE, "IK %b", ik, AKA_IK_LEN); {
DBG3(DBG_IKE, "IK %b", ik, AKA_IK_LEN);
return TRUE;
}
return FALSE;
} }
/** /**
* Calculate AK from a RAND using K * Calculate AK from a RAND using K
*/ */
METHOD(eap_aka_3gpp2_functions_t, f5, void, METHOD(eap_aka_3gpp2_functions_t, f5, bool,
private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN]) u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN])
{ {
f5x(this->prf, F5, k, rand, ak); if (f5x(this->prf, F5, k, rand, ak))
DBG3(DBG_IKE, "AK %b", ak, AKA_AK_LEN); {
DBG3(DBG_IKE, "AK %b", ak, AKA_AK_LEN);
return TRUE;
}
return FALSE;
} }
/** /**
* Calculate AKS from a RAND using K * Calculate AKS from a RAND using K
*/ */
METHOD(eap_aka_3gpp2_functions_t, f5star, void, METHOD(eap_aka_3gpp2_functions_t, f5star, bool,
private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char aks[AKA_AK_LEN]) u_char rand[AKA_RAND_LEN], u_char aks[AKA_AK_LEN])
{ {
f5x(this->prf, F5STAR, k, rand, aks); if (f5x(this->prf, F5STAR, k, rand, aks))
DBG3(DBG_IKE, "AKS %b", aks, AKA_AK_LEN); {
DBG3(DBG_IKE, "AKS %b", aks, AKA_AK_LEN);
return TRUE;
}
return FALSE;
} }
METHOD(eap_aka_3gpp2_functions_t, destroy, void, METHOD(eap_aka_3gpp2_functions_t, destroy, void,
@@ -45,8 +45,9 @@ struct eap_aka_3gpp2_functions_t {
* @param sqn sequence number * @param sqn sequence number
* @param amf authentication management field * @param amf authentication management field
* @param mac buffer receiving mac MAC * @param mac buffer receiving mac MAC
* @return TRUE if calculations successful
*/ */
void (*f1)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], bool (*f1)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN], u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN]); u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN]);
@@ -58,8 +59,9 @@ struct eap_aka_3gpp2_functions_t {
* @param sqn sequence number * @param sqn sequence number
* @param amf authentication management field * @param amf authentication management field
* @param macs buffer receiving resynchronization mac MACS * @param macs buffer receiving resynchronization mac MACS
* @return TRUE if calculations successful
*/ */
void (*f1star)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], bool (*f1star)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN], u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
u_char amf[AKA_AMF_LEN], u_char macs[AKA_MAC_LEN]); u_char amf[AKA_AMF_LEN], u_char macs[AKA_MAC_LEN]);
@@ -69,8 +71,9 @@ struct eap_aka_3gpp2_functions_t {
* @param k secret key K * @param k secret key K
* @param rand random value RAND * @param rand random value RAND
* @param res buffer receiving result RES, uses full 128 bit * @param res buffer receiving result RES, uses full 128 bit
* @return TRUE if calculations successful
*/ */
void (*f2)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], bool (*f2)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char res[AKA_RES_MAX]); u_char rand[AKA_RAND_LEN], u_char res[AKA_RES_MAX]);
/** /**
* Calculate CK from RAND using K * Calculate CK from RAND using K
@@ -78,8 +81,9 @@ struct eap_aka_3gpp2_functions_t {
* @param k secret key K * @param k secret key K
* @param rand random value RAND * @param rand random value RAND
* @param macs buffer receiving encryption key CK * @param macs buffer receiving encryption key CK
* @return TRUE if calculations successful
*/ */
void (*f3)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], bool (*f3)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char ck[AKA_CK_LEN]); u_char rand[AKA_RAND_LEN], u_char ck[AKA_CK_LEN]);
/** /**
* Calculate IK from RAND using K * Calculate IK from RAND using K
@@ -87,8 +91,9 @@ struct eap_aka_3gpp2_functions_t {
* @param k secret key K * @param k secret key K
* @param rand random value RAND * @param rand random value RAND
* @param macs buffer receiving integrity key IK * @param macs buffer receiving integrity key IK
* @return TRUE if calculations successful
*/ */
void (*f4)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], bool (*f4)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char ik[AKA_IK_LEN]); u_char rand[AKA_RAND_LEN], u_char ik[AKA_IK_LEN]);
/** /**
* Calculate AK from a RAND using K * Calculate AK from a RAND using K
@@ -96,8 +101,9 @@ struct eap_aka_3gpp2_functions_t {
* @param k secret key K * @param k secret key K
* @param rand random value RAND * @param rand random value RAND
* @param macs buffer receiving anonymity key AK * @param macs buffer receiving anonymity key AK
* @return TRUE if calculations successful
*/ */
void (*f5)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], bool (*f5)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN]); u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN]);
/** /**
* Calculate AKS from a RAND using K * Calculate AKS from a RAND using K
@@ -105,8 +111,9 @@ struct eap_aka_3gpp2_functions_t {
* @param k secret key K * @param k secret key K
* @param rand random value RAND * @param rand random value RAND
* @param macs buffer receiving resynchronization anonymity key AKS * @param macs buffer receiving resynchronization anonymity key AKS
* @return TRUE if calculations successful
*/ */
void (*f5star)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], bool (*f5star)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
u_char rand[AKA_RAND_LEN], u_char aks[AKA_AK_LEN]); u_char rand[AKA_RAND_LEN], u_char aks[AKA_AK_LEN]);
/** /**
@@ -107,12 +107,13 @@ METHOD(simaka_provider_t, get_quintuplet, bool,
DBG3(DBG_IKE, "generated rand %b", rand, AKA_RAND_LEN); DBG3(DBG_IKE, "generated rand %b", rand, AKA_RAND_LEN);
DBG3(DBG_IKE, "using K %b", k, AKA_K_LEN); DBG3(DBG_IKE, "using K %b", k, AKA_K_LEN);
/* MAC */ /* MAC, AK, XRES as expected from client */
this->f->f1(this->f, k, rand, this->sqn, amf, mac); if (!this->f->f1(this->f, k, rand, this->sqn, amf, mac) ||
/* AK */ !this->f->f5(this->f, k, rand, ak) ||
this->f->f5(this->f, k, rand, ak); !this->f->f2(this->f, k, rand, xres))
/* XRES as expected from client */ {
this->f->f2(this->f, k, rand, xres); return FALSE;
}
*xres_len = AKA_RES_MAX; *xres_len = AKA_RES_MAX;
/* AUTN = (SQN xor AK) || AMF || MAC */ /* AUTN = (SQN xor AK) || AMF || MAC */
memcpy(autn, this->sqn, AKA_SQN_LEN); memcpy(autn, this->sqn, AKA_SQN_LEN);
@@ -121,9 +122,11 @@ METHOD(simaka_provider_t, get_quintuplet, bool,
memcpy(autn + AKA_SQN_LEN + AKA_AMF_LEN, mac, AKA_MAC_LEN); memcpy(autn + AKA_SQN_LEN + AKA_AMF_LEN, mac, AKA_MAC_LEN);
DBG3(DBG_IKE, "AUTN %b", autn, AKA_AUTN_LEN); DBG3(DBG_IKE, "AUTN %b", autn, AKA_AUTN_LEN);
/* CK/IK */ /* CK/IK */
this->f->f3(this->f, k, rand, ck); if (!this->f->f3(this->f, k, rand, ck) ||
this->f->f4(this->f, k, rand, ik); !this->f->f4(this->f, k, rand, ik))
{
return FALSE;
}
return TRUE; return TRUE;
} }
@@ -143,12 +146,18 @@ METHOD(simaka_provider_t, resync, bool,
/* AUTHS = (AK xor SQN) | MAC */ /* AUTHS = (AK xor SQN) | MAC */
sqn = auts; sqn = auts;
macs = auts + AKA_SQN_LEN; macs = auts + AKA_SQN_LEN;
this->f->f5star(this->f, k, rand, aks); if (!this->f->f5star(this->f, k, rand, aks))
{
return FALSE;
}
memxor(sqn, aks, AKA_AK_LEN); memxor(sqn, aks, AKA_AK_LEN);
/* verify XMACS, AMF of zero is used in resynchronization */ /* verify XMACS, AMF of zero is used in resynchronization */
memset(amf, 0, AKA_AMF_LEN); memset(amf, 0, AKA_AMF_LEN);
this->f->f1star(this->f, k, rand, sqn, amf, xmacs); if (!this->f->f1star(this->f, k, rand, sqn, amf, xmacs))
{
return FALSE;
}
if (!memeq(macs, xmacs, AKA_MAC_LEN)) if (!memeq(macs, xmacs, AKA_MAC_LEN))
{ {
DBG1(DBG_IKE, "received MACS does not match XMACS"); DBG1(DBG_IKE, "received MACS does not match XMACS");