mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-30 16:51:41 +00:00
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
This commit is contained in:
parent
462b35ac65
commit
95d9a127b2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=305785
@ -1153,28 +1153,36 @@ hostap_auth_shared(struct ieee80211_node *ni, struct ieee80211_frame *wh,
|
||||
* 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 *vap, const uint8_t *frm,
|
||||
{
|
||||
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 *vap, const uint8_t *frm,
|
||||
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 *vap, const uint8_t *frm,
|
||||
}
|
||||
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 *vap, const uint8_t *frm,
|
||||
* 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 *vap, const uint8_t *frm,
|
||||
{
|
||||
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 *vap, const uint8_t *frm,
|
||||
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 *vap, const uint8_t *frm,
|
||||
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 *vap, const uint8_t *frm,
|
||||
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, struct ieee80211_rsnparms *rsnparms,
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user