add support for MFP negotiation during association.
-/* $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 $ */
/*-
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 */
};
/*
-/* $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
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 */
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);
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;
}
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;
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.
-/* $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 $ */
/*-
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];
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) {
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
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;
-/* $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 $ */
/*-
/* 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:
break;
default:
/* can't get there */
- panic("invalid group cipher!");
+ panic("invalid group data cipher!");
}
pcount = frm; frm += 2;
/* 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;
}