From db011a80b4cf6bde215fbb5749c5f2ca336ff6d6 Mon Sep 17 00:00:00 2001 From: damien Date: Tue, 12 Aug 2008 19:21:04 +0000 Subject: [PATCH] add/process group integrity cipher suite in RSN IEs. add support for MFP negotiation during association. --- sys/net80211/ieee80211.h | 6 ++-- sys/net80211/ieee80211_input.c | 63 +++++++++++++++++++++++++++------ sys/net80211/ieee80211_node.c | 30 ++++++++++++++-- sys/net80211/ieee80211_output.c | 30 ++++++++++++---- 4 files changed, 108 insertions(+), 21 deletions(-) diff --git a/sys/net80211/ieee80211.h b/sys/net80211/ieee80211.h index 10afb2914e2..6e018bfe8e0 100644 --- a/sys/net80211/ieee80211.h +++ b/sys/net80211/ieee80211.h @@ -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 */ }; /* diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index e643380dd14..7163e65f305 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -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. diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index ee8b5d78420..ff9ff6adff0 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -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; diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index 9fb019879f1..b794ced62fb 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -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; } -- 2.20.1