/*
 * Send 4-Way Handshake Message 1 to the supplicant.
 */
int
ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
{
	struct ieee80211_eapol_key *key;
	struct mbuf *m;
	u_int16_t info, keylen;
	u_int8_t *frm;

	ni->ni_rsn_state = RSNA_PTKSTART;
	if (++ni->ni_rsn_retries > 3) {
		IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
		    IEEE80211_REASON_4WAY_TIMEOUT);
		ieee80211_node_leave(ic, ni);
		return 0;
	}
	m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
	    (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ? 2 + 20 : 0);
	if (m == NULL)
		return ENOMEM;
	key = mtod(m, struct ieee80211_eapol_key *);
	memset(key, 0, sizeof(*key));

	info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYACK;
	BE_WRITE_2(key->info, info);

	/* copy the authenticator's nonce (ANonce) */
	memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN);

	keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
	BE_WRITE_2(key->keylen, keylen);

	frm = (u_int8_t *)&key[1];
	/* NB: WPA does not have PMKID KDE */
	if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN &&
	    ieee80211_is_8021x_akm(ni->ni_rsnakms))
		frm = ieee80211_add_pmkid_kde(frm, ni->ni_pmkid);

	m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;

	if (ic->ic_if.if_flags & IFF_DEBUG)
		printf("%s: sending msg %d/%d of the %s handshake to %s\n",
		    ic->ic_if.if_xname, 1, 4, "4-way",
		    ether_sprintf(ni->ni_macaddr));

	ni->ni_replaycnt++;
	BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);

	return ieee80211_send_eapol_key(ic, m, ni, NULL);
}
/*
 * Send 4-Way Handshake Message 2 to the authenticator.
 */
int
ieee80211_send_4way_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
    const u_int8_t *replaycnt, const struct ieee80211_ptk *tptk)
{
	struct ieee80211_eapol_key *key;
	struct mbuf *m;
	u_int16_t info;
	u_int8_t *frm;

	m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
	    (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) ?
		2 + IEEE80211_WPAIE_MAXLEN :
		2 + IEEE80211_RSNIE_MAXLEN);
	if (m == NULL)
		return ENOMEM;
	key = mtod(m, struct ieee80211_eapol_key *);
	memset(key, 0, sizeof(*key));

	info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYMIC;
	BE_WRITE_2(key->info, info);

	/* copy key replay counter from Message 1/4 */
	memcpy(key->replaycnt, replaycnt, 8);

	/* copy the supplicant's nonce (SNonce) */
	memcpy(key->nonce, ic->ic_nonce, EAPOL_KEY_NONCE_LEN);

	frm = (u_int8_t *)&key[1];
	/* add the WPA/RSN IE used in the (Re)Association Request */
	if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
		int keylen;
		frm = ieee80211_add_wpa(frm, ic, ni);
		/* WPA sets the key length field here */
		keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
		BE_WRITE_2(key->keylen, keylen);
	} else	/* RSN */
		frm = ieee80211_add_rsn(frm, ic, ni);

	m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;

	if (ic->ic_if.if_flags & IFF_DEBUG)
		printf("%s: sending msg %d/%d of the %s handshake to %s\n",
		    ic->ic_if.if_xname, 2, 4, "4-way",
		    ether_sprintf(ni->ni_macaddr));

	return ieee80211_send_eapol_key(ic, m, ni, tptk);
}
/*
 * Send 4-Way Handshake Message 4 to the authenticator.
 */
int
ieee80211_send_4way_msg4(struct ieee80211com *ic, struct ieee80211_node *ni)
{
	struct ieee80211_eapol_key *key;
	struct mbuf *m;
	u_int16_t info;

	m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA, 0);
	if (m == NULL)
		return ENOMEM;
	key = mtod(m, struct ieee80211_eapol_key *);
	memset(key, 0, sizeof(*key));

	info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYMIC;

	/* copy key replay counter from authenticator */
	BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);

	if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
		int keylen;
		/* WPA sets the key length field here */
		keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
		BE_WRITE_2(key->keylen, keylen);
	} else
		info |= EAPOL_KEY_SECURE;

	/* write the key info field */
	BE_WRITE_2(key->info, info);

	/* empty key data field */
	m->m_pkthdr.len = m->m_len = sizeof(*key);

	if (ic->ic_if.if_flags & IFF_DEBUG)
		printf("%s: sending msg %d/%d of the %s handshake to %s\n",
		    ic->ic_if.if_xname, 4, 4, "4-way",
		    ether_sprintf(ni->ni_macaddr));

	return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
}
/*
 * Send 4-Way Handshake Message 3 to the supplicant.
 */
int
ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni)
{
	struct ieee80211_eapol_key *key;
	struct ieee80211_key *k = NULL;
	struct mbuf *m;
	u_int16_t info, keylen;
	u_int8_t *frm;

	ni->ni_rsn_state = RSNA_PTKINITNEGOTIATING;
	if (++ni->ni_rsn_retries > 3) {
		IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
		    IEEE80211_REASON_4WAY_TIMEOUT);
		ieee80211_node_leave(ic, ni);
		return 0;
	}
	if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) {
		k = &ic->ic_nw_keys[ic->ic_def_txkey];
		m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
		    2 + IEEE80211_RSNIE_MAXLEN + 2 + 6 + k->k_len + 15 +
		    ((ni->ni_flags & IEEE80211_NODE_MFP) ? 2 + 28 : 0));
	} else { /* WPA */
		m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
		    2 + IEEE80211_WPAIE_MAXLEN +
		    ((ni->ni_flags & IEEE80211_NODE_MFP) ? 2 + 28 : 0));
	}
	if (m == NULL)
		return ENOMEM;
	key = mtod(m, struct ieee80211_eapol_key *);
	memset(key, 0, sizeof(*key));

	info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYACK | EAPOL_KEY_KEYMIC;
	if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP)
		info |= EAPOL_KEY_INSTALL;

	/* use same nonce as in Message 1 */
	memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN);

	ni->ni_replaycnt++;
	BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);

	keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
	BE_WRITE_2(key->keylen, keylen);

	frm = (u_int8_t *)&key[1];
	/* 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 */
		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);

	/* write the key info field */
	BE_WRITE_2(key->info, info);

	m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;

	if (ic->ic_if.if_flags & IFF_DEBUG)
		printf("%s: sending msg %d/%d of the %s handshake to %s\n",
		    ic->ic_if.if_xname, 3, 4, "4-way",
		    ether_sprintf(ni->ni_macaddr));

	return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
}
Esempio n. 5
0
void
ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
{
	struct ieee80211_node *ni;
	struct ifnet *ifp = &ic->ic_if;

	ni = ic->ic_bss;
	if (ifp->if_flags & IFF_DEBUG)
		printf("%s: creating ibss\n", ifp->if_xname);
	ic->ic_flags |= IEEE80211_F_SIBSS;
	ni->ni_chan = chan;
	ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
	ni->ni_txrate = 0;
	IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr);
	IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
	if (ic->ic_opmode == IEEE80211_M_IBSS) {
		if ((ic->ic_flags & IEEE80211_F_DESBSSID) != 0)
			IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid);
		else
			ni->ni_bssid[0] |= 0x02;	/* local bit for IBSS */
	}
	ni->ni_esslen = ic->ic_des_esslen;
	memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
	ni->ni_rssi = 0;
	ni->ni_rstamp = 0;
	memset(ni->ni_tstamp, 0, sizeof(ni->ni_tstamp));
	ni->ni_intval = ic->ic_lintval;
	ni->ni_capinfo = IEEE80211_CAPINFO_IBSS;
	if (ic->ic_flags & IEEE80211_F_WEPON)
		ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
	if (ic->ic_flags & IEEE80211_F_RSNON) {
		struct ieee80211_key *k;

		/* initialize 256-bit global key counter to a random value */
		arc4random_buf(ic->ic_globalcnt, EAPOL_KEY_NONCE_LEN);

		ni->ni_rsnprotos = ic->ic_rsnprotos;
		ni->ni_rsnakms = ic->ic_rsnakms;
		ni->ni_rsnciphers = ic->ic_rsnciphers;
		ni->ni_rsngroupcipher = ic->ic_rsngroupcipher;
		ni->ni_rsngroupmgmtcipher = ic->ic_rsngroupmgmtcipher;
		ni->ni_rsncaps = 0;
		if (ic->ic_caps & IEEE80211_C_MFP) {
			ni->ni_rsncaps |= IEEE80211_RSNCAP_MFPC;
			if (ic->ic_flags & IEEE80211_F_MFPR)
				ni->ni_rsncaps |= IEEE80211_RSNCAP_MFPR;
		}

		ic->ic_def_txkey = 1;
		k = &ic->ic_nw_keys[ic->ic_def_txkey];
		memset(k, 0, sizeof(*k));
		k->k_id = ic->ic_def_txkey;
		k->k_cipher = ni->ni_rsngroupcipher;
		k->k_flags = IEEE80211_KEY_GROUP | IEEE80211_KEY_TX;
		k->k_len = ieee80211_cipher_keylen(k->k_cipher);
		arc4random_buf(k->k_key, k->k_len);
		(*ic->ic_set_key)(ic, ni, k);	/* XXX */

		if (ic->ic_caps & IEEE80211_C_MFP) {
			ic->ic_igtk_kid = 4;
			k = &ic->ic_nw_keys[ic->ic_igtk_kid];
			memset(k, 0, sizeof(*k));
			k->k_id = ic->ic_igtk_kid;
			k->k_cipher = ni->ni_rsngroupmgmtcipher;
			k->k_flags = IEEE80211_KEY_IGTK | IEEE80211_KEY_TX;
			k->k_len = 16;
			arc4random_buf(k->k_key, k->k_len);
			(*ic->ic_set_key)(ic, ni, k);	/* XXX */
		}
		/*
		 * In HostAP mode, multicast traffic is sent using ic_bss
		 * as the Tx node, so mark our node as valid so we can send
		 * multicast frames using the group key we've just configured.
		 */
		ni->ni_port_valid = 1;
		ni->ni_flags |= IEEE80211_NODE_TXPROT;

		/* schedule a GTK/IGTK rekeying after 3600s */
		timeout_add_sec(&ic->ic_rsn_timeout, 3600);
	}
	timeout_add_sec(&ic->ic_inact_timeout, IEEE80211_INACT_WAIT);
	timeout_add_sec(&ic->ic_node_cache_timeout, IEEE80211_CACHE_WAIT);
	ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
}