diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2007-08-27 20:14:22 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2007-08-27 20:14:22 +0000 |
commit | 58539899cfe072884268bb8d2718faa616f36e3e (patch) | |
tree | e4c1e149cf2f847463ec1dfba259b53ee723f051 | |
parent | 7c2b325da7734bb3e0fd9d4e92cde7c44fb85895 (diff) |
rework ieee80211_recv_4way_msg2() function.
add some RSNA authenticator state machine bits.
-rw-r--r-- | sys/net80211/ieee80211_input.c | 110 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.h | 27 | ||||
-rw-r--r-- | sys/net80211/ieee80211_output.c | 13 |
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) ? |