Android wpa_supplicant 四次握手 流程分析

记录wpa_supplicant四次握手的过程。

相关log:https://www.cnblogs.com/helloworldtoyou/p/9633603.html

接收到第一次握手,会设置一个认证超时时间,根据情况,设置成10s或者70s。
四次握手,如果出错,将会等待这个超时时间后,才会判断认证失败。然后从新连接。

wpa_supplicant/wpa_supplicant.c
void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
                 const u8 *buf, size_t len)
{
    struct wpa_supplicant *wpa_s = ctx;
    // 接受到EAPOL帧
    wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
    wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);

#ifdef CONFIG_TESTING_OPTIONS
    if (wpa_s->ignore_auth_resp) {
        wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
        return;
    }
#endif /* CONFIG_TESTING_OPTIONS */

#ifdef CONFIG_PEERKEY
    if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid &&
        wpa_s->current_ssid->peerkey &&
        !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
        wpa_sm_rx_eapol_peerkey(wpa_s->wpa, src_addr, buf, len) == 1) {
        wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Processed PeerKey EAPOL-Key");
        return;
    }
#endif /* CONFIG_PEERKEY */

    if (wpa_s->wpa_state < WPA_ASSOCIATED ||
        (wpa_s->last_eapol_matches_bssid &&
#ifdef CONFIG_AP
         !wpa_s->ap_iface &&
#endif /* CONFIG_AP */
         os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) != 0)) {
        /*
         * There is possible race condition between receiving the
         * association event and the EAPOL frame since they are coming
         * through different paths from the driver. In order to avoid
         * issues in trying to process the EAPOL frame before receiving
         * association information, lets queue it for processing until
         * the association event is received. This may also be needed in
         * driver-based roaming case, so also use src_addr != BSSID as a
         * trigger if we have previously confirmed that the
         * Authenticator uses BSSID as the src_addr (which is not the
         * case with wired IEEE 802.1X).
         */
        wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing "
            "of received EAPOL frame (state=%s bssid=" MACSTR ")",
            wpa_supplicant_state_txt(wpa_s->wpa_state),
            MAC2STR(wpa_s->bssid));
        wpabuf_free(wpa_s->pending_eapol_rx);
        wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
        if (wpa_s->pending_eapol_rx) {
            os_get_reltime(&wpa_s->pending_eapol_rx_time);
            os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
                  ETH_ALEN);
        }
        return;
    }

    wpa_s->last_eapol_matches_bssid =
        os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) == 0;

#ifdef CONFIG_AP
    if (wpa_s->ap_iface) {
        wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
        return;
    }
#endif /* CONFIG_AP */
                                                            // 没有配置密钥,退出
    if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
        wpa_dbg(wpa_s, MSG_DEBUG, "Ignored received EAPOL frame since "
            "no key management is configured");
        return;
    }
                                                            // 第一次收到EAPOL帧,设置认证超时时间,
    if (wpa_s->eapol_received == 0 &&
        (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) ||
         !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
         wpa_s->wpa_state != WPA_COMPLETED) &&
        (wpa_s->current_ssid == NULL ||
         wpa_s->current_ssid->mode != IEEE80211_MODE_IBSS)) {
        /* Timeout for completing IEEE 802.1X and WPA authentication */
        int timeout = 10;                                   // 认证超时时间10s

        if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
            wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
            wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
            /* Use longer timeout for IEEE 802.1X/EAP */
            timeout = 70;                                   // 802.1X/EAP认证超时时间设置成70s
        }
                                                            // WPS相关设置
#ifdef CONFIG_WPS
        if (wpa_s->current_ssid && wpa_s->current_bss &&
            (wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
            eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
            /*
             * Use shorter timeout if going through WPS AP iteration
             * for PIN config method with an AP that does not
             * advertise Selected Registrar.
             */
            struct wpabuf *wps_ie;

            wps_ie = wpa_bss_get_vendor_ie_multi(
                wpa_s->current_bss, WPS_IE_VENDOR_TYPE);
            if (wps_ie &&
                !wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1))
                timeout = 10;
            else {
                /* We should apply a flexible timeout value,
                * becasue some AP which send M2D MSG
                * need more time to complete EAP auth,such as Marvell.
                * */
                timeout = 70;
            }
            wpabuf_free(wps_ie);
        }
#endif /* CONFIG_WPS */

        wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);         // 设置认证超时,10s或者70s
    }
    wpa_s->eapol_received++;                                        // 接受到的EAPOL计数加一

    if (wpa_s->countermeasures) {
        wpa_msg(wpa_s, MSG_INFO, "WPA: Countermeasures - dropped "
            "EAPOL packet");
        return;
    }

#ifdef CONFIG_IBSS_RSN
    if (wpa_s->current_ssid &&
        wpa_s->current_ssid->mode == WPAS_MODE_IBSS) {
        ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len);
        return;
    }
#endif /* CONFIG_IBSS_RSN */

    /* Source address of the incoming EAPOL frame could be compared to the
     * current BSSID. However, it is possible that a centralized
     * Authenticator could be using another MAC address than the BSSID of
     * an AP, so just allow any address to be used for now. The replies are
     * still sent to the current BSSID (if available), though. */

    os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
    if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
        wpa_s->key_mgmt != WPA_KEY_MGMT_OWE &&
        wpa_s->key_mgmt != WPA_KEY_MGMT_DPP &&
        eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
        return;
    wpa_drv_poll(wpa_s);
    if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
        wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);                // 处理接受的EAPOL帧
    else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
        /*
         * Set portValid = TRUE here since we are going to skip 4-way
         * handshake processing which would normally set portValid. We
         * need this to allow the EAPOL state machines to be completed
         * without going through EAPOL-Key handshake.
         */
        eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
    }
}

src/rsn_supp/wpa.c
int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
            const u8 *buf, size_t len)
{
    各种帧内容判断
...
    if (key_info & WPA_KEY_INFO_KEY_TYPE) {
        if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
            wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                "WPA: Ignored EAPOL-Key (Pairwise) with "
                "non-zero key index");
            goto out;
        }
        if (peerkey) {
            /* PeerKey 4-Way Handshake */
            peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver,
                          key_data, key_data_len);
        } else if (key_info & (WPA_KEY_INFO_MIC |
                       WPA_KEY_INFO_ENCR_KEY_DATA)) {
            /* 3/4 4-Way Handshake */                        // 第三次握手
            wpa_supplicant_process_3_of_4(sm, key, ver, key_data,
                              key_data_len);
        } else {
            /* 1/4 4-Way Handshake */                        // 第一次握手
            wpa_supplicant_process_1_of_4(sm, src_addr, key,
                              ver, key_data,
                              key_data_len);
        }
    } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
        /* PeerKey SMK Handshake */
        peerkey_rx_eapol_smk(sm, src_addr, key, key_data, key_data_len,
                     key_info, ver);
    } else {
        if ((mic_len && (key_info & WPA_KEY_INFO_MIC)) ||
            (!mic_len && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA))) {
            /* 1/2 Group Key Handshake */
            wpa_supplicant_process_1_of_2(sm, src_addr, key,
                              key_data, key_data_len,
                              ver);
        } else {
            wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                "WPA: EAPOL-Key (Group) without Mic/Encr bit - "
                "dropped");
        }
    }
...
}

static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
                      const unsigned char *src_addr,
                      const struct wpa_eapol_key *key,
                      u16 ver, const u8 *key_data,
                      size_t key_data_len)
{
    struct wpa_eapol_ie_parse ie;
    struct wpa_ptk *ptk;
    int res;
    u8 *kde, *kde_buf = NULL;
    size_t kde_len;

    if (wpa_sm_get_network_ctx(sm) == NULL) {
        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info "
            "found (msg 1 of 4)");
        return;
    }

    wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
    wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of 4-Way "
        "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);

    os_memset(&ie, 0, sizeof(ie));

    if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
        /* RSN: msg 1/4 should contain PMKID for the selected PMK */
        wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data",
                key_data, key_data_len);
        if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
            goto failed;
        if (ie.pmkid) {
            wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
                    "Authenticator", ie.pmkid, PMKID_LEN);
        }
    }

    res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
    if (res == -2) {
        wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Do not reply to "
            "msg 1/4 - requesting full EAP authentication");
        return;
    }
    if (res)
        goto failed;

    if (sm->renew_snonce) {
        if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
            wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                "WPA: Failed to get random data for SNonce");
            goto failed;
        }
        sm->renew_snonce = 0;
        wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
                sm->snonce, WPA_NONCE_LEN);
    }

    /* Calculate PTK which will be stored as a temporary PTK until it has
     * been verified when processing message 3/4. */
    ptk = &sm->tptk;
    wpa_derive_ptk(sm, src_addr, key, ptk);
    if (sm->pairwise_cipher == WPA_CIPHER_TKIP) {
        u8 buf[8];
        /* Supplicant: swap tx/rx Mic keys */
        os_memcpy(buf, &ptk->tk[16], 8);
        os_memcpy(&ptk->tk[16], &ptk->tk[24], 8);
        os_memcpy(&ptk->tk[24], buf, 8);
        os_memset(buf, 0, sizeof(buf));
    }
    sm->tptk_set = 1;

    kde = sm->assoc_wpa_ie;
    kde_len = sm->assoc_wpa_ie_len;

...
                            // 发送第二次握手的包
    if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
                       kde, kde_len, ptk) < 0)
        goto failed;

    os_free(kde_buf);
    os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
    return;

failed:
    os_free(kde_buf);
    wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}

Liutao

2018-11-22

原文地址:https://www.cnblogs.com/helloworldtoyou/p/10000495.html

时间: 2024-11-06 22:30:20

Android wpa_supplicant 四次握手 流程分析的相关文章

Android 4.4 音量调节流程分析(二)

之前在Android 4.4 音量调节流程分析(一)里已经有简单的分析音量控制的流程,今天想接着继续分析下音量大小计算的方法.对于任一播放文件而言其本身都有着固定大小的音量Volume_Max,而在AudioPolicyManagerBase.cpp文件中音量调节可以理解为在Volume_Max的基础上乘以系数κ(0≤κ≤1). 现在对AudioPolicyManagerBase.cpp中volIndexToAmpl函数做具体分析,volIndexToAmpl的函数定义如下: 1 float A

Android 4.4 音量调节流程分析(一)

最近在做Android Audio方面的工作,有需求是在调节Volume_Up_Key & Volume_Down_key时,Spearker or Headset每音阶的衰减变为3db左右.所以利用Source Insight分析Android源码中音量控制的流程,如有错误,欢迎指正,谢谢! 以下是调节音量的流程: Step_1.首先在调节机台Volume_Up_Key & Volume_Down_Key操作时,系统会调用到AudioManager.java中handleKeyUp &a

TCP/IP协议三次握手与四次握手流程解析

原文链接地址:http://www.2cto.com/net/201310/251896.html TCP/IP协议的详细信息参看<TCP/IP协议详解>三卷本.下面是TCP报文格式图 上图中有几个字段需要重点介绍下:   (1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记.   (2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1.   (3)标志位:共6个,即URG.ACK.PSH.RST

TCP/IP协议三次握手与四次握手流程解析(转)

一.TCP报文格式 下面是TCP报文格式图: 上图中有几个字段需要重点介绍下:  (1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记.  (2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1.  (3)标志位:共6个,即URG.ACK.PSH.RST.SYN.FIN等,具体含义如下:  (A)URG:紧急指针(urgent pointer)有效.  (B)ACK:确认序号有效.  (C)PSH:

PPTP协议握手流程分析--转载

一  PPTP概述 PPTP(Point to Point Tunneling Protocol),即点对点隧道协议.该协议是在PPP协议的基础上开发的一种新的增强型安全协议,支持多协议虚拟专用网,可以通过密码验证协议,可扩展认证协议等方法增强安全性.远程用户可以通过ISP.直接连接Internet或者其他网络安全地访问企业网: 它能够将PPP(点到点协议)帧封装成IP数据包,以便能够在基于IP的互联网上进行传输.PPTP使用TCP是实现隧道的创建.维护与终止,并使用GRE(通用路由封装)将PP

Android视图状态及重绘流程分析,带你一步步深入了解View(三)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17045157 在 前面一篇文章中,我带着大家一起从源码的层面上分析了视图的绘制流程,了解了视图绘制流程中onMeasure.onLayout.onDraw这三个最 重要步骤的工作原理,那么今天我们将继续对View进行深入探究,学习一下视图状态以及重绘方面的知识.如果你还没有看过我前面一篇文章,可以先去阅读 Android视图绘制流程完全解析,带你一步步深入了解View(二) .

Android平台语言Locale设置流程分析

Android系统Setting程序中对于语言设置这块的内容.具体位置有以下两处: 1).设置显示语言:Settings -> Language & keyboard -> Select language 2).设置输入语言:Settings -> Language & keyboard -> Android keyboard [settings] -> Input languages Settings工程中,Settings -> Language &

(转)Android视图状态及重绘流程分析,带你一步步深入了解View(三)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17045157 在前面一篇文章中,我带着大家一起从源码的层面上分析了视图的绘制流程,了解了视图绘制流程中onMeasure.onLayout.onDraw这三个最重要步骤的工作原理,那么今天我们将继续对View进行深入探究,学习一下视图状态以及重绘方面的知识.如果你还没有看过我前面一篇文章,可以先去阅读 Android视图绘制流程完全解析,带你一步步深入了解View(二) . 相信

TCP/IP协议三次握手与四次握手流程

(1)第一次握手:Client将标志位SYN设置为1,随机产生一个值seq=x,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认.(2)第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=x+1,随机产生一个值seq=y,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态.(3)第三次握手:Client收到确认后,检查ack是否为x+1,A