OCV: Insert OCI in 4-way and group key handshake

If Operating Channel Verification is negotiated, include the OCI KDE
element in EAPOL-Key msg 2/4 and 3/4 of the 4-way handshake and both
messages of the group key handshake.

Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
This commit is contained in:
Mathy Vanhoef 2018-08-06 15:46:27 -04:00 committed by Jouni Malinen
parent 6ab73efa72
commit 17c2559caf
3 changed files with 139 additions and 6 deletions

View file

@ -13,6 +13,7 @@
#include "utils/state_machine.h"
#include "utils/bitfield.h"
#include "common/ieee802_11_defs.h"
#include "common/ocv.h"
#include "crypto/aes.h"
#include "crypto/aes_wrap.h"
#include "crypto/aes_siv.h"
@ -22,6 +23,7 @@
#include "crypto/sha384.h"
#include "crypto/random.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "drivers/driver.h"
#include "ap_config.h"
#include "ieee802_11.h"
#include "wpa_auth.h"
@ -238,6 +240,17 @@ static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
}
#ifdef CONFIG_OCV
static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
struct wpa_channel_info *ci)
{
if (!wpa_auth->cb->channel_info)
return -1;
return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
}
#endif /* CONFIG_OCV */
static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_authenticator *wpa_auth = eloop_ctx;
@ -2883,6 +2896,36 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
#endif /* CONFIG_IEEE80211W */
static int ocv_oci_len(struct wpa_state_machine *sm)
{
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm))
return OCV_OCI_KDE_LEN;
#endif /* CONFIG_OCV */
return 0;
}
static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
{
#ifdef CONFIG_OCV
struct wpa_channel_info ci;
if (!wpa_auth_uses_ocv(sm))
return 0;
if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
wpa_printf(MSG_WARNING,
"Failed to get channel info for OCI element");
return -1;
}
return ocv_insert_oci_kde(&ci, argpos);
#else /* CONFIG_OCV */
return 0;
#endif /* CONFIG_OCV */
}
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
@ -2966,7 +3009,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
}
}
kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@ -3011,6 +3054,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
gtk, gtk_len);
}
pos = ieee80211w_kde_add(sm, pos);
if (ocv_oci_add(sm, &pos) < 0) {
os_free(kde);
return;
}
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@ -3322,7 +3369,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
}
if (sm->wpa == WPA_VERSION_WPA2) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm);
ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
if (kde_buf == NULL)
return;
@ -3333,6 +3380,10 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gsm->GTK_len);
pos = ieee80211w_kde_add(sm, pos);
if (ocv_oci_add(sm, &pos) < 0) {
os_free(kde_buf);
return;
}
kde_len = pos - kde;
} else {
kde = gtk;
@ -4666,7 +4717,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
}
}
kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@ -4715,6 +4766,10 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
os_memset(opos, 0, 6); /* clear PN */
}
#endif /* CONFIG_IEEE80211W */
if (ocv_oci_add(sm, &pos) < 0) {
os_free(kde);
return -1;
}
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@ -4796,7 +4851,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
gtk = gsm->GTK[gsm->GN - 1];
if (sm->wpa == WPA_VERSION_WPA2) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm);
ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
if (kde_buf == NULL)
return -1;
@ -4816,6 +4871,10 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
os_memset(opos, 0, 6); /* clear PN */
}
#endif /* CONFIG_IEEE80211W */
if (ocv_oci_add(sm, &pos) < 0) {
os_free(kde_buf);
return -1;
}
kde_len = pos - kde;
} else {
kde = gtk;

View file

@ -20,8 +20,10 @@
#include "crypto/sha512.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
#include "eap_common/eap_defs.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "drivers/driver.h"
#include "wpa.h"
#include "eloop.h"
#include "preauth.h"
@ -618,6 +620,33 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
kde = sm->assoc_wpa_ie;
kde_len = sm->assoc_wpa_ie_len;
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm)) {
struct wpa_channel_info ci;
u8 *pos;
if (wpa_sm_channel_info(sm, &ci) != 0) {
wpa_printf(MSG_WARNING,
"Failed to get channel info for OCI element in EAPOL-Key 2/4");
goto failed;
}
kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 3);
if (!kde_buf) {
wpa_printf(MSG_WARNING,
"Failed to allocate memory for KDE with OCI in EAPOL-Key 2/4");
goto failed;
}
os_memcpy(kde_buf, kde, kde_len);
kde = kde_buf;
pos = kde + kde_len;
if (ocv_insert_oci_kde(&ci, &pos) < 0)
goto failed;
kde_len = pos - kde;
}
#endif /* CONFIG_OCV */
#ifdef CONFIG_P2P
if (sm->p2p) {
kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
@ -1631,11 +1660,17 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
u8 *rbuf, *key_mic;
size_t kde_len = 0;
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm))
kde_len = OCV_OCI_KDE_LEN;
#endif /* CONFIG_OCV */
mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
hdrlen = sizeof(*reply) + mic_len + 2;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
hdrlen, &rlen, (void *) &reply);
hdrlen + kde_len, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
@ -1657,7 +1692,27 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
WPA_REPLAY_COUNTER_LEN);
key_mic = (u8 *) (reply + 1);
WPA_PUT_BE16(key_mic + mic_len, 0);
WPA_PUT_BE16(key_mic + mic_len, kde_len); /* Key Data Length */
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm)) {
struct wpa_channel_info ci;
u8 *pos;
if (wpa_sm_channel_info(sm, &ci) != 0) {
wpa_printf(MSG_WARNING,
"Failed to get channel info for OCI element in EAPOL-Key 2/2");
os_free(rbuf);
return -1;
}
pos = key_mic + mic_len + 2; /* Key Data */
if (ocv_insert_oci_kde(&ci, &pos) < 0) {
os_free(rbuf);
return -1;
}
}
#endif /* CONFIG_OCV */
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
return wpa_eapol_key_send(sm, &sm->ptk, ver, sm->bssid, ETH_P_EAPOL,
@ -2941,6 +2996,19 @@ int wpa_sm_pmf_enabled(struct wpa_sm *sm)
}
int wpa_sm_ocv_enabled(struct wpa_sm *sm)
{
struct wpa_ie_data rsn;
if (!sm->ocv || !sm->ap_rsn_ie)
return 0;
return wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len,
&rsn) >= 0 &&
(rsn.capabilities & WPA_CAPABILITY_OCVC);
}
/**
* wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
* @sm: Pointer to WPA state machine data from wpa_sm_init()

View file

@ -144,6 +144,7 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose);
int wpa_sm_pmf_enabled(struct wpa_sm *sm);
int wpa_sm_ocv_enabled(struct wpa_sm *sm);
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
@ -282,6 +283,11 @@ static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm)
return 0;
}
static inline int wpa_sm_ocv_enabled(struct wpa_sm *sm)
{
return 0;
}
static inline void wpa_sm_key_request(struct wpa_sm *sm, int error,
int pairwise)
{