-/* $OpenBSD: ieee80211_pae_input.c,v 1.8 2008/08/12 17:53:13 damien Exp $ */
+/* $OpenBSD: ieee80211_pae_input.c,v 1.9 2008/08/12 18:22:41 damien Exp $ */
/*-
* Copyright (c) 2007,2008 Damien Bergamini <damien.bergamini@free.fr>
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * This code implements the 4-Way Handshake and Group Key Handshake protocols
+ * (both Supplicant and Authenticator Key Receive state machines) defined in
+ * IEEE Std 802.11-2007 section 8.5.
+ */
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
}
/*
- * 4-Way Handshake Message 1 is sent by the authenticator to the supplicant
- * (see 8.5.3.1).
+ * Process Message 1 of the 4-Way Handshake (sent by Authenticator).
*/
void
ieee80211_recv_4way_msg1(struct ieee80211com *ic,
ic->ic_stats.is_rx_eapol_replay++;
return;
}
- /* save authenticator's nonce (ANonce) */
- memcpy(ni->ni_nonce, key->nonce, EAPOL_KEY_NONCE_LEN);
/* parse key data field (may contain an encapsulated PMKID) */
frm = (const u_int8_t *)&key[1];
if (pmkid != NULL && pmkid[1] < 4 + 16)
return;
- /* generate a new supplicant's nonce (SNonce) */
- arc4random_buf(ic->ic_nonce, EAPOL_KEY_NONCE_LEN);
-
- /* retrieve PMK and derive TPTK */
- if ((pmk = ieee80211_get_pmk(ic, ni, pmkid)) == NULL) {
+ /* retrieve PMK */
+ if ((pmk = ieee80211_get_pmk(ic, ni, &pmkid[6])) == NULL) {
/* no PMK configured for this STA/PMKID */
return;
}
+ /* save authenticator's nonce (ANonce) */
+ memcpy(ni->ni_nonce, key->nonce, EAPOL_KEY_NONCE_LEN);
+
+ /* generate supplicant's nonce (SNonce) */
+ arc4random_buf(ic->ic_nonce, EAPOL_KEY_NONCE_LEN);
+
+ /* derive TPTK */
ieee80211_derive_ptk(ni->ni_rsnakms, pmk, ni->ni_macaddr,
- ic->ic_myaddr, key->nonce, ic->ic_nonce, &tptk);
+ ic->ic_myaddr, ni->ni_nonce, ic->ic_nonce, &tptk);
if (ic->ic_if.if_flags & IFF_DEBUG)
printf("%s: received msg %d/%d of the %s handshake from %s\n",
}
/*
- * 4-Way Handshake Message 2 is sent by the supplicant to the authenticator
- * (see 8.5.3.2).
+ * Process Message 2 of the 4-Way Handshake (sent by Supplicant).
*/
void
ieee80211_recv_4way_msg2(struct ieee80211com *ic,
}
/*
- * 4-Way Handshake Message 3 is sent by the authenticator to the supplicant
- * (see 8.5.3.3).
+ * Process Message 3 of the 4-Way Handshake (sent by Authenticator).
*/
void
ieee80211_recv_4way_msg3(struct ieee80211com *ic,
struct ieee80211_ptk tptk;
struct ieee80211_key *k;
const u_int8_t *frm, *efrm;
- const u_int8_t *rsnie1, *rsnie2, *gtk;
+ const u_int8_t *rsnie1, *rsnie2, *gtk, *igtk;
const u_int8_t *pmk;
u_int16_t info, reason = 0;
int keylen;
* RSN IEs in message 3/4. We only take into account the IE of the
* version of the protocol we negotiated at association time.
*/
- rsnie1 = rsnie2 = gtk = NULL;
+ rsnie1 = rsnie2 = gtk = igtk = NULL;
while (frm + 2 <= efrm) {
if (frm + 2 + frm[1] > efrm)
break;
case IEEE80211_KDE_GTK:
gtk = frm;
break;
+ case IEEE80211_KDE_IGTK:
+ if (ni->ni_flags & IEEE80211_NODE_MFP)
+ igtk = frm;
+ break;
}
} else if (memcmp(&frm[2], MICROSOFT_OUI, 3) == 0) {
switch (frm[5]) {
DPRINTF(("GTK not encrypted\n"));
return;
}
+ /* GTK KDE must be included if IGTK KDE is present */
+ if (igtk != NULL && gtk == NULL) {
+ DPRINTF(("IGTK KDE found but GTK KDE missing\n"));
+ return;
+ }
+
/*
* Check that first WPA/RSN IE is identical to the one received in
* the beacon or probe response frame.
reason = IEEE80211_REASON_AUTH_LEAVE;
goto deauth;
}
+ ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT;
ni->ni_flags |= IEEE80211_NODE_RXPROT;
}
if (gtk != NULL) {
goto deauth;
}
}
+ if (igtk != NULL) { /* implies MFP && gtk != NULL */
+ u_int16_t kid;
+
+ /* check that the IGTK KDE is valid */
+ if (igtk[1] != 4 + 24) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
+ kid = LE_READ_2(&igtk[6]);
+ if (kid != 4 && kid != 5) {
+ DPRINTF(("unsupported IGTK id %u\n", kid));
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
+ /* map IGTK to 802.11 key */
+ k = &ic->ic_nw_keys[kid];
+ memset(k, 0, sizeof(*k));
+ k->k_id = kid; /* either 4 or 5 */
+ k->k_cipher = ni->ni_rsngroupmgmtcipher;
+ k->k_flags = IEEE80211_KEY_IGTK;
+ k->k_mgmt_rsc = LE_READ_6(&igtk[8]); /* IPN */
+ k->k_len = 16;
+ memcpy(k->k_key, &igtk[14], k->k_len);
+ /* install the IGTK */
+ if ((*ic->ic_set_key)(ic, ni, k) != 0) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
+ }
if (info & EAPOL_KEY_INSTALL)
ni->ni_flags |= IEEE80211_NODE_TXRXPROT;
}
/*
- * 4-Way Handshake Message 4 is sent by the supplicant to the authenticator
- * (see 8.5.3.4).
+ * Process Message 4 of the 4-Way Handshake (sent by Supplicant).
*/
void
ieee80211_recv_4way_msg4(struct ieee80211com *ic,
}
/*
- * Group Key Handshake Message 1 is sent by the authenticator to the
- * supplicant (see 8.5.4.1).
+ * Process Message 1 of the RSN Group Key Handshake (sent by Authenticator).
*/
void
ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic,
{
struct ieee80211_key *k;
const u_int8_t *frm, *efrm;
- const u_int8_t *gtk;
- u_int16_t info;
- u_int8_t kid;
+ const u_int8_t *gtk, *igtk;
+ u_int16_t info, kid, reason = 0;
int keylen;
if (ic->ic_opmode != IEEE80211_M_STA &&
frm = (const u_int8_t *)&key[1];
efrm = frm + BE_READ_2(key->paylen);
- gtk = NULL;
+ gtk = igtk = NULL;
while (frm + 2 <= efrm) {
if (frm + 2 + frm[1] > efrm)
break;
case IEEE80211_KDE_GTK:
gtk = frm;
break;
+ case IEEE80211_KDE_IGTK:
+ if (ni->ni_flags & IEEE80211_NODE_MFP)
+ igtk = frm;
+ break;
}
}
break;
k->k_len = keylen;
/* install the GTK */
if ((*ic->ic_set_key)(ic, ni, k) != 0) {
- IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_AUTH_LEAVE);
- ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
- return;
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
+ if (igtk != NULL) { /* implies MFP */
+ /* check that the IGTK KDE is valid */
+ if (igtk[1] != 4 + 24) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
+ kid = LE_READ_2(&igtk[6]);
+ if (kid != 4 && kid != 5) {
+ DPRINTF(("unsupported IGTK id %u\n", kid));
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
+ /* map IGTK to 802.11 key */
+ k = &ic->ic_nw_keys[kid];
+ memset(k, 0, sizeof(*k));
+ k->k_id = kid; /* either 4 or 5 */
+ k->k_cipher = ni->ni_rsngroupmgmtcipher;
+ k->k_flags = IEEE80211_KEY_IGTK;
+ k->k_mgmt_rsc = LE_READ_6(&igtk[8]); /* IPN */
+ k->k_len = 16;
+ memcpy(k->k_key, &igtk[14], k->k_len);
+ /* install the IGTK */
+ if ((*ic->ic_set_key)(ic, ni, k) != 0) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
}
if (info & EAPOL_KEY_SECURE) {
if (ic->ic_opmode != IEEE80211_M_IBSS ||
ether_sprintf(ni->ni_macaddr));
/* send message 2 to authenticator */
- (void)ieee80211_send_group_msg2(ic, ni, k);
+ (void)ieee80211_send_group_msg2(ic, ni, NULL);
+ return;
+ deauth:
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, reason);
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
}
+/*
+ * Process Message 1 of the WPA Group Key Handshake (sent by Authenticator).
+ */
void
ieee80211_recv_wpa_group_msg1(struct ieee80211com *ic,
struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
}
/*
- * Group Key Handshake Message 2 is sent by the supplicant to the
- * authenticator (see 8.5.4.2).
+ * Process Message 2 of the Group Key Handshake (sent by Supplicant).
*/
void
ieee80211_recv_group_msg2(struct ieee80211com *ic,
if (!(info & EAPOL_KEY_KEYMIC) ||
ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
- DPRINTF(("key MIC failed\n"));
+ DPRINTF(("key request MIC failed\n"));
ic->ic_stats.is_rx_eapol_badmic++;
return;
}
-/* $OpenBSD: ieee80211_pae_output.c,v 1.5 2008/08/02 08:33:21 damien Exp $ */
+/* $OpenBSD: ieee80211_pae_output.c,v 1.6 2008/08/12 18:22:41 damien Exp $ */
/*-
* Copyright (c) 2007,2008 Damien Bergamini <damien.bergamini@free.fr>
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+ * This code implements the 4-Way Handshake and Group Key Handshake protocols
+ * (both Supplicant and Authenticator Key Transmit state machines) defined in
+ * IEEE Std 802.11-2007 section 8.5.
+ */
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
int ieee80211_send_eapol_key(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *, const struct ieee80211_ptk *);
-u_int8_t *ieee80211_add_gtk_kde(u_int8_t *, struct ieee80211_node *,
+u_int8_t *ieee80211_add_gtk_kde(u_int8_t *, struct ieee80211_node *,
const struct ieee80211_key *);
u_int8_t *ieee80211_add_pmkid_kde(u_int8_t *, const u_int8_t *);
+u_int8_t *ieee80211_add_igtk_kde(u_int8_t *,
+ const struct ieee80211_key *);
struct mbuf *ieee80211_get_eapol_key(int, int, u_int);
/*
return frm + IEEE80211_PMKID_LEN;
}
+/*
+ * Add an IGTK KDE to an EAPOL-Key frame (see Figure 8-32a).
+ */
+u_int8_t *
+ieee80211_add_igtk_kde(u_int8_t *frm, const struct ieee80211_key *k)
+{
+ KASSERT(k->k_flags & IEEE80211_KEY_IGTK);
+
+ *frm++ = IEEE80211_ELEMID_VENDOR;
+ *frm++ = 4 + 24;
+ memcpy(frm, IEEE80211_OUI, 3); frm += 3;
+ *frm++ = IEEE80211_KDE_IGTK;
+ LE_WRITE_2(frm, k->k_id); frm += 2;
+ LE_WRITE_6(frm, k->k_tsc); frm += 6; /* IPN */
+ memcpy(frm, k->k_key, 16);
+ return frm + 16;
+}
+
struct mbuf *
ieee80211_get_eapol_key(int flags, int type, u_int pktlen)
{
}
/*
- * 4-Way Handshake Message 1 is sent by the authenticator to the supplicant
- * (see 8.5.3.1).
+ * Send 4-Way Handshake Message 1 to the supplicant.
*/
int
ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
}
/*
- * 4-Way Handshake Message 2 is sent by the supplicant to the authenticator
- * (see 8.5.3.2).
+ * Send 4-Way Handshake Message 2 to the authenticator.
*/
int
ieee80211_send_4way_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
frm = (u_int8_t *)&key[1];
/* add the WPA/RSN IE used in the (Re)Association Request */
if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
- u_int16_t keylen;
+ int keylen;
frm = ieee80211_add_wpa(frm, ic, ni);
/* WPA sets the key length field here */
keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
}
/*
- * 4-Way Handshake Message 3 is sent by the authenticator to the supplicant
- * (see 8.5.3.3).
+ * Send 4-Way Handshake Message 3 to the supplicant.
*/
int
ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni)
2 + 48 +
((ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ?
2 + 6 + k->k_len : 0) +
+ ((ni->ni_flags & IEEE80211_NODE_MFP) ? 2 + 28 : 0) +
8);
if (m == NULL)
return ENOMEM;
/* add the WPA/RSN IE included in Beacon/Probe Response */
if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) {
frm = ieee80211_add_rsn(frm, ic, ic->ic_bss);
- /* encapsulate the GTK and ask for encryption */
+ /* encapsulate the GTK */
frm = ieee80211_add_gtk_kde(frm, ni, k);
LE_WRITE_6(key->rsc, k->k_tsc);
+ /* encapsulate the IGTK if MFP was negotiated */
+ if (ni->ni_flags & IEEE80211_NODE_MFP) {
+ frm = ieee80211_add_igtk_kde(frm,
+ &ic->ic_nw_keys[ic->ic_igtk_kid]);
+ }
+ /* ask that the EAPOL-Key frame be encrypted */
info |= EAPOL_KEY_ENCRYPTED | EAPOL_KEY_SECURE;
} else /* WPA */
frm = ieee80211_add_wpa(frm, ic, ic->ic_bss);
}
/*
- * 4-Way Handshake Message 4 is sent by the supplicant to the authenticator
- * (see 8.5.3.4).
+ * Send 4-Way Handshake Message 4 to the authenticator.
*/
int
ieee80211_send_4way_msg4(struct ieee80211com *ic, struct ieee80211_node *ni)
BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
- u_int16_t keylen;
+ int keylen;
/* WPA sets the key length field here */
keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
BE_WRITE_2(key->keylen, keylen);
}
/*
- * Group Key Handshake Message 1 is sent by the authenticator to the
- * supplicant (see 8.5.4.1).
+ * Send Group Key Handshake Message 1 to the supplicant.
*/
int
ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
((ni->ni_rsnprotos == IEEE80211_PROTO_WPA) ?
k->k_len : 2 + 6 + k->k_len) +
+ ((ni->ni_flags & IEEE80211_NODE_MFP) ? 2 + 28 : 0) +
8);
if (m == NULL)
return ENOMEM;
info |= (k->k_id & 0x3) << EAPOL_KEY_WPA_KID_SHIFT;
if (ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP)
info |= EAPOL_KEY_WPA_TX;
- } else /* RSN */
+ } else { /* RSN */
frm = ieee80211_add_gtk_kde(frm, ni, k);
-
+ if (ni->ni_flags & IEEE80211_NODE_MFP) {
+ frm = ieee80211_add_igtk_kde(frm,
+ &ic->ic_nw_keys[ic->ic_igtk_kid]);
+ }
+ }
/* RSC = last transmit sequence number for the GTK */
LE_WRITE_6(key->rsc, k->k_tsc);
}
/*
- * Group Key Handshake Message 2 is sent by the supplicant to the
- * authenticator (see 8.5.4.2).
+ * Send Group Key Handshake Message 2 to the authenticator.
*/
int
ieee80211_send_group_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,