/* $OpenBSD: ieee80211_pae_input.c,v 1.17 2010/02/06 15:16:27 jcs Exp $ */ /*- * Copyright (c) 2007,2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * This code implements the 4-Way Handshake and Group Key Handshake protocols * (both Supplicant and Authenticator Key Receive state machines) defined in * IEEE Std 802.11-2007 section 8.5. */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET #include #include #include #endif #include #include #include void ieee80211_recv_4way_msg1(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY void ieee80211_recv_4way_msg2(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *, const u_int8_t *); #endif void ieee80211_recv_4way_msg3(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY void ieee80211_recv_4way_msg4(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); void ieee80211_recv_4way_msg2or4(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); #endif void ieee80211_recv_rsn_group_msg1(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); void ieee80211_recv_wpa_group_msg1(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY void ieee80211_recv_group_msg2(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); void ieee80211_recv_eapol_key_req(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); #endif /* * Process an incoming EAPOL frame. Notice that we are only interested in * EAPOL-Key frames with an IEEE 802.11 or WPA descriptor type. */ void ieee80211_eapol_key_input(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni) { struct ifnet *ifp = &ic->ic_if; struct ether_header *eh; struct ieee80211_eapol_key *key; u_int16_t info, desc; int totlen; ifp->if_ibytes += m->m_pkthdr.len; eh = mtod(m, struct ether_header *); if (IEEE80211_IS_MULTICAST(eh->ether_dhost)) { ifp->if_imcasts++; goto done; } m_adj(m, sizeof(*eh)); if (m->m_pkthdr.len < sizeof(*key)) goto done; if (m->m_len < sizeof(*key) && (m = m_pullup(m, sizeof(*key))) == NULL) { ic->ic_stats.is_rx_nombuf++; goto done; } key = mtod(m, struct ieee80211_eapol_key *); if (key->type != EAPOL_KEY) goto done; ic->ic_stats.is_rx_eapol_key++; if ((ni->ni_rsnprotos == IEEE80211_PROTO_RSN && key->desc != EAPOL_KEY_DESC_IEEE80211) || (ni->ni_rsnprotos == IEEE80211_PROTO_WPA && key->desc != EAPOL_KEY_DESC_WPA)) goto done; /* check packet body length */ if (m->m_pkthdr.len < 4 + BE_READ_2(key->len)) goto done; /* check key data length */ totlen = sizeof(*key) + BE_READ_2(key->paylen); if (m->m_pkthdr.len < totlen || totlen > MCLBYTES) goto done; info = BE_READ_2(key->info); /* discard EAPOL-Key frames with an unknown descriptor version */ desc = info & EAPOL_KEY_VERSION_MASK; if (desc < EAPOL_KEY_DESC_V1 || desc > EAPOL_KEY_DESC_V3) goto done; if (ieee80211_is_sha256_akm(ni->ni_rsnakms)) { if (desc != EAPOL_KEY_DESC_V3) goto done; } else if (ni->ni_rsncipher == IEEE80211_CIPHER_CCMP || ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP) { if (desc != EAPOL_KEY_DESC_V2) goto done; } /* make sure the key data field is contiguous */ if (m->m_len < totlen && (m = m_pullup2(m, totlen)) == NULL) { ic->ic_stats.is_rx_nombuf++; goto done; } key = mtod(m, struct ieee80211_eapol_key *); /* determine message type (see 8.5.3.7) */ if (info & EAPOL_KEY_REQUEST) { #ifndef IEEE80211_STA_ONLY /* EAPOL-Key Request frame */ ieee80211_recv_eapol_key_req(ic, key, ni); #endif } else if (info & EAPOL_KEY_PAIRWISE) { /* 4-Way Handshake */ if (info & EAPOL_KEY_KEYMIC) { if (info & EAPOL_KEY_KEYACK) ieee80211_recv_4way_msg3(ic, key, ni); #ifndef IEEE80211_STA_ONLY else ieee80211_recv_4way_msg2or4(ic, key, ni); #endif } else if (info & EAPOL_KEY_KEYACK) ieee80211_recv_4way_msg1(ic, key, ni); } else { /* Group Key Handshake */ if (!(info & EAPOL_KEY_KEYMIC)) goto done; if (info & EAPOL_KEY_KEYACK) { if (key->desc == EAPOL_KEY_DESC_WPA) ieee80211_recv_wpa_group_msg1(ic, key, ni); else ieee80211_recv_rsn_group_msg1(ic, key, ni); } #ifndef IEEE80211_STA_ONLY else ieee80211_recv_group_msg2(ic, key, ni); #endif } done: if (m != NULL) m_freem(m); } /* * Process Message 1 of the 4-Way Handshake (sent by Authenticator). */ void ieee80211_recv_4way_msg1(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { struct ieee80211_ptk tptk; struct ieee80211_pmk *pmk; const u_int8_t *frm, *efrm; const u_int8_t *pmkid; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_STA && ic->ic_opmode != IEEE80211_M_IBSS) return; #endif if (ni->ni_replaycnt_ok && BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } /* parse key data field (may contain an encapsulated PMKID) */ frm = (const u_int8_t *)&key[1]; efrm = frm + BE_READ_2(key->paylen); pmkid = NULL; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) break; switch (frm[0]) { case IEEE80211_ELEMID_VENDOR: if (frm[1] < 4) break; if (memcmp(&frm[2], IEEE80211_OUI, 3) == 0) { switch (frm[5]) { case IEEE80211_KDE_PMKID: pmkid = frm; break; } } break; } frm += 2 + frm[1]; } /* check that the PMKID KDE is valid (if present) */ if (pmkid != NULL && pmkid[1] != 4 + 16) return; if (ieee80211_is_8021x_akm(ni->ni_rsnakms)) { /* retrieve the PMK for this (AP,PMKID) */ pmk = ieee80211_pmksa_find(ic, ni, (pmkid != NULL) ? &pmkid[6] : NULL); if (pmk == NULL) { DPRINTF(("no PMK available for %s\n", ether_sprintf(ni->ni_macaddr))); return; } memcpy(ni->ni_pmk, pmk->pmk_key, IEEE80211_PMK_LEN); } else /* use pre-shared key */ memcpy(ni->ni_pmk, ic->ic_psk, IEEE80211_PMK_LEN); ni->ni_flags |= IEEE80211_NODE_PMK; /* save authenticator's nonce (ANonce) */ memcpy(ni->ni_nonce, key->nonce, EAPOL_KEY_NONCE_LEN); /* generate supplicant's nonce (SNonce) */ arc4random_buf(ic->ic_nonce, EAPOL_KEY_NONCE_LEN); /* TPTK = CalcPTK(PMK, ANonce, SNonce) */ ieee80211_derive_ptk(ni->ni_rsnakms, ni->ni_pmk, ni->ni_macaddr, ic->ic_myaddr, ni->ni_nonce, ic->ic_nonce, &tptk); if (ic->ic_if.if_flags & IFF_DEBUG) printf("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 1, 4, "4-way", ether_sprintf(ni->ni_macaddr)); /* send message 2 to authenticator using TPTK */ (void)ieee80211_send_4way_msg2(ic, ni, key->replaycnt, &tptk); } #ifndef IEEE80211_STA_ONLY /* * Process Message 2 of the 4-Way Handshake (sent by Supplicant). */ void ieee80211_recv_4way_msg2(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni, const u_int8_t *rsnie) { struct ieee80211_ptk tptk; if (ic->ic_opmode != IEEE80211_M_HOSTAP && ic->ic_opmode != IEEE80211_M_IBSS) return; /* discard if we're not expecting this message */ if (ni->ni_rsn_state != RSNA_PTKSTART && ni->ni_rsn_state != RSNA_PTKCALCNEGOTIATING) { DPRINTF(("unexpected in state: %d\n", ni->ni_rsn_state)); return; } ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING; /* NB: replay counter has already been verified by caller */ /* PTK = CalcPTK(ANonce, SNonce) */ ieee80211_derive_ptk(ni->ni_rsnakms, ni->ni_pmk, ic->ic_myaddr, ni->ni_macaddr, ni->ni_nonce, key->nonce, &tptk); /* check Key MIC field using KCK */ if (ieee80211_eapol_key_check_mic(key, tptk.kck) != 0) { DPRINTF(("key MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; /* will timeout.. */ } timeout_del(&ni->ni_eapol_to); ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING_2; ni->ni_rsn_retries = 0; /* install TPTK as PTK now that MIC is verified */ memcpy(&ni->ni_ptk, &tptk, sizeof(tptk)); /* * The RSN IE must match bit-wise with what the STA included in its * (Re)Association Request. */ if (ni->ni_rsnie == NULL || rsnie[1] != ni->ni_rsnie[1] || memcmp(rsnie, ni->ni_rsnie, 2 + rsnie[1]) != 0) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_RSN_DIFFERENT_IE); ieee80211_node_leave(ic, ni); return; } if (ic->ic_if.if_flags & IFF_DEBUG) printf("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 2, 4, "4-way", ether_sprintf(ni->ni_macaddr)); /* send message 3 to supplicant */ (void)ieee80211_send_4way_msg3(ic, ni); } #endif /* IEEE80211_STA_ONLY */ /* * Process Message 3 of the 4-Way Handshake (sent by Authenticator). */ void ieee80211_recv_4way_msg3(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { struct ieee80211_ptk tptk; struct ieee80211_key *k; const u_int8_t *frm, *efrm; const u_int8_t *rsnie1, *rsnie2, *gtk, *igtk; u_int16_t info, reason = 0; int keylen; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_STA && ic->ic_opmode != IEEE80211_M_IBSS) return; #endif if (ni->ni_replaycnt_ok && BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } /* make sure that a PMK has been selected */ if (!(ni->ni_flags & IEEE80211_NODE_PMK)) { DPRINTF(("no PMK found for %s\n", ether_sprintf(ni->ni_macaddr))); return; } /* check that ANonce matches that of Message 1 */ if (memcmp(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN) != 0) { DPRINTF(("ANonce does not match msg 1/4\n")); return; } /* TPTK = CalcPTK(PMK, ANonce, SNonce) */ ieee80211_derive_ptk(ni->ni_rsnakms, ni->ni_pmk, ni->ni_macaddr, ic->ic_myaddr, key->nonce, ic->ic_nonce, &tptk); info = BE_READ_2(key->info); /* check Key MIC field using KCK */ if (ieee80211_eapol_key_check_mic(key, tptk.kck) != 0) { DPRINTF(("key MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; } /* install TPTK as PTK now that MIC is verified */ memcpy(&ni->ni_ptk, &tptk, sizeof(tptk)); /* if encrypted, decrypt Key Data field using KEK */ if ((info & EAPOL_KEY_ENCRYPTED) && ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) { DPRINTF(("decryption failed\n")); return; } /* parse key data field */ frm = (const u_int8_t *)&key[1]; efrm = frm + BE_READ_2(key->paylen); /* * Some WPA1+WPA2 APs (like hostapd) appear to include both WPA and * RSN IEs in message 3/4. We only take into account the IE of the * version of the protocol we negotiated at association time. */ rsnie1 = rsnie2 = gtk = igtk = NULL; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) break; switch (frm[0]) { case IEEE80211_ELEMID_RSN: if (ni->ni_rsnprotos != IEEE80211_PROTO_RSN) break; if (rsnie1 == NULL) rsnie1 = frm; else if (rsnie2 == NULL) rsnie2 = frm; /* ignore others if more than two RSN IEs */ break; case IEEE80211_ELEMID_VENDOR: if (frm[1] < 4) break; if (memcmp(&frm[2], IEEE80211_OUI, 3) == 0) { switch (frm[5]) { case IEEE80211_KDE_GTK: gtk = frm; break; case IEEE80211_KDE_IGTK: if (ni->ni_flags & IEEE80211_NODE_MFP) igtk = frm; break; } } else if (memcmp(&frm[2], MICROSOFT_OUI, 3) == 0) { switch (frm[5]) { case 1: /* WPA */ if (ni->ni_rsnprotos != IEEE80211_PROTO_WPA) break; rsnie1 = frm; break; } } break; } frm += 2 + frm[1]; } /* first WPA/RSN IE is mandatory */ if (rsnie1 == NULL) { DPRINTF(("missing RSN IE\n")); return; } /* key data must be encrypted if GTK is included */ if (gtk != NULL && !(info & EAPOL_KEY_ENCRYPTED)) { DPRINTF(("GTK not encrypted\n")); return; } /* GTK KDE must be included if IGTK KDE is present */ if (igtk != NULL && gtk == NULL) { DPRINTF(("IGTK KDE found but GTK KDE missing\n")); return; } /* check that the Install bit is set if using pairwise keys */ if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP && !(info & EAPOL_KEY_INSTALL)) { DPRINTF(("pairwise cipher but !Install\n")); return; } /* * Check that first WPA/RSN IE is identical to the one received in * the beacon or probe response frame. */ if (ni->ni_rsnie == NULL || rsnie1[1] != ni->ni_rsnie[1] || memcmp(rsnie1, ni->ni_rsnie, 2 + rsnie1[1]) != 0) { reason = IEEE80211_REASON_RSN_DIFFERENT_IE; goto deauth; } /* * If a second RSN information element is present, use its pairwise * cipher suite or deauthenticate. */ if (rsnie2 != NULL) { struct ieee80211_rsnparams rsn; if (ieee80211_parse_rsn(ic, rsnie2, &rsn) == 0) { if (rsn.rsn_akms != ni->ni_rsnakms || rsn.rsn_groupcipher != ni->ni_rsngroupcipher || rsn.rsn_nciphers != 1 || !(rsn.rsn_ciphers & ic->ic_rsnciphers)) { reason = IEEE80211_REASON_BAD_PAIRWISE_CIPHER; goto deauth; } /* use pairwise cipher suite of second RSN IE */ ni->ni_rsnciphers = rsn.rsn_ciphers; ni->ni_rsncipher = ni->ni_rsnciphers; } } /* update the last seen value of the key replay counter field */ ni->ni_replaycnt = BE_READ_8(key->replaycnt); ni->ni_replaycnt_ok = 1; if (ic->ic_if.if_flags & IFF_DEBUG) printf("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 3, 4, "4-way", ether_sprintf(ni->ni_macaddr)); /* send message 4 to authenticator */ if (ieee80211_send_4way_msg4(ic, ni) != 0) return; /* ..authenticator will retry */ if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) { u_int64_t prsc; /* check that key length matches that of pairwise cipher */ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher); if (BE_READ_2(key->keylen) != keylen) { reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } prsc = (gtk == NULL) ? LE_READ_6(key->rsc) : 0; /* map PTK to 802.11 key */ k = &ni->ni_pairwise_key; memset(k, 0, sizeof(*k)); k->k_cipher = ni->ni_rsncipher; k->k_rsc[0] = prsc; k->k_len = keylen; memcpy(k->k_key, ni->ni_ptk.tk, k->k_len); /* install the PTK */ if ((*ic->ic_set_key)(ic, ni, k) != 0) { reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT; ni->ni_flags |= IEEE80211_NODE_RXPROT; } if (gtk != NULL) { u_int8_t kid; /* check that key length matches that of group cipher */ keylen = ieee80211_cipher_keylen(ni->ni_rsngroupcipher); if (gtk[1] != 6 + keylen) { reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } /* map GTK to 802.11 key */ kid = gtk[6] & 3; k = &ic->ic_nw_keys[kid]; memset(k, 0, sizeof(*k)); k->k_id = kid; /* 0-3 */ k->k_cipher = ni->ni_rsngroupcipher; k->k_flags = IEEE80211_KEY_GROUP; if (gtk[6] & (1 << 2)) k->k_flags |= IEEE80211_KEY_TX; k->k_rsc[0] = LE_READ_6(key->rsc); k->k_len = keylen; memcpy(k->k_key, >k[8], k->k_len); /* install the GTK */ if ((*ic->ic_set_key)(ic, ni, k) != 0) { reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } } if (igtk != NULL) { /* implies MFP && gtk != NULL */ u_int16_t kid; /* check that the IGTK KDE is valid */ if (igtk[1] != 4 + 24) { reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } kid = LE_READ_2(&igtk[6]); if (kid != 4 && kid != 5) { DPRINTF(("unsupported IGTK id %u\n", kid)); reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } /* map IGTK to 802.11 key */ k = &ic->ic_nw_keys[kid]; memset(k, 0, sizeof(*k)); k->k_id = kid; /* either 4 or 5 */ k->k_cipher = ni->ni_rsngroupmgmtcipher; k->k_flags = IEEE80211_KEY_IGTK; k->k_mgmt_rsc = LE_READ_6(&igtk[8]); /* IPN */ k->k_len = 16; memcpy(k->k_key, &igtk[14], k->k_len); /* install the IGTK */ if ((*ic->ic_set_key)(ic, ni, k) != 0) { reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } } if (info & EAPOL_KEY_INSTALL) ni->ni_flags |= IEEE80211_NODE_TXRXPROT; if (info & EAPOL_KEY_SECURE) { ni->ni_flags |= IEEE80211_NODE_TXRXPROT; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_IBSS || ++ni->ni_key_count == 2) #endif { DPRINTF(("marking port %s valid\n", ether_sprintf(ni->ni_macaddr))); ni->ni_port_valid = 1; ieee80211_set_link_state(ic, LINK_STATE_UP); } } deauth: if (reason != 0) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, reason); ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); } } #ifndef IEEE80211_STA_ONLY /* * Process Message 4 of the 4-Way Handshake (sent by Supplicant). */ void ieee80211_recv_4way_msg4(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { if (ic->ic_opmode != IEEE80211_M_HOSTAP && ic->ic_opmode != IEEE80211_M_IBSS) return; /* discard if we're not expecting this message */ if (ni->ni_rsn_state != RSNA_PTKINITNEGOTIATING) { DPRINTF(("unexpected in state: %d\n", ni->ni_rsn_state)); return; } /* NB: replay counter has already been verified by caller */ /* check Key MIC field using KCK */ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) { DPRINTF(("key MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; /* will timeout.. */ } timeout_del(&ni->ni_eapol_to); ni->ni_rsn_state = RSNA_PTKINITDONE; ni->ni_rsn_retries = 0; if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) { struct ieee80211_key *k; /* map PTK to 802.11 key */ k = &ni->ni_pairwise_key; memset(k, 0, sizeof(*k)); k->k_cipher = ni->ni_rsncipher; k->k_len = ieee80211_cipher_keylen(k->k_cipher); memcpy(k->k_key, ni->ni_ptk.tk, k->k_len); /* install the PTK */ if ((*ic->ic_set_key)(ic, ni, k) != 0) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_ASSOC_TOOMANY); ieee80211_node_leave(ic, ni); return; } ni->ni_flags |= IEEE80211_NODE_TXRXPROT; } if (ic->ic_opmode != IEEE80211_M_IBSS || ++ni->ni_key_count == 2) { DPRINTF(("marking port %s valid\n", ether_sprintf(ni->ni_macaddr))); ni->ni_port_valid = 1; } if (ic->ic_if.if_flags & IFF_DEBUG) printf("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 4, 4, "4-way", ether_sprintf(ni->ni_macaddr)); /* initiate a group key handshake for WPA */ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) (void)ieee80211_send_group_msg1(ic, ni); else ni->ni_rsn_gstate = RSNA_IDLE; } /* * Differentiate Message 2 from Message 4 of the 4-Way Handshake based on * the presence of an RSN or WPA Information Element. */ void ieee80211_recv_4way_msg2or4(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { const u_int8_t *frm, *efrm; const u_int8_t *rsnie; if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } /* parse key data field (check if an RSN IE is present) */ frm = (const u_int8_t *)&key[1]; efrm = frm + BE_READ_2(key->paylen); rsnie = NULL; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) break; switch (frm[0]) { case IEEE80211_ELEMID_RSN: rsnie = frm; break; case IEEE80211_ELEMID_VENDOR: if (frm[1] < 4) break; if (memcmp(&frm[2], MICROSOFT_OUI, 3) == 0) { switch (frm[5]) { case 1: /* WPA */ rsnie = frm; break; } } } frm += 2 + frm[1]; } if (rsnie != NULL) ieee80211_recv_4way_msg2(ic, key, ni, rsnie); else ieee80211_recv_4way_msg4(ic, key, ni); } #endif /* IEEE80211_STA_ONLY */ /* * Process Message 1 of the RSN Group Key Handshake (sent by Authenticator). */ void ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { struct ieee80211_key *k; const u_int8_t *frm, *efrm; const u_int8_t *gtk, *igtk; u_int16_t info, kid, reason = 0; int keylen; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_STA && ic->ic_opmode != IEEE80211_M_IBSS) return; #endif if (BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } /* check Key MIC field using KCK */ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) { DPRINTF(("key MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; } info = BE_READ_2(key->info); /* check that encrypted and decrypt Key Data field using KEK */ if (!(info & EAPOL_KEY_ENCRYPTED) || ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) { DPRINTF(("decryption failed\n")); return; } /* parse key data field (shall contain a GTK KDE) */ frm = (const u_int8_t *)&key[1]; efrm = frm + BE_READ_2(key->paylen); gtk = igtk = NULL; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) break; switch (frm[0]) { case IEEE80211_ELEMID_VENDOR: if (frm[1] < 4) break; if (memcmp(&frm[2], IEEE80211_OUI, 3) == 0) { switch (frm[5]) { case IEEE80211_KDE_GTK: gtk = frm; break; case IEEE80211_KDE_IGTK: if (ni->ni_flags & IEEE80211_NODE_MFP) igtk = frm; break; } } break; } frm += 2 + frm[1]; } /* check that the GTK KDE is present */ if (gtk == NULL) { DPRINTF(("GTK KDE missing\n")); return; } /* check that key length matches that of group cipher */ keylen = ieee80211_cipher_keylen(ni->ni_rsngroupcipher); if (gtk[1] != 6 + keylen) return; /* map GTK to 802.11 key */ kid = gtk[6] & 3; k = &ic->ic_nw_keys[kid]; memset(k, 0, sizeof(*k)); k->k_id = kid; /* 0-3 */ k->k_cipher = ni->ni_rsngroupcipher; k->k_flags = IEEE80211_KEY_GROUP; if (gtk[6] & (1 << 2)) k->k_flags |= IEEE80211_KEY_TX; k->k_rsc[0] = LE_READ_6(key->rsc); k->k_len = keylen; memcpy(k->k_key, >k[8], k->k_len); /* install the GTK */ if ((*ic->ic_set_key)(ic, ni, k) != 0) { reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } if (igtk != NULL) { /* implies MFP */ /* check that the IGTK KDE is valid */ if (igtk[1] != 4 + 24) { reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } kid = LE_READ_2(&igtk[6]); if (kid != 4 && kid != 5) { DPRINTF(("unsupported IGTK id %u\n", kid)); reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } /* map IGTK to 802.11 key */ k = &ic->ic_nw_keys[kid]; memset(k, 0, sizeof(*k)); k->k_id = kid; /* either 4 or 5 */ k->k_cipher = ni->ni_rsngroupmgmtcipher; k->k_flags = IEEE80211_KEY_IGTK; k->k_mgmt_rsc = LE_READ_6(&igtk[8]); /* IPN */ k->k_len = 16; memcpy(k->k_key, &igtk[14], k->k_len); /* install the IGTK */ if ((*ic->ic_set_key)(ic, ni, k) != 0) { reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } } if (info & EAPOL_KEY_SECURE) { #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_IBSS || ++ni->ni_key_count == 2) #endif { DPRINTF(("marking port %s valid\n", ether_sprintf(ni->ni_macaddr))); ni->ni_port_valid = 1; ieee80211_set_link_state(ic, LINK_STATE_UP); } } /* update the last seen value of the key replay counter field */ ni->ni_replaycnt = BE_READ_8(key->replaycnt); if (ic->ic_if.if_flags & IFF_DEBUG) printf("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 1, 2, "group key", ether_sprintf(ni->ni_macaddr)); /* send message 2 to authenticator */ (void)ieee80211_send_group_msg2(ic, ni, NULL); return; deauth: IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, reason); ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); } /* * Process Message 1 of the WPA Group Key Handshake (sent by Authenticator). */ void ieee80211_recv_wpa_group_msg1(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { struct ieee80211_key *k; u_int16_t info; u_int8_t kid; int keylen; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_STA && ic->ic_opmode != IEEE80211_M_IBSS) return; #endif if (BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } /* check Key MIC field using KCK */ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) { DPRINTF(("key MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; } /* * EAPOL-Key data field is encrypted even though WPA doesn't set * the ENCRYPTED bit in the info field. */ if (ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) { DPRINTF(("decryption failed\n")); return; } /* check that key length matches that of group cipher */ keylen = ieee80211_cipher_keylen(ni->ni_rsngroupcipher); if (BE_READ_2(key->keylen) != keylen) return; /* check that the data length is large enough to hold the key */ if (BE_READ_2(key->paylen) < keylen) return; info = BE_READ_2(key->info); /* map GTK to 802.11 key */ kid = (info >> EAPOL_KEY_WPA_KID_SHIFT) & 3; k = &ic->ic_nw_keys[kid]; memset(k, 0, sizeof(*k)); k->k_id = kid; /* 0-3 */ k->k_cipher = ni->ni_rsngroupcipher; k->k_flags = IEEE80211_KEY_GROUP; if (info & EAPOL_KEY_WPA_TX) k->k_flags |= IEEE80211_KEY_TX; k->k_rsc[0] = LE_READ_6(key->rsc); k->k_len = keylen; /* key data field contains the GTK */ memcpy(k->k_key, &key[1], k->k_len); /* install the GTK */ if ((*ic->ic_set_key)(ic, ni, k) != 0) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE); ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); return; } if (info & EAPOL_KEY_SECURE) { #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_IBSS || ++ni->ni_key_count == 2) #endif { DPRINTF(("marking port %s valid\n", ether_sprintf(ni->ni_macaddr))); ni->ni_port_valid = 1; ieee80211_set_link_state(ic, LINK_STATE_UP); } } /* update the last seen value of the key replay counter field */ ni->ni_replaycnt = BE_READ_8(key->replaycnt); if (ic->ic_if.if_flags & IFF_DEBUG) printf("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 1, 2, "group key", ether_sprintf(ni->ni_macaddr)); /* send message 2 to authenticator */ (void)ieee80211_send_group_msg2(ic, ni, k); } #ifndef IEEE80211_STA_ONLY /* * Process Message 2 of the Group Key Handshake (sent by Supplicant). */ void ieee80211_recv_group_msg2(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { if (ic->ic_opmode != IEEE80211_M_HOSTAP && ic->ic_opmode != IEEE80211_M_IBSS) return; /* discard if we're not expecting this message */ if (ni->ni_rsn_gstate != RSNA_REKEYNEGOTIATING) { DPRINTF(("%s: unexpected in state: %d\n", ni->ni_rsn_gstate)); return; } if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } /* check Key MIC field using KCK */ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) { DPRINTF(("key MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; } timeout_del(&ni->ni_eapol_to); ni->ni_rsn_gstate = RSNA_REKEYESTABLISHED; if ((ni->ni_flags & IEEE80211_NODE_REKEY) && --ic->ic_rsn_keydonesta == 0) ieee80211_setkeysdone(ic); ni->ni_flags &= ~IEEE80211_NODE_REKEY; ni->ni_flags |= IEEE80211_NODE_TXRXPROT; ni->ni_rsn_gstate = RSNA_IDLE; ni->ni_rsn_retries = 0; if (ic->ic_if.if_flags & IFF_DEBUG) printf("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 2, 2, "group key", ether_sprintf(ni->ni_macaddr)); } /* * EAPOL-Key Request frames are sent by the supplicant to request that the * authenticator initiates either a 4-Way Handshake or Group Key Handshake, * or to report a MIC failure in a TKIP MSDU. */ void ieee80211_recv_eapol_key_req(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { u_int16_t info; if (ic->ic_opmode != IEEE80211_M_HOSTAP && ic->ic_opmode != IEEE80211_M_IBSS) return; /* enforce monotonicity of key request replay counter */ if (ni->ni_reqreplaycnt_ok && BE_READ_8(key->replaycnt) <= ni->ni_reqreplaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } info = BE_READ_2(key->info); if (!(info & EAPOL_KEY_KEYMIC) || ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) { DPRINTF(("key request MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; } /* update key request replay counter now that MIC is verified */ ni->ni_reqreplaycnt = BE_READ_8(key->replaycnt); ni->ni_reqreplaycnt_ok = 1; if (info & EAPOL_KEY_ERROR) { /* TKIP MIC failure */ /* ignore reports from STAs not using TKIP */ if (ic->ic_bss->ni_rsngroupcipher != IEEE80211_CIPHER_TKIP && ni->ni_rsncipher != IEEE80211_CIPHER_TKIP) { DPRINTF(("MIC failure report from !TKIP STA: %s\n", ether_sprintf(ni->ni_macaddr))); return; } ic->ic_stats.is_rx_remmicfail++; ieee80211_michael_mic_failure(ic, LE_READ_6(key->rsc)); } else if (info & EAPOL_KEY_PAIRWISE) { /* initiate a 4-Way Handshake */ } else { /* * Should change the GTK, initiate the 4-Way Handshake and * then execute a Group Key Handshake with all supplicants. */ } } #endif /* IEEE80211_STA_ONLY */