/** * protect_frame - add in-place the MIC and the (encrypted) AMPE ie to a frame * @cand: The candidate this frame is destined for * @mgmt: The frame, populated with all the information elements up to where the MIC information element should go * @mic_start: Pointer to where the mic and AMPE ies are to be written. Should point to the start of the IE, not the IE body. * @len: On input, the total buffer size that contains this frame. On output, the actual lenght of the frame * including the two information elements added by this function. * * Returns: The zero on success, or some error. */ static int protect_frame(struct candidate *cand, struct ieee80211_mgmt_frame *mgmt, unsigned char *mic_start, int *len) { unsigned char *clear_ampe_ie; unsigned char *ie; unsigned short cat_to_mic_len; assert(mic_start && cand && mgmt && len); #define MIC_IE_BODY_SIZE AES_BLOCK_SIZE if (mic_start + MIC_IE_BODY_SIZE + 2 + sizeof(struct ampe_ie) + 2 - (unsigned char *) mgmt > *len) { sae_debug(AMPE_DEBUG_KEYS, "protect frame: buffer too small\n"); return -EINVAL; } clear_ampe_ie = malloc(sizeof(struct ampe_ie) + 2); if (!clear_ampe_ie) { sae_debug(AMPE_DEBUG_KEYS, "protect frame: out of memory\n"); return -ENOMEM; } /* IE: AMPE */ ie = clear_ampe_ie; *ie++ = IEEE80211_EID_AMPE; *ie++ = sizeof(struct ampe_ie); memcpy(ie, pw_suite_selector, 4); ie += 4; memcpy(ie, cand->my_nonce, 32); ie += 32; memcpy(ie, cand->peer_nonce, 32); ie += 32; memcpy(ie, mgtk_tx, 16); ie += 16; memset(ie, 0, 8); /* TODO: Populate Key RSC */ ie += 8; memset(ie, 0xff, 4); /* expire in 13 decades or so */ ie += 4; /* IE: MIC */ ie = mic_start; *ie++ = IEEE80211_EID_MIC; *ie++ = MIC_IE_BODY_SIZE; cat_to_mic_len = mic_start - (unsigned char *) &mgmt->action; siv_encrypt(&cand->sivctx, clear_ampe_ie, ie + MIC_IE_BODY_SIZE, sizeof(struct ampe_ie) + 2, ie, 3, cand->my_mac, ETH_ALEN, cand->peer_mac, ETH_ALEN, &mgmt->action, cat_to_mic_len); *len = mic_start - (unsigned char *) mgmt + sizeof(struct ampe_ie) + 2 + MIC_IE_BODY_SIZE + 2; sae_debug(AMPE_DEBUG_KEYS, "Protecting frame from " MACSTR " to " MACSTR "\n", MAC2STR(cand->my_mac), MAC2STR(cand->peer_mac)); sae_debug(AMPE_DEBUG_KEYS, "Checking tricky lengths of protected frame %d, %d\n", cat_to_mic_len, sizeof(struct ampe_ie) + 2); sae_hexdump(AMPE_DEBUG_KEYS, "SIV- Put AAD[3]: ", (unsigned char *) &mgmt->action, cat_to_mic_len); free(clear_ampe_ie); return 0; }
/** * protect_frame - add in-place the MIC and the (encrypted) AMPE ie to a frame * @cand: The candidate this frame is destined for * @mgmt: The frame, populated with all the information elements up to where the MIC information element should go * @mic_start: Pointer to where the mic and AMPE ies are to be written. Should point to the start of the IE, not the IE body. * @len: On input, the total buffer size that contains this frame. On output, the actual lenght of the frame * including the two information elements added by this function. * * Returns: The zero on success, or some error. */ static int protect_frame(struct candidate *cand, struct ieee80211_mgmt_frame *mgmt, unsigned char *mic_start, int *len) { unsigned char *clear_ampe_ie; unsigned char *ie; unsigned short cat_to_mic_len; struct mesh_node *mesh = cand->conf->mesh; size_t ampe_ie_len; u8 ftype = mgmt->action.action_code; le16 igtk_keyid; assert(mic_start && cand && mgmt && len); #define MIC_IE_BODY_SIZE AES_BLOCK_SIZE ampe_ie_len = sizeof(struct ampe_ie); if (ftype != PLINK_CLOSE) { /* MGTK + RSC + Exp */ ampe_ie_len += 16 + 8 + 4; if (mesh->conf->pmf) { /* IGTK KeyId + IPN + IGTK */ ampe_ie_len += 2 + 6 + 16; } } if (mic_start + MIC_IE_BODY_SIZE + 2 + 2 + ampe_ie_len - (unsigned char *) mgmt > *len) { sae_debug(AMPE_DEBUG_KEYS, "protect frame: buffer too small\n"); return -EINVAL; } clear_ampe_ie = malloc(ampe_ie_len + 2); if (!clear_ampe_ie) { sae_debug(AMPE_DEBUG_KEYS, "protect frame: out of memory\n"); return -ENOMEM; } /* IE: AMPE */ ie = clear_ampe_ie; *ie++ = IEEE80211_EID_AMPE; *ie++ = ampe_ie_len; memcpy(ie, pw_suite_selector, 4); ie += 4; memcpy(ie, cand->my_nonce, 32); ie += 32; memcpy(ie, cand->peer_nonce, 32); ie += 32; if (ftype != PLINK_CLOSE) { memcpy(ie, mgtk_tx, 16); ie += 16; memset(ie, 0, 8); /* TODO: Populate Key RSC */ ie += 8; memset(ie, 0xff, 4); /* expire in 13 decades or so */ ie += 4; if (mesh->conf->pmf) { igtk_keyid = htole16(mesh->igtk_keyid); memcpy(ie, &igtk_keyid, 2); ie += 2; memcpy(ie, mesh->igtk_ipn, 6); ie += 6; memcpy(ie, mesh->igtk_tx, 16); ie += 16; } } /* IE: MIC */ ie = mic_start; *ie++ = IEEE80211_EID_MIC; *ie++ = MIC_IE_BODY_SIZE; cat_to_mic_len = mic_start - (unsigned char *) &mgmt->action; siv_encrypt(&cand->sivctx, clear_ampe_ie, ie + MIC_IE_BODY_SIZE, ampe_ie_len + 2, ie, 3, cand->my_mac, ETH_ALEN, cand->peer_mac, ETH_ALEN, &mgmt->action, cat_to_mic_len); *len = mic_start - (unsigned char *) mgmt + ampe_ie_len + 2 + MIC_IE_BODY_SIZE + 2; sae_debug(AMPE_DEBUG_KEYS, "Protecting frame from " MACSTR " to " MACSTR "\n", MAC2STR(cand->my_mac), MAC2STR(cand->peer_mac)); sae_debug(AMPE_DEBUG_KEYS, "Checking tricky lengths of protected frame %d, %d\n", cat_to_mic_len, ampe_ie_len + 2); sae_hexdump(AMPE_DEBUG_KEYS, "SIV- Put AAD[3]: ", (unsigned char *) &mgmt->action, cat_to_mic_len); free(clear_ampe_ie); return 0; }