hostapd程式碼分析-完全的802.1X認證過程(radius伺服器)
第一章、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;