process IGTK KDEs in EAPOL-Key frames and install integrity group keys
authordamien <damien@openbsd.org>
Tue, 12 Aug 2008 18:22:41 +0000 (18:22 +0000)
committerdamien <damien@openbsd.org>
Tue, 12 Aug 2008 18:22:41 +0000 (18:22 +0000)
if MFP was negotiated with the peer (not possible yet).

sys/net80211/ieee80211.h
sys/net80211/ieee80211_node.h
sys/net80211/ieee80211_pae_input.c
sys/net80211/ieee80211_pae_output.c

index d50766e..8ed2c5d 100644 (file)
@@ -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 */
 };
 
 /*
index 8e375b8..a600796 100644 (file)
@@ -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);
index ca08d4e..9c46df0 100644 (file)
@@ -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>
  * 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;
        }
index b1e2c04..66b4069 100644 (file)
@@ -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>
  * 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>
 
 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,