[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;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章