]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Testing functionality for EAPOL-Key Key Data field encryption
authorJouni Malinen <quic_jouni@quicinc.com>
Tue, 16 Jan 2024 19:11:23 +0000 (21:11 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 16 Jan 2024 20:04:55 +0000 (22:04 +0200)
Allow the Key Data field to be encrypted in EAPOL-Key msg 2/4 and 4/4.
This is for testing purposes to enable a convenient mechanism for
testing Authenticator behavior with either potential future extensions
or unexpected Supplicant behavior.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
src/rsn_supp/wpa_i.h
wpa_supplicant/Android.mk
wpa_supplicant/Makefile
wpa_supplicant/ctrl_iface.c

index e2e05eb455c667ceacd87f3ac8115fbb5c6779f6..6797d65d639afc42f9f7f8323560123ec534be9a 100644 (file)
@@ -526,6 +526,9 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
        u8 *rbuf, *key_mic;
        u8 *rsn_ie_buf = NULL;
        u16 key_info;
+#ifdef CONFIG_TESTING_OPTIONS
+       size_t pad_len = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
 
        if (wpa_ie == NULL) {
                wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No wpa_ie set - "
@@ -576,6 +579,12 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
 #ifdef CONFIG_TESTING_OPTIONS
        if (sm->test_eapol_m2_elems)
                extra_len = wpabuf_len(sm->test_eapol_m2_elems);
+       if (sm->encrypt_eapol_m2) {
+               pad_len = (wpa_ie_len + extra_len) % 8;
+               if (pad_len)
+                       pad_len = 8 - pad_len;
+               extra_len += pad_len + 8;
+       }
 #endif /* CONFIG_TESTING_OPTIONS */
 
        mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
@@ -598,6 +607,10 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
                key_info |= WPA_KEY_INFO_MIC;
        else
                key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
+#ifdef CONFIG_TESTING_OPTIONS
+       if (sm->encrypt_eapol_m2)
+               key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
+#endif /* CONFIG_TESTING_OPTIONS */
        WPA_PUT_BE16(reply->key_info, key_info);
        if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
                WPA_PUT_BE16(reply->key_length, 0);
@@ -619,6 +632,37 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
                          wpabuf_head(sm->test_eapol_m2_elems),
                          wpabuf_len(sm->test_eapol_m2_elems));
        }
+
+       if (sm->encrypt_eapol_m2) {
+               u8 *plain;
+               size_t plain_len;
+
+               if (sm->test_eapol_m2_elems)
+                       extra_len = wpabuf_len(sm->test_eapol_m2_elems);
+               else
+                       extra_len = 0;
+               plain_len = wpa_ie_len + extra_len + pad_len;
+               plain = os_memdup(key_mic + mic_len + 2, plain_len);
+               if (!plain) {
+                       os_free(rbuf);
+                       return -1;
+               }
+               if (pad_len)
+                       plain[plain_len - pad_len] = 0xdd;
+
+               wpa_hexdump_key(MSG_DEBUG, "RSN: AES-WRAP using KEK",
+                               ptk->kek, ptk->kek_len);
+               if (aes_wrap(ptk->kek, ptk->kek_len, plain_len / 8, plain,
+                            key_mic + mic_len + 2)) {
+                       os_free(plain);
+                       os_free(rbuf);
+                       return -1;
+               }
+               wpa_hexdump(MSG_DEBUG,
+                           "RSN: Encrypted Key Data from AES-WRAP",
+                           key_mic + mic_len + 2, plain_len + 8);
+               os_free(plain);
+       }
 #endif /* CONFIG_TESTING_OPTIONS */
 
        os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
@@ -2168,6 +2212,9 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
        u8 *rbuf, *key_mic;
        u8 *kde = NULL;
        size_t kde_len = 0, extra_len = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+       size_t pad_len = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
 
        if (sm->mlo.valid_links) {
                u8 *pos;
@@ -2187,6 +2234,12 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
 #ifdef CONFIG_TESTING_OPTIONS
        if (sm->test_eapol_m4_elems)
                extra_len = wpabuf_len(sm->test_eapol_m4_elems);
+       if (sm->encrypt_eapol_m4) {
+               pad_len = (kde_len + extra_len) % 8;
+               if (pad_len)
+                       pad_len = 8 - pad_len;
+               extra_len += pad_len + 8;
+       }
 #endif /* CONFIG_TESTING_OPTIONS */
 
        mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
@@ -2208,6 +2261,10 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
                key_info |= WPA_KEY_INFO_MIC;
        else
                key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
+#ifdef CONFIG_TESTING_OPTIONS
+       if (sm->encrypt_eapol_m4)
+               key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
+#endif /* CONFIG_TESTING_OPTIONS */
        WPA_PUT_BE16(reply->key_info, key_info);
        if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
                WPA_PUT_BE16(reply->key_length, 0);
@@ -2230,6 +2287,37 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
                          wpabuf_head(sm->test_eapol_m4_elems),
                          wpabuf_len(sm->test_eapol_m4_elems));
        }
+
+       if (sm->encrypt_eapol_m4) {
+               u8 *plain;
+               size_t plain_len;
+
+               if (sm->test_eapol_m4_elems)
+                       extra_len = wpabuf_len(sm->test_eapol_m4_elems);
+               else
+                       extra_len = 0;
+               plain_len = kde_len + extra_len + pad_len;
+               plain = os_memdup(key_mic + mic_len + 2, plain_len);
+               if (!plain) {
+                       os_free(rbuf);
+                       return -1;
+               }
+               if (pad_len)
+                       plain[plain_len - pad_len] = 0xdd;
+
+               wpa_hexdump_key(MSG_DEBUG, "RSN: AES-WRAP using KEK",
+                               ptk->kek, ptk->kek_len);
+               if (aes_wrap(ptk->kek, ptk->kek_len, plain_len / 8, plain,
+                            key_mic + mic_len + 2)) {
+                       os_free(plain);
+                       os_free(rbuf);
+                       return -1;
+               }
+               wpa_hexdump(MSG_DEBUG,
+                           "RSN: Encrypted Key Data from AES-WRAP",
+                           key_mic + mic_len + 2, plain_len + 8);
+               os_free(plain);
+       }
 #endif /* CONFIG_TESTING_OPTIONS */
 
        wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
@@ -4585,6 +4673,12 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
        case WPA_PARAM_DISABLE_EAPOL_G2_TX:
                sm->disable_eapol_g2_tx = value;
                break;
+       case WPA_PARAM_ENCRYPT_EAPOL_M2:
+               sm->encrypt_eapol_m2 = value;
+               break;
+       case WPA_PARAM_ENCRYPT_EAPOL_M4:
+               sm->encrypt_eapol_m4 = value;
+               break;
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifdef CONFIG_DPP2
        case WPA_PARAM_DPP_PFS:
index d99e5f676bddb9099a36635f950470015f7c382b..3d2c2812e3e31b2f7b219590ec9d568d6251f7f1 100644 (file)
@@ -132,6 +132,8 @@ enum wpa_sm_conf_params {
        WPA_PARAM_OCI_FREQ_FT_ASSOC,
        WPA_PARAM_OCI_FREQ_FILS_ASSOC,
        WPA_PARAM_DISABLE_EAPOL_G2_TX,
+       WPA_PARAM_ENCRYPT_EAPOL_M2,
+       WPA_PARAM_ENCRYPT_EAPOL_M4,
 };
 
 struct rsn_supp_config {
index aa1d739c5fc49a2e368ab9a87572b47f4501966c..f326f43e9b27c0be831529336f10876f6b0e8596 100644 (file)
@@ -190,6 +190,8 @@ struct wpa_sm {
        unsigned int oci_freq_override_ft_assoc;
        unsigned int oci_freq_override_fils_assoc;
        unsigned int disable_eapol_g2_tx;
+       bool encrypt_eapol_m2;
+       bool encrypt_eapol_m4;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 #ifdef CONFIG_FILS
index 287be70cb215441f5a402e5f4b69193a51d92100..c80c17a0b9a7f86e1fc46f26ea107680be4ca120 100644 (file)
@@ -1006,6 +1006,7 @@ endif
 
 ifdef CONFIG_TESTING_OPTIONS
 L_CFLAGS += -DCONFIG_TESTING_OPTIONS
+NEED_AES_WRAP=y
 endif
 
 ifdef NEED_RSN_AUTHENTICATOR
index ff4237032a64453a684a42bd290f97c08728f1b8..60042bcc777e07d7fbcacebfc2b01e37dc25f060 100644 (file)
@@ -64,6 +64,7 @@ ifdef CONFIG_TESTING_OPTIONS
 CFLAGS += -DCONFIG_TESTING_OPTIONS
 CONFIG_WPS_TESTING=y
 CONFIG_TDLS_TESTING=y
+NEED_AES_WRAP=y
 endif
 
 mkconfig:
index 8317b1a7a022690a7156d892eff488429a80b878..99a8475f0bd07e80b11ab44b2c9113388c5458b0 100644 (file)
@@ -739,6 +739,12 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                                wpa_s->ext_eapol_frame_io;
                }
 #endif /* CONFIG_AP */
+       } else if (os_strcasecmp(cmd, "encrypt_eapol_m2") == 0) {
+               wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_ENCRYPT_EAPOL_M2,
+                                !!atoi(value));
+       } else if (os_strcasecmp(cmd, "encrypt_eapol_m4") == 0) {
+               wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_ENCRYPT_EAPOL_M4,
+                                !!atoi(value));
        } else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) {
                wpa_s->extra_roc_dur = atoi(value);
        } else if (os_strcasecmp(cmd, "test_failure") == 0) {
@@ -8854,6 +8860,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
        wpa_sm_set_test_eapol_m2_elems(wpa_s->wpa, NULL);
        wpa_sm_set_test_eapol_m4_elems(wpa_s->wpa, NULL);
+       wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_ENCRYPT_EAPOL_M2, 0);
+       wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_ENCRYPT_EAPOL_M4, 0);
        os_free(wpa_s->get_pref_freq_list_override);
        wpa_s->get_pref_freq_list_override = NULL;
        wpabuf_free(wpa_s->sae_commit_override);