Handle PRF failures in eap-aka-3gpp2
authorMartin Willi <martin@revosec.ch>
Tue, 10 Jul 2012 13:11:25 +0000 (15:11 +0200)
committerMartin Willi <martin@revosec.ch>
Mon, 16 Jul 2012 12:55:08 +0000 (14:55 +0200)
src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c
src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.c
src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.h
src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c

index 2425833..1bfc39e 100644 (file)
@@ -74,13 +74,19 @@ METHOD(simaka_card_t, get_quintuplet, status_t,
        mac = autn + AKA_SQN_LEN + AKA_AMF_LEN;
 
        /* 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);
        memxor(sqn, ak, AKA_SQN_LEN);
        DBG3(DBG_IKE, "using sqn %b", sqn, AKA_SQN_LEN);
 
        /* 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))
        {
                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 */
        memcpy(this->sqn, sqn, AKA_SQN_LEN);
 
-       /* CK/IK */
-       this->f->f3(this->f, k, rand, ck);
-       this->f->f4(this->f, k, rand, ik);
-       /* calculate RES */
-       this->f->f2(this->f, k, rand, res);
+       /* CK/IK, calculate RES */
+       if (!this->f->f3(this->f, k, rand, ck) ||
+               !this->f->f4(this->f, k, rand, ik) ||
+               !this->f->f2(this->f, k, rand, res))
+       {
+               return FAILED;
+       }
        *res_len = AKA_RES_MAX;
 
        return SUCCESS;
@@ -122,8 +130,11 @@ METHOD(simaka_card_t, resync, bool,
 
        /* AMF is set to zero in resync */
        memset(amf, 0, AKA_AMF_LEN);
-       this->f->f5star(this->f, k, rand, aks);
-       this->f->f1star(this->f, k, rand, this->sqn, amf, macs);
+       if (!this->f->f5star(this->f, k, rand, aks) ||
+               !this->f->f1star(this->f, k, rand, this->sqn, amf, macs))
+       {
+               return FALSE;
+       }
        /* AUTS = SQN xor AKS | MACS */
        memcpy(auts, this->sqn, AKA_SQN_LEN);
        memxor(auts, aks, AKA_AK_LEN);
index d000beb..93ea8d0 100644 (file)
@@ -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:
  * 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])
 {
        /* use the keyed hasher to build the hash */
-       prf->set_key(prf, chunk_create(k, AKA_K_LEN));
-       prf->get_bytes(prf, chunk_create(payload, AKA_PAYLOAD_LEN), h);
+       return prf->set_key(prf, chunk_create(k, AKA_K_LEN)) &&
+                  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()
  */
-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 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[51] ^= i;
 
-               step3(prf, k, payload, h);
+               if (!step3(prf, k, payload, h))
+               {
+                       return FALSE;
+               }
                step4(h);
                memcpy(out + i * 8, h, 8);
        }
+       return TRUE;
 }
 
 /**
  * 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 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 + 42, amf, AKA_AMF_LEN);
 
-       step3(prf, k, payload, h);
+       if (!step3(prf, k, payload, h))
+       {
+               return FALSE;
+       }
        step4(h);
        memcpy(mac, h, AKA_MAC_LEN);
+       return TRUE;
 }
 
 /**
  * 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 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 + 16, rand, AKA_RAND_LEN);
 
-       step3(prf, k, payload, h);
+       if (!step3(prf, k, payload, h))
+       {
+               return FALSE;
+       }
        step4(h);
        memcpy(ak, h, AKA_AK_LEN);
+       return TRUE;
 }
 
 /**
  * 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],
        u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
        u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN])
 {
-       f1x(this->prf, F1, k, rand, sqn, amf, mac);
-       DBG3(DBG_IKE, "MAC %b", mac, AKA_MAC_LEN);
+       if (f1x(this->prf, F1, k, rand, sqn, amf, mac))
+       {
+               DBG3(DBG_IKE, "MAC %b", mac, AKA_MAC_LEN);
+               return TRUE;
+       }
+       return FALSE;
 }
 
 /**
  * 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],
        u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
        u_char amf[AKA_AMF_LEN], u_char macs[AKA_MAC_LEN])
 {
-       f1x(this->prf, F1STAR, k, rand, sqn, amf, macs);
-       DBG3(DBG_IKE, "MACS %b", macs, AKA_MAC_LEN);
+       if (f1x(this->prf, F1STAR, k, rand, sqn, amf, macs))
+       {
+               DBG3(DBG_IKE, "MACS %b", macs, AKA_MAC_LEN);
+               return TRUE;
+       }
+       return FALSE;
 }
 
 /**
  * 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],
        u_char rand[AKA_RAND_LEN], u_char res[AKA_RES_MAX])
 {
-       fx(this->prf, F2, k, rand, res);
-       DBG3(DBG_IKE, "RES %b", res, AKA_RES_MAX);
+       if (fx(this->prf, F2, k, rand, res))
+       {
+               DBG3(DBG_IKE, "RES %b", res, AKA_RES_MAX);
+               return TRUE;
+       }
+       return FALSE;
 }
 
 /**
  * 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],
        u_char rand[AKA_RAND_LEN], u_char ck[AKA_CK_LEN])
 {
-       fx(this->prf, F3, k, rand, ck);
-       DBG3(DBG_IKE, "CK %b", ck, AKA_CK_LEN);
+       if (fx(this->prf, F3, k, rand, ck))
+       {
+               DBG3(DBG_IKE, "CK %b", ck, AKA_CK_LEN);
+               return TRUE;
+       }
+       return FALSE;
 }
 
 /**
  * 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],
        u_char rand[AKA_RAND_LEN], u_char ik[AKA_IK_LEN])
 {
-       fx(this->prf, F4, k, rand, ik);
-       DBG3(DBG_IKE, "IK %b", ik, AKA_IK_LEN);
+       if (fx(this->prf, F4, k, rand, ik))
+       {
+               DBG3(DBG_IKE, "IK %b", ik, AKA_IK_LEN);
+               return TRUE;
+       }
+       return FALSE;
 }
 
 /**
  * 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],
        u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN])
 {
-       f5x(this->prf, F5, k, rand, ak);
-       DBG3(DBG_IKE, "AK %b", ak, AKA_AK_LEN);
+       if (f5x(this->prf, F5, k, rand, ak))
+       {
+               DBG3(DBG_IKE, "AK %b", ak, AKA_AK_LEN);
+               return TRUE;
+       }
+       return FALSE;
 }
 
 /**
  * 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],
        u_char rand[AKA_RAND_LEN], u_char aks[AKA_AK_LEN])
 {
-       f5x(this->prf, F5STAR, k, rand, aks);
-       DBG3(DBG_IKE, "AKS %b", aks, AKA_AK_LEN);
+       if (f5x(this->prf, F5STAR, k, rand, aks))
+       {
+               DBG3(DBG_IKE, "AKS %b", aks, AKA_AK_LEN);
+               return TRUE;
+       }
+       return FALSE;
 }
 
 METHOD(eap_aka_3gpp2_functions_t, destroy, void,
index 855efec..2706da3 100644 (file)
@@ -45,8 +45,9 @@ struct eap_aka_3gpp2_functions_t {
         * @param sqn   sequence number
         * @param amf   authentication management field
         * @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 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 amf   authentication management field
         * @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 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 rand  random value RAND
         * @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]);
        /**
         * Calculate CK from RAND using K
@@ -78,8 +81,9 @@ struct eap_aka_3gpp2_functions_t {
         * @param k             secret key K
         * @param rand  random value RAND
         * @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]);
        /**
         * Calculate IK from RAND using K
@@ -87,8 +91,9 @@ struct eap_aka_3gpp2_functions_t {
         * @param k             secret key K
         * @param rand  random value RAND
         * @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]);
        /**
         * Calculate AK from a RAND using K
@@ -96,8 +101,9 @@ struct eap_aka_3gpp2_functions_t {
         * @param k             secret key K
         * @param rand  random value RAND
         * @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]);
        /**
         * Calculate AKS from a RAND using K
@@ -105,8 +111,9 @@ struct eap_aka_3gpp2_functions_t {
         * @param k             secret key K
         * @param rand  random value RAND
         * @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]);
 
        /**
index 317a820..0be1221 100644 (file)
@@ -107,12 +107,13 @@ METHOD(simaka_provider_t, get_quintuplet, bool,
        DBG3(DBG_IKE, "generated rand %b", rand, AKA_RAND_LEN);
        DBG3(DBG_IKE, "using K %b", k, AKA_K_LEN);
 
-       /* MAC */
-       this->f->f1(this->f, k, rand, this->sqn, amf, mac);
-       /* AK */
-       this->f->f5(this->f, k, rand, ak);
-       /* XRES as expected from client */
-       this->f->f2(this->f, k, rand, xres);
+       /* MAC, AK, XRES as expected from client */
+       if (!this->f->f1(this->f, k, rand, this->sqn, amf, mac) ||
+               !this->f->f5(this->f, k, rand, ak) ||
+               !this->f->f2(this->f, k, rand, xres))
+       {
+               return FALSE;
+       }
        *xres_len = AKA_RES_MAX;
        /* AUTN = (SQN xor AK) || AMF || MAC */
        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);
        DBG3(DBG_IKE, "AUTN %b", autn, AKA_AUTN_LEN);
        /* CK/IK */
-       this->f->f3(this->f, k, rand, ck);
-       this->f->f4(this->f, k, rand, ik);
-
+       if (!this->f->f3(this->f, k, rand, ck) ||
+               !this->f->f4(this->f, k, rand, ik))
+       {
+               return FALSE;
+       }
        return TRUE;
 }
 
@@ -143,12 +146,18 @@ METHOD(simaka_provider_t, resync, bool,
        /* AUTHS = (AK xor SQN) | MAC */
        sqn = auts;
        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);
 
        /* verify XMACS, AMF of zero is used in resynchronization */
        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))
        {
                DBG1(DBG_IKE, "received MACS does not match XMACS");