eapol_sm.c
来自「一个Linux下无线网卡的设置工具」· C语言 代码 · 共 1,729 行 · 第 1/3 页
C
1,729 行
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); 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; 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 && 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) */ memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN); 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 (memcmp(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN) != 0) { wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in " "EAPOL-Key packet"); 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) { memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN); memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key, encr_key_len); 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; 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; 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){ u8 *resp; size_t resp_len; wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp"); resp = eap_get_eapRespData(sm->eap, &resp_len); 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, resp, resp_len); /* eapRespData is not used anymore, so free it here */ 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 */ free(sm->last_rx_key); sm->last_rx_key = NULL; 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_sm_step(sm->eap)) sm->changed = TRUE; } 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); }}static 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"; }}static const char *eapol_supp_be_state(int state){ switch (state) { case SUPP_BE_REQUEST: return "REQUEST"; case SUPP_BE_RESPONSE: return "RESPONSE"; case SUPP_BE_SUCCESS: return "SUCCESS"; case SUPP_BE_FAIL: return "FAIL"; case SUPP_BE_TIMEOUT: return "TIMEOUT"; case SUPP_BE_IDLE: return "IDLE"; case SUPP_BE_INITIALIZE: return "INITIALIZE"; case SUPP_BE_RECEIVE: return "RECEIVE"; default: return "UNKNOWN"; }}static const char * eapol_port_status(PortStatus status){ if (status == Authorized) return "Authorized"; else return "Unauthorized";}static const char * eapol_port_control(PortControl ctrl){ switch (ctrl) { case Auto: return "Auto"; case ForceUnauthorized: return "ForceUnauthorized"; case ForceAuthorized: return "ForceAuthorized"; default: return "Unknown"; }}/** * eapol_sm_configure - Set EAPOL variables * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() * @heldPeriod: dot1xSuppHeldPeriod * @authPeriod: dot1xSuppAuthPeriod * @startPeriod: dot1xSuppStartPeriod * @maxStart: dot1xSuppMaxStart * * Set configurable EAPOL state machine variables. Each variable can be set to * the given value or ignored if set to -1 (to set only some of the variables). */void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod, int startPeriod, int maxStart){ if (sm == NULL) return; if (heldPeriod >= 0) sm->heldPeriod = heldPeriod; if (authPeriod >= 0) sm->authPeriod = authPeriod; if (startPeriod >= 0) sm->startPeriod = startPeriod; if (maxStart >= 0) sm->maxStart = maxStart;}/** * eapol_sm_get_status - Get EAPOL state machine status * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() * @buf: Buffer for status information * @buflen: Maximum buffer length * @verbose: Whether to include verbose status information * Returns: Number of bytes written to buf. * * Query EAPOL state machine for status information. This function fills in a * text area with current status information from the EAPOL state machine. If * the buffer (buf) is not large enough, status information will be truncated * to fit the buffer. */int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen, int verbose){ int len; if (sm == NULL) return 0; len = snprintf(buf, buflen, "Supplicant PAE state=%s\n" "suppPortStatus=%s\n", eapol_supp_pae_state(sm->SUPP_PAE_state), eapol_port_status(sm->suppPortStatus)); if (verbose) { len += snprintf(buf + len, buflen - len, "heldPeriod=%u\n" "authPeriod=%u\n" "startPeriod=%u\n" "maxStart=%u\n" "portControl=%s\n" "Supplicant Backend state=%s\n", sm->heldPeriod, sm->authPeriod, sm->startPeriod, sm->maxStart, eapol_port_control(sm->portControl), eapol_supp_be_state(sm->SUPP_BE_state)); } len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose); return len;}/** * eapol_sm_get_mib - Get EAPOL state machine MIBs * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() * @buf: Buffer for MIB information * @buflen: Maximum buffer length * Returns: Number of bytes written to buf. * * Query EAPOL state machine for MIB information. This function fills in a * text area with current MIB information from the EAPOL state machine. If * the buffer (buf) is not large enough, MIB information will be truncated to * fit the buffer. */int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen){ int len; if (sm == NULL) return 0; len = snprintf(buf, buflen, "dot1xSuppPaeState=%d\n" "dot1xSuppHeldPeriod=%u\n" "dot1xSuppAuthPeriod=%u\n" "dot1xSuppStartPeriod=%u\n" "dot1xSuppMaxStart=%u\n" "dot1xSuppSuppControlledPortStatus=%s\n" "dot1xSuppBackendPaeState=%d\n" "dot1xSuppEapolFramesRx=%u\n" "dot1xSuppEapolFramesTx=%u\n" "dot1xSuppEapolStartFramesTx=%u\n" "dot1xSuppEapolLogoffFramesTx=%u\n" "dot1xSuppEapolRespFramesTx=%u\n" "dot1xSuppEapolReqIdFramesRx=%u\n" "dot1xSuppEapolReqFramesRx=%u\n" "dot1xSuppInvalidEapolFramesRx=%u\n" "dot1xSuppEapLengthErrorFramesRx=%u\n" "dot1xSuppLastEapolFrameVersion=%u\n" "dot1xSuppLastEapolFrameSource=" MACSTR "\n", sm->SUPP_PAE_state, sm->heldPeriod, sm->authPeriod, sm->startPeriod, sm->maxStart, sm->suppPortStatus == Authorized ? "Authorized" : "Unauthorized", sm->SUPP_BE_state, sm->dot1xSuppEapolFramesRx, sm->dot1xSuppEapolFramesTx, sm->dot1xSuppEapolStartFramesTx, sm->dot1xSuppEapolLogoffFramesTx, sm->dot1xSuppEapolRespFramesTx, sm->dot1xSuppEapolReqIdFramesRx, sm->dot1xSuppEapolReqFramesRx, sm->dot1xSuppInvalidEapolFramesRx, sm->dot1xSuppEapLengthErrorFramesRx, sm->dot1xSuppLastEapolFrameVersion, MAC2STR(sm->dot1xSuppLastEapolFrameSource)); return len;}/** * eapol_sm_rx_eapol - Process received EAPOL frames * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() * @src: Source MAC address of the EAPOL packet * @buf: Pointer to the beginning of the EAPOL data (EAPOL header) * @len: Length of the EAPOL frame * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine, * -1 failure */int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, size_t len){ const struct ieee802_1x_hdr *hdr; const struct ieee802_1x_eapol_key *key; int plen, data_len; int res = 1; if (sm == NULL) return 0; sm->dot1xSuppEapolFramesRx++; if (len < sizeof(*hdr)) { sm->dot1xSuppInvalidEapolFramesRx++; return 0; } hdr = (const struct ieee802_1x_hdr *) buf; sm->dot1xSuppLastEapolFrameVersion = hdr->version; memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN); if (hdr->version < EAPOL_VERSION) { /* TODO: backwards compatibility */ } plen = be_to_host16(hdr->length); if (plen > len - sizeof(*hdr)) { sm->dot1xSuppEapLengthErrorFramesRx++; return 0; } data_len = plen + sizeof(*hdr); switch (hdr->type) { case IEEE802_1X_TYPE_EAP_PACKET: if (sm->cached_pmk) { /* Trying to use PMKSA caching, but Authenticator did * not seem to have a matching entry. Need to restart * EAPOL state machines. */ eapol_sm_abort_cached(sm); } free(sm->eapReqData); sm->eapReqDataLen = plen; sm->eapReqData = malloc(sm->eapReqDataLen); if (sm->eapReqData) { wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet " "frame"); memcpy(sm->eapReqData, (u8 *) (hdr + 1), sm->eapReqDataLen); sm->eapolEap = TRUE; eapol_sm_step(sm); } break; case IEEE802_1X_TYPE_EAPOL_KEY: if (plen < sizeof(*key)) { wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key " "frame received"); break; } key = (const struct ieee802_1x_eapol_key *) (hdr + 1); if (key->type == EAPOL_KEY_TYPE_WPA || key->type == EAPOL_KEY_TYPE_RSN) { /* WPA Supplicant takes care of this frame. */ wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key " "frame in EAPOL state machines"); res = 0; break; } if (key->type != EAPOL_KEY_TYPE_RC4) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?