📄 wpa.c
字号:
return -1; } ok = 1; } if (!ok) { wpa_printf(MSG_WARNING, "WPA: Could not verify EAPOL-Key MIC " "- dropping packet"); return -1; } memcpy(sm->rx_replay_counter, key->replay_counter, WPA_REPLAY_COUNTER_LEN); sm->rx_replay_counter_set = 1; return 0;}/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, struct wpa_eapol_key *key, u16 ver){ u16 keydatalen = WPA_GET_BE16(key->key_data_length); wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data", (u8 *) (key + 1), keydatalen); if (!sm->ptk_set) { wpa_printf(MSG_WARNING, "WPA: PTK not available, " "cannot decrypt EAPOL-Key key data."); return -1; } /* Decrypt key data here so that this operation does not need * to be implemented separately for each message type. */ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { u8 ek[32]; memcpy(ek, key->key_iv, 16); memcpy(ek + 16, sm->ptk.kek, 16); rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen); } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { u8 *buf; if (keydatalen % 8) { wpa_printf(MSG_WARNING, "WPA: Unsupported " "AES-WRAP len %d", keydatalen); return -1; } keydatalen -= 8; /* AES-WRAP adds 8 bytes */ buf = malloc(keydatalen); if (buf == NULL) { wpa_printf(MSG_WARNING, "WPA: No memory for " "AES-UNWRAP buffer"); return -1; } if (aes_unwrap(sm->ptk.kek, keydatalen / 8, (u8 *) (key + 1), buf)) { free(buf); wpa_printf(MSG_WARNING, "WPA: AES unwrap failed - " "could not decrypt EAPOL-Key key data"); return -1; } memcpy(key + 1, buf, keydatalen); free(buf); WPA_PUT_BE16(key->key_data_length, keydatalen); } wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data", (u8 *) (key + 1), keydatalen); return 0;}/** * wpa_sm_aborted_cached - Notify WPA that PMKSA caching was aborted * @sm: Pointer to WPA state machine data from wpa_sm_init() */void wpa_sm_aborted_cached(struct wpa_sm *sm){ if (sm && sm->cur_pmksa) { wpa_printf(MSG_DEBUG, "RSN: Cancelling PMKSA caching attempt"); sm->cur_pmksa = NULL; }}static void wpa_eapol_key_dump(const struct wpa_eapol_key *key){#ifndef CONFIG_NO_STDOUT_DEBUG u16 key_info = WPA_GET_BE16(key->key_info); wpa_printf(MSG_DEBUG, " EAPOL-Key type=%d", key->type); wpa_printf(MSG_DEBUG, " key_info 0x%x (ver=%d keyidx=%d rsvd=%d %s" "%s%s%s%s%s%s%s)", key_info, key_info & WPA_KEY_INFO_TYPE_MASK, (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> WPA_KEY_INFO_KEY_INDEX_SHIFT, (key_info & (BIT(13) | BIT(14) | BIT(15))) >> 13, key_info & WPA_KEY_INFO_KEY_TYPE ? "Pairwise" : "Group", key_info & WPA_KEY_INFO_INSTALL ? " Install" : "", key_info & WPA_KEY_INFO_ACK ? " Ack" : "", key_info & WPA_KEY_INFO_MIC ? " MIC" : "", key_info & WPA_KEY_INFO_SECURE ? " Secure" : "", key_info & WPA_KEY_INFO_ERROR ? " Error" : "", key_info & WPA_KEY_INFO_REQUEST ? " Request" : "", key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : ""); wpa_printf(MSG_DEBUG, " key_length=%u key_data_length=%u", WPA_GET_BE16(key->key_length), WPA_GET_BE16(key->key_data_length)); wpa_hexdump(MSG_DEBUG, " replay_counter", key->replay_counter, WPA_REPLAY_COUNTER_LEN); wpa_hexdump(MSG_DEBUG, " key_nonce", key->key_nonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, " key_iv", key->key_iv, 16); wpa_hexdump(MSG_DEBUG, " key_rsc", key->key_rsc, 8); wpa_hexdump(MSG_DEBUG, " key_id (reserved)", key->key_id, 8); wpa_hexdump(MSG_DEBUG, " key_mic", key->key_mic, 16);#endif /* CONFIG_NO_STDOUT_DEBUG */}/** * wpa_sm_rx_eapol - Process received WPA EAPOL frames * @sm: Pointer to WPA state machine data from wpa_sm_init() * @src_addr: 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 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure * * This function is called for each received EAPOL frame. Other than EAPOL-Key * frames can be skipped if filtering is done elsewhere. wpa_sm_rx_eapol() is * only processing WPA and WPA2 EAPOL-Key frames. * * The received EAPOL-Key packets are validated and valid packets are replied * to. In addition, key material (PTK, GTK) is configured at the end of a * successful key handshake. */int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, const u8 *buf, size_t len){ size_t plen, data_len, extra_len; struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; u16 key_info, ver; u8 *tmp; int ret = -1; if (len < sizeof(*hdr) + sizeof(*key)) { wpa_printf(MSG_DEBUG, "WPA: EAPOL frame too short to be a WPA " "EAPOL-Key (len %lu, expecting at least %lu)", (unsigned long) len, (unsigned long) sizeof(*hdr) + sizeof(*key)); return 0; } tmp = malloc(len); if (tmp == NULL) return -1; memcpy(tmp, buf, len); hdr = (struct ieee802_1x_hdr *) tmp; key = (struct wpa_eapol_key *) (hdr + 1); plen = ntohs(hdr->length); data_len = plen + sizeof(*hdr); wpa_printf(MSG_DEBUG, "IEEE 802.1X RX: version=%d type=%d length=%lu", hdr->version, hdr->type, (unsigned long) plen); if (hdr->version < EAPOL_VERSION) { /* TODO: backwards compatibility */ } if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) { wpa_printf(MSG_DEBUG, "WPA: EAPOL frame (type %u) discarded, " "not a Key frame", hdr->type); ret = 0; goto out; } if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) { wpa_printf(MSG_DEBUG, "WPA: EAPOL frame payload size %lu " "invalid (frame size %lu)", (unsigned long) plen, (unsigned long) len); ret = 0; goto out; } if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN) { wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key type (%d) unknown, " "discarded", key->type); ret = 0; goto out; } wpa_eapol_key_dump(key); eapol_sm_notify_lower_layer_success(sm->eapol); wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len); if (data_len < len) { wpa_printf(MSG_DEBUG, "WPA: ignoring %lu bytes after the IEEE " "802.1X data", (unsigned long) len - data_len); } key_info = WPA_GET_BE16(key->key_info); ver = key_info & WPA_KEY_INFO_TYPE_MASK; if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { wpa_printf(MSG_INFO, "WPA: Unsupported EAPOL-Key descriptor " "version %d.", ver); goto out; } if (sm->pairwise_cipher == WPA_CIPHER_CCMP && ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { wpa_printf(MSG_INFO, "WPA: CCMP is used, but EAPOL-Key " "descriptor version (%d) is not 2.", ver); if (sm->group_cipher != WPA_CIPHER_CCMP && !(key_info & WPA_KEY_INFO_KEY_TYPE)) { /* Earlier versions of IEEE 802.11i did not explicitly * require version 2 descriptor for all EAPOL-Key * packets, so allow group keys to use version 1 if * CCMP is not used for them. */ wpa_printf(MSG_INFO, "WPA: Backwards compatibility: " "allow invalid version for non-CCMP group " "keys"); } else goto out; } if (sm->rx_replay_counter_set && memcmp(key->replay_counter, sm->rx_replay_counter, WPA_REPLAY_COUNTER_LEN) <= 0) { wpa_printf(MSG_WARNING, "WPA: EAPOL-Key Replay Counter did not" " increase - dropping packet"); goto out; } if (!(key_info & WPA_KEY_INFO_ACK)) { wpa_printf(MSG_INFO, "WPA: No Ack bit in key_info"); goto out; } if (key_info & WPA_KEY_INFO_REQUEST) { wpa_printf(MSG_INFO, "WPA: EAPOL-Key with Request bit - " "dropped"); goto out; } if ((key_info & WPA_KEY_INFO_MIC) && wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len)) goto out; extra_len = data_len - sizeof(*hdr) - sizeof(*key); if (WPA_GET_BE16(key->key_data_length) > extra_len) { wpa_msg(sm->ctx->ctx, MSG_INFO, "WPA: Invalid EAPOL-Key " "frame - key_data overflow (%d > %lu)", WPA_GET_BE16(key->key_data_length), (unsigned long) extra_len); goto out; } if (sm->proto == WPA_PROTO_RSN && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) && wpa_supplicant_decrypt_key_data(sm, key, ver)) goto out; if (key_info & WPA_KEY_INFO_KEY_TYPE) { if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) { wpa_printf(MSG_WARNING, "WPA: Ignored EAPOL-Key " "(Pairwise) with non-zero key index"); goto out; } if (key_info & WPA_KEY_INFO_MIC) { /* 3/4 4-Way Handshake */ wpa_supplicant_process_3_of_4(sm, key, extra_len, ver); } else { /* 1/4 4-Way Handshake */ wpa_supplicant_process_1_of_4(sm, src_addr, key, ver); } } else { if (key_info & WPA_KEY_INFO_MIC) { /* 1/2 Group Key Handshake */ wpa_supplicant_process_1_of_2(sm, src_addr, key, extra_len, ver); } else { wpa_printf(MSG_WARNING, "WPA: EAPOL-Key (Group) " "without Mic bit - dropped"); } } ret = 1;out: free(tmp); return ret;}static int wpa_cipher_bits(int cipher){ switch (cipher) { case WPA_CIPHER_CCMP: return 128; case WPA_CIPHER_TKIP: return 256; case WPA_CIPHER_WEP104: return 104; case WPA_CIPHER_WEP40: return 40; default: return 0; }}static const u8 * wpa_key_mgmt_suite(struct wpa_sm *sm){ static const u8 *dummy = (u8 *) "\x00\x00\x00\x00"; switch (sm->key_mgmt) { case WPA_KEY_MGMT_IEEE8021X: return (sm->proto == WPA_PROTO_RSN ? RSN_AUTH_KEY_MGMT_UNSPEC_802_1X : WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); case WPA_KEY_MGMT_PSK: return (sm->proto == WPA_PROTO_RSN ? RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X : WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); case WPA_KEY_MGMT_WPA_NONE: return WPA_AUTH_KEY_MGMT_NONE; default: return dummy; }}static const u8 * wpa_cipher_suite(struct wpa_sm *sm, int cipher){ static const u8 *dummy = (u8 *) "\x00\x00\x00\x00"; switch (cipher) { case WPA_CIPHER_CCMP: return (sm->proto == WPA_PROTO_RSN ? RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP); case WPA_CIPHER_TKIP: return (sm->proto == WPA_PROTO_RSN ? RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP); case WPA_CIPHER_WEP104: return (sm->proto == WPA_PROTO_RSN ? RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104); case WPA_CIPHER_WEP40: return (sm->proto == WPA_PROTO_RSN ? RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40); case WPA_CIPHER_NONE: return (sm->proto == WPA_PROTO_RSN ? RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); default: return dummy; }}#define RSN_SUITE "%02x-%02x-%02x-%d"#define RSN_SUITE_ARG(s) (s)[0], (s)[1], (s)[2], (s)[3]/** * wpa_sm_get_mib - Dump text list of MIB entries * @sm: Pointer to WPA state machine data from wpa_sm_init() * @buf: Buffer for the list * @buflen: Length of the buffer * Returns: Number of bytes written to buffer * * This function is used fetch dot11 MIB variables. */int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen){ int len, i; char pmkid_txt[PMKID_LEN * 2 + 1]; int rsna; if (sm->cur_pmksa) { char *pos = pmkid_txt; for (i = 0; i < PMKID_LEN; i++) { pos += sprintf(pos, "%02x", sm->cur_pmksa->pmkid[i]); } } else pmkid_txt[0] = '\0'; if ((sm->key_mgmt == WPA_KEY_MGMT_PSK || sm->key_mgmt == WPA_KEY_MGMT_IEEE8021X) && sm->proto == WPA_PROTO_RSN) rsna = 1; else rsna = 0; len = snprintf(buf, buflen, "dot11RSNAOptionImplemented=TRUE\n" "dot11RSNAPreauthenticationImplemented=TRUE\n" "dot11RSNAEnabled=%s\n" "dot11RSNAPreauthenticationEnabled=%s\n" "dot11RSNAConfigVersion=%d\n" "dot11RSNAConfigPairwiseKeysSupported=5\n" "dot11RSNAConfigGroupCipherSize=%d\n" "dot11RSNAConfigPMKLifetime=%d\n" "dot11RSNAConfigPMKReauthThreshold=%d\n" "dot11RSNAConfigNumberOfPTKSAReplayCounters=1\n" "dot11RSNAConfigSATimeout=%d\n" "dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n" "dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n" "dot11RSNAGroupCipherSelected=" RSN_SUITE "\n" "dot11RSNAPMKIDUsed=%s\n" "dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n" "dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n" "dot11RSNAGroupCipherRequested=" RSN_SUITE "\n" "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n" "dot11RSNA4WayHandshakeFailures=%u\n", rsna ? "TRUE" : "FALSE", rsna ? "TRUE" : "FALSE", RSN_VERSION, wpa_cipher_bits(sm->group_cipher), sm->dot11RSNAConfigPMKLifetime, sm->dot11RSNAConfigPMKReauthThreshold, sm->dot11RSNAConfigSATimeout, RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)), RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->pairwise_cipher)), RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)), pmkid_txt, RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)), RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->pairwise_cipher)), RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)), sm->dot11RSNA4WayHandshakeFailures); return len;}/** * wpa_sm_init - Initialize WPA state machine * @ctx: Context pointer for callbacks; this needs to be an allocated buffer * Returns: Pointer to the allocated WPA state machine data * * This function is used to allocate a new WPA state machine and the returned * value is passed to all WPA state machine calls. */struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx){ struct wpa_sm *sm; sm = malloc(sizeof(*sm)); if (sm == NULL) return NULL; memset(sm, 0, sizeof(*sm)); sm->renew_snonce = 1; sm->ctx = ctx; sm->dot11RSNAConfigPMKLifetime = 43200; sm->dot11RSNAConfigPMKReauthThreshold = 70; sm->dot11RSNAConfigSATimeout = 60; return sm;}/** * wpa_sm_deinit - Deinitialize WPA state machine * @sm: Pointer to WPA state machine
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -