第一章、802.1X认证过程简述
802.1x认证的函数调用如下所示:
图 1-1
由上图可以看出,802.1x认证主要是在函数eapol_sm_step_run中完成。过程可以分为,认证、连接、EAP处理、四次握手(在图中未体现)四个过程。
红色线段:
表示在hostapd_notif_assoc函数结束之后,执行eapol_sm_step_run发送request/identity报文
橙色线段:
表示接收EAP报文,发送radius报文过程
绿色线段:
表示接收radius报文,发送EAP报文过程
1.1、 认证
802.1X认证的认证步骤与PSK认证、open认证相同。
步骤如下:
1、wpa_supplicant_event(Drv_callback.c):根据不同报文获取不同的操作函数。
2、hostapd_notif_auth(Drv_callback.c):authentication request处理函数
3、hostapd_sta_auth(Ap_drv_ops.c):authentication response发送
4、atheros_sta_auth(driver_atheros.c):发送authentication response
Note:该函数由函数指针调用,函数指针结构体赋值见附录
5、ioctl:发送报文给底层驱动。然后由驱动发送authentication response报文
小结:
认证过程,即由认证处理函数进行简单的处理,然后创建authentication response报文交给底层驱动发送出去。
1.2、 连接
连接过程如下:
1、wpa_supplicant_event(1)(Drv_callback.c):根据不同报文获取不同的操作函数。
2、hostapd_notif_assoc(2)(Drv_callback.c):association request处理函数
3、hostapd_sta_assoc(3)(Ap_drv_ops.c):association request发送
4、atheros_sta_assoc(4)(driver_atheros.c):发送association request
5、ioctl:发送报文给底层驱动。然后由驱动发送association response报文
6、hostapd_new_assoc_sta(3)(hostapd.c):通知一个新的工作站连入AP
7、ieee802_1x_new_station(4)(ieee802_1x.c):处理一个新的工作站
8、ieee802_1x_alloc_eapol_sm调用eapol_auth_alloc
调用eapol_auth_initializeàeapol_sm_step_run(状态机初始化):图1-1的红色线段指向即为该过程。
9、wpa_auth_sta_associated(4)(wpa_auth.c):wpa认证连接
10、wpa_sm_step(5)(wpa_auth.c):设置WPA_PTK状态。
Note:
(n):代表下钻的等级。
802.1X认证的连接和PSK以及OPEN认证之间有一些不同
主要不同之处:
802.1X认证将WPA_PTK状态进行到authentication2过程即结束。然后等待802.1X认证结束之后再进行四次握手过程
PSK认证将WPA_PTK状态进行到PSKSTART,发送四次握手的报文1
Open认证无WAP_PTK过程。
1.3、 802.1X认证
1x认证过程模型如下(由radius服务器)
图1-2 802.1X认证模型
在有认证服务器的情况下,认证者(AP)将主要的认证功能全部交给认证服务器,自身只进行EAP报文和radius报文之间的转化。但是第一个request/identity报文需要由认证者创建并发送。所以整个过程大致分为五步:
1、 认证者发送request/identity报文
2、 认证者处理response/identity报文,并将其转换为radius报文,并发送
3、 认证者接收radius报文,解封出EAP报文并发送
4、 认证者接收EAP报文,封装成radius报文并发送
5、 认证帧接收radius-accept报文,解封出EAP-success报文并发送
1.3.1、发送request/identity
1、在hostapd_notif_assoc执行完毕后。调用struct eloop_timeout结构体的函数指针所指向的eapol_sm_step_cb函数。
2、eapol_sm_step_cb调用eapol_sm_step_run函数发送request/identity
1.3.2、处理response/identity,发送radius
1、hostapd_event_eapol_rx(1)(drv_callback.c)函数处理
2、ieee802_1x_receive(2)
3、handle_eap(3):根据EAP报文的类型,选择相应的函数
4、handle_eap_response(4):EAP响应报文处理函数
5、eapol_auth_step(3):配置eloop_timeout回调函数
6、timeout回调函数eapol_sm_step_cb调用eapol_sm_step_run:发送radius报文
1.3.3、接收radius报文,发送EAP报文
即图1-1中的绿色线段所表示过程
1、ieee802_1x_receive_auth(1):经过radius_client_receive函数进行简单处理后回调
2、ieee802_1x_decapsulate_radius(2):解封出EAP报文
3、eapol_auth_step(2):配置eloop_timeout回调函数
4、timeout回调函数eapol_sm_step_cbàeapol_sm_step_run:发送EAP报文
1.3.4、接收EAP报文,发送radius报文
即图1-1中的橙色线段所表示过程
1、hostapd_event_eapol_rx(1)(drv_callback.c)函数处理
2、ieee802_1x_receive(2)
3、handle_eap(3):根据EAP报文的类型,选择相应的函数
4、handle_eap_response(4):EAP响应报文处理函数
5、eapol_auth_step(3):配置eloop_timeout回调函数
6、timeout回调函数eapol_sm_step_cbàeapol_sm_step_run:发送radius报文
注意:1.3.2与1.3.4在上述介绍中看似相同,但是实际在eapol_sm_step_run处理中不同。下章将详细介绍里边的具体执行
1.3.5、接收radius-accept报文,发送EAP-success报文
1、ieee802_1x_receive_auth(1):经过radius_client_receive函数进行简单处理后回调
2、ieee802_1x_decapsulate_radius(2):解封出EAP报文
3、eapol_auth_step(2):配置eloop_timeout回调函数
4、timeout回调函数eapol_sm_step_cb调用eapol_sm_step_run:发送EAP报文
注意:1.3.3与1.3.5在上述介绍中看似相同,但是实际在eapol_sm_step_run处理中不同。下章将详细介绍里边的具体执行
第二章、eapol_sm_step_run函数
2.1、 eapol_sm_step_runhan数介绍
功能:
eapol状态机状态切换运行函数
参数:
sm:eapol状态机数据结构体struct eapol_state_machine
过程:
包含一个goto循环,包含两个阶段
1、记录AUTH_PAE、BE_AUTH、REAUTH_TIMER、AUTH_KEY_TX、KEY_RX、CTRL_DIR
的状态,然后执行这六种状态机的SM_STEP函数,然后根据现有条件去切换状态。
2、如果上述六种状态机,任何一个状态机状态发生改变,那么重新执行步骤1
3、如果上述六种状态机未发生改变,执行eap_server_sm_step函数,进行EAP状态机状态切换。如果EAP状态机状态发生改变,那么重新执行步骤1
并且在eapol_sm_step_run函数中定义了一个max_steps。每执行一次goto,该值减一。如果减到为0,则跳出goto循环。
如图所示:
图2-1eapol_sm_step_run函数执行流程
2.2、 六种状态机介绍
2.2.1、AUTH_PAE
连接埠认证状态,主要是在802.1x认证前准备阶段和认证后的四次握手后进行状态切换
有以下10个状态
1、 AUTH_PAE_INITIALIZE
初始化:
sm->portMode = Auto;
sm->keyRun = FALSE;
2、 AUTH_PAE_DISCONNECTED
断开连接
设置端口和下网标志位,并通知底层驱动
3、AUTH_PAE_CONNECTING
连接
sm->authEntersConnecting++;
sm->reAuthenticate= FALSE
sm->reAuthCount++
4、AUTH_PAE_AUTHENTICATING
认证中
sm->eapolStart= FALSE;
sm->authSuccess= FALSE;
sm->authFail= FALSE;
sm->authTimeout= FALSE;
sm->authStart= TRUE;
sm->keyRun= FALSE;
sm->keyDone= FALSE;
5、AUTH_PAE_AUTHENTICATED
已认证(代表整个认证过程全部结束,可以DHCP获取IP了)
设置端口标志位,并通知底层驱动
调用_ieee802_1x_finished函数,认证成功 (该状态在四次握手之后表示成功)
6、AUTH_PAE_ABORTING
中止
7、AUTH_PAE_HELD
挂起
8、AUTH_PAE_FORCE_AUTH,
强行认证
9、AUTH_PAE_FORCE_UNAUTH
强行断开认证
10、AUTH_PAE_RESTART
重新开始
sm->eap_if->eapRestart= TRUE
注意: INITIALIZE DISCONNECTED RESTART CONNECTING AUTHENTICATING五个状态在802.1x中使用
AUTH_PAE_AUTHENTICATED状态在四次握手成功后调用
2.2.2、BE_AUTH
后端认证,伴随802.1x认证过程。处理接收到的EAP报文,发送EAP报文
由以下8个状态
1、 BE_AUTH_REQUEST
发送EAP报文给申请者
txReq(); //发送报文
sm->eap_if->eapReq = FALSE; //发送后发送申请标志位清零
sm->backendOtherRequestsToSupplicant++;
2、 BE_AUTH_RESPONSE
处理接收到的EAP报文
sm->authTimeout= FALSE;
sm->eapolEap= FALSE;
sm->eap_if->eapNoReq= FALSE;
sm->aWhile =sm->serverTimeout;
sm->eap_if->eapResp= TRUE; //接收到EAP报文标志位置位
sm->backendResponses++;
3、 BE_AUTH_SUCCESS
后端认证成功,即802.1X认证成功
txReq(); //向申请者发送EAP/success报文
sm->authSuccess= TRUE;
sm->keyRun = TRUE;
4、 BE_AUTH_FAIL
认证失败
txReq(); //发送EAP/failure报文
sm->authFail = TRUE;
5、 BE_AUTH_TIMEOUT
认证超时
sm->authTimeout = TRUE;
6、 BE_AUTH_IDLE
闲置等待
sm->authStart = FALSE;
7、 BE_AUTH_INITIALIZE,
初始化
abortAuth(); //中止认证
sm->eap_if->eapNoReq= FALSE;
sm->authAbort = FALSE;
8、BE_AUTH_IGNORE
忽略
sm->eap_if->eapNoReq= FALSE
(这个状态只有在response状态之后,eapNoReq仍旧为true)
认证开始前:BE_AUTH_INITIALIZE、BE_AUTH_IDLE
认证过程中:BE_AUTH_REQUEST 和 BE_AUTH_RESPONSE交替进行
认证成功:BE_AUTH_SUCCESS、BE_AUTH_IDLE
2.2.3、REAUTH_TIMER
重新认证计时器状态机
有以下两种状态
1、 REAUTH_TIMER_INITIALIZE
重新认证计时器初始化
sm->reAuthWhen = sm->reAuthPeriod; //设置重新认证时间间隔为重新认证时间周期
2、 REAUTH_TIMER_REAUTHENTICATE
重新认证
sm->reAuthenticate = TRUE
wpa_auth_sm_event
2.2.4、AUTH_KEY_TX
认证者密钥发送状态机
1、 AUTH_KEY_TX_NO_KEY_TRANSMIT
没有密钥发送
仅改变状态,无任何操作
2、 AUTH_KEY_TX_KEY_TRANSMIT
发送密钥
txKey(); //密钥发送
sm->eap_if->eapKeyAvailable= FALSE;
sm->keyDone= TRUE;
2.2.5、KEY_RX
密钥接收状态机
1、KEY_RX_NO_KEY_RECEIVE
无密钥接收
仅仅改变状态,无任何操作
2、KEY_RX_KEY_RECEIVE
有密钥接收
processKey();
sm->rxKey= FALSE;
2.2.6、CTRL_DIR
控制方向状态机
1、 CTRL_DIR_FORCE_BOTH
sm->operControlledDirections = Both
2、 CTRL_DIR_IN_OR_BOTH
sm->operControlledDirections= sm->adminControlledDirections;
2.2.7、小结
AUTH_PAE是连接埠的认证状态机,可以分为三个阶段
1、 连接处理函数hostapd_notif_assoc函数中的初始化阶段 INITIALIZE
2、 发送EAP-identity/request报文之前的重新开始阶段 DISCONNECTED RESTART CONNECTING AUTHENTICATING
3、 四次握手之后的认证完成确认阶段 AUTH_PAE_AUTHENTICATED
所以AUTH_PAE并不负责,802.1x认证,以及认证后的四次握手。这些有BE_AUTH进行处理
1、认证开始前:BE_AUTH_INITIALIZE、BE_AUTH_IDLE(hostapd_notif_assoc中)
2、认证过程中:BE_AUTH_REQUEST和 BE_AUTH_RESPONSE交替进行(802.1x认证具体过程)
3、认证成功:BE_AUTH_SUCCESS、BE_AUTH_IDLE:802.1x认证结束,可以开始四次握手
REAUTH_TIMER伴随着每一步操作,无论是发送还是接受,只要是成功的步骤,都要将重新认证计时器初始化
而AUTH_KEY_RX、KEY_RX、CTRL_DIR只在hostapd_notif_assoc函数进行初始化,之后的过程不参加
第三章、eap_server_sm_step函数
如图2-1所示,eapol_sm_step_run函数中,六种状态执行完毕,之后,会调用
eap_server_sm_step函数,进行EAP状态机的处理
3.1、EAP状态列表
struct eap_sm {
enum{
0、EAP_DISABLED,
1、EAP_INITIALIZE,
2、EAP_IDLE,
3、EAP_RECEIVED,
4、EAP_INTEGRITY_CHECK,
5、EAP_METHOD_RESPONSE,
6、EAP_METHOD_REQUEST,
7、EAP_PROPOSE_METHOD,
8、EAP_SELECT_ACTION,
9、EAP_SEND_REQUEST,
10、EAP_DISCARD
11、EAP_NAK,
12、EAP_RETRANSMIT,
13、EAP_SUCCESS,
14、EAP_FAILURE,
15、EAP_TIMEOUT_FAILURE,
16、EAP_PICK_UP_METHOD,
17、EAP_INITIALIZE_PASSTHROUGH,
18、EAP_IDLE2,
19、EAP_RETRANSMIT2,
20、EAP_RECEIVED2,
21、EAP_DISCARD2,
22、EAP_SEND_REQUEST2,
23、EAP_AAA_REQUEST,
24、EAP_AAA_RESPONSE,
25、EAP_AAA_IDLE,
26、EAP_TIMEOUT_FAILURE2,
27、EAP_FAILURE2,
28、EAP_SUCCESS2,
29、EAP_INITIATE_REAUTH_START,
30、EAP_INITIATE_RECEIVED
}EAP_state;
总共三十一个状态
3.2、802.1X认证中的EAP状态切换
1、 开始
INITIALIZE //eapRestart=1;portEnabled=1,EAP_state=0
将eapRestart=0
SELECT_ACTION //选择行为 continue
PROPOSE_METHOD //获取建议method
METHOD_REQUEST//创建请求数据报
SEND_REQUEST //将创建的数据报放置到lastReqData,并设置标志位
IDLE //重新发送时间间隔
2、接收EAP发送radius
RECEIVED //分析EAP报文,为sm结构体赋值
INTEGRITY_CHECK //完整性检查
METHOD_RESPONSE //处理获取身份,key,session id
SELECT_ACTION //选择行为 PASSTHROUGH
INITIALIZE_PASSTHROUGH//释放aaaEapRespData
AAA_REQUEST //将接收到的EAP报文放到aaaEapRespData中
AAA_IDLE //设置重发时间间隔
3、接收radius发送EAP
AAA_RESPONSE //接收radius后的处理,获取EAP报文数据,radius ID,timeout;
SEND_REQUEST2 //从radius获取的EAP报文放到lastReqData,并设置标志位
IDLE2 //重新发送时间间隔
4、 接收EAP发送radius
RECEIVED2 //分析EAP报文,为sm结构体赋值
AAA_REQUEST //将接收到的EAP报文放到aaaEapRespData中
AAA_IDLE //设置重发时间间隔
3/4步循环……
5、 接收radius accept报文
SUCCESS2 // eapSuccess和start_reauth为true
过程如图3-1所示
图3-1EAP状态机状态切换(802.1x认证过程)
附录:
A: 驱动函数接口
const struct wpa_driver_opswpa_driver_atheros_ops = {
.name = "atheros",
.hapd_init = atheros_init,
.hapd_deinit = atheros_deinit,
.set_ieee8021x = atheros_set_ieee8021x,
.set_privacy = atheros_set_privacy,
.set_key = atheros_set_key,
.get_seqnum =atheros_get_seqnum,
.flush = atheros_flush,
.set_generic_elem = atheros_set_opt_ie,
.sta_set_flags = atheros_sta_set_flags,
.read_sta_data = atheros_read_sta_driver_data,
.read_sta_info = atheros_read_sta_driver_info,
.get_sta_idle_time = atheros_get_sta_idle_time,
.hapd_send_eapol = atheros_send_eapol,
.sta_disassoc = atheros_sta_disassoc,
.sta_deauth = atheros_sta_deauth,
.hapd_set_ssid = atheros_set_ssid,
.hapd_get_ssid = atheros_get_ssid,
.set_countermeasures = atheros_set_countermeasures,
.sta_clear_stats = atheros_sta_clear_stats,
.commit = atheros_commit,
.set_ap_wps_ie = atheros_set_ap_wps_ie,
.set_authmode = atheros_set_authmode,
.set_ap = atheros_set_ap,
#if defined(CONFIG_IEEE80211R) ||defined(CONFIG_IEEE80211W)
.sta_assoc = atheros_sta_assoc,
.sta_auth = atheros_sta_auth,
.send_mlme =atheros_send_mgmt,
#endif /* CONFIG_IEEE80211R ||CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
.add_tspec =atheros_add_tspec,
.add_sta_node =atheros_add_sta_node,
#endif /* CONFIG_IEEE80211R */
.send_action = atheros_send_action,
#if defined(CONFIG_WNM) &&defined(IEEE80211_APPIE_FRAME_WNM)
.wnm_oper = atheros_wnm_oper,
#endif /* CONFIG_WNM &&IEEE80211_APPIE_FRAME_WNM */
.set_qos_map = atheros_set_qos_map,
};
Note:不同的设备可能不同。
B: eapol_auth_cb函数接口
(eapol认证控制接口)
cb.eapol_send = ieee802_1x_eapol_send;
cb.aaa_send= ieee802_1x_aaa_send;
cb.finished= _ieee802_1x_finished;
cb.get_eap_user= ieee802_1x_get_eap_user;
cb.sta_entry_alive= ieee802_1x_sta_entry_alive;
cb.logger= ieee802_1x_logger;
cb.set_port_authorized= ieee802_1x_set_port_authorized;
cb.abort_auth= _ieee802_1x_abort_auth;
cb.tx_key= _ieee802_1x_tx_key;
cb.eapol_event= ieee802_1x_eapol_event;
#ifdef CONFIG_ERP
cb.erp_get_key= ieee802_1x_erp_get_key;
cb.erp_add_key= ieee802_1x_erp_add_key;
#endif /* CONFIG_ERP */
C: eap_method函数接口
eap->init= eap_identity_init;
eap->initPickUp= eap_identity_initPickUp;
eap->reset= eap_identity_reset;
eap->buildReq= eap_identity_buildReq;
eap->check= eap_identity_check;
eap->process= eap_identity_process;
eap->isDone= eap_identity_isDone;
eap->isSuccess= eap_identity_isSuccess;