summaryrefslogtreecommitdiff
path: root/sys/net80211/ieee80211_input.c
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2007-08-22 20:40:35 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2007-08-22 20:40:35 +0000
commit4f19245ee53a151b1ae297678ba39835912a1efe (patch)
treeffc09b7a85fca0e699375187b82c2732970611ec /sys/net80211/ieee80211_input.c
parentdd654a77e55db513af679bbba472472b1a70b096 (diff)
- add k_rxmic and k_txmic fields to struct ieee80211_key to store the
Tx/Rx MIC for TKIP. - add two functions to map a PTK and a GTK to an IEEE 802.11 key and use them in ieee80211_input.c instead of duplicating the same code. properly set Tx/Rx MIC in the IEEE 802.11 key in the case of TKIP. - add ic_psk to struct ieee80211com to store the pre-shared key. - fix setting of the SECURE bit in outgoing EAPOL-Key frames. - when receiving msg 2 of the 4-way handshake, deauthenticate the station if the RSN IE does not match that of the (Re)Association request. - before parsing an RSN or WPA IE, check that there's enough room for the version field (2 bytes) which is mandatory. - various tweaks while i'm here.
Diffstat (limited to 'sys/net80211/ieee80211_input.c')
-rw-r--r--sys/net80211/ieee80211_input.c147
1 files changed, 68 insertions, 79 deletions
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index 4b28c04c9ff..73f6bbcf5ea 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.63 2007/08/16 14:59:14 deraadt Exp $ */
+/* $OpenBSD: ieee80211_input.c,v 1.64 2007/08/22 20:40:34 damien Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
@@ -1034,9 +1034,9 @@ ieee80211_parse_rsn(struct ieee80211com *ic, struct ieee80211_node *ni,
const u_int8_t *frm)
{
/* check IE length */
- if (frm[1] < 2) {
+ if (frm[1] < 4) {
IEEE80211_DPRINTF(("%s: invalid RSN/WPA2 IE;"
- " length %u, expecting at least 2\n", __func__, frm[1]));
+ " length %u, expecting at least 4\n", __func__, frm[1]));
ic->ic_stats.is_rx_elem_toosmall++;
return IEEE80211_REASON_IE_INVALID;
}
@@ -1048,9 +1048,9 @@ ieee80211_parse_wpa1(struct ieee80211com *ic, struct ieee80211_node *ni,
const u_int8_t *frm)
{
/* check IE length */
- if (frm[1] < 6) {
+ if (frm[1] < 8) {
IEEE80211_DPRINTF(("%s: invalid WPA1 IE;"
- " length %u, expecting at least 6\n", __func__, frm[1]));
+ " length %u, expecting at least 8\n", __func__, frm[1]));
ic->ic_stats.is_rx_elem_toosmall++;
return IEEE80211_REASON_IE_INVALID;
}
@@ -1932,7 +1932,7 @@ ieee80211_recv_4way_msg1(struct ieee80211com *ic,
frm += 2 + frm[1];
}
/* check that the PMKID KDE is valid */
- if (pmkid != NULL && pmkid[1] - 4 < 16)
+ if (pmkid != NULL && pmkid[1] < 4 + 16)
return;
/* update the last seen value of the key replay counter field */
@@ -1945,7 +1945,9 @@ ieee80211_recv_4way_msg1(struct ieee80211com *ic,
if (ni->ni_akm == IEEE80211_AKM_IEEE8021X) {
/* XXX find the PMK in the PMKSA cache using the PMKID */
} else {
- /* XXX the PMK is the PSK */
+ /* the PMK is the PSK */
+ pmk = ic->ic_psk;
+ pmk_len = IEEE80211_PMK_LEN;
}
/* derive PTK from PMK */
@@ -1982,12 +1984,6 @@ ieee80211_recv_4way_msg2(struct ieee80211com *ic,
if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt)
return;
- /* derive PTK 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_ptk_ok = 1;
-
/* parse key data field (shall contain an RSN IE) */
frm = (const u_int8_t *)&key[1];
efrm = frm + BE_READ_2(key->paylen);
@@ -2021,8 +2017,18 @@ ieee80211_recv_4way_msg2(struct ieee80211com *ic,
* (Re)Association Request.
*/
if (ni->ni_rsnie == NULL || rsn[1] != ni->ni_rsnie[1] ||
- memcmp(rsn, ni->ni_rsnie, 2 + rsn[1]) != 0)
+ memcmp(rsn, ni->ni_rsnie, 2 + rsn[1]) != 0) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_IE_INVALID);
+ ieee80211_node_leave(ic, ni);
return;
+ }
+
+ /* derive PTK 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_ptk_ok = 1;
if (ic->ic_if.if_flags & IFF_DEBUG)
printf("%s: received msg %d/%d of the %s handshake from %s\n",
@@ -2105,55 +2111,58 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
*/
if (ni->ni_rsnie == NULL || rsn1[1] != ni->ni_rsnie[1] ||
memcmp(rsn1, ni->ni_rsnie, 2 + rsn1[1]) != 0)
+ /*ieee80211_new_state();*/
return;
- /* update the last seen value of the key replay counter field */
- ni->ni_replaycnt = BE_READ_8(key->replaycnt);
- ni->ni_replaycnt_ok = 1;
-
/*
* If a second RSN information element is present, use its pairwise
* cipher suite or deauthenticate.
*/
if (rsn2 != NULL) {
/* XXX ieee80211_parse_rsn(rsn2); */
+ /*ieee80211_new_state();*/
+ return;
}
+ /* update the last-seen value of the key replay counter field */
+ ni->ni_replaycnt = BE_READ_8(key->replaycnt);
+ ni->ni_replaycnt_ok = 1;
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: received msg %d/%d of the %s handshake from %s\n",
+ ic->ic_if.if_xname, 3, 4, "4-way",
+ ether_sprintf(ni->ni_macaddr));
+
+ /* 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;
- memset(k, 0, sizeof(*k));
- k->k_cipher = ni->ni_pairwise_cipher;
- k->k_flags = IEEE80211_KEY_TX;
- k->k_len = BE_READ_2(key->keylen);
- /* check that key length matches pairwise cipher */
- if (k->k_len != ieee80211_cipher_keylen(k->k_cipher))
- return;
- memcpy(k->k_key, ni->ni_ptk.tk, k->k_len);
+ 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;
if (gtk != NULL) {
+ u_int64_t rsc;
u_int8_t kid;
/* check that the GTK KDE is valid */
- if (gtk[1] - 4 < 2)
+ if (gtk[1] < 4 + 2)
return;
-
+ /* check that key length matches that of group cipher */
+ if (gtk[1] - 6 != ieee80211_cipher_keylen(ni->ni_group_cipher))
+ return; /* XXX PTK already installed! */
/* install the GTK */
kid = gtk[6] & 3;
+ rsc = LE_READ_8(key->rsc);
k = &ic->ic_nw_keys[kid];
- memset(k, 0, sizeof(*k));
- k->k_id = kid;
- k->k_cipher = ni->ni_group_cipher;
- k->k_flags = IEEE80211_KEY_GROUP;
- if (gtk[6] & (1 << 2)) /* Tx bit */
- k->k_flags |= IEEE80211_KEY_TX;
- k->k_len = gtk[1] - 6;
- /* check that key length matches group cipher */
- if (k->k_len != ieee80211_cipher_keylen(k->k_cipher))
- return; /* XXX PTK already installed! */
- memcpy(k->k_key, &gtk[8], k->k_len);
- k->k_rsc = LE_READ_8(key->rsc);
+ 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)
return;
@@ -2161,14 +2170,6 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
/* mark the PAE port as valid */
ni->ni_port_valid = 1;
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: received msg %d/%d of the %s handshake from %s\n",
- ic->ic_if.if_xname, 3, 4, "4-way",
- ether_sprintf(ni->ni_macaddr));
-
- /* send message 4 to authenticator */
- ieee80211_send_4way_msg4(ic, ni);
}
/*
@@ -2192,11 +2193,7 @@ ieee80211_recv_4way_msg4(struct ieee80211com *ic,
/* install the PTK */
k = &ni->ni_pairwise_key;
- memset(k, 0, sizeof(*k));
- k->k_cipher = ni->ni_pairwise_cipher;
- k->k_flags = IEEE80211_KEY_TX;
- k->k_len = ieee80211_cipher_keylen(k->k_cipher);
- memcpy(k->k_key, ni->ni_ptk.tk, k->k_len);
+ 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;
@@ -2213,6 +2210,8 @@ ieee80211_recv_4way_msg4(struct ieee80211com *ic,
printf("%s: received msg %d/%d of the %s handshake from %s\n",
ic->ic_if.if_xname, 4, 4, "4-way",
ether_sprintf(ni->ni_macaddr));
+
+ /* XXX start a group key handshake w/ WPA1 */
}
/*
@@ -2226,6 +2225,7 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic,
struct ieee80211_key *k;
const u_int8_t *frm, *efrm;
const u_int8_t *gtk;
+ u_int64_t rsc;
u_int8_t kid;
if (ic->ic_opmode != IEEE80211_M_STA &&
@@ -2262,24 +2262,17 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic,
return;
/* check that the GTK KDE is valid */
- if (gtk[1] - 4 < 2)
+ if (gtk[1] < 4 + 2)
+ return;
+ /* check that key length matches that of group cipher */
+ if (gtk[1] - 6 != ieee80211_cipher_keylen(ni->ni_group_cipher))
return;
-
/* install the GTK */
kid = gtk[6] & 3;
+ rsc = LE_READ_8(key->rsc);
k = &ic->ic_nw_keys[kid];
- memset(k, 0, sizeof(*k));
- k->k_id = kid;
- k->k_cipher = ni->ni_group_cipher;
- k->k_flags = IEEE80211_KEY_GROUP;
- if (gtk[6] & (1 << 2)) /* Tx bit */
- k->k_flags |= IEEE80211_KEY_TX;
- k->k_len = gtk[1] - 6;
- /* check that key length matches group cipher */
- if (k->k_len != ieee80211_cipher_keylen(k->k_cipher))
- return;
- memcpy(k->k_key, &gtk[8], k->k_len);
- k->k_rsc = LE_READ_8(key->rsc);
+ 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)
return;
@@ -2300,6 +2293,7 @@ ieee80211_recv_wpa_group_msg1(struct ieee80211com *ic,
struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
{
struct ieee80211_key *k;
+ u_int64_t rsc;
u_int16_t info;
u_int8_t kid;
@@ -2320,21 +2314,16 @@ ieee80211_recv_wpa_group_msg1(struct ieee80211com *ic,
info = BE_READ_2(key->info);
+ /* check that key length matches that of group cipher */
+ if (BE_READ_2(key->keylen) !=
+ ieee80211_cipher_keylen(ni->ni_group_cipher))
+ return;
/* install the GTK */
kid = (info >> EAPOL_KEY_WPA_KID_SHIFT) & 3;
+ rsc = LE_READ_8(key->rsc);
k = &ic->ic_nw_keys[kid];
- memset(k, 0, sizeof(*k));
- k->k_id = kid;
- k->k_cipher = ni->ni_group_cipher;
- k->k_flags = IEEE80211_KEY_GROUP;
- if (info & EAPOL_KEY_WPA_TX)
- k->k_flags |= IEEE80211_KEY_TX;
- k->k_len = BE_READ_2(key->keylen);
- /* check that key length matches group cipher */
- if (k->k_len != ieee80211_cipher_keylen(k->k_cipher))
- return;
- memcpy(k->k_key, (u_int8_t *)&key[1], k->k_len);
- k->k_rsc = LE_READ_8(key->rsc);
+ ieee80211_map_gtk((u_int8_t *)&key[1], ni->ni_group_cipher, kid,
+ info & EAPOL_KEY_WPA_TX, rsc, k);
if (ic->ic_set_key != NULL && (*ic->ic_set_key)(ic, ni, k) != 0)
return;