summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2007-08-27 20:14:22 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2007-08-27 20:14:22 +0000
commit58539899cfe072884268bb8d2718faa616f36e3e (patch)
treee4c1e149cf2f847463ec1dfba259b53ee723f051
parent7c2b325da7734bb3e0fd9d4e92cde7c44fb85895 (diff)
rework ieee80211_recv_4way_msg2() function.
add some RSNA authenticator state machine bits.
-rw-r--r--sys/net80211/ieee80211_input.c110
-rw-r--r--sys/net80211/ieee80211_node.h27
-rw-r--r--sys/net80211/ieee80211_output.c13
3 files changed, 101 insertions, 49 deletions
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index 714a1711918..3734c26d48a 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.68 2007/08/27 18:53:27 damien Exp $ */
+/* $OpenBSD: ieee80211_input.c,v 1.69 2007/08/27 20:14:21 damien Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
@@ -102,11 +102,14 @@ void ieee80211_recv_disassoc(struct ieee80211com *, struct mbuf *,
void ieee80211_recv_4way_msg1(struct ieee80211com *,
struct ieee80211_eapol_key *, struct ieee80211_node *);
void ieee80211_recv_4way_msg2(struct ieee80211com *,
- struct ieee80211_eapol_key *, struct ieee80211_node *);
+ struct ieee80211_eapol_key *, struct ieee80211_node *,
+ const u_int8_t *);
void ieee80211_recv_4way_msg3(struct ieee80211com *,
struct ieee80211_eapol_key *, struct ieee80211_node *);
void ieee80211_recv_4way_msg4(struct ieee80211com *,
struct ieee80211_eapol_key *, struct ieee80211_node *);
+void ieee80211_recv_4way_msg2or4(struct ieee80211com *,
+ struct ieee80211_eapol_key *, struct ieee80211_node *);
void ieee80211_recv_rsn_group_msg1(struct ieee80211com *,
struct ieee80211_eapol_key *, struct ieee80211_node *);
void ieee80211_recv_wpa_group_msg1(struct ieee80211com *,
@@ -2012,50 +2015,18 @@ ieee80211_recv_4way_msg1(struct ieee80211com *ic,
*/
void
ieee80211_recv_4way_msg2(struct ieee80211com *ic,
- struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
+ struct ieee80211_eapol_key *key, struct ieee80211_node *ni,
+ const u_int8_t *rsn)
{
- const u_int8_t *frm, *efrm;
- const u_int8_t *rsn;
const u_int8_t *pmk;
size_t pmk_len;
- if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
- ic->ic_opmode != IEEE80211_M_IBSS)
- return;
-
- if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt)
+ /* discard if we're not expecting this message */
+ if (ni->ni_rsn_state != RSNA_PTKSTART &&
+ ni->ni_rsn_state != RSNA_PTKCALCNEGOTIATING)
return;
- /* parse key data field (shall contain an RSN IE) */
- frm = (const u_int8_t *)&key[1];
- efrm = frm + BE_READ_2(key->paylen);
-
- rsn = NULL;
- while (frm + 2 <= efrm) {
- if (frm + 2 + frm[1] > efrm)
- break;
- switch (frm[0]) {
- case IEEE80211_ELEMID_RSN:
- rsn = frm;
- break;
- case IEEE80211_ELEMID_VENDOR:
- if (frm[1] < 4)
- break;
- if (memcmp(&frm[2], MICROSOFT_OUI, 3) == 0) {
- switch (frm[5]) {
- case 1: /* WPA */
- rsn = frm;
- break;
- }
- }
- }
- frm += 2 + frm[1];
- }
- if (rsn == NULL) {
- /* no RSN/WPA IE, must be message 4 of the 4-Way Handshake */
- ieee80211_recv_4way_msg4(ic, key, ni);
- return;
- }
+ ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING;
/* derive PTK from PMK */
ieee80211_derive_ptk(pmk, pmk_len, ic->ic_myaddr, ni->ni_macaddr,
@@ -2078,6 +2049,9 @@ ieee80211_recv_4way_msg2(struct ieee80211com *ic,
return;
}
+ ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING_2;
+ ni->ni_rsn_tocnt = 0;
+
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, 2, 4, "4-way",
@@ -2242,15 +2216,16 @@ ieee80211_recv_4way_msg4(struct ieee80211com *ic,
{
struct ieee80211_key *k;
- /*
- * ic->ic_opmode and key->replaycnt have already been validated by
- * ieee80211_recv_4way_msg2() from where we're called.
- */
+ /* discard if we're not expecting this message */
+ if (ni->ni_rsn_state != RSNA_PTKINITNEGOTIATING)
+ return;
/* check Key MIC field using KCK */
if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0)
return;
+ ni->ni_rsn_state = RSNA_PTKINITDONE;
+
/* empty key data field */
/* install the PTK */
@@ -2277,6 +2252,51 @@ ieee80211_recv_4way_msg4(struct ieee80211com *ic,
}
/*
+ * Differentiate Message 2 from Message 4 of the 4-Way Handshake based on
+ * the presence of an RSN or WPA Information Element.
+ */
+void
+ieee80211_recv_4way_msg2or4(struct ieee80211com *ic,
+ struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
+{
+ const u_int8_t *frm, *efrm;
+ const u_int8_t *rsn;
+
+ if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt)
+ return;
+
+ /* parse key data field (check if an RSN IE is present) */
+ frm = (const u_int8_t *)&key[1];
+ efrm = frm + BE_READ_2(key->paylen);
+
+ rsn = NULL;
+ while (frm + 2 <= efrm) {
+ if (frm + 2 + frm[1] > efrm)
+ break;
+ switch (frm[0]) {
+ case IEEE80211_ELEMID_RSN:
+ rsn = frm;
+ break;
+ case IEEE80211_ELEMID_VENDOR:
+ if (frm[1] < 4)
+ break;
+ if (memcmp(&frm[2], MICROSOFT_OUI, 3) == 0) {
+ switch (frm[5]) {
+ case 1: /* WPA */
+ rsn = frm;
+ break;
+ }
+ }
+ }
+ frm += 2 + frm[1];
+ }
+ if (rsn != NULL)
+ ieee80211_recv_4way_msg2(ic, key, ni, rsn);
+ else
+ ieee80211_recv_4way_msg4(ic, key, ni);
+}
+
+/*
* Group Key Handshake Message 1 is sent by the authenticator to the
* supplicant (see 8.5.4.1).
*/
@@ -2565,7 +2585,7 @@ ieee80211_recv_eapol(struct ieee80211com *ic, struct mbuf *m0,
if (info & EAPOL_KEY_KEYACK)
ieee80211_recv_4way_msg3(ic, key, ni);
else
- ieee80211_recv_4way_msg2(ic, key, ni);
+ ieee80211_recv_4way_msg2or4(ic, key, ni);
} else
ieee80211_recv_4way_msg1(ic, key, ni);
} else {
diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h
index 790fb4606ec..ebb61be724d 100644
--- a/sys/net80211/ieee80211_node.h
+++ b/sys/net80211/ieee80211_node.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_node.h,v 1.22 2007/08/27 18:53:27 damien Exp $ */
+/* $OpenBSD: ieee80211_node.h,v 1.23 2007/08/27 20:14:21 damien Exp $ */
/* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */
/*-
@@ -65,6 +65,29 @@ enum ieee80211_node_state {
(__ni)->ni_state = (__state); \
} while (0)
+/* RSNA Authenticator state machine (see 8.5.6). */
+enum {
+ RSNA_AUTHENTICATION,
+ RSNA_AUTHENTICATION_2,
+ RSNA_INITPMK,
+ RSNA_INITPSK,
+ RSNA_PTKSTART,
+ RSNA_PTKCALCNEGOTIATING,
+ RSNA_PTKCALCNEGOTIATING_2,
+ RSNA_PTKINITNEGOTIATING,
+ RSNA_PTKINITDONE,
+ RSNA_DISCONNECT,
+ RSNA_DISCONNECTED,
+ RSNA_INITIALIZE,
+ RSNA_IDLE,
+ RSNA_REKEYNEGOTIATING,
+ RSNA_KEYERROR,
+ RSNA_REKEYESTABLISHED,
+ RSNA_GTK_INIT,
+ RSNA_SETKEYSDONE,
+ RSNA_SETKEYS
+};
+
/*
* Node specific information. Note that drivers are expected
* to derive from this structure to add device-specific per-node
@@ -113,6 +136,8 @@ struct ieee80211_node {
struct ifqueue ni_savedq; /* packets queued for pspoll */
/* RSN */
+ u_int ni_rsn_state;
+ u_int ni_rsn_tocnt;
u_int ni_group_cipher;
enum ieee80211_cipher ni_pairwise_cipher;
u_int ni_pairwise_cipherset;
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index 31e8a3a15a5..6523e409cf8 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_output.c,v 1.57 2007/08/27 18:53:27 damien Exp $ */
+/* $OpenBSD: ieee80211_output.c,v 1.58 2007/08/27 20:14:21 damien Exp $ */
/* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */
/*-
@@ -1627,6 +1627,10 @@ ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
u_int8_t *pmkid;
u_int8_t *frm;
+ ni->ni_rsn_state = RSNA_PTKSTART;
+ if (++ni->ni_rsn_tocnt == 3)
+ return 0; /* XXX move to RSNA_DISCONNECT */
+
m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
(ni->ni_eapol_desc == EAPOL_KEY_DESC_IEEE80211) ? 2 + 20 : 0);
if (m == NULL)
@@ -1637,8 +1641,7 @@ ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYACK;
BE_WRITE_2(key->info, info);
- /* generate a new nonce ANonce */
- get_random_bytes(ni->ni_nonce, EAPOL_KEY_NONCE_LEN);
+ /* copy the authenticator's nonce (ANonce) */
memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN);
keylen = ieee80211_cipher_keylen(ni->ni_pairwise_cipher);
@@ -1724,6 +1727,10 @@ ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni)
u_int16_t info, keylen;
u_int8_t *frm;
+ ni->ni_rsn_state = RSNA_PTKINITNEGOTIATING;
+ if (++ni->ni_rsn_tocnt == 3)
+ return 0; /* XXX move to RSNA_KEYERROR */
+
m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
2 + 48 +
((ni->ni_eapol_desc == EAPOL_KEY_DESC_IEEE80211) ?