add/process group integrity cipher suite in RSN IEs.
authordamien <damien@openbsd.org>
Tue, 12 Aug 2008 19:21:04 +0000 (19:21 +0000)
committerdamien <damien@openbsd.org>
Tue, 12 Aug 2008 19:21:04 +0000 (19:21 +0000)
add support for MFP negotiation during association.

sys/net80211/ieee80211.h
sys/net80211/ieee80211_input.c
sys/net80211/ieee80211_node.c
sys/net80211/ieee80211_output.c

index 10afb29..6e018bf 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211.h,v 1.42 2008/08/12 18:48:35 damien Exp $   */
+/*     $OpenBSD: ieee80211.h,v 1.43 2008/08/12 19:21:04 damien Exp $   */
 /*     $NetBSD: ieee80211.h,v 1.6 2004/04/30 23:51:53 dyoung Exp $     */
 
 /*-
@@ -392,7 +392,9 @@ enum {
        IEEE80211_REASON_RSN_IE_VER_UNSUP       = 21,
        IEEE80211_REASON_RSN_IE_BAD_CAP         = 22,
 
-       IEEE80211_REASON_CIPHER_REJ_POLICY      = 24
+       IEEE80211_REASON_CIPHER_REJ_POLICY      = 24,
+       IEEE80211_REASON_BAD_GROUP_MGMT_CIPHER  = 25,   /* 11w */
+       IEEE80211_REASON_MFP_POLICY             = 26    /* 11w */
 };
 
 /*
index e643380..7163e65 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_input.c,v 1.90 2008/08/12 17:53:13 damien Exp $     */
+/*     $OpenBSD: ieee80211_input.c,v 1.91 2008/08/12 19:21:04 damien Exp $     */
 
 /*-
  * Copyright (c) 2001 Atsushi Onoe
@@ -689,20 +689,34 @@ ieee80211_parse_wmm_params(struct ieee80211com *ic, const u_int8_t *frm)
 enum ieee80211_cipher
 ieee80211_parse_rsn_cipher(const u_int8_t selector[4])
 {
-       /* from IEEE Std 802.11i-2004 - Table 20da */
-       if (memcmp(selector, MICROSOFT_OUI, 3) == 0 ||  /* WPA */
-           memcmp(selector, IEEE80211_OUI, 3) == 0) {  /* RSN */
+       if (memcmp(selector, MICROSOFT_OUI, 3) == 0) {  /* WPA */
+               switch (selector[3]) {
+               case 0: /* use group data cipher suite */
+                       return IEEE80211_CIPHER_USEGROUP;
+               case 1: /* WEP-40 */
+                       return IEEE80211_CIPHER_WEP40;
+               case 2: /* TKIP */
+                       return IEEE80211_CIPHER_TKIP;
+               case 4: /* CCMP (RSNA default) */
+                       return IEEE80211_CIPHER_CCMP;
+               case 5: /* WEP-104 */
+                       return IEEE80211_CIPHER_WEP104;
+               }
+       } else if (memcmp(selector, IEEE80211_OUI, 3) == 0) {   /* RSN */
+               /* from IEEE Std 802.11 - Table 20da */
                switch (selector[3]) {
-               case 0: /* use group cipher suite */
+               case 0: /* use group data cipher suite */
                        return IEEE80211_CIPHER_USEGROUP;
-               case 1: /* WEP-40 */
+               case 1: /* WEP-40 */
                        return IEEE80211_CIPHER_WEP40;
-               case 2: /* TKIP */
+               case 2: /* TKIP */
                        return IEEE80211_CIPHER_TKIP;
-               case 4: /* CCMP (RSNA default) */
+               case 4: /* CCMP (RSNA default) */
                        return IEEE80211_CIPHER_CCMP;
-               case 5: /* WEP-104 */
+               case 5: /* WEP-104 */
                        return IEEE80211_CIPHER_WEP104;
+               case 6: /* AES-128-CMAC */
+                       return IEEE80211_CIPHER_AES128_CMAC;
                }
        }
        return IEEE80211_CIPHER_NONE;   /* ignore unknown ciphers */
@@ -747,13 +761,15 @@ ieee80211_parse_rsn_body(struct ieee80211com *ic, const u_int8_t *frm,
        rsn->rsn_groupcipher = IEEE80211_CIPHER_CCMP;
        rsn->rsn_nciphers = 1;
        rsn->rsn_ciphers = IEEE80211_CIPHER_CCMP;
+       /* if Group Management Cipher Suite missing, defaut to AES-128-CMAC */
+       rsn->rsn_groupmgmtcipher = IEEE80211_CIPHER_AES128_CMAC;
        /* if AKM Suite missing, default to 802.1X */
        rsn->rsn_nakms = 1;
        rsn->rsn_akms = IEEE80211_AKM_IEEE8021X;
        /* if RSN capabilities missing, default to 0 */
        rsn->rsn_caps = 0;
 
-       /* read Group Cipher Suite field */
+       /* read Group Data Cipher Suite field */
        if (frm + 4 > efrm)
                return 0;
        rsn->rsn_groupcipher = ieee80211_parse_rsn_cipher(frm);
@@ -817,6 +833,11 @@ ieee80211_parse_rsn_body(struct ieee80211com *ic, const u_int8_t *frm,
                frm += IEEE80211_PMKID_LEN;
        }
 
+       /* read Group Management Cipher Suite field */
+       if (frm + 4 > efrm)
+               return 0;
+       rsn->rsn_groupmgmtcipher = ieee80211_parse_rsn_cipher(frm);
+
        return IEEE80211_STATUS_SUCCESS;
 }
 
@@ -1146,6 +1167,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0,
                        ni->ni_rsnakms = rsn.rsn_akms;
                        ni->ni_rsnciphers = rsn.rsn_ciphers;
                        ni->ni_rsngroupcipher = rsn.rsn_groupcipher;
+                       ni->ni_rsngroupmgmtcipher = rsn.rsn_groupmgmtcipher;
                        ni->ni_rsncaps = rsn.rsn_caps;
                } else
                        ni->ni_rsnprotos = IEEE80211_PROTO_NONE;
@@ -1499,6 +1521,27 @@ ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0,
                        status = IEEE80211_STATUS_BAD_GROUP_CIPHER;
                        goto end;
                }
+
+               if (!(rsn.rsn_caps & IEEE80211_RSNCAP_MFPC) &&
+                   (ic->ic_bss->ni_rsncaps & IEEE80211_RSNCAP_MFPR)) {
+                       status = IEEE80211_REASON_MFP_POLICY;   /* XXX */
+                       goto end;
+               }
+               if ((ic->ic_bss->ni_rsncaps & IEEE80211_RSNCAP_MFPC) &&
+                   (rsn.rsn_caps & (IEEE80211_RSNCAP_MFPC |
+                    IEEE80211_RSNCAP_MFPR)) == IEEE80211_RSNCAP_MFPR) {
+                       /* STA advertises an invalid setting */
+                       status = IEEE80211_REASON_MFP_POLICY;   /* XXX */
+                       goto end;
+               }
+               if ((rsn.rsn_caps & IEEE80211_RSNCAP_MFPC) &&
+                   rsn.rsn_groupmgmtcipher !=
+                   ic->ic_bss->ni_rsngroupmgmtcipher) {
+                       /* XXX satus not reason?! */
+                       status = IEEE80211_REASON_BAD_GROUP_MGMT_CIPHER;
+                       goto end;
+               }
+
                /*
                 * Disallow new associations using TKIP if countermeasures
                 * are active.
index ee8b5d7..ff9ff6a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_node.c,v 1.41 2008/08/12 18:41:18 damien Exp $      */
+/*     $OpenBSD: ieee80211_node.c,v 1.42 2008/08/12 19:21:04 damien Exp $      */
 /*     $NetBSD: ieee80211_node.c,v 1.14 2004/05/09 09:18:47 dyoung Exp $       */
 
 /*-
@@ -315,6 +315,11 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
                ni->ni_rsngroupcipher = ic->ic_rsngroupcipher;
                ni->ni_rsngroupmgmtcipher = ic->ic_rsngroupmgmtcipher;
                ni->ni_rsncaps = 0;
+               if (ic->ic_caps & IEEE80211_C_MFP) {
+                       ni->ni_rsncaps |= IEEE80211_RSNCAP_MFPC;
+                       if (ic->ic_flags & IEEE80211_F_MFPR)
+                               ni->ni_rsncaps |= IEEE80211_RSNCAP_MFPR;
+               }
 
                ic->ic_def_txkey = 1;
                k = &ic->ic_nw_keys[ic->ic_def_txkey];
@@ -345,7 +350,7 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
                ni->ni_port_valid = 1;
                ni->ni_flags |= IEEE80211_NODE_TXPROT;
 
-               /* schedule a GTK rekeying after 3600s */
+               /* schedule a GTK/IGTK rekeying after 3600s */
                timeout_add(&ic->ic_rsn_timeout, 3600 * hz);
        }
        if (ic->ic_phytype == IEEE80211_T_FH) {
@@ -408,6 +413,22 @@ ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
                        fail |= 0x40;
                if ((ni->ni_rsnciphers & ic->ic_rsnciphers) == 0)
                        fail |= 0x40;
+
+               /* we only support AES-128-CMAC as the IGTK cipher */
+               if ((ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC) &&
+                   ni->ni_rsngroupmgmtcipher != IEEE80211_CIPHER_AES128_CMAC)
+                       fail |= 0x40;
+
+               /* we do not support MFP but AP requires it */
+               if (!(ic->ic_caps & IEEE80211_C_MFP) &&
+                   (ni->ni_rsncaps & IEEE80211_RSNCAP_MFPR))
+                       fail |= 0x40;
+
+               /* we require MFP but AP does not support it */
+               if ((ic->ic_caps & IEEE80211_C_MFP) &&
+                   (ic->ic_flags & IEEE80211_F_MFPR) &&
+                   !(ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC))
+                       fail |= 0x40;
        }
 
 #ifdef IEEE80211_DEBUG
@@ -580,6 +601,11 @@ ieee80211_end_scan(struct ifnet *ifp)
 
                ni->ni_rsncipher = ni->ni_rsnciphers;
 
+               /* use MFP if we both support it */
+               if ((ic->ic_caps & IEEE80211_C_MFP) &&
+                   (ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC))
+                       ni->ni_flags |= IEEE80211_NODE_MFP;
+
        } else if (ic->ic_flags & IEEE80211_F_WEPON)
                ni->ni_rsncipher = IEEE80211_CIPHER_USEGROUP;
 
index 9fb0198..b794ced 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_output.c,v 1.67 2008/08/12 19:05:39 damien Exp $    */
+/*     $OpenBSD: ieee80211_output.c,v 1.68 2008/08/12 19:21:04 damien Exp $    */
 /*     $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $     */
 
 /*-
@@ -823,7 +823,7 @@ ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211com *ic,
        /* write Version field */
        LE_WRITE_2(frm, 1); frm += 2;
 
-       /* write Group Cipher Suite field (see Table 20da) */
+       /* write Group Data Cipher Suite field (see Table 20da) */
        memcpy(frm, oui, 3); frm += 3;
        switch (ni->ni_rsngroupcipher) {
        case IEEE80211_CIPHER_WEP40:
@@ -840,7 +840,7 @@ ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211com *ic,
                break;
        default:
                /* can't get there */
-               panic("invalid group cipher!");
+               panic("invalid group data cipher!");
        }
 
        pcount = frm; frm += 2;
@@ -880,11 +880,27 @@ ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211com *ic,
        /* write AKM Suite List Count field */
        LE_WRITE_2(pcount, count);
 
-       if (!wpa) {
-               /* write RSN Capabilities field */
-               LE_WRITE_2(frm, ni->ni_rsncaps); frm += 2;
+       if (wpa)
+               return frm;
 
-               /* no PMKID List for now */
+       /* write RSN Capabilities field */
+       LE_WRITE_2(frm, ni->ni_rsncaps); frm += 2;
+
+       if (!(ic->ic_caps & IEEE80211_C_MFP))
+               return frm;
+
+       /* no PMKID List for now */
+       LE_WRITE_2(frm, 0); frm += 2;
+
+       /* write Group Integrity Cipher Suite field */
+       memcpy(frm, oui, 3); frm += 3;
+       switch (ic->ic_rsngroupmgmtcipher) {
+       case IEEE80211_CIPHER_AES128_CMAC:
+               *frm++ = 6;
+               break;
+       default:
+               /* can't get there */
+               panic("invalid integrity group cipher!");
        }
        return frm;
 }