svn commit: r305785 - head/sys/net80211
Andriy Voskoboinyk
avos at FreeBSD.org
Tue Sep 13 22:59:39 UTC 2016
Author: avos
Date: Tue Sep 13 22:59:38 2016
New Revision: 305785
URL: https://svnweb.freebsd.org/changeset/base/305785
Log:
net80211: improve error checking in ieee80211_parse_{wpa,rsn}()
- Add few checks for group/pairwise ciphers into
ieee80211_parse_{wpa,rsn}().
- Split error code and cipher value in wpa_cipher() / rsn_cipher(); current
hack with (1 << 32) does not work - it's 1, not 0 (detected by CSA).
- Return IEEE80211_REASON_UNSUPP_RSN_IE_VERSION instead of
IEEE80211_REASON_IE_INVALID when version field is not equal to RSN_VERSION.
Tested with wpi(4) / urtwn(4) (HOSTAP mode).
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D7887
Modified:
head/sys/net80211/ieee80211_hostap.c
Modified: head/sys/net80211/ieee80211_hostap.c
==============================================================================
--- head/sys/net80211/ieee80211_hostap.c Tue Sep 13 22:56:21 2016 (r305784)
+++ head/sys/net80211/ieee80211_hostap.c Tue Sep 13 22:59:38 2016 (r305785)
@@ -1153,28 +1153,36 @@ bad:
* record any key length.
*/
static int
-wpa_cipher(const uint8_t *sel, uint8_t *keylen)
+wpa_cipher(const uint8_t *sel, uint8_t *keylen, uint8_t *cipher)
{
#define WPA_SEL(x) (((x)<<24)|WPA_OUI)
uint32_t w = le32dec(sel);
switch (w) {
case WPA_SEL(WPA_CSE_NULL):
- return IEEE80211_CIPHER_NONE;
+ *cipher = IEEE80211_CIPHER_NONE;
+ break;
case WPA_SEL(WPA_CSE_WEP40):
if (keylen)
*keylen = 40 / NBBY;
- return IEEE80211_CIPHER_WEP;
+ *cipher = IEEE80211_CIPHER_WEP;
+ break;
case WPA_SEL(WPA_CSE_WEP104):
if (keylen)
*keylen = 104 / NBBY;
- return IEEE80211_CIPHER_WEP;
+ *cipher = IEEE80211_CIPHER_WEP;
+ break;
case WPA_SEL(WPA_CSE_TKIP):
- return IEEE80211_CIPHER_TKIP;
+ *cipher = IEEE80211_CIPHER_TKIP;
+ break;
case WPA_SEL(WPA_CSE_CCMP):
- return IEEE80211_CIPHER_AES_CCM;
+ *cipher = IEEE80211_CIPHER_AES_CCM;
+ break;
+ default:
+ return (EINVAL);
}
- return 32; /* NB: so 1<< is discarded */
+
+ return (0);
#undef WPA_SEL
}
@@ -1212,7 +1220,7 @@ ieee80211_parse_wpa(struct ieee80211vap
{
uint8_t len = frm[1];
uint32_t w;
- int n;
+ int error, n;
/*
* Check the length once for fixed parts: OUI, type,
@@ -1245,7 +1253,14 @@ ieee80211_parse_wpa(struct ieee80211vap
memset(rsn, 0, sizeof(*rsn));
/* multicast/group cipher */
- rsn->rsn_mcastcipher = wpa_cipher(frm, &rsn->rsn_mcastkeylen);
+ error = wpa_cipher(frm, &rsn->rsn_mcastkeylen, &rsn->rsn_mcastcipher);
+ if (error != 0) {
+ IEEE80211_DISCARD_IE(vap,
+ IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
+ wh, "WPA", "unknown mcast cipher suite %08X",
+ le32dec(frm));
+ return IEEE80211_REASON_GROUP_CIPHER_INVALID;
+ }
frm += 4, len -= 4;
/* unicast ciphers */
@@ -1260,13 +1275,26 @@ ieee80211_parse_wpa(struct ieee80211vap
}
w = 0;
for (; n > 0; n--) {
- w |= 1<<wpa_cipher(frm, &rsn->rsn_ucastkeylen);
+ uint8_t cipher;
+
+ error = wpa_cipher(frm, &rsn->rsn_ucastkeylen, &cipher);
+ if (error == 0)
+ w |= 1 << cipher;
+
frm += 4, len -= 4;
}
- if (w & (1<<IEEE80211_CIPHER_TKIP))
- rsn->rsn_ucastcipher = IEEE80211_CIPHER_TKIP;
- else
+ if (w == 0) {
+ IEEE80211_DISCARD_IE(vap,
+ IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
+ wh, "WPA", "no usable pairwise cipher suite found (w=%d)",
+ w);
+ return IEEE80211_REASON_PAIRWISE_CIPHER_INVALID;
+ }
+ /* XXX other? */
+ if (w & (1 << IEEE80211_CIPHER_AES_CCM))
rsn->rsn_ucastcipher = IEEE80211_CIPHER_AES_CCM;
+ else
+ rsn->rsn_ucastcipher = IEEE80211_CIPHER_TKIP;
/* key management algorithms */
n = le16dec(frm);
@@ -1300,30 +1328,39 @@ ieee80211_parse_wpa(struct ieee80211vap
* record any key length.
*/
static int
-rsn_cipher(const uint8_t *sel, uint8_t *keylen)
+rsn_cipher(const uint8_t *sel, uint8_t *keylen, uint8_t *cipher)
{
#define RSN_SEL(x) (((x)<<24)|RSN_OUI)
uint32_t w = le32dec(sel);
switch (w) {
case RSN_SEL(RSN_CSE_NULL):
- return IEEE80211_CIPHER_NONE;
+ *cipher = IEEE80211_CIPHER_NONE;
+ break;
case RSN_SEL(RSN_CSE_WEP40):
if (keylen)
*keylen = 40 / NBBY;
- return IEEE80211_CIPHER_WEP;
+ *cipher = IEEE80211_CIPHER_WEP;
+ break;
case RSN_SEL(RSN_CSE_WEP104):
if (keylen)
*keylen = 104 / NBBY;
- return IEEE80211_CIPHER_WEP;
+ *cipher = IEEE80211_CIPHER_WEP;
+ break;
case RSN_SEL(RSN_CSE_TKIP):
- return IEEE80211_CIPHER_TKIP;
+ *cipher = IEEE80211_CIPHER_TKIP;
+ break;
case RSN_SEL(RSN_CSE_CCMP):
- return IEEE80211_CIPHER_AES_CCM;
+ *cipher = IEEE80211_CIPHER_AES_CCM;
+ break;
case RSN_SEL(RSN_CSE_WRAP):
- return IEEE80211_CIPHER_AES_OCB;
+ *cipher = IEEE80211_CIPHER_AES_OCB;
+ break;
+ default:
+ return (EINVAL);
}
- return 32; /* NB: so 1<< is discarded */
+
+ return (0);
#undef WPA_SEL
}
@@ -1360,7 +1397,7 @@ ieee80211_parse_rsn(struct ieee80211vap
{
uint8_t len = frm[1];
uint32_t w;
- int n;
+ int error, n;
/*
* Check the length once for fixed parts:
@@ -1373,6 +1410,7 @@ ieee80211_parse_rsn(struct ieee80211vap
wh, "WPA", "not RSN, flags 0x%x", vap->iv_flags);
return IEEE80211_REASON_IE_INVALID;
}
+ /* XXX may be shorter */
if (len < 10) {
IEEE80211_DISCARD_IE(vap,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
@@ -1385,14 +1423,28 @@ ieee80211_parse_rsn(struct ieee80211vap
IEEE80211_DISCARD_IE(vap,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
wh, "RSN", "bad version %u", w);
- return IEEE80211_REASON_IE_INVALID;
+ return IEEE80211_REASON_UNSUPP_RSN_IE_VERSION;
}
frm += 2, len -= 2;
memset(rsn, 0, sizeof(*rsn));
/* multicast/group cipher */
- rsn->rsn_mcastcipher = rsn_cipher(frm, &rsn->rsn_mcastkeylen);
+ error = rsn_cipher(frm, &rsn->rsn_mcastkeylen, &rsn->rsn_mcastcipher);
+ if (error != 0) {
+ IEEE80211_DISCARD_IE(vap,
+ IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
+ wh, "RSN", "unknown mcast cipher suite %08X",
+ le32dec(frm));
+ return IEEE80211_REASON_GROUP_CIPHER_INVALID;
+ }
+ if (rsn->rsn_mcastcipher == IEEE80211_CIPHER_NONE) {
+ IEEE80211_DISCARD_IE(vap,
+ IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
+ wh, "RSN", "invalid mcast cipher suite %d",
+ rsn->rsn_mcastcipher);
+ return IEEE80211_REASON_GROUP_CIPHER_INVALID;
+ }
frm += 4, len -= 4;
/* unicast ciphers */
@@ -1406,14 +1458,33 @@ ieee80211_parse_rsn(struct ieee80211vap
return IEEE80211_REASON_IE_INVALID;
}
w = 0;
+
for (; n > 0; n--) {
- w |= 1<<rsn_cipher(frm, &rsn->rsn_ucastkeylen);
+ uint8_t cipher;
+
+ error = rsn_cipher(frm, &rsn->rsn_ucastkeylen, &cipher);
+ if (error == 0)
+ w |= 1 << cipher;
+
frm += 4, len -= 4;
}
- if (w & (1<<IEEE80211_CIPHER_TKIP))
+ if (w & (1 << IEEE80211_CIPHER_AES_CCM))
+ rsn->rsn_ucastcipher = IEEE80211_CIPHER_AES_CCM;
+ else if (w & (1 << IEEE80211_CIPHER_AES_OCB))
+ rsn->rsn_ucastcipher = IEEE80211_CIPHER_AES_OCB;
+ else if (w & (1 << IEEE80211_CIPHER_TKIP))
rsn->rsn_ucastcipher = IEEE80211_CIPHER_TKIP;
- else
- rsn->rsn_ucastcipher = IEEE80211_CIPHER_AES_CCM;
+ else if ((w & (1 << IEEE80211_CIPHER_NONE)) &&
+ (rsn->rsn_mcastcipher == IEEE80211_CIPHER_WEP ||
+ rsn->rsn_mcastcipher == IEEE80211_CIPHER_TKIP))
+ rsn->rsn_ucastcipher = IEEE80211_CIPHER_NONE;
+ else {
+ IEEE80211_DISCARD_IE(vap,
+ IEEE80211_MSG_ELEMID | IEEE80211_MSG_WPA,
+ wh, "RSN", "no usable pairwise cipher suite found (w=%d)",
+ w);
+ return IEEE80211_REASON_PAIRWISE_CIPHER_INVALID;
+ }
/* key management algorithms */
n = le16dec(frm);
@@ -1510,6 +1581,7 @@ wpa_assocreq(struct ieee80211_node *ni,
else
reason = ieee80211_parse_rsn(vap, rsn, rsnparms, wh);
if (reason != 0) {
+ /* XXX wpa->rsn fallback? */
/* XXX distinguish WPA/RSN? */
vap->iv_stats.is_rx_assoc_badwpaie++;
goto bad;
More information about the svn-src-head
mailing list