diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2007-08-22 20:40:35 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2007-08-22 20:40:35 +0000 |
commit | 4f19245ee53a151b1ae297678ba39835912a1efe (patch) | |
tree | ffc09b7a85fca0e699375187b82c2732970611ec /sys/net80211/ieee80211_input.c | |
parent | dd654a77e55db513af679bbba472472b1a70b096 (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.c | 147 |
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, >k[8], k->k_len); - k->k_rsc = LE_READ_8(key->rsc); + ieee80211_map_gtk(>k[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, >k[8], k->k_len); - k->k_rsc = LE_READ_8(key->rsc); + ieee80211_map_gtk(>k[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; |