summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2007-08-29 19:54:47 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2007-08-29 19:54:47 +0000
commit08aa8be7ff220d0c9410026ffdf71ca2af94465a (patch)
tree7689f826bd6da6096228ef09aae788d44bac532a /sys
parent7f1d21ca6829268a5ae3241f3a9121a88d01198f (diff)
- use ieee80211_get_hdrlen() where appropriate.
- discard all EAPOL-Key frames with an unknown descriptor version. - when receiving message 3/4 of the 4-way handshake, do not install the PTK if the INSTALL bit is not set. this fixes 4-way handshake with APs using group keys only. - similarly, do not mark the 802.1X port as valid if the SECURE bit is not set (it will be marked as valid after group key handshake).
Diffstat (limited to 'sys')
-rw-r--r--sys/net80211/ieee80211_crypto.c25
-rw-r--r--sys/net80211/ieee80211_input.c78
2 files changed, 59 insertions, 44 deletions
diff --git a/sys/net80211/ieee80211_crypto.c b/sys/net80211/ieee80211_crypto.c
index 34791f3bf23..4f18d2b1a52 100644
--- a/sys/net80211/ieee80211_crypto.c
+++ b/sys/net80211/ieee80211_crypto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_crypto.c,v 1.34 2007/08/23 16:49:57 damien Exp $ */
+/* $OpenBSD: ieee80211_crypto.c,v 1.35 2007/08/29 19:54:46 damien Exp $ */
/* $NetBSD: ieee80211_crypto.c,v 1.5 2003/12/14 09:56:53 dyoung Exp $ */
/*-
@@ -167,7 +167,7 @@ ieee80211_decrypt(struct ieee80211com *ic, struct mbuf *m0,
wh = mtod(m0, struct ieee80211_frame *);
if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
ni->ni_pairwise_cipher == IEEE80211_CIPHER_USEGROUP) {
- size_t hdrlen = sizeof(*wh); /* XXX QoS */
+ int hdrlen = ieee80211_get_hdrlen(wh);
u_int8_t *ivp = (u_int8_t *)wh + hdrlen;
/* key identifier is always located at the same index */
int kid = ivp[IEEE80211_WEP_IVLEN] >> 6;
@@ -199,9 +199,11 @@ ieee80211_ccmp_encrypt(struct ieee80211com *ic, struct mbuf *m0,
struct ieee80211_key *k)
{
struct ieee80211_frame *wh;
- size_t hdrlen = sizeof(*wh); /* XXX QoS */
u_int8_t *ivp;
+ int hdrlen;
+ wh = mtod(m0, struct ieee80211_frame *);
+ hdrlen = ieee80211_get_hdrlen(wh);
M_PREPEND(m0, IEEE80211_CCMP_HDRLEN, M_NOWAIT);
if (m0 == NULL)
return m0;
@@ -229,11 +231,12 @@ ieee80211_ccmp_decrypt(struct ieee80211com *ic, struct mbuf *m0,
struct ieee80211_key *k)
{
struct ieee80211_frame *wh;
- size_t hdrlen = sizeof(*wh); /* XXX QoS */
u_int64_t pn;
u_int8_t *ivp;
+ int hdrlen;
wh = mtod(m0, struct ieee80211_frame *);
+ hdrlen = ieee80211_get_hdrlen(wh);
ivp = (u_int8_t *)wh + hdrlen;
/* check that ExtIV bit is be set */
@@ -274,9 +277,11 @@ ieee80211_tkip_encrypt(struct ieee80211com *ic, struct mbuf *m0,
struct ieee80211_key *k)
{
struct ieee80211_frame *wh;
- size_t hdrlen = sizeof(*wh); /* XXX QoS */
u_int8_t *ivp;
+ int hdrlen;
+ wh = mtod(m0, struct ieee80211_frame *);
+ hdrlen = ieee80211_get_hdrlen(wh);
M_PREPEND(m0, IEEE80211_TKIP_HDRLEN, M_NOWAIT);
if (m0 == NULL)
return m0;
@@ -306,11 +311,12 @@ ieee80211_tkip_decrypt(struct ieee80211com *ic, struct mbuf *m0,
struct ieee80211_key *k)
{
struct ieee80211_frame *wh;
- size_t hdrlen = sizeof(*wh); /* XXX QoS */
u_int64_t tsc;
u_int8_t *ivp;
+ int hdrlen;
wh = mtod(m0, struct ieee80211_frame *);
+ hdrlen = ieee80211_get_hdrlen(wh);
ivp = (u_int8_t *)wh + hdrlen;
/* check that ExtIV bit is be set */
@@ -399,12 +405,7 @@ ieee80211_wep_crypt(struct ifnet *ifp, struct mbuf *m0, int txflag)
n->m_len = n->m_ext.ext_size;
}
wh = mtod(m, struct ieee80211_frame *);
- if ((wh->i_fc[0] &
- (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) ==
- (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS))
- len = sizeof(struct ieee80211_qosframe);
- else
- len = sizeof(struct ieee80211_frame);
+ len = ieee80211_get_hdrlen(wh);
memcpy(mtod(n, caddr_t), wh, len);
wh = mtod(n, struct ieee80211_frame *);
left -= len;
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index 3734c26d48a..99103adf6b6 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -1,5 +1,5 @@
/* $NetBSD: ieee80211_input.c,v 1.24 2004/05/31 11:12:24 dyoung Exp $ */
-/* $OpenBSD: ieee80211_input.c,v 1.69 2007/08/27 20:14:21 damien Exp $ */
+/* $OpenBSD: ieee80211_input.c,v 1.70 2007/08/29 19:54:46 damien Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
@@ -368,10 +368,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
/* can't get there */
goto out;
}
- if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS)
- hdrlen = sizeof(struct ieee80211_qosframe);
- else
- hdrlen = sizeof(struct ieee80211_frame);
+
+ hdrlen = ieee80211_get_hdrlen(wh);
+
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
if (ic->ic_flags & IEEE80211_F_WEPON) {
m = ieee80211_wep_crypt(ifp, m, 0);
@@ -1981,10 +1980,6 @@ ieee80211_recv_4way_msg1(struct ieee80211com *ic,
if (pmkid != NULL && pmkid[1] < 4 + 16)
return;
- /* update the last seen value of the key replay counter field */
- ni->ni_replaycnt = BE_READ_8(key->replaycnt);
- /* do not set ni_replaycnt_ok since the frame contains no MIC */
-
/* generate a new nonce (SNonce) */
get_random_bytes(snonce, EAPOL_KEY_NONCE_LEN);
@@ -2018,6 +2013,7 @@ ieee80211_recv_4way_msg2(struct ieee80211com *ic,
struct ieee80211_eapol_key *key, struct ieee80211_node *ni,
const u_int8_t *rsn)
{
+ struct ieee80211_ptk tptk;
const u_int8_t *pmk;
size_t pmk_len;
@@ -2028,15 +2024,17 @@ ieee80211_recv_4way_msg2(struct ieee80211com *ic,
ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING;
- /* derive PTK from PMK */
+ /* derive TPTK from PMK */
ieee80211_derive_ptk(pmk, pmk_len, ic->ic_myaddr, ni->ni_macaddr,
- ni->ni_nonce, key->nonce, (u_int8_t *)&ni->ni_ptk,
- sizeof(ni->ni_ptk));
+ ni->ni_nonce, key->nonce, (u_int8_t *)&tptk, sizeof(tptk));
/* check Key MIC field using KCK */
- if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0)
+ if (ieee80211_eapol_key_check_mic(key, tptk.kck) != 0)
return;
+ /* use TPTK as PTK now that MIC is verified */
+ memcpy(&ni->ni_ptk, &tptk, sizeof(tptk));
+
/*
* The RSN IE must match bit-wise with what the STA included in its
* (Re)Association Request.
@@ -2140,13 +2138,14 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
return;
/*
- * Check that first RSN IE is identical to the one received in
+ * Check that first WPA/RSN IE is identical to the one received in
* the beacon or probe response frame.
*/
if (ni->ni_rsnie == NULL || rsn1[1] != ni->ni_rsnie[1] ||
- memcmp(rsn1, ni->ni_rsnie, 2 + rsn1[1]) != 0)
+ memcmp(rsn1, ni->ni_rsnie, 2 + rsn1[1]) != 0) {
/*ieee80211_new_state();*/
return;
+ }
/*
* If a second RSN information element is present, use its pairwise
@@ -2169,18 +2168,22 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
/* send message 4 to authenticator */
if (ieee80211_send_4way_msg4(ic, ni) != 0)
- return;
-
- /* check that key length matches that of pairwise cipher */
- if (BE_READ_2(key->keylen) !=
- ieee80211_cipher_keylen(ni->ni_pairwise_cipher))
- return;
- /* install the PTK */
- k = &ni->ni_pairwise_key;
- ieee80211_map_ptk(&ni->ni_ptk, ni->ni_pairwise_cipher, k);
- if (ic->ic_set_key != NULL && (*ic->ic_set_key)(ic, ni, k) != 0)
- return;
+ return; /* ..authenticator will timeout */
+ if (info & EAPOL_KEY_INSTALL) {
+ /* check that key length matches that of pairwise cipher */
+ if (BE_READ_2(key->keylen) !=
+ ieee80211_cipher_keylen(ni->ni_pairwise_cipher))
+ return;
+ /* install the PTK */
+ k = &ni->ni_pairwise_key;
+ ieee80211_map_ptk(&ni->ni_ptk, ni->ni_pairwise_cipher, k);
+ if (ic->ic_set_key != NULL &&
+ (*ic->ic_set_key)(ic, ni, k) != 0) {
+ /* XXX deauthenticate */
+ return;
+ }
+ }
if (gtk != NULL) {
u_int64_t rsc;
u_int8_t kid;
@@ -2198,12 +2201,18 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
ieee80211_map_gtk(&gtk[8], ni->ni_group_cipher, kid,
gtk[6] & (1 << 2), rsc, k);
if (ic->ic_set_key != NULL &&
- (*ic->ic_set_key)(ic, ni, k) != 0)
+ (*ic->ic_set_key)(ic, ni, k) != 0) {
+ /* XXX deauthenticate */
return;
+ }
+ }
+ if (info & EAPOL_KEY_SECURE) {
+ if (ic->ic_opmode == IEEE80211_M_IBSS) {
+ if (++ni->ni_key_count == 2)
+ ni->ni_port_valid = 1;
+ } else
+ ni->ni_port_valid = 1;
}
-
- /* mark the PAE port as valid */
- ni->ni_port_valid = 1;
}
/*
@@ -2545,7 +2554,7 @@ ieee80211_recv_eapol(struct ieee80211com *ic, struct mbuf *m0,
struct ieee80211_node *ni)
{
struct ieee80211_eapol_key *key;
- u_int16_t info;
+ u_int16_t info, desc;
if (m0->m_len < sizeof(struct ether_header) + sizeof(*key))
goto out;
@@ -2570,8 +2579,13 @@ ieee80211_recv_eapol(struct ieee80211com *ic, struct mbuf *m0,
#endif
info = BE_READ_2(key->info);
+ /* discard EAPOL-Key frames with an unknown descriptor version */
+ desc = info & EAPOL_KEY_VERSION_MASK;
+ if (desc != EAPOL_KEY_DESC_V1 && desc != EAPOL_KEY_DESC_V2)
+ goto out;
+
if (ni->ni_pairwise_cipher == IEEE80211_CIPHER_CCMP &&
- (info & EAPOL_KEY_VERSION_MASK) != EAPOL_KEY_DESC_V2)
+ desc != EAPOL_KEY_DESC_V2)
goto out;
/* determine message type (see 8.5.3.7) */