]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
OCV: Insert OCI in 4-way and group key handshake
authorMathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
Mon, 6 Aug 2018 19:46:27 +0000 (15:46 -0400)
committerJouni Malinen <j@w1.fi>
Sun, 16 Dec 2018 22:02:14 +0000 (00:02 +0200)
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>
src/ap/wpa_auth.c
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h

index 34969e79e46ff6aa61b207a61d85f3d9e58875ce..b67fd6c44cc48954df7ed4735f2d11b75a652a41 100644 (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;
index 521f5a22073f08a6084b64e6852858e65170e084..183bd1aa298ed5051e54e3224abca57298e247c9 100644 (file)
 #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()
index b832267a51a7f9ed230f83fd326d216112579250..9eee383de60f38145fd2e40e2f3a5ceccac6f52a 100644 (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)
 {