diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2008-08-12 18:22:42 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2008-08-12 18:22:42 +0000 |
commit | 8321c622bc4b888984d8c49d465de349ddf196a6 (patch) | |
tree | 61d2fe7a42cde40203f51a35710d475f7154fd82 | |
parent | ab5a9e9d81fc4c62ba8686abf635e9b0da2420c9 (diff) |
process IGTK KDEs in EAPOL-Key frames and install integrity group keys
if MFP was negotiated with the peer (not possible yet).
-rw-r--r-- | sys/net80211/ieee80211.h | 5 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.h | 16 | ||||
-rw-r--r-- | sys/net80211/ieee80211_pae_input.c | 143 | ||||
-rw-r--r-- | sys/net80211/ieee80211_pae_output.c | 70 |
4 files changed, 174 insertions, 60 deletions
diff --git a/sys/net80211/ieee80211.h b/sys/net80211/ieee80211.h index d50766ef7b6..8ed2c5d880f 100644 --- a/sys/net80211/ieee80211.h +++ b/sys/net80211/ieee80211.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211.h,v 1.39 2008/08/12 16:51:39 damien Exp $ */ +/* $OpenBSD: ieee80211.h,v 1.40 2008/08/12 18:22:41 damien Exp $ */ /* $NetBSD: ieee80211.h,v 1.6 2004/04/30 23:51:53 dyoung Exp $ */ /*- @@ -581,7 +581,8 @@ enum { IEEE80211_KDE_SMK = 5, IEEE80211_KDE_NONCE = 6, IEEE80211_KDE_LIFETIME = 7, - IEEE80211_KDE_ERROR = 8 + IEEE80211_KDE_ERROR = 8, + IEEE80211_KDE_IGTK = 9 /* 11w */ }; /* diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index 8e375b81895..a60079601ef 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_node.h,v 1.30 2008/08/02 08:24:15 damien Exp $ */ +/* $OpenBSD: ieee80211_node.h,v 1.31 2008/08/12 18:22:41 damien Exp $ */ /* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */ /*- @@ -154,6 +154,7 @@ struct ieee80211_node { u_int ni_rsnakms; u_int ni_rsnciphers; enum ieee80211_cipher ni_rsngroupcipher; + enum ieee80211_cipher ni_rsngroupmgmtcipher; u_int16_t ni_rsncaps; enum ieee80211_cipher ni_rsncipher; u_int8_t ni_nonce[EAPOL_KEY_NONCE_LEN]; @@ -179,13 +180,16 @@ struct ieee80211_node { int ni_state; u_int8_t ni_flags; /* special-purpose state */ -#define IEEE80211_NODE_ERP 0x01 -#define IEEE80211_NODE_QOS 0x02 -#define IEEE80211_NODE_REKEY 0x04 /* GTK rekeying in progress */ -#define IEEE80211_NODE_RXPROT 0x08 /* RX protection ON */ -#define IEEE80211_NODE_TXPROT 0x10 /* TX protection ON */ +#define IEEE80211_NODE_ERP 0x01 +#define IEEE80211_NODE_QOS 0x02 +#define IEEE80211_NODE_REKEY 0x04 /* GTK rekeying in progress */ +#define IEEE80211_NODE_RXPROT 0x08 /* RX protection ON */ +#define IEEE80211_NODE_TXPROT 0x10 /* TX protection ON */ #define IEEE80211_NODE_TXRXPROT \ (IEEE80211_NODE_TXPROT | IEEE80211_NODE_RXPROT) +#define IEEE80211_NODE_RXMGMTPROT 0x20 /* RX MMPDU protection ON */ +#define IEEE80211_NODE_TXMGMTPROT 0x40 /* TX MMPDU protection ON */ +#define IEEE80211_NODE_MFP 0x80 /* MFP negotiated */ }; RB_HEAD(ieee80211_tree, ieee80211_node); diff --git a/sys/net80211/ieee80211_pae_input.c b/sys/net80211/ieee80211_pae_input.c index ca08d4e8ad3..9c46df076ef 100644 --- a/sys/net80211/ieee80211_pae_input.c +++ b/sys/net80211/ieee80211_pae_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_pae_input.c,v 1.8 2008/08/12 17:53:13 damien Exp $ */ +/* $OpenBSD: ieee80211_pae_input.c,v 1.9 2008/08/12 18:22:41 damien Exp $ */ /*- * Copyright (c) 2007,2008 Damien Bergamini <damien.bergamini@free.fr> @@ -16,6 +16,12 @@ * 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 <sys/param.h> #include <sys/systm.h> #include <sys/mbuf.h> @@ -165,8 +171,7 @@ ieee80211_eapol_key_input(struct ieee80211com *ic, struct mbuf *m0, } /* - * 4-Way Handshake Message 1 is sent by the authenticator to the supplicant - * (see 8.5.3.1). + * Process Message 1 of the 4-Way Handshake (sent by Authenticator). */ void ieee80211_recv_4way_msg1(struct ieee80211com *ic, @@ -186,8 +191,6 @@ ieee80211_recv_4way_msg1(struct ieee80211com *ic, ic->ic_stats.is_rx_eapol_replay++; return; } - /* save authenticator's nonce (ANonce) */ - memcpy(ni->ni_nonce, key->nonce, EAPOL_KEY_NONCE_LEN); /* parse key data field (may contain an encapsulated PMKID) */ frm = (const u_int8_t *)&key[1]; @@ -216,16 +219,20 @@ ieee80211_recv_4way_msg1(struct ieee80211com *ic, if (pmkid != NULL && pmkid[1] < 4 + 16) return; - /* generate a new supplicant's nonce (SNonce) */ - arc4random_buf(ic->ic_nonce, EAPOL_KEY_NONCE_LEN); - - /* retrieve PMK and derive TPTK */ - if ((pmk = ieee80211_get_pmk(ic, ni, pmkid)) == NULL) { + /* retrieve PMK */ + if ((pmk = ieee80211_get_pmk(ic, ni, &pmkid[6])) == NULL) { /* no PMK configured for this STA/PMKID */ return; } + /* 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); + + /* derive TPTK */ ieee80211_derive_ptk(ni->ni_rsnakms, pmk, ni->ni_macaddr, - ic->ic_myaddr, key->nonce, ic->ic_nonce, &tptk); + 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", @@ -237,8 +244,7 @@ ieee80211_recv_4way_msg1(struct ieee80211com *ic, } /* - * 4-Way Handshake Message 2 is sent by the supplicant to the authenticator - * (see 8.5.3.2). + * Process Message 2 of the 4-Way Handshake (sent by Supplicant). */ void ieee80211_recv_4way_msg2(struct ieee80211com *ic, @@ -306,8 +312,7 @@ ieee80211_recv_4way_msg2(struct ieee80211com *ic, } /* - * 4-Way Handshake Message 3 is sent by the authenticator to the supplicant - * (see 8.5.3.3). + * Process Message 3 of the 4-Way Handshake (sent by Authenticator). */ void ieee80211_recv_4way_msg3(struct ieee80211com *ic, @@ -316,7 +321,7 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic, struct ieee80211_ptk tptk; struct ieee80211_key *k; const u_int8_t *frm, *efrm; - const u_int8_t *rsnie1, *rsnie2, *gtk; + const u_int8_t *rsnie1, *rsnie2, *gtk, *igtk; const u_int8_t *pmk; u_int16_t info, reason = 0; int keylen; @@ -371,7 +376,7 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic, * 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 = NULL; + rsnie1 = rsnie2 = gtk = igtk = NULL; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) break; @@ -393,6 +398,10 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic, 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]) { @@ -418,6 +427,12 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic, 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 first WPA/RSN IE is identical to the one received in * the beacon or probe response frame. @@ -485,6 +500,7 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic, reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } + ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT; ni->ni_flags |= IEEE80211_NODE_RXPROT; } if (gtk != NULL) { @@ -519,6 +535,35 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic, 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; @@ -540,8 +585,7 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic, } /* - * 4-Way Handshake Message 4 is sent by the supplicant to the authenticator - * (see 8.5.3.4). + * Process Message 4 of the 4-Way Handshake (sent by Supplicant). */ void ieee80211_recv_4way_msg4(struct ieee80211com *ic, @@ -655,8 +699,7 @@ ieee80211_recv_4way_msg2or4(struct ieee80211com *ic, } /* - * Group Key Handshake Message 1 is sent by the authenticator to the - * supplicant (see 8.5.4.1). + * Process Message 1 of the RSN Group Key Handshake (sent by Authenticator). */ void ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic, @@ -664,9 +707,8 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic, { struct ieee80211_key *k; const u_int8_t *frm, *efrm; - const u_int8_t *gtk; - u_int16_t info; - u_int8_t kid; + const u_int8_t *gtk, *igtk; + u_int16_t info, kid, reason = 0; int keylen; if (ic->ic_opmode != IEEE80211_M_STA && @@ -696,7 +738,7 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic, frm = (const u_int8_t *)&key[1]; efrm = frm + BE_READ_2(key->paylen); - gtk = NULL; + gtk = igtk = NULL; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) break; @@ -709,6 +751,10 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic, case IEEE80211_KDE_GTK: gtk = frm; break; + case IEEE80211_KDE_IGTK: + if (ni->ni_flags & IEEE80211_NODE_MFP) + igtk = frm; + break; } } break; @@ -739,10 +785,35 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic, k->k_len = keylen; /* 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; + 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) { if (ic->ic_opmode != IEEE80211_M_IBSS || @@ -761,9 +832,16 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic, ether_sprintf(ni->ni_macaddr)); /* send message 2 to authenticator */ - (void)ieee80211_send_group_msg2(ic, ni, k); + (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) @@ -847,8 +925,7 @@ ieee80211_recv_wpa_group_msg1(struct ieee80211com *ic, } /* - * Group Key Handshake Message 2 is sent by the supplicant to the - * authenticator (see 8.5.4.2). + * Process Message 2 of the Group Key Handshake (sent by Supplicant). */ void ieee80211_recv_group_msg2(struct ieee80211com *ic, @@ -917,7 +994,7 @@ ieee80211_recv_eapol_key_req(struct ieee80211com *ic, if (!(info & EAPOL_KEY_KEYMIC) || ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) { - DPRINTF(("key MIC failed\n")); + DPRINTF(("key request MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; } diff --git a/sys/net80211/ieee80211_pae_output.c b/sys/net80211/ieee80211_pae_output.c index b1e2c04bcc9..66b406978e1 100644 --- a/sys/net80211/ieee80211_pae_output.c +++ b/sys/net80211/ieee80211_pae_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_pae_output.c,v 1.5 2008/08/02 08:33:21 damien Exp $ */ +/* $OpenBSD: ieee80211_pae_output.c,v 1.6 2008/08/12 18:22:41 damien Exp $ */ /*- * Copyright (c) 2007,2008 Damien Bergamini <damien.bergamini@free.fr> @@ -16,6 +16,12 @@ * 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 Transmit state machines) defined in + * IEEE Std 802.11-2007 section 8.5. + */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/mbuf.h> @@ -45,9 +51,11 @@ int ieee80211_send_eapol_key(struct ieee80211com *, struct mbuf *, struct ieee80211_node *, const struct ieee80211_ptk *); -u_int8_t *ieee80211_add_gtk_kde(u_int8_t *, struct ieee80211_node *, +u_int8_t *ieee80211_add_gtk_kde(u_int8_t *, struct ieee80211_node *, const struct ieee80211_key *); u_int8_t *ieee80211_add_pmkid_kde(u_int8_t *, const u_int8_t *); +u_int8_t *ieee80211_add_igtk_kde(u_int8_t *, + const struct ieee80211_key *); struct mbuf *ieee80211_get_eapol_key(int, int, u_int); /* @@ -199,6 +207,24 @@ ieee80211_add_pmkid_kde(u_int8_t *frm, const u_int8_t *pmkid) return frm + IEEE80211_PMKID_LEN; } +/* + * Add an IGTK KDE to an EAPOL-Key frame (see Figure 8-32a). + */ +u_int8_t * +ieee80211_add_igtk_kde(u_int8_t *frm, const struct ieee80211_key *k) +{ + KASSERT(k->k_flags & IEEE80211_KEY_IGTK); + + *frm++ = IEEE80211_ELEMID_VENDOR; + *frm++ = 4 + 24; + memcpy(frm, IEEE80211_OUI, 3); frm += 3; + *frm++ = IEEE80211_KDE_IGTK; + LE_WRITE_2(frm, k->k_id); frm += 2; + LE_WRITE_6(frm, k->k_tsc); frm += 6; /* IPN */ + memcpy(frm, k->k_key, 16); + return frm + 16; +} + struct mbuf * ieee80211_get_eapol_key(int flags, int type, u_int pktlen) { @@ -223,8 +249,7 @@ ieee80211_get_eapol_key(int flags, int type, u_int pktlen) } /* - * 4-Way Handshake Message 1 is sent by the authenticator to the supplicant - * (see 8.5.3.1). + * Send 4-Way Handshake Message 1 to the supplicant. */ int ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni) @@ -279,8 +304,7 @@ ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni) } /* - * 4-Way Handshake Message 2 is sent by the supplicant to the authenticator - * (see 8.5.3.2). + * Send 4-Way Handshake Message 2 to the authenticator. */ int ieee80211_send_4way_msg2(struct ieee80211com *ic, struct ieee80211_node *ni, @@ -310,7 +334,7 @@ ieee80211_send_4way_msg2(struct ieee80211com *ic, struct ieee80211_node *ni, frm = (u_int8_t *)&key[1]; /* add the WPA/RSN IE used in the (Re)Association Request */ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) { - u_int16_t keylen; + int keylen; frm = ieee80211_add_wpa(frm, ic, ni); /* WPA sets the key length field here */ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher); @@ -329,8 +353,7 @@ ieee80211_send_4way_msg2(struct ieee80211com *ic, struct ieee80211_node *ni, } /* - * 4-Way Handshake Message 3 is sent by the authenticator to the supplicant - * (see 8.5.3.3). + * Send 4-Way Handshake Message 3 to the supplicant. */ int ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni) @@ -355,6 +378,7 @@ ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni) 2 + 48 + ((ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ? 2 + 6 + k->k_len : 0) + + ((ni->ni_flags & IEEE80211_NODE_MFP) ? 2 + 28 : 0) + 8); if (m == NULL) return ENOMEM; @@ -378,9 +402,15 @@ ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni) /* add the WPA/RSN IE included in Beacon/Probe Response */ if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) { frm = ieee80211_add_rsn(frm, ic, ic->ic_bss); - /* encapsulate the GTK and ask for encryption */ + /* encapsulate the GTK */ frm = ieee80211_add_gtk_kde(frm, ni, k); LE_WRITE_6(key->rsc, k->k_tsc); + /* encapsulate the IGTK if MFP was negotiated */ + if (ni->ni_flags & IEEE80211_NODE_MFP) { + frm = ieee80211_add_igtk_kde(frm, + &ic->ic_nw_keys[ic->ic_igtk_kid]); + } + /* ask that the EAPOL-Key frame be encrypted */ info |= EAPOL_KEY_ENCRYPTED | EAPOL_KEY_SECURE; } else /* WPA */ frm = ieee80211_add_wpa(frm, ic, ic->ic_bss); @@ -399,8 +429,7 @@ ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni) } /* - * 4-Way Handshake Message 4 is sent by the supplicant to the authenticator - * (see 8.5.3.4). + * Send 4-Way Handshake Message 4 to the authenticator. */ int ieee80211_send_4way_msg4(struct ieee80211com *ic, struct ieee80211_node *ni) @@ -421,7 +450,7 @@ ieee80211_send_4way_msg4(struct ieee80211com *ic, struct ieee80211_node *ni) BE_WRITE_8(key->replaycnt, ni->ni_replaycnt); if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) { - u_int16_t keylen; + int keylen; /* WPA sets the key length field here */ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher); BE_WRITE_2(key->keylen, keylen); @@ -443,8 +472,7 @@ ieee80211_send_4way_msg4(struct ieee80211com *ic, struct ieee80211_node *ni) } /* - * Group Key Handshake Message 1 is sent by the authenticator to the - * supplicant (see 8.5.4.1). + * Send Group Key Handshake Message 1 to the supplicant. */ int ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni) @@ -467,6 +495,7 @@ ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni) m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA, ((ni->ni_rsnprotos == IEEE80211_PROTO_WPA) ? k->k_len : 2 + 6 + k->k_len) + + ((ni->ni_flags & IEEE80211_NODE_MFP) ? 2 + 28 : 0) + 8); if (m == NULL) return ENOMEM; @@ -488,9 +517,13 @@ ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni) info |= (k->k_id & 0x3) << EAPOL_KEY_WPA_KID_SHIFT; if (ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP) info |= EAPOL_KEY_WPA_TX; - } else /* RSN */ + } else { /* RSN */ frm = ieee80211_add_gtk_kde(frm, ni, k); - + if (ni->ni_flags & IEEE80211_NODE_MFP) { + frm = ieee80211_add_igtk_kde(frm, + &ic->ic_nw_keys[ic->ic_igtk_kid]); + } + } /* RSC = last transmit sequence number for the GTK */ LE_WRITE_6(key->rsc, k->k_tsc); @@ -508,8 +541,7 @@ ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni) } /* - * Group Key Handshake Message 2 is sent by the supplicant to the - * authenticator (see 8.5.4.2). + * Send Group Key Handshake Message 2 to the authenticator. */ int ieee80211_send_group_msg2(struct ieee80211com *ic, struct ieee80211_node *ni, |