int rsn_cipher_put_suites(u8 *pos, int ciphers) { int num_suites = 0; if (ciphers & WPA_CIPHER_CCMP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; num_suites++; } if (ciphers & WPA_CIPHER_GCMP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP); pos += RSN_SELECTOR_LEN; num_suites++; } if (ciphers & WPA_CIPHER_TKIP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); pos += RSN_SELECTOR_LEN; num_suites++; } if (ciphers & WPA_CIPHER_NONE) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); pos += RSN_SELECTOR_LEN; num_suites++; } return num_suites; }
static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len, int pairwise_cipher, int group_cipher, int key_mgmt) { u8 *pos, *len; u32 suite; if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN) return -1; pos = wpa_ie; *pos++ = WLAN_EID_VENDOR_SPECIFIC; len = pos++; /* to be filled */ WPA_PUT_BE24(pos, OUI_WFA); pos += 3; *pos++ = HS20_OSEN_OUI_TYPE; /* Group Data Cipher Suite */ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); if (suite == 0) { wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", group_cipher); return -1; } RSN_SELECTOR_PUT(pos, suite); pos += RSN_SELECTOR_LEN; /* Pairwise Cipher Suite Count and List */ WPA_PUT_LE16(pos, 1); pos += 2; suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); if (suite == 0 || (!wpa_cipher_valid_pairwise(pairwise_cipher) && pairwise_cipher != WPA_CIPHER_NONE)) { wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", pairwise_cipher); return -1; } RSN_SELECTOR_PUT(pos, suite); pos += RSN_SELECTOR_LEN; /* AKM Suite Count and List */ WPA_PUT_LE16(pos, 1); pos += 2; RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN); pos += RSN_SELECTOR_LEN; *len = pos - len - 1; WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); return pos - wpa_ie; }
u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid) { u8 *len; u16 capab; if (!hapd->conf->osen) return eid; *eid++ = WLAN_EID_VENDOR_SPECIFIC; len = eid++; /* to be filled */ WPA_PUT_BE24(eid, OUI_WFA); eid += 3; *eid++ = HS20_OSEN_OUI_TYPE; /* Group Data Cipher Suite */ RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); eid += RSN_SELECTOR_LEN; /* Pairwise Cipher Suite Count and List */ WPA_PUT_LE16(eid, 1); eid += 2; RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP); eid += RSN_SELECTOR_LEN; /* AKM Suite Count and List */ WPA_PUT_LE16(eid, 1); eid += 2; RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN); eid += RSN_SELECTOR_LEN; /* RSN Capabilities */ capab = 0; if (hapd->conf->wmm_enabled) { /* 4 PTKSA replay counters when using WMM */ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); } #ifdef CONFIG_IEEE80211W if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { capab |= WPA_CAPABILITY_MFPC; if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) capab |= WPA_CAPABILITY_MFPR; } #endif /* CONFIG_IEEE80211W */ WPA_PUT_LE16(eid, capab); eid += 2; *len = eid - len - 1; return eid; }
int wpa_cipher_put_suites(u8 *start, int ciphers) { u8 *pos = start; if (ciphers & WPA_CIPHER_CCMP) { RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); pos += WPA_SELECTOR_LEN; } if (ciphers & WPA_CIPHER_TKIP) { RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); pos += WPA_SELECTOR_LEN; } if (ciphers & WPA_CIPHER_NONE) { RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); pos += WPA_SELECTOR_LEN; } return (pos - start) / RSN_SELECTOR_LEN; }
static u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len) { *pos++ = WLAN_EID_VENDOR_SPECIFIC; *pos++ = RSN_SELECTOR_LEN + data_len; RSN_SELECTOR_PUT(pos, kde); pos += RSN_SELECTOR_LEN; os_memcpy(pos, data, data_len); pos += data_len; return pos; }
/* derive mesh temporal key from pmk */ int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta) { u8 *ptr; u8 *min, *max; u16 min_lid, max_lid; size_t nonce_len = sizeof(sta->my_nonce); size_t lid_len = sizeof(sta->my_lid); u8 *myaddr = wpa_s->own_addr; u8 *peer = sta->addr; /* 2 nonces, 2 linkids, akm suite, 2 mac addrs */ u8 context[64 + 4 + 4 + 12]; ptr = context; if (os_memcmp(sta->my_nonce, sta->peer_nonce, nonce_len) < 0) { min = sta->my_nonce; max = sta->peer_nonce; } else { min = sta->peer_nonce; max = sta->my_nonce; } os_memcpy(ptr, min, nonce_len); os_memcpy(ptr + nonce_len, max, nonce_len); ptr += 2 * nonce_len; if (sta->my_lid < sta->peer_lid) { min_lid = host_to_le16(sta->my_lid); max_lid = host_to_le16(sta->peer_lid); } else { min_lid = host_to_le16(sta->peer_lid); max_lid = host_to_le16(sta->my_lid); } os_memcpy(ptr, &min_lid, lid_len); os_memcpy(ptr + lid_len, &max_lid, lid_len); ptr += 2 * lid_len; /* SAE */ RSN_SELECTOR_PUT(ptr, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP)); ptr += 4; if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) { min = myaddr; max = peer; } else { min = peer; max = myaddr; } os_memcpy(ptr, min, ETH_ALEN); os_memcpy(ptr + ETH_ALEN, max, ETH_ALEN); sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "Temporal Key Derivation", context, sizeof(context), sta->mtk, sizeof(sta->mtk)); return 0; }
int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos) { u8 *pos = *argpos; *pos++ = WLAN_EID_VENDOR_SPECIFIC; *pos++ = RSN_SELECTOR_LEN + 3; RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_OCI); pos += RSN_SELECTOR_LEN; *argpos = pos; return ocv_insert_oci(ci, argpos); }
static void mesh_rsn_derive_aek(struct mesh_rsn *rsn, struct sta_info *sta) { u8 *myaddr = rsn->wpa_s->own_addr; u8 *peer = sta->addr; u8 *addr1 = peer, *addr2 = myaddr; u8 context[AES_BLOCK_SIZE]; /* SAE */ RSN_SELECTOR_PUT(context, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP)); if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) { addr1 = myaddr; addr2 = peer; } os_memcpy(context + 4, addr1, ETH_ALEN); os_memcpy(context + 10, addr2, ETH_ALEN); sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "AEK Derivation", context, sizeof(context), sta->aek, sizeof(sta->aek)); }
static int wpa_supplicant_process_smk_m2( struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, size_t extra_len, int ver) { struct wpa_peerkey *peerkey; struct wpa_eapol_ie_parse kde; struct wpa_ie_data ie; int cipher; struct rsn_ie_hdr *hdr; u8 *pos; wpa_printf(MSG_DEBUG, "RSN: Received SMK M2"); if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for " "the current network"); return -1; } if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) < 0) { wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2"); return -1; } if (kde.rsn_ie == NULL || kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN) { wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in " "SMK M2"); return -1; } wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR, MAC2STR(kde.mac_addr)); if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) { wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK " "M2"); return -1; } if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2"); return -1; } cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher; if (cipher & WPA_CIPHER_CCMP) { wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey"); cipher = WPA_CIPHER_CCMP; } else if (cipher & WPA_CIPHER_TKIP) { wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey"); cipher = WPA_CIPHER_TKIP; } else { wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2"); wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr, STK_MUI_SMK, STK_ERR_CPHR_NS, ver); return -1; } /* TODO: find existing entry and if found, use that instead of adding * a new one; how to handle the case where both ends initiate at the * same time? */ peerkey = os_zalloc(sizeof(*peerkey)); if (peerkey == NULL) return -1; os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN); os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN); os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len); peerkey->rsnie_i_len = kde.rsn_ie_len; peerkey->cipher = cipher; #ifdef CONFIG_IEEE80211W if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 | WPA_KEY_MGMT_PSK_SHA256)) peerkey->use_sha256 = 1; #endif /* CONFIG_IEEE80211W */ if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to get random data for PNonce"); wpa_supplicant_peerkey_free(sm, peerkey); return -1; } hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p; hdr->elem_id = WLAN_EID_RSN; WPA_PUT_LE16(hdr->version, RSN_VERSION); pos = (u8 *) (hdr + 1); /* Group Suite can be anything for SMK RSN IE; receiver will just * ignore it. */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; /* Include only the selected cipher in pairwise cipher suite */ WPA_PUT_LE16(pos, 1); pos += 2; if (cipher == WPA_CIPHER_CCMP) RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); else if (cipher == WPA_CIPHER_TKIP) RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); pos += RSN_SELECTOR_LEN; hdr->len = (pos - peerkey->rsnie_p) - 2; peerkey->rsnie_p_len = pos - peerkey->rsnie_p; wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake", peerkey->rsnie_p, peerkey->rsnie_p_len); wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey); peerkey->next = sm->peerkey; sm->peerkey = peerkey; return 0; }
/** * wpa_sm_stkstart - Send EAPOL-Key Request for STK handshake (STK M1) * @sm: Pointer to WPA state machine data from wpa_sm_init() * @peer: MAC address of the peer STA * Returns: 0 on success, or -1 on failure * * Send an EAPOL-Key Request to the current authenticator to start STK * handshake with the peer. */ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) { size_t rlen, kde_len; struct wpa_eapol_key *req; int key_info, ver; u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos; u16 count; struct rsn_ie_hdr *hdr; struct wpa_peerkey *peerkey; struct wpa_ie_data ie; if (sm->proto != WPA_PROTO_RSN || !sm->ptk_set || !sm->peerkey_enabled) return -1; if (sm->ap_rsn_ie && wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &ie) == 0 && !(ie.capabilities & WPA_CAPABILITY_PEERKEY_ENABLED)) { wpa_printf(MSG_DEBUG, "RSN: Current AP does not support STK"); return -1; } if (sm->pairwise_cipher == WPA_CIPHER_CCMP) ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; else ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; if (wpa_sm_get_bssid(sm, bssid) < 0) { wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key " "SMK M1"); return -1; } /* TODO: find existing entry and if found, use that instead of adding * a new one */ peerkey = os_zalloc(sizeof(*peerkey)); if (peerkey == NULL) return -1; peerkey->initiator = 1; os_memcpy(peerkey->addr, peer, ETH_ALEN); #ifdef CONFIG_IEEE80211W if (wpa_key_mgmt_sha256(sm->key_mgmt)) peerkey->use_sha256 = 1; #endif /* CONFIG_IEEE80211W */ /* SMK M1: * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce, * MIC=MIC, DataKDs=(RSNIE_I, MAC_P KDE)) */ hdr = (struct rsn_ie_hdr *) peerkey->rsnie_i; hdr->elem_id = WLAN_EID_RSN; WPA_PUT_LE16(hdr->version, RSN_VERSION); pos = (u8 *) (hdr + 1); /* Group Suite can be anything for SMK RSN IE; receiver will just * ignore it. */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; count_pos = pos; pos += 2; count = 0; if (sm->allowed_pairwise_cipher & WPA_CIPHER_CCMP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; count++; } if (sm->allowed_pairwise_cipher & WPA_CIPHER_TKIP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); pos += RSN_SELECTOR_LEN; count++; } WPA_PUT_LE16(count_pos, count); hdr->len = (pos - peerkey->rsnie_i) - 2; peerkey->rsnie_i_len = pos - peerkey->rsnie_i; wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake", peerkey->rsnie_i, peerkey->rsnie_i_len); kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN; rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, sizeof(*req) + kde_len, &rlen, (void *) &req); if (rbuf == NULL) { wpa_supplicant_peerkey_free(sm, peerkey); return -1; } req->type = EAPOL_KEY_TYPE_RSN; key_info = WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE | WPA_KEY_INFO_REQUEST | ver; WPA_PUT_BE16(req->key_info, key_info); WPA_PUT_BE16(req->key_length, 0); os_memcpy(req->replay_counter, sm->request_counter, WPA_REPLAY_COUNTER_LEN); inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to get random data for INonce"); os_free(rbuf); wpa_supplicant_peerkey_free(sm, peerkey); return -1; } os_memcpy(req->key_nonce, peerkey->inonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake", req->key_nonce, WPA_NONCE_LEN); WPA_PUT_BE16(req->key_data_length, (u16) kde_len); pos = (u8 *) (req + 1); /* Initiator RSN IE */ pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len); /* Peer MAC address KDE */ wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN); wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer " MACSTR ")", MAC2STR(peer)); wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL, rbuf, rlen, req->key_mic); peerkey->next = sm->peerkey; sm->peerkey = peerkey; return 0; }
static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, int pairwise_cipher, int group_cipher, int key_mgmt) { u8 *pos; struct wpa_ie_hdr *hdr; u32 suite; if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) return -1; hdr = (struct wpa_ie_hdr *) wpa_ie; hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); WPA_PUT_LE16(hdr->version, WPA_VERSION); pos = (u8 *) (hdr + 1); suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher); if (suite == 0) { wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", group_cipher); return -1; } RSN_SELECTOR_PUT(pos, suite); pos += WPA_SELECTOR_LEN; *pos++ = 1; *pos++ = 0; suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher); if (suite == 0 || (!wpa_cipher_valid_pairwise(pairwise_cipher) && pairwise_cipher != WPA_CIPHER_NONE)) { wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", pairwise_cipher); return -1; } RSN_SELECTOR_PUT(pos, suite); pos += WPA_SELECTOR_LEN; *pos++ = 1; *pos++ = 0; if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); } else if (key_mgmt == WPA_KEY_MGMT_PSK) { RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM); } else { wpa_printf(MSG_WARNING, "Invalid key management type (%d).", key_mgmt); return -1; } pos += WPA_SELECTOR_LEN; /* WPA Capabilities; use defaults, so no need to include it */ hdr->len = (pos - wpa_ie) - 2; WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); return pos - wpa_ie; }
static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, int pairwise_cipher, int group_cipher, int key_mgmt, int mgmt_group_cipher, struct wpa_sm *sm) { #ifndef CONFIG_NO_WPA2 u8 *pos; struct rsn_ie_hdr *hdr; u16 capab; u32 suite; if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) { wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", (unsigned long) rsn_ie_len); return -1; } hdr = (struct rsn_ie_hdr *) rsn_ie; hdr->elem_id = WLAN_EID_RSN; WPA_PUT_LE16(hdr->version, RSN_VERSION); pos = (u8 *) (hdr + 1); suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); if (suite == 0) { wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", group_cipher); return -1; } RSN_SELECTOR_PUT(pos, suite); pos += RSN_SELECTOR_LEN; *pos++ = 1; *pos++ = 0; suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); if (suite == 0 || (!wpa_cipher_valid_pairwise(pairwise_cipher) && pairwise_cipher != WPA_CIPHER_NONE)) { wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", pairwise_cipher); return -1; } RSN_SELECTOR_PUT(pos, suite); pos += RSN_SELECTOR_LEN; *pos++ = 1; *pos++ = 0; if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); } else if (key_mgmt == WPA_KEY_MGMT_PSK) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM); #ifdef CONFIG_IEEE80211R } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_SAE } else if (key_mgmt == WPA_KEY_MGMT_SAE) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); #endif /* CONFIG_SAE */ } else { wpa_printf(MSG_WARNING, "Invalid key management type (%d).", key_mgmt); return -1; } pos += RSN_SELECTOR_LEN; /* RSN Capabilities */ capab = 0; #ifdef CONFIG_IEEE80211W if (sm->mfp) capab |= WPA_CAPABILITY_MFPC; if (sm->mfp == 2) capab |= WPA_CAPABILITY_MFPR; #endif /* CONFIG_IEEE80211W */ WPA_PUT_LE16(pos, capab); pos += 2; if (sm->cur_pmksa) { /* PMKID Count (2 octets, little endian) */ *pos++ = 1; *pos++ = 0; /* PMKID */ os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); pos += PMKID_LEN; } #ifdef CONFIG_IEEE80211W if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { if (!sm->cur_pmksa) { /* PMKID Count */ WPA_PUT_LE16(pos, 0); pos += 2; } /* Management Group Cipher Suite */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); pos += RSN_SELECTOR_LEN; } #endif /* CONFIG_IEEE80211W */ hdr->len = (pos - rsn_ie) - 2; WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); return pos - rsn_ie; #else /* CONFIG_NO_WPA2 */ return -1; #endif /* CONFIG_NO_WPA2 */ }
/** * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth/ReAssoc Request * @sm: Pointer to WPA state machine data from wpa_sm_init() * @len: Buffer for returning the length of the IEs * @anonce: ANonce or %NULL if not yet available * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List * @kck: 128-bit KCK for MIC or %NULL if no MIC is used * @kck_len: KCK length in octets * @target_ap: Target AP address * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL * @ric_ies_len: Length of ric_ies buffer in octets * @ap_mdie: Mobility Domain IE from the target AP * Returns: Pointer to buffer with IEs or %NULL on failure * * Caller is responsible for freeing the returned buffer with os_free(); */ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, const u8 *anonce, const u8 *pmk_name, const u8 *kck, size_t kck_len, const u8 *target_ap, const u8 *ric_ies, size_t ric_ies_len, const u8 *ap_mdie) { size_t buf_len; u8 *buf, *pos, *ftie_len, *ftie_pos; struct rsn_mdie *mdie; struct rsn_ftie *ftie; struct rsn_ie_hdr *rsnie; u16 capab; sm->ft_completed = 0; buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + 2 + sm->r0kh_id_len + ric_ies_len + 100; buf = os_zalloc(buf_len); if (buf == NULL) return NULL; pos = buf; /* RSNIE[PMKR0Name/PMKR1Name] */ rsnie = (struct rsn_ie_hdr *) pos; rsnie->elem_id = WLAN_EID_RSN; WPA_PUT_LE16(rsnie->version, RSN_VERSION); pos = (u8 *) (rsnie + 1); /* Group Suite Selector */ if (!wpa_cipher_valid_group(sm->group_cipher)) { wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)", sm->group_cipher); os_free(buf); return NULL; } RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, sm->group_cipher)); pos += RSN_SELECTOR_LEN; /* Pairwise Suite Count */ WPA_PUT_LE16(pos, 1); pos += 2; /* Pairwise Suite List */ if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) { wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)", sm->pairwise_cipher); os_free(buf); return NULL; } RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, sm->pairwise_cipher)); pos += RSN_SELECTOR_LEN; /* Authenticated Key Management Suite Count */ WPA_PUT_LE16(pos, 1); pos += 2; /* Authenticated Key Management Suite List */ if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE) RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); else { wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)", sm->key_mgmt); os_free(buf); return NULL; } pos += RSN_SELECTOR_LEN; /* RSN Capabilities */ capab = 0; #ifdef CONFIG_IEEE80211W if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) capab |= WPA_CAPABILITY_MFPC; #endif /* CONFIG_IEEE80211W */ WPA_PUT_LE16(pos, capab); pos += 2; /* PMKID Count */ WPA_PUT_LE16(pos, 1); pos += 2; /* PMKID List [PMKR0Name/PMKR1Name] */ os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN); pos += WPA_PMK_NAME_LEN; #ifdef CONFIG_IEEE80211W if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { /* Management Group Cipher Suite */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); pos += RSN_SELECTOR_LEN; } #endif /* CONFIG_IEEE80211W */ rsnie->len = (pos - (u8 *) rsnie) - 2; /* MDIE */ *pos++ = WLAN_EID_MOBILITY_DOMAIN; *pos++ = sizeof(*mdie); mdie = (struct rsn_mdie *) pos; pos += sizeof(*mdie); os_memcpy(mdie->mobility_domain, sm->mobility_domain, MOBILITY_DOMAIN_ID_LEN); mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] : sm->mdie_ft_capab; /* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */ ftie_pos = pos; *pos++ = WLAN_EID_FAST_BSS_TRANSITION; ftie_len = pos++; ftie = (struct rsn_ftie *) pos; pos += sizeof(*ftie); os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN); if (anonce) os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN); if (kck) { /* R1KH-ID sub-element in third FT message */ *pos++ = FTIE_SUBELEM_R1KH_ID; *pos++ = FT_R1KH_ID_LEN; os_memcpy(pos, sm->r1kh_id, FT_R1KH_ID_LEN); pos += FT_R1KH_ID_LEN; } /* R0KH-ID sub-element */ *pos++ = FTIE_SUBELEM_R0KH_ID; *pos++ = sm->r0kh_id_len; os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len); pos += sm->r0kh_id_len; *ftie_len = pos - ftie_len - 1; if (ric_ies) { /* RIC Request */ os_memcpy(pos, ric_ies, ric_ies_len); pos += ric_ies_len; } if (kck) { /* * IEEE Std 802.11r-2008, 11A.8.4 * MIC shall be calculated over: * non-AP STA MAC address * Target AP MAC address * Transaction seq number (5 for ReassocReq, 3 otherwise) * RSN IE * MDIE * FTIE (with MIC field set to 0) * RIC-Request (if present) */ /* Information element count */ ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies, ric_ies_len); if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5, ((u8 *) mdie) - 2, 2 + sizeof(*mdie), ftie_pos, 2 + *ftie_len, (u8 *) rsnie, 2 + rsnie->len, ric_ies, ric_ies_len, ftie->mic) < 0) { wpa_printf(MSG_INFO, "FT: Failed to calculate MIC"); os_free(buf); return NULL; } } *len = pos - buf; return buf; }
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, const u8 *pmkid) { struct rsn_ie_hdr *hdr; int num_suites, res; u8 *pos, *count; u16 capab; u32 suite; hdr = (struct rsn_ie_hdr *) buf; hdr->elem_id = WLAN_EID_RSN; WPA_PUT_LE16(hdr->version, RSN_VERSION); pos = (u8 *) (hdr + 1); suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group); if (suite == 0) { wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", conf->wpa_group); return -1; } RSN_SELECTOR_PUT(pos, suite); pos += RSN_SELECTOR_LEN; num_suites = 0; count = pos; pos += 2; #ifdef CONFIG_RSN_TESTING if (rsn_testing) { RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1)); pos += RSN_SELECTOR_LEN; num_suites++; } #endif /* CONFIG_RSN_TESTING */ res = rsn_cipher_put_suites(pos, conf->rsn_pairwise); num_suites += res; pos += res * RSN_SELECTOR_LEN; #ifdef CONFIG_RSN_TESTING if (rsn_testing) { RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2)); pos += RSN_SELECTOR_LEN; num_suites++; } #endif /* CONFIG_RSN_TESTING */ if (num_suites == 0) { wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", conf->rsn_pairwise); return -1; } WPA_PUT_LE16(count, num_suites); num_suites = 0; count = pos; pos += 2; #ifdef CONFIG_RSN_TESTING if (rsn_testing) { RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1)); pos += RSN_SELECTOR_LEN; num_suites++; } #endif /* CONFIG_RSN_TESTING */ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); pos += RSN_SELECTOR_LEN; num_suites++; } if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); pos += RSN_SELECTOR_LEN; num_suites++; } #ifdef CONFIG_IEEE80211R if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); pos += RSN_SELECTOR_LEN; num_suites++; } if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); pos += RSN_SELECTOR_LEN; num_suites++; } #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); pos += RSN_SELECTOR_LEN; num_suites++; } if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); pos += RSN_SELECTOR_LEN; num_suites++; } #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_SAE if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); pos += RSN_SELECTOR_LEN; num_suites++; } if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); pos += RSN_SELECTOR_LEN; num_suites++; } #endif /* CONFIG_SAE */ #ifdef CONFIG_RSN_TESTING if (rsn_testing) { RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2)); pos += RSN_SELECTOR_LEN; num_suites++; } #endif /* CONFIG_RSN_TESTING */ if (num_suites == 0) { wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", conf->wpa_key_mgmt); return -1; } WPA_PUT_LE16(count, num_suites); /* RSN Capabilities */ capab = 0; if (conf->rsn_preauth) capab |= WPA_CAPABILITY_PREAUTH; if (conf->peerkey) capab |= WPA_CAPABILITY_PEERKEY_ENABLED; if (conf->wmm_enabled) { /* 4 PTKSA replay counters when using WMM */ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); } #ifdef CONFIG_IEEE80211W if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { capab |= WPA_CAPABILITY_MFPC; if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) capab |= WPA_CAPABILITY_MFPR; } #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_RSN_TESTING if (rsn_testing) capab |= BIT(8) | BIT(14) | BIT(15); #endif /* CONFIG_RSN_TESTING */ WPA_PUT_LE16(pos, capab); pos += 2; if (pmkid) { if (pos + 2 + PMKID_LEN > buf + len) return -1; /* PMKID Count */ WPA_PUT_LE16(pos, 1); pos += 2; os_memcpy(pos, pmkid, PMKID_LEN); pos += PMKID_LEN; } #ifdef CONFIG_IEEE80211W if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { if (pos + 2 + 4 > buf + len) return -1; if (pmkid == NULL) { /* PMKID Count */ WPA_PUT_LE16(pos, 0); pos += 2; } /* Management Group Cipher Suite */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); pos += RSN_SELECTOR_LEN; } #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_RSN_TESTING if (rsn_testing) { /* * Fill in any defined fields and add extra data to the end of * the element. */ int pmkid_count_set = pmkid != NULL; if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) pmkid_count_set = 1; /* PMKID Count */ WPA_PUT_LE16(pos, 0); pos += 2; if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) { /* Management Group Cipher Suite */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); pos += RSN_SELECTOR_LEN; } os_memset(pos, 0x12, 17); pos += 17; } #endif /* CONFIG_RSN_TESTING */ hdr->len = (pos - buf) - 2; return pos - buf; }
static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len) { struct wpa_ie_hdr *hdr; int num_suites; u8 *pos, *count; u32 suite; hdr = (struct wpa_ie_hdr *) buf; hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); WPA_PUT_LE16(hdr->version, WPA_VERSION); pos = (u8 *) (hdr + 1); suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group); if (suite == 0) { wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", conf->wpa_group); return -1; } RSN_SELECTOR_PUT(pos, suite); pos += WPA_SELECTOR_LEN; count = pos; pos += 2; num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise); if (num_suites == 0) { wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", conf->wpa_pairwise); return -1; } pos += num_suites * WPA_SELECTOR_LEN; WPA_PUT_LE16(count, num_suites); num_suites = 0; count = pos; pos += 2; if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); pos += WPA_SELECTOR_LEN; num_suites++; } if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); pos += WPA_SELECTOR_LEN; num_suites++; } if (num_suites == 0) { wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", conf->wpa_key_mgmt); return -1; } WPA_PUT_LE16(count, num_suites); /* WPA Capabilities; use defaults, so no need to include it */ hdr->len = (pos - buf) - 2; return pos - buf; }
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, const u8 *pmkid) { struct rsn_ie_hdr *hdr; int num_suites; u8 *pos, *count; u16 capab; hdr = (struct rsn_ie_hdr *) buf; hdr->elem_id = WLAN_EID_RSN; WPA_PUT_LE16(hdr->version, RSN_VERSION); pos = (u8 *) (hdr + 1); if (conf->wpa_group == WPA_CIPHER_CCMP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); } else if (conf->wpa_group == WPA_CIPHER_TKIP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); } else if (conf->wpa_group == WPA_CIPHER_WEP104) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104); } else if (conf->wpa_group == WPA_CIPHER_WEP40) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40); } else { wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", conf->wpa_group); return -1; } pos += RSN_SELECTOR_LEN; num_suites = 0; count = pos; pos += 2; if (conf->rsn_pairwise & WPA_CIPHER_CCMP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; num_suites++; } if (conf->rsn_pairwise & WPA_CIPHER_TKIP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); pos += RSN_SELECTOR_LEN; num_suites++; } if (conf->rsn_pairwise & WPA_CIPHER_NONE) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); pos += RSN_SELECTOR_LEN; num_suites++; } if (num_suites == 0) { wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", conf->rsn_pairwise); return -1; } WPA_PUT_LE16(count, num_suites); num_suites = 0; count = pos; pos += 2; if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); pos += RSN_SELECTOR_LEN; num_suites++; } if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); pos += RSN_SELECTOR_LEN; num_suites++; } #ifdef CONFIG_IEEE80211R if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); pos += RSN_SELECTOR_LEN; num_suites++; } if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); pos += RSN_SELECTOR_LEN; num_suites++; } #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); pos += RSN_SELECTOR_LEN; num_suites++; } if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); pos += RSN_SELECTOR_LEN; num_suites++; } #endif /* CONFIG_IEEE80211W */ if (num_suites == 0) { wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", conf->wpa_key_mgmt); return -1; } WPA_PUT_LE16(count, num_suites); /* RSN Capabilities */ capab = 0; if (conf->rsn_preauth) capab |= WPA_CAPABILITY_PREAUTH; if (conf->peerkey) capab |= WPA_CAPABILITY_PEERKEY_ENABLED; if (conf->wmm_enabled) { /* 4 PTKSA replay counters when using WMM */ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); } #ifdef CONFIG_IEEE80211W if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { capab |= WPA_CAPABILITY_MFPC; if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) capab |= WPA_CAPABILITY_MFPR; } #endif /* CONFIG_IEEE80211W */ WPA_PUT_LE16(pos, capab); pos += 2; if (pmkid) { if (pos + 2 + PMKID_LEN > buf + len) return -1; /* PMKID Count */ WPA_PUT_LE16(pos, 1); pos += 2; os_memcpy(pos, pmkid, PMKID_LEN); pos += PMKID_LEN; } #ifdef CONFIG_IEEE80211W if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { if (pos + 2 + 4 > buf + len) return -1; if (pmkid == NULL) { /* PMKID Count */ WPA_PUT_LE16(pos, 0); pos += 2; } /* Management Group Cipher Suite */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); pos += RSN_SELECTOR_LEN; } #endif /* CONFIG_IEEE80211W */ hdr->len = (pos - buf) - 2; return pos - buf; }
/* insert AMPE and encrypted MIC at @ie. * @mesh_rsn: mesh RSN context * @sta: STA we're sending to * @cat: pointer to category code in frame header. * @buf: wpabuf to add encrypted AMPE and MIC to. * */ int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta, const u8 *cat, struct wpabuf *buf) { struct ieee80211_ampe_ie *ampe; u8 const *ie = wpabuf_head_u8(buf) + wpabuf_len(buf); u8 *ampe_ie = NULL, *mic_ie = NULL, *mic_payload; const u8 *aad[] = { rsn->wpa_s->own_addr, sta->addr, cat }; const size_t aad_len[] = { ETH_ALEN, ETH_ALEN, ie - cat }; int ret = 0; if (AES_BLOCK_SIZE + 2 + sizeof(*ampe) + 2 > wpabuf_tailroom(buf)) { wpa_printf(MSG_ERROR, "protect frame: buffer too small"); return -EINVAL; } ampe_ie = os_zalloc(2 + sizeof(*ampe)); if (!ampe_ie) { wpa_printf(MSG_ERROR, "protect frame: out of memory"); return -ENOMEM; } mic_ie = os_zalloc(2 + AES_BLOCK_SIZE); if (!mic_ie) { wpa_printf(MSG_ERROR, "protect frame: out of memory"); ret = -ENOMEM; goto free; } /* IE: AMPE */ ampe_ie[0] = WLAN_EID_AMPE; ampe_ie[1] = sizeof(*ampe); ampe = (struct ieee80211_ampe_ie *) (ampe_ie + 2); RSN_SELECTOR_PUT(ampe->selected_pairwise_suite, wpa_cipher_to_suite(WPA_PROTO_RSN, WPA_CIPHER_CCMP)); os_memcpy(ampe->local_nonce, sta->my_nonce, 32); os_memcpy(ampe->peer_nonce, sta->peer_nonce, 32); /* incomplete: see 13.5.4 */ /* TODO: static mgtk for now since we don't support rekeying! */ os_memcpy(ampe->mgtk, rsn->mgtk, 16); /* TODO: Populate Key RSC */ /* expire in 13 decades or so */ os_memset(ampe->key_expiration, 0xff, 4); /* IE: MIC */ mic_ie[0] = WLAN_EID_MIC; mic_ie[1] = AES_BLOCK_SIZE; wpabuf_put_data(buf, mic_ie, 2); /* MIC field is output ciphertext */ /* encrypt after MIC */ mic_payload = (u8 *) wpabuf_put(buf, 2 + sizeof(*ampe) + AES_BLOCK_SIZE); if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + sizeof(*ampe), 3, aad, aad_len, mic_payload)) { wpa_printf(MSG_ERROR, "protect frame: failed to encrypt"); ret = -ENOMEM; goto free; } free: os_free(ampe_ie); os_free(mic_ie); return ret; }