static int check_frame_protection(struct candidate *cand, struct ieee80211_mgmt_frame *mgmt, int len, struct info_elems *elems) { unsigned char *clear_ampe_ie; struct info_elems ies_parsed; unsigned short ampe_ie_len, cat_to_mic_len; int r; unsigned int* key_expiration_p; assert(len && cand && mgmt); clear_ampe_ie = malloc(sizeof(struct ampe_ie) + 2); if (!clear_ampe_ie) { sae_debug(AMPE_DEBUG_KEYS, "Verify frame: out of memory\n"); return -1; } if (!elems->mic || elems->mic_len != MIC_IE_BODY_SIZE) { sae_debug(AMPE_DEBUG_KEYS, "Verify frame: invalid MIC\n"); free(clear_ampe_ie); return -1; } /* * ampe_ie_len is the length of the ciphertext (the encrypted * AMPE IE) and it needs to be inferred from the total frame * size */ ampe_ie_len = len - (elems->mic + elems->mic_len - (unsigned char *)mgmt); /* * cat_to_mic_len is the length of the contents of the frame * from the category (inclusive) to the mic (exclusive) */ cat_to_mic_len = elems->mic - 2 - (unsigned char *) &mgmt->action; r = siv_decrypt(&cand->sivctx, elems->mic + elems->mic_len, clear_ampe_ie, ampe_ie_len, elems->mic, 3, cand->peer_mac, ETH_ALEN, cand->my_mac, ETH_ALEN, &mgmt->action, cat_to_mic_len); sae_debug(AMPE_DEBUG_KEYS, "Checking protection to " MACSTR " from " MACSTR "\n", MAC2STR(cand->my_mac), MAC2STR(cand->peer_mac)); sae_debug(AMPE_DEBUG_KEYS, "Len checking cat-to-mic len:%d ampe ie full length: %d\n", cat_to_mic_len, ampe_ie_len); sae_hexdump(AMPE_DEBUG_KEYS, "SIV- Got AAD[3]: ", (unsigned char *) &mgmt->action, cat_to_mic_len); if (r != 1) { sae_debug(AMPE_DEBUG_KEYS, "Protection check failed\n"); free(clear_ampe_ie); return -1; } sae_hexdump(AMPE_DEBUG_KEYS, "AMPE IE: ", clear_ampe_ie, ampe_ie_len); parse_ies(clear_ampe_ie, ampe_ie_len, &ies_parsed); if (memcmp(ies_parsed.ampe->peer_nonce, null_nonce, 32) != 0 && memcmp(ies_parsed.ampe->peer_nonce, cand->my_nonce, 32) != 0) { sae_hexdump(AMPE_DEBUG_KEYS, "IE peer_nonce ", ies_parsed.ampe->peer_nonce, 32); sae_debug(AMPE_DEBUG_KEYS, "Unexpected nonce\n"); free(clear_ampe_ie); return -1; } memcpy(cand->peer_nonce, ies_parsed.ampe->local_nonce, 32); memcpy(cand->mgtk, ies_parsed.ampe->mgtk, sizeof(cand->mgtk)); sae_hexdump(AMPE_DEBUG_KEYS, "Received mgtk: ", cand->mgtk, sizeof(cand->mgtk)); key_expiration_p = (unsigned int *)ies_parsed.ampe->key_expiration; cand->mgtk_expiration = le32toh(*key_expiration_p); free(clear_ampe_ie); return -1; #undef MIC_IE_BODY_SIZE }
static int check_frame_protection(struct candidate *cand, struct ieee80211_mgmt_frame *mgmt, int len, struct info_elems *elems) { unsigned char *clear_ampe_ie; struct info_elems ies_parsed; struct mesh_node *mesh = cand->conf->mesh; unsigned short ampe_ie_len, cat_to_mic_len; int r; unsigned int* key_expiration_p; u8 ftype = mgmt->action.action_code; u8 *gtkdata, *igtkdata; assert(len && cand && mgmt); if (!elems->mic || elems->mic_len != MIC_IE_BODY_SIZE) { sae_debug(AMPE_DEBUG_KEYS, "Verify frame: invalid MIC\n"); return -1; } /* * ampe_ie_len is the length of the ciphertext (the encrypted * AMPE IE) and it needs to be inferred from the total frame * size */ ampe_ie_len = len - (elems->mic + elems->mic_len - (unsigned char *)mgmt); /* expect at least MGTK + RSC + expiry for open/confirm */ if (ftype != PLINK_CLOSE && ampe_ie_len < 2 + sizeof(struct ampe_ie) + 16 + 8 + 4) { sae_debug(AMPE_DEBUG_KEYS, "Verify frame: AMPE IE too small\n"); return -1; } /* if PMF, then we also need IGTKData */ if (mesh->conf->pmf) { if (ampe_ie_len < 2 + sizeof(struct ampe_ie) + 16 + 8 + 4 + 2 + 6 + 16 /* IGTKData */) { sae_debug(AMPE_DEBUG_KEYS, "Verify frame: AMPE IE missing IGTK\n"); return -1; } } clear_ampe_ie = malloc(ampe_ie_len); if (!clear_ampe_ie) { sae_debug(AMPE_DEBUG_KEYS, "Verify frame: out of memory\n"); return -1; } /* * cat_to_mic_len is the length of the contents of the frame * from the category (inclusive) to the mic (exclusive) */ cat_to_mic_len = elems->mic - 2 - (unsigned char *) &mgmt->action; r = siv_decrypt(&cand->sivctx, elems->mic + elems->mic_len, clear_ampe_ie, ampe_ie_len, elems->mic, 3, cand->peer_mac, ETH_ALEN, cand->my_mac, ETH_ALEN, &mgmt->action, cat_to_mic_len); sae_debug(AMPE_DEBUG_KEYS, "Checking protection to " MACSTR " from " MACSTR "\n", MAC2STR(cand->my_mac), MAC2STR(cand->peer_mac)); sae_debug(AMPE_DEBUG_KEYS, "Len checking cat-to-mic len:%d ampe ie full length: %d\n", cat_to_mic_len, ampe_ie_len); sae_hexdump(AMPE_DEBUG_KEYS, "SIV- Got AAD[3]: ", (unsigned char *) &mgmt->action, cat_to_mic_len); if (r != 1) { sae_debug(AMPE_DEBUG_KEYS, "Protection check failed\n"); free(clear_ampe_ie); return -1; } if (ampe_ie_len != clear_ampe_ie[1] + 2) { sae_debug(AMPE_DEBUG_KEYS, "AMPE -Invalid length (expected %d, got %d)\n", ampe_ie_len, clear_ampe_ie[1] + 2); free(clear_ampe_ie); return -1; } sae_hexdump(AMPE_DEBUG_KEYS, "AMPE IE: ", clear_ampe_ie, ampe_ie_len); parse_ies(clear_ampe_ie, ampe_ie_len, &ies_parsed); if (memcmp(ies_parsed.ampe->peer_nonce, null_nonce, 32) != 0 && memcmp(ies_parsed.ampe->peer_nonce, cand->my_nonce, 32) != 0) { sae_hexdump(AMPE_DEBUG_KEYS, "IE peer_nonce ", ies_parsed.ampe->peer_nonce, 32); sae_debug(AMPE_DEBUG_KEYS, "Unexpected nonce\n"); free(clear_ampe_ie); return -1; } memcpy(cand->peer_nonce, ies_parsed.ampe->local_nonce, 32); gtkdata = ies_parsed.ampe->variable; memcpy(cand->mgtk, gtkdata, sizeof(cand->mgtk)); sae_hexdump(AMPE_DEBUG_KEYS, "Received mgtk: ", cand->mgtk, sizeof(cand->mgtk)); key_expiration_p = (unsigned int *) (gtkdata + 16 + 8); cand->mgtk_expiration = le32toh(*key_expiration_p); igtkdata = gtkdata + 16 + 8 + 4; if (mesh->conf->pmf) { cand->igtk_keyid = le16toh(*(u16 *) igtkdata); igtkdata += 2 + 6; memcpy(cand->igtk, igtkdata, 16); } free(clear_ampe_ie); return -1; #undef MIC_IE_BODY_SIZE }