]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Remove fr_sim_crypto_mac_verify and use fr_sim_crypto_sign_packet
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sun, 10 Dec 2017 12:56:54 +0000 (12:56 +0000)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sun, 10 Dec 2017 12:56:54 +0000 (12:56 +0000)
for signing and validating

src/modules/rlm_eap/lib/sim/crypto.c
src/modules/rlm_eap/lib/sim/encode.c
src/modules/rlm_eap/lib/sim/sim_proto.h
src/modules/rlm_eap/types/rlm_eap_aka/rlm_eap_aka.c
src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c

index 6ef090d5aebf8fdd58ce17e50a195c5efb0236b7..bb6b68520c77dc6bda8de95eb7d0c0b18a2043ac 100644 (file)
@@ -35,92 +35,53 @@ RCSID("$Id$")
 #include <freeradius-devel/eap.sim.h>
 #include <openssl/evp.h>
 
-/*
- * calculate the MAC for the EAP message, given the key.
- * The "extra" will be appended to the EAP message and included in the
- * HMAC.
+/** Locate the start of the AT_MAC value in the buffer
  *
+ * @param[in,out] data to search for the AT_MAC in.
+ * @param[in] data_len size of the data.
+ * @return
+ *     - 1 if we couldn't find a MAC.
+ *     - 0 if we found and zeroed out the mac field.
+ *     - -1 if the field was malformed.
  */
-int fr_sim_crypto_mac_verify(TALLOC_CTX *ctx, fr_dict_attr_t const *root,
-                            VALUE_PAIR *reply,
-                            eap_packet_raw_t *packet,
-                            uint8_t key[EAP_SIM_AUTH_SIZE],
-                            uint8_t *extra, int extra_len, uint8_t calc_mac[20])
+static int fr_sim_find_mac(uint8_t const **out, uint8_t *data, size_t data_len)
 {
-       int                     ret;
-       uint8_t                 *buffer;
-       int                     elen, len;
-       VALUE_PAIR              *mac;
-       fr_dict_attr_t const    *da;
-
-       da = fr_dict_attr_child_by_num(root, FR_EAP_SIM_MAC);
-       if (!da) {
-               fr_strerror_printf("Missing definition for EAP-SIM-MAC");
-               return -1;
-       }
-
-       mac = fr_pair_find_by_da(reply, da, TAG_ANY);
-       if (!mac || mac->vp_length != 16) {
-               /* can't check a packet with no AT_MAC attribute */
-               return 0;
-       }
-
-       /* make copy big enough for everything */
-       elen = (packet->length[0] * 256) + packet->length[1];
-       len = elen + extra_len;
-
-       buffer = talloc_array(ctx, uint8_t, len);
-       if (!buffer) return 0;
-
-       memcpy(buffer, packet, elen);
-       memcpy(buffer + elen, extra, extra_len);
+       uint8_t *p = data, *end = p + data_len;
+       size_t len;
+
+       *out = NULL;
+
+       p += 3; /* Skip header */
+       while ((p + 2) < end) {
+               if (p[0] == FR_SIM_MAC) {
+                       len = p[1] << 2;
+                       if ((p + len) > end) {
+                               fr_strerror_printf("Malformed AT_MAC: Length (%zu) exceeds buffer (%zu)", len, end - p);
+                               return -1;
+                       }
 
-       /*
-        * now look for the AT_MAC attribute in the copy of the buffer
-        * and make sure that the checksum is zero.
-        *
-        */
-       {
-               uint8_t *attr;
-
-               /* first attribute is 8 bytes into the EAP packet.
-                * 4 bytes for EAP, 1 for type, 1 for subtype, 2 reserved.
-                */
-               attr = buffer + 8;
-               while (attr < (buffer + elen)) {
-                       if (attr[0] == FR_EAP_SIM_MAC) {
-                               /* zero the data portion, after making sure
-                                * the size is >=5. Maybe future versions.
-                                * will use more bytes, so be liberal.
-                                */
-                               if (attr[1] < 5) {
-                                       ret = 0;
-                                       goto done;
-                               }
-                               memset(&attr[4], 0, (attr[1]-1)*4);
+                       if (len != SIM_MAC_SIZE) {
+                               fr_strerror_printf("Malformed AT_MAC: Length (%zu) incorrect (%u)",
+                                                  len, SIM_MAC_SIZE);
+                               return -1;
                        }
-                       /* advance the pointer */
-                       attr += attr[1]*4;
+                       *out = p + 4;
+
+                       return 0;
                }
+               p += p[1] << 2;         /* Advance */
        }
 
-       /* now, HMAC-SHA1 it with the key. */
-       fr_hmac_sha1(calc_mac, buffer, len, key, 16);
+       fr_strerror_printf("No MAC attribute found");
 
-       ret = memcmp(&mac->vp_strvalue, calc_mac, 16) == 0 ? 1 : 0;             //-V512
- done:
-       talloc_free(buffer);
-       return ret;
+       return 1;
 }
 
-
 /** Append AT_MAC to the end a packet.
  *
  * Run SHA1 digest over a fake EAP header, the entire SIM packet and any extra HMAC data,
  * writing out the complete AT_HMAC and digest to out.
  *
- * @note out must point to (buff) end - 20.  It's easier to write AT_MAC last.
- *
  * @param[out] out             Where to write the digest.
  * @param[in] eap_packet       to extract header values from.
  * @param[in] key              to use to sign the packet.
@@ -129,19 +90,22 @@ int fr_sim_crypto_mac_verify(TALLOC_CTX *ctx, fr_dict_attr_t const *root,
  *                             (may be NULL).
  * @param[in] hmac_extra_len   Length of hmac_extra.
  * @return
- *     - <= 0 on failure.
+ *     - < 0 on failure.
+ *     - 0 if there's no MAC attribute to verify.
  *     - > 0 the number of bytes written to out.
  */
-ssize_t fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet,
+ssize_t fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet, bool zero_mac,
                                  uint8_t const *key, size_t const key_len,
                                  uint8_t const *hmac_extra, size_t const hmac_extra_len)
 {
        EVP_MD_CTX              *md_ctx = NULL;
-       EVP_MD const            *md = EVP_get_digestbyname("SHA1");
+       EVP_MD const            *md = EVP_sha1();
        EVP_PKEY                *pkey;
 
        uint8_t                 digest[SHA1_DIGEST_LENGTH];
        size_t                  digest_len = 0;
+       uint8_t const           *mac;
+       uint8_t                 *p = eap_packet->type.data, *end = p + eap_packet->type.length;
 
        eap_packet_raw_t        eap_hdr;
        uint16_t                packet_len;
@@ -184,11 +148,51 @@ ssize_t fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet,
        }
 
        /*
-        *      Digest most of the packet, except the bit at
-        *      the end we're leaving for the HMAC.
+        *      Digest the packet up to the AT_MAC, value, then
+        *      ingest 16 bytes of zero.
+        */
+       if (zero_mac) {
+               switch (fr_sim_find_mac(&mac, p, end - p)) {
+               case 0:
+               {
+                       uint8_t zero[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+                       /*
+                        *      Digest everything up to the hash
+                        *      part of the AT_MAC, including
+                        *      AT_MAC header and reserved bytes.
+                        */
+                       if (EVP_DigestSignUpdate(md_ctx, p, mac - p) != 1) {
+                               tls_strerror_printf(true, "Failed digesting header");
+                               goto error;
+                       }
+                       p += mac - p;
+
+                       /*
+                        *      Feed in 16 bytes of zeroes to
+                        *      simulated the zeroed out Mac.
+                        */
+                       if (EVP_DigestSignUpdate(md_ctx, zero, sizeof(zero)) != 1) {
+                               tls_strerror_printf(true, "Failed zeroes mac");
+                               goto error;
+                       }
+                       p += sizeof(zero);
+               }
+                       break;
+
+               case 1:
+                       return 0;
+
+               case -1:
+                       rad_assert(0);  /* Should have been checked by encoder or decoder */
+                       goto error;
+               }
+       }
+
+       /*
+        *      Digest the rest of the packet.
         */
-       FR_PROTO_HEX_DUMP("hmac input sim_body", eap_packet->type.data, eap_packet->type.length);
-       if (EVP_DigestSignUpdate(md_ctx, eap_packet->type.data, eap_packet->type.length) != 1) {
+       if (EVP_DigestSignUpdate(md_ctx, p, end - p) != 1) {
                tls_strerror_printf(true, "Failed digesting body");
                goto error;
        }
@@ -584,11 +588,11 @@ int fr_sim_crypto_kdf_1_umts(fr_sim_keys_t *keys)
  */
 void fr_sim_crypto_keys_log(REQUEST *request, fr_sim_keys_t *keys)
 {
-       RDEBUG3("Key data from AuC/static vectors");
+       RDEBUG3("Cryptographic inputs");
 
        RINDENT();
        RHEXDUMP_INLINE(L_DBG_LVL_3, keys->identity, keys->identity_len,
-                       "identity     :");
+                       "Identity     :");
        switch (keys->vector_type) {
        case SIM_VECTOR_GSM:
        {
index 4f25a45cf16786195b77e8806354e2d56be24a41..739418c10c833aea404978f3e9ea46307c93d566 100644 (file)
@@ -972,7 +972,7 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty
 
        unsigned int            id, eap_code;
 
-       uint8_t                 *buff, *p, *end;
+       uint8_t                 *buff, *p, *end, *hmac = NULL;
        size_t                  len = 0;
        ssize_t                 slen;
 
@@ -998,22 +998,15 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty
        }
        subtype = vp->vp_uint16;
 
-       vp = fr_pair_find_by_child_num(to_encode, parent, FR_EAP_ID, TAG_ANY);
-       id = vp ? vp->vp_uint32 : ((int)getpid() & 0xff);
-
        vp = fr_pair_find_by_child_num(to_encode, parent, FR_EAP_CODE, TAG_ANY);
        eap_code = vp ? vp->vp_uint32 : FR_EAP_CODE_REQUEST;
 
-       vp = fr_pair_find_by_child_num(to_encode, parent, FR_EAP_SIM_MAC, TAG_ANY);
-       if (vp) do_hmac = true;
-
        /*
         *      Fill in some bits in the EAP packet
         *
         *      These are needed even if we're sending an almost empty packet.
         */
        if (eap_packet->code != FR_EAP_CODE_SUCCESS) eap_packet->code = eap_code;
-       eap_packet->id = (id & 0xff);
        eap_packet->type.num = type;
 
        /*
@@ -1041,12 +1034,32 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty
 
        MEM(p = buff = talloc_zero_array(eap_packet, uint8_t, 1024));   /* We'll shrink this later */
        end = p + talloc_array_length(p);
-       if (do_hmac) end -= SIM_CALC_MAC_SIZE;
 
        *p++ = subtype;                 /* Subtype */
        *p++ = 0;                       /* Reserved (0) */
        *p++ = 0;                       /* Reserved (1) */
 
+       /*
+        *      Add space in the packet for AT_MAC
+        */
+       vp = fr_pair_find_by_child_num(to_encode, parent, FR_EAP_SIM_MAC, TAG_ANY);
+       if (vp) {
+               if ((end - p) < SIM_MAC_SIZE) {
+                       fr_strerror_printf("Insufficient space to store AT_MAC");
+                       return -1;
+               }
+
+               do_hmac = true;
+
+               *p++ = FR_SIM_MAC;
+               *p++ = (SIM_MAC_SIZE >> 2);
+               *p++ = 0x00;
+               *p++ = 0x00;
+               hmac = p;
+               memset(p, 0, 16);
+               p += 16;
+       }
+
        /*
         *      Encode all the things...
         */
@@ -1069,26 +1082,12 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty
         *      Calculate a SHA1-HMAC over the complete EAP packet
         */
        if (do_hmac) {
-#ifndef NDEBUG
-               uint8_t *start = p;
-#endif
-
-               /*
-                *      We left some room earlier...
-                */
-               *p++ = FR_SIM_MAC;
-               *p++ = (SIM_CALC_MAC_SIZE >> 2);
-               *p++ = 0x00;
-               *p++ = 0x00;
-
-               slen = fr_sim_crypto_sign_packet(p, eap_packet,
-                                                keys->k_aut, keys->k_aut_len,
+               slen = fr_sim_crypto_sign_packet(hmac, eap_packet, false,
+                                                keys->k_aut, keys->k_aut_len,
                                                 keys->vector_type == SIM_VECTOR_GSM ? keys->gsm.nonce_mt : NULL,
                                                 keys->vector_type == SIM_VECTOR_GSM ? sizeof(keys->gsm.nonce_mt) : 0);
                if (slen < 0) goto error;
-
-               eap_packet->type.length += SIM_CALC_MAC_SIZE;
-               FR_PROTO_HEX_DUMP("hmac attribute", start, (p - start) + slen);
+               FR_PROTO_HEX_DUMP("hmac attribute", hmac - 4, SIM_MAC_SIZE);
        }
        FR_PROTO_HEX_DUMP("sim packet", buff, eap_packet->type.length);
 
index 13c1ea7fc19ab7f8f5b67e9c5e2599f3ef55a80f..8b3099e6ccded31248a84a3c507b46e489d692bd 100644 (file)
@@ -222,19 +222,10 @@ int               fr_sim_global_init(void);
 /*
  *     crypto.c
  */
-ssize_t                fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet,
+ssize_t                fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet, bool zero_mac,
                                          uint8_t const *key, size_t const key_len,
                                          uint8_t const *hmac_extra, size_t const hmac_extra_len);
 
-int            fr_sim_crypto_mac_verify(TALLOC_CTX *ctx, fr_dict_attr_t const *root,
-                                        VALUE_PAIR *rvps,
-                                        eap_packet_raw_t *packet,
-                                        uint8_t key[8],
-                                        uint8_t *extra, int extra_len,
-                                        uint8_t calc_mac[20])
-                                        CC_BOUNDED(__size__, 3, 8, 8)
-                                        CC_BOUNDED(__size__, 6, 20, 20);
-
 int            fr_sim_crypto_kdf_0_gsm(fr_sim_keys_t *keys);
 
 int            fr_sim_crypto_kdf_0_umts(fr_sim_keys_t *keys);
index b016719f239c711e5f00329e6df4d20e1263d803..94019825c3bf30954cbda8cbd25b13f7438f4b46 100644 (file)
@@ -415,7 +415,7 @@ static int process_eap_aka_challenge(eap_session_t *eap_session, VALUE_PAIR *vps
        ssize_t                 slen;
        VALUE_PAIR              *vp = NULL, *mac;
 
-       mac = fr_pair_find_by_child_num(vps, dict_aka_root, FR_EAP_AKA_RES, TAG_ANY);
+       mac = fr_pair_find_by_child_num(vps, dict_aka_root, FR_EAP_AKA_MAC, TAG_ANY);
        if (!mac) {
                REDEBUG("Missing AT_MAC attribute");
                return -1;
index b53c28ffddd27d69eafcca77f765252b9f43b8b6..4ac0b6619781abcb67f6b5477b16e827464e3438 100644 (file)
@@ -366,13 +366,15 @@ static int process_eap_sim_start(eap_session_t *eap_session, VALUE_PAIR *vps)
  */
 static int process_eap_sim_challenge(eap_session_t *eap_session, VALUE_PAIR *vps)
 {
-       REQUEST *request = eap_session->request;
-       eap_sim_session_t *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
+       REQUEST                 *request = eap_session->request;
+       eap_sim_session_t       *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
 
-       uint8_t sres_cat[SIM_VECTOR_GSM_SRES_SIZE * 3];
-       uint8_t *p = sres_cat;
+       uint8_t                 sres_cat[SIM_VECTOR_GSM_SRES_SIZE * 3];
+       uint8_t                 *p = sres_cat;
 
-       uint8_t calc_mac[SIM_CALC_MAC_SIZE];
+       uint8_t                 calc_mac[SIM_MAC_SIZE];
+       ssize_t                 slen;
+       VALUE_PAIR              *mac;
 
        memcpy(p, eap_sim_session->keys.gsm.vector[0].sres, SIM_VECTOR_GSM_SRES_SIZE);
        p += SIM_VECTOR_GSM_SRES_SIZE;
@@ -380,30 +382,36 @@ static int process_eap_sim_challenge(eap_session_t *eap_session, VALUE_PAIR *vps
        p += SIM_VECTOR_GSM_SRES_SIZE;
        memcpy(p, eap_sim_session->keys.gsm.vector[2].sres, SIM_VECTOR_GSM_SRES_SIZE);
 
-       /*
-        *      Verify the MAC, now that we have all the keys
-        */
-       if (fr_sim_crypto_mac_verify(eap_session, dict_sim_root, vps,
-                                    (eap_packet_raw_t *)eap_session->this_round->response->packet,
-                                    eap_sim_session->keys.k_aut,
-                                    sres_cat, sizeof(sres_cat), calc_mac)) {
+       mac = fr_pair_find_by_child_num(vps, dict_aka_root, FR_EAP_AKA_RES, TAG_ANY);
+       if (!mac) {
+               REDEBUG("Missing AT_MAC attribute");
+               return -1;
+       }
+       if (mac->vp_length != SIM_MAC_SIZE) {
+               REDEBUG("AT_MAC incorrect length, expected %u bytes got %zu bytes",
+                       SIM_MAC_SIZE, mac->vp_length);
+               return -1;
+       }
+
+       slen = fr_sim_crypto_sign_packet(calc_mac, eap_session->this_round->response, true,
+                                        eap_sim_session->keys.k_aut, sizeof(eap_sim_session->keys.k_aut),
+                                        NULL, 0);
+       if (slen < 0) {
+               RPEDEBUG("Failed calculating MAC");
+               return -1;
+       }
+
+       if (slen == 0) {
+               REDEBUG("Missing AT_MAC attribute in packet buffer");
+               return -1;
+       }
+
+       if (memcmp(mac->vp_octets, calc_mac, sizeof(calc_mac)) == 0) {
                RDEBUG2("MAC check succeed");
        } else {
-               int i, j;
-               char macline[20*3];
-               char *m = macline;
-
-               for (i = 0, j = 0; i < SIM_CALC_MAC_SIZE; i++) {
-                       if (j == 4) {
-                               *m++ = '_';
-                               j=0;
-                       }
-                       j++;
-
-                       sprintf(m, "%02x", calc_mac[i]);
-                       m = m + strlen(m);
-               }
-               REDEBUG("Calculated MAC (%s) did not match", macline);
+               REDEBUG("MAC checked failed");
+               RHEXDUMP_INLINE(L_DBG_LVL_2, mac->vp_octets, SIM_MAC_SIZE, "Received");
+               RHEXDUMP_INLINE(L_DBG_LVL_2, calc_mac, SIM_MAC_SIZE, "Expected");
                return -1;
        }
 
@@ -441,6 +449,7 @@ static rlm_rcode_t mod_process(UNUSED void *arg, eap_session_t *eap_session)
        vps = eap_session->request->packet->vps;
 
        fr_pair_cursor_init(&cursor, &request->packet->vps);
+       fr_pair_cursor_last(&cursor);
 
        ret = fr_sim_decode(eap_session->request,
                            &cursor,
@@ -449,9 +458,9 @@ static rlm_rcode_t mod_process(UNUSED void *arg, eap_session_t *eap_session)
                            &ctx);
        if (ret < 0) return 0;
 
-       vp = fr_pair_cursor_next(&cursor);
+       vp = fr_pair_cursor_current(&cursor);
        if (vp && RDEBUG_ENABLED2) {
-               RDEBUG2("Eecoded EAP-SIM attributes");
+               RDEBUG2("Decoded EAP-SIM attributes");
                rdebug_pair_list(L_DBG_LVL_2, request, vp, NULL);
        }