您的位置:首页 > 其它

跟一下wpa_supplicant(3-2) connect AP

2013-03-25 20:42 429 查看
原文地址:http://blog.chinaunix.net/uid-20514606-id-3260320.html

接前面(3-1)继续:

5. 接分支4.

authenticate response 来了

和前面一样:

wpa_driver_nl80211_event_receive到

=> process_event

收到 NL80211_CMD_AUTHENTICATE=37

==> mlme_event (37)

===> mlme_event_auth

authenticate response 管理帧中的AP mac 是我们感兴趣的,

收了它,放wpa_driver_nl80211_data 的auth_bssid

并放到wpa_event_data->auth_info->peer

====> wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);

Event 11 received on interface wlan0 被扔出来

=====> sme_event_auth(wpa_s, data);

紧接着

D/wpa_supplicant( 2129): SME: Authentication response:

peer=00:1f:33:b9:5d:e0 auth_type=0 status_code=0

被扔出来

======> eloop_cancel_timeout(sme_auth_timer,

wpa_s, NULL);

取消auth 失败的警戒,可以进城了

======> sme_associate(wpa_s, ssid->mode,

data->auth.peer, data->auth.auth_type);

启动关联

=======>wpa_supplicant_set_state(wpa_s,

WPA_ASSOCIATING);

========> wpa_s->new_connection = 1;

========> wpa_drv_set_operstate(wpa_s, 0);

/* 设置到IF_OPER_DORMANT */

========> wpa_s->wpa_state = state;

========> wpas_notify_state_changed(wpa_s,

wpa_s->wpa_state, old_state);

如果 oldstate 不同情况下执行

=======> 设置参数等,ie

=======> wpa_drv_associate(wpa_s, ¶ms)

wpa_driver_nl80211_associate driver interface

通过netlink 给dirver 发assoc request

wpa_printf(MSG_DEBUG, "nl80211:

Association request send " "successfully");

发完了应该,别忘警戒下:

=======> eloop_register_timeout(SME_ASSOC_TIMEOUT,

0, sme_assoc_timer, wpa_s, NULL);

/* 关联超时失败处理*/

接下来到分支6.
6. 接分支5.

38 event 来了!

wpa_driver_nl80211_event_receive到

=> process_event

==> mlme_event (38= NL80211_CMD_ASSOCIATE)

asscoicate response 来了

===> mlme_event_assoc(drv, nla_data(frame),

nla_len(frame));

这里的 frame 应该就是关联响应帧

去读下rp frame state 判断response为成功

====> drv->associated = 1;

====> 获得resp 中的IE们 到 event.assoc_info.resp_ies

====> event.assoc_info.freq = drv->assoc_freq;

关联时的频率放到 struct assoc_info

有了IE,就象口袋有钱,可以来事了,EVENT_ASSOC发出去

====> wpa_supplicant_event(drv->ctx, EVENT_ASSOC,&event);

=====> wpa_supplicant_event_assoc(wpa_s, data);

======> wpa_supplicant_event_associnfo

获取AP 的assoc info!

就是挖掘前面说的已经存到event.assoc_info的resp ie

其中如果挖到PMKID,是要注意

去call wpa_find_assoc_pmkid

干什么? 如果忘记了,到第1篇搜索:

'成对主蜜钥安全关联'字样,我就不讲了
======> wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);

State: ASSOCIATING -> ASSOCIATED

======> wpa_clear_keys (clear driver config key)

======> wpa_supplicant_select_config

我们设置为AP_SCAN =1(让wpa_supplciant选择AP)

所以它什么也不做,return

======> wpa_sm_notify_assoc(wpa_s->wpa, bssid);

WPA state machine 的rx_replay_counter_set 清0,

的renew_snonce 置1

比较下是否是在preauth的ap 的mac,是的话就deinit它

最后清下wap state machine 的 old PTK

这么做是因为人家IEEE 802.11协议8.4.10部分说了

Delete PTK SA on (re)association if this is not

part of a Fast BSS Transition.

PTK 有两种格式,TKIP,和CCMP
======> eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);

======>eapol_sm_notify_portValid(wpa_s->eapol, FALSE);

======> if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||

ft_completed)

eapol_sm_notify_eap_success(wpa_s->eapol,

FALSE);

到这里PAE还没变化,下面就要变了

======> eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);

portEnabled=1

PAE状态要发生变化了,从disconnect 变到connecting

这个disconnect是在 eapol_sm_init,开始设置的

之后一直保持该状态

EAP状态一直为disable,因为我们是WPA-psk,所以

没有EAP,他就一直处于disable
======> /* Timeout for receiving the first

EAPOL packet */

wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);

/* 10 秒后没收到第1个 eapol packet 后 ,

就处理auth 失败 */

======> wpa_supplicant_cancel_sched_scan(wpa_s);

/* 要做正事了, 就先停sched scan ,scan */

wpa_supplicant_cancel_scan(wpa_s);
======> wpa_supplicant_event_assoc中

接下来的部分不会执行到

到这里已经关联已经完成,在AP 发来EAPOL frame 前,我们会收到

NL80211_CMD_CONNECT 通知,根据cmd注释,可以了解该命令是在不分开进行认证

和关联的情况下,来请求连接到一个指点网络的,连接完成会收到NL80211_CMD_CONNECT

的response,目前的driver capa里设置了WPA_DRIVER_FLAGS_SME,表示driver 支持

auth 和associate 分开的命令,所以能收到NL80211_CMD_CONNECT,但不处理

为什么呢? 注释里已经写了,为了避免2次报告关联事件,引起核心代码混乱

/** Avoid reporting two association events that would confuse

* the core code.

*/
进入7. 继续
7. 前面6.中完成asscicate 后,讲过就会等待EAPOL FRAME到来

在wpa init 中 wpa_supplicant_driver_init 会注册 l2 rx callback

wpa_s->l2 = l2_packet_init(wpa_s->ifname,

wpa_drv_get_mac_addr(wpa_s),

ETH_P_EAPOL,

wpa_supplicant_rx_eapol, wpa_s, 0);
可以看出收到l2 packet 后call back wpa_supplicant_rx_eapol,就从它开始

=> wpa_supplicant_rx_eapol:

==> wpa_supplicant_req_auth_timeout(wpa_s,

(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) ? 70 : 10, 0);

和前面associate最后设置的10s timeout 一样,这里只是收到

第1个,reset 下一次认证超时为10s
==> wpa_s->eapol_received++; 是第1次,eapol_received++ 后等于1

==> 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 frame

分析可得:

* type =2 时 EAPOL-Key

* key_info =0x8a

(ver=2 keyidx=0 rsvd=0 Pairwise Ack)

* key length =16, key data lenght 22

key_info 各bit 所代表的内容在:

wpa_comm.h中定义如下:

点击(此处)折叠或打开

/* IEEE 802.11, 8.5.2
EAPOL-Key frames */

#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2)))

#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)

#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)

#define WPA_KEY_INFO_TYPE_AES_128_CMAC 3

#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group
key */

/* bit4..5 is used in WPA, but is reserved in IEEE
802.11i/RSN */

#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5))

#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4

#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */

#define WPA_KEY_INFO_TXRX BIT(6) /* group */

#define WPA_KEY_INFO_ACK BIT(7)

#define WPA_KEY_INFO_MIC BIT(8)

#define WPA_KEY_INFO_SECURE BIT(9)

#define WPA_KEY_INFO_ERROR BIT(10)

#define WPA_KEY_INFO_REQUEST BIT(11)

#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE
802.11i/RSN only */

#define WPA_KEY_INFO_SMK_MESSAGE BIT(13)

第1个发过来的eapol frame 表示4次握手的第1次握手已经开始了!!!
==> 接下来就是部分4 way handle 的代码,直接贴上:

点击(此处)折叠或打开

if (key_info & WPA_KEY_INFO_KEY_TYPE) {

/* 走到这里, WPA_KEY_INFO_KEY_TYPE ,pairwise ,or group
key !!!*/

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) { /* 如果4way
的第1次没有peerkey */

/* PeerKey 4-Way Handshake */

peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver);

} else if (key_info & WPA_KEY_INFO_MIC) {

/* 3/4 4-Way
Handshake */

wpa_supplicant_process_3_of_4(sm, key, ver);

} else {

/* 1/4 4-Way
Handshake */

wpa_supplicant_process_1_of_4(sm, src_addr, key, ver);

}

} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {

/* PeerKey SMK Handshake */

peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info,ver);

} else {

if (key_info & WPA_KEY_INFO_MIC) {

/* 1/2 Group Key Handshake */

wpa_supplicant_process_1_of_2(sm, src_addr, key, extra_len, ver);

} else {

wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,

"WPA: EAPOL-Key (Group) without Mic bit - "

"dropped");

}

}

wpa_supplicant_process_1_of_4(sm, src_addr, key, ver);

wpa_supplicant_process_3_of_4(sm, key, ver);

是我们关心的
为什么没有0_of_4, 2_of_4? 不是没有,4次握手的第1,3次都在AP端处理

我们不管了,所以目前阶段,直接跑到1_fo_4,处理如下

===> wpa_supplicant_process_1_of_4(sm, src_addr, key, ver);

====> wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);

wap state 变化了 , ASSOCIATED -> 4WAY_HANDSHAKE

====> wpa_supplicant_parse_ies(_buf, len, &ie);

将buf 内容解析到 struct wpa_eapol_ie_parse

包括我们下面要用的pmkid

====> wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);

如果pmksa cashe 不空,

先从PMKSA cache中根据传来的ie.pmkid 去匹配

然后获得PMK,它是计算 PTK必须的,但现在cur_pmksa

为空,那如何获得pmk ,其实上面已经设置了,

在wpa_supplicant_associate 的

最后 wpa_sm_set_pmk 将预共享密钥PSK,copy到

struct wpa_sm->pmk

====> ptk = &sm->tptk;

====> wpa_derive_ptk(sm, src_addr, key, ptk);

计算方法:

wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",

sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,

(u8 *) ptk, ptk_len,

wpa_key_mgmt_sha256(sm->key_mgmt));

公式:

* PTK = PRF-X(PMK, "Pairwise key expansion",

* Min(AA, SA) || Max(AA, SA) ||

* Min(ANonce, SNonce) || Max(ANonce, SNonce))
====> wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver,

sm->snonce, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, ptk)

=====> wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,

NULL, sizeof(*reply) + wpa_ie_len, &rlen,

(void *) &reply);

os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);

wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,

rbuf, rlen, reply->key_mic);

/* 发出去,然后等下次 wpa_supplicant_rx_eapol*/
接下来到8.

8.

l2 packet 又来了

=> wpa_supplicant_rx_eapol:

==> 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 frame

分析可得:

* type =2 时 EAPOL-Key

* key_info =0x13ca

(ver=2 keyidx=0 rsvd=0 Pairwise Install Ack MIC Secure Encr)

* key length =16, key data lenght 80

==> else if (key_info & WPA_KEY_INFO_MIC) {

/*wpa_commom.h #define WPA_KEY_INFO_MIC BIT(8)*/

/* 3/4 4-Way Handshake */

==> wpa_supplicant_process_3_of_4(sm, key, ver);

其中key 就是 EAPOL-KEY 内容

struct wpa_eapol_key { /* EAPOL-KEY 结构!!! */

u8 type;

/* Note: key_info, key_length, and key_data_length are unaligned */

u8 key_info[2]; /* big endian */

u8 key_length[2]; /* big endian */

u8 replay_counter[WPA_REPLAY_COUNTER_LEN];

u8 key_nonce[WPA_NONCE_LEN];

u8 key_iv[16];

u8 key_rsc[WPA_KEY_RSC_LEN];

u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */

u8 key_mic[16];

u8 key_data_length[2]; /* big endian */

/* followed by key_data_length bytes of key_data */

} STRUCT_PACKED;

下面对eapol key data 部分进行处理,将获得的ie,放到

struct wpa_eapol_ie_parse

===> pos = (const u8 *) (key + 1); eapol key 后就是ie

len = WPA_GET_BE16(key->key_data_length);

wpa_supplicant_parse_ies(pos, len, &ie);

===> wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,

NULL, 0, &sm->ptk)

====> wpa_sm_alloc_eapol ,init epaol packet

=====> wpa_eapol_key_send(sm, ptk->kck, ver, dst,

ETH_P_EAPOL, rbuf, rlen, reply->key_mic);

一个ACK ,没有什么实质内容,也不加密

===> wpa_supplicant_install_ptk (struct wpa_sm *sm,

const struct wpa_eapol_key *key)

====> 设置driver key !!! wpa_sm_set_key

wpa_driver_nl80211_set_key (nl80211 driver)

wap_supplicant 的 终极目标,终于看到了!

PTK 安装好了,稍侯片刻,马上结束
===> eapol_sm_notify_portValid(sm->eapol, TRUE);

前面associate 成功后 PAE 处于 CONNECTING

到这里 portValid = TRUE, 但PAE 状态没发生变化
===> wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);

WPA State 从 4WAY_HANDSHAKE -> GROUP_HANDSHAKE
===> wpa_supplicant_pairwise_gtk(sm, key, ie.gtk,ie.gtk_len,

key_info)

从代码中看加密的GTK 3/4 way 中的IE部分就发来了!!!

wpa_supplicant_check_group_cipher

用双方都已知道的PTK 的 EPAOL KEK 加的密 )现在解开来

====> wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)

安装组密码

====> wpa_supplicant_key_neg_complete key 协商完成

=====> wpa_sm_cancel_auth_timeout(sm);

将前面设置的认证超时处理取消

=====> wpa_sm_set_state(sm, WPA_COMPLETED);

wpa state 从 GROUP_HANDSHAKE -> COMPLETED

=====> if (secure) {

......

eapol_sm_notify_portValid(sm->eapol, TRUE);

eapol_sm_notify_eap_success(sm->eapol, TRUE);

PAE 进入AUTHENTICATING

BE 进入success

EAP 返回diable

PAE 最终进入AUTHENTICATED

然后eapol_sm_set_port_authorized

然后wpa_supplicant_port_cb

然后wpa_drv_set_supp_port

设置driver NL80211_STA_FLAG_AUTHORIZED

到此为止,认证完成
整个过程的WPA State变化如下:

(wpa_supplicant)

DISCONNECTED -> SCANNING

SCANNING -> AUTHENTICATING (802.11身份认证 )

AUTHENTICATING -> ASSOCIATING

SCANNING -> ASSOCIATING

ASSOCIATING -> ASSOCIATED

ASSOCIATED -> 4WAY_HANDSHAKE

4WAY_HANDSHAKE -> 4WAY_HANDSHAKE

4WAY_HANDSHAKE -> GROUP_HANDSHAKE

GROUP_HANDSHAKE -> COMPLETED
PAE supplicant 端状态图





结束
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: