📄 eapol_supp_sm.c
字号:
break; }}SM_STATE(SUPP_BE, REQUEST){ SM_ENTRY(SUPP_BE, REQUEST); sm->authWhile = 0; sm->eapReq = TRUE; eapol_sm_getSuppRsp(sm);}SM_STATE(SUPP_BE, RESPONSE){ SM_ENTRY(SUPP_BE, RESPONSE); eapol_sm_txSuppRsp(sm); sm->eapResp = FALSE;}SM_STATE(SUPP_BE, SUCCESS){ SM_ENTRY(SUPP_BE, SUCCESS); sm->keyRun = TRUE; sm->suppSuccess = TRUE; if (eap_key_available(sm->eap)) { /* New key received - clear IEEE 802.1X EAPOL-Key replay * counter */ sm->replay_counter_valid = FALSE; }}SM_STATE(SUPP_BE, FAIL){ SM_ENTRY(SUPP_BE, FAIL); sm->suppFail = TRUE;}SM_STATE(SUPP_BE, TIMEOUT){ SM_ENTRY(SUPP_BE, TIMEOUT); sm->suppTimeout = TRUE;}SM_STATE(SUPP_BE, IDLE){ SM_ENTRY(SUPP_BE, IDLE); sm->suppStart = FALSE; sm->initial_req = TRUE;}SM_STATE(SUPP_BE, INITIALIZE){ SM_ENTRY(SUPP_BE, INITIALIZE); eapol_sm_abortSupp(sm); sm->suppAbort = FALSE;}SM_STATE(SUPP_BE, RECEIVE){ SM_ENTRY(SUPP_BE, RECEIVE); sm->authWhile = sm->authPeriod; eapol_enable_timer_tick(sm); sm->eapolEap = FALSE; sm->eapNoResp = FALSE; sm->initial_req = FALSE;}SM_STEP(SUPP_BE){ if (sm->initialize || sm->suppAbort) SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE); else switch (sm->SUPP_BE_state) { case SUPP_BE_UNKNOWN: break; case SUPP_BE_REQUEST: /* * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL * and SUCCESS based on eapFail and eapSuccess, respectively. * However, IEEE Std 802.1X-2004 is also specifying that * eapNoResp should be set in conjuction with eapSuccess and * eapFail which would mean that more than one of the * transitions here would be activated at the same time. * Skipping RESPONSE and/or RECEIVE states in these cases can * cause problems and the direct transitions to do not seem * correct. Because of this, the conditions for these * transitions are verified only after eapNoResp. They are * unlikely to be used since eapNoResp should always be set if * either of eapSuccess or eapFail is set. */ if (sm->eapResp && sm->eapNoResp) { wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both " "eapResp and eapNoResp set?!"); } if (sm->eapResp) SM_ENTER(SUPP_BE, RESPONSE); else if (sm->eapNoResp) SM_ENTER(SUPP_BE, RECEIVE); else if (sm->eapFail) SM_ENTER(SUPP_BE, FAIL); else if (sm->eapSuccess) SM_ENTER(SUPP_BE, SUCCESS); break; case SUPP_BE_RESPONSE: SM_ENTER(SUPP_BE, RECEIVE); break; case SUPP_BE_SUCCESS: SM_ENTER(SUPP_BE, IDLE); break; case SUPP_BE_FAIL: SM_ENTER(SUPP_BE, IDLE); break; case SUPP_BE_TIMEOUT: SM_ENTER(SUPP_BE, IDLE); break; case SUPP_BE_IDLE: if (sm->eapFail && sm->suppStart) SM_ENTER(SUPP_BE, FAIL); else if (sm->eapolEap && sm->suppStart) SM_ENTER(SUPP_BE, REQUEST); else if (sm->eapSuccess && sm->suppStart) SM_ENTER(SUPP_BE, SUCCESS); break; case SUPP_BE_INITIALIZE: SM_ENTER(SUPP_BE, IDLE); break; case SUPP_BE_RECEIVE: if (sm->eapolEap) SM_ENTER(SUPP_BE, REQUEST); else if (sm->eapFail) SM_ENTER(SUPP_BE, FAIL); else if (sm->authWhile == 0) SM_ENTER(SUPP_BE, TIMEOUT); else if (sm->eapSuccess) SM_ENTER(SUPP_BE, SUCCESS); break; }}static void eapol_sm_txLogoff(struct eapol_sm *sm){ wpa_printf(MSG_DEBUG, "EAPOL: txLogoff"); sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0); sm->dot1xSuppEapolLogoffFramesTx++; sm->dot1xSuppEapolFramesTx++;}static void eapol_sm_txStart(struct eapol_sm *sm){ wpa_printf(MSG_DEBUG, "EAPOL: txStart"); sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0); sm->dot1xSuppEapolStartFramesTx++; sm->dot1xSuppEapolFramesTx++;}#define IEEE8021X_ENCR_KEY_LEN 32#define IEEE8021X_SIGN_KEY_LEN 32struct eap_key_data { u8 encr_key[IEEE8021X_ENCR_KEY_LEN]; u8 sign_key[IEEE8021X_SIGN_KEY_LEN];};static void eapol_sm_processKey(struct eapol_sm *sm){ struct ieee802_1x_hdr *hdr; struct ieee802_1x_eapol_key *key; struct eap_key_data keydata; u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32]; u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN]; int key_len, res, sign_key_len, encr_key_len; u16 rx_key_length; wpa_printf(MSG_DEBUG, "EAPOL: processKey"); if (sm->last_rx_key == NULL) return; if (!sm->conf.accept_802_1x_keys) { wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key" " even though this was not accepted - " "ignoring this packet"); return; } hdr = (struct ieee802_1x_hdr *) sm->last_rx_key; key = (struct ieee802_1x_eapol_key *) (hdr + 1); if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) { wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame"); return; } rx_key_length = WPA_GET_BE16(key->key_length); wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d " "EAPOL-Key: type=%d key_length=%d key_index=0x%x", hdr->version, hdr->type, be_to_host16(hdr->length), key->type, rx_key_length, key->key_index); eapol_sm_notify_lower_layer_success(sm, 1); sign_key_len = IEEE8021X_SIGN_KEY_LEN; encr_key_len = IEEE8021X_ENCR_KEY_LEN; res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata)); if (res < 0) { wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for " "decrypting EAPOL-Key keys"); return; } if (res == 16) { /* LEAP derives only 16 bytes of keying material. */ res = eapol_sm_get_key(sm, (u8 *) &keydata, 16); if (res) { wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP " "master key for decrypting EAPOL-Key keys"); return; } sign_key_len = 16; encr_key_len = 16; os_memcpy(keydata.sign_key, keydata.encr_key, 16); } else if (res) { wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key " "data for decrypting EAPOL-Key keys (res=%d)", res); return; } /* The key replay_counter must increase when same master key */ if (sm->replay_counter_valid && os_memcmp(sm->last_replay_counter, key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN) >= 0) { wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did " "not increase - ignoring key"); wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter", sm->last_replay_counter, IEEE8021X_REPLAY_COUNTER_LEN); wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter", key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN); return; } /* Verify key signature (HMAC-MD5) */ os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN); os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN); hmac_md5(keydata.sign_key, sign_key_len, sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length), key->key_signature); if (os_memcmp(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN) != 0) { wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in " "EAPOL-Key packet"); os_memcpy(key->key_signature, orig_key_sign, IEEE8021X_KEY_SIGN_LEN); return; } wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified"); key_len = be_to_host16(hdr->length) - sizeof(*key); if (key_len > 32 || rx_key_length > 32) { wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d", key_len ? key_len : rx_key_length); return; } if (key_len == rx_key_length) { os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN); os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key, encr_key_len); os_memcpy(datakey, key + 1, key_len); rc4(datakey, key_len, ekey, IEEE8021X_KEY_IV_LEN + encr_key_len); wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key", datakey, key_len); } else if (key_len == 0) { /* * IEEE 802.1X-2004 specifies that least significant Key Length * octets from MS-MPPE-Send-Key are used as the key if the key * data is not present. This seems to be meaning the beginning * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator. * Anyway, taking the beginning of the keying material from EAP * seems to interoperate with Authenticators. */ key_len = rx_key_length; os_memcpy(datakey, keydata.encr_key, key_len); wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying " "material data encryption key", datakey, key_len); } else { wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d " "(key_length=%d)", key_len, rx_key_length); return; } sm->replay_counter_valid = TRUE; os_memcpy(sm->last_replay_counter, key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN); wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d " "len %d", key->key_index & IEEE8021X_KEY_INDEX_FLAG ? "unicast" : "broadcast", key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len); if (sm->ctx->set_wep_key && sm->ctx->set_wep_key(sm->ctx->ctx, key->key_index & IEEE8021X_KEY_INDEX_FLAG, key->key_index & IEEE8021X_KEY_INDEX_MASK, datakey, key_len) < 0) { wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the " " driver."); } else { if (key->key_index & IEEE8021X_KEY_INDEX_FLAG) sm->unicast_key_received = TRUE; else sm->broadcast_key_received = TRUE; if ((sm->unicast_key_received || !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) && (sm->broadcast_key_received || !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST))) { wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key " "frames received"); sm->portValid = TRUE; if (sm->ctx->eapol_done_cb) sm->ctx->eapol_done_cb(sm->ctx->ctx); } }}static void eapol_sm_getSuppRsp(struct eapol_sm *sm){ wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp"); /* EAP layer processing; no special code is needed, since Supplicant * Backend state machine is waiting for eapNoResp or eapResp to be set * and these are only set in the EAP state machine when the processing * has finished. */}static void eapol_sm_txSuppRsp(struct eapol_sm *sm){ struct wpabuf *resp; wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp"); resp = eap_get_eapRespData(sm->eap); if (resp == NULL) { wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data " "not available"); return; } /* Send EAP-Packet from the EAP layer to the Authenticator */ sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp), wpabuf_len(resp)); /* eapRespData is not used anymore, so free it here */ wpabuf_free(resp); if (sm->initial_req) sm->dot1xSuppEapolReqIdFramesRx++; else sm->dot1xSuppEapolReqFramesRx++; sm->dot1xSuppEapolRespFramesTx++; sm->dot1xSuppEapolFramesTx++;}static void eapol_sm_abortSupp(struct eapol_sm *sm){ /* release system resources that may have been allocated for the * authentication session */ os_free(sm->last_rx_key); sm->last_rx_key = NULL; wpabuf_free(sm->eapReqData); sm->eapReqData = NULL; eap_sm_abort(sm->eap);}static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx){ eapol_sm_step(timeout_ctx);}/** * eapol_sm_step - EAPOL state machine step function * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() * * This function is called to notify the state machine about changed external * variables. It will step through the EAPOL state machines in loop to process * all triggered state changes. */void eapol_sm_step(struct eapol_sm *sm){ int i; /* In theory, it should be ok to run this in loop until !changed. * However, it is better to use a limit on number of iterations to * allow events (e.g., SIGTERM) to stop the program cleanly if the * state machine were to generate a busy loop. */ for (i = 0; i < 100; i++) { sm->changed = FALSE; SM_STEP_RUN(SUPP_PAE); SM_STEP_RUN(KEY_RX); SM_STEP_RUN(SUPP_BE); if (eap_peer_sm_step(sm->eap)) sm->changed = TRUE; if (!sm->changed) break; } if (sm->changed) { /* restart EAPOL state machine step from timeout call in order * to allow other events to be processed. */ eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm); eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm); } if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) { int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0; sm->cb_status = EAPOL_CB_IN_PROGRESS; sm->ctx->cb(sm, success, sm->ctx->cb_ctx); }}#ifdef CONFIG_CTRL_IFACEstatic const char *eapol_supp_pae_state(int state){ switch (state) { case SUPP_PAE_LOGOFF: return "LOGOFF"; case SUPP_PAE_DISCONNECTED: return "DISCONNECTED"; case SUPP_PAE_CONNECTING: return "CONNECTING"; case SUPP_PAE_AUTHENTICATING: return "AUTHENTICATING"; case SUPP_PAE_HELD: return "HELD"; case SUPP_PAE_AUTHENTICATED: return "AUTHENTICATED"; case SUPP_PAE_RESTART: return "RESTART"; default: return "UNKNOWN"; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -