📄 peerkey.c
字号:
/* * WPA Supplicant - PeerKey for Direct Link Setup (DLS) * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#ifdef CONFIG_PEERKEY#include "common.h"#include "sha1.h"#include "sha256.h"#include "eloop.h"#include "wpa.h"#include "wpa_i.h"#include "wpa_ie.h"#include "ieee802_11_defs.h"#include "peerkey.h"static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len){ os_memcpy(pos, ie, ie_len); return pos + ie_len;}static u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len){ *pos++ = WLAN_EID_VENDOR_SPECIFIC; *pos++ = RSN_SELECTOR_LEN + data_len; RSN_SELECTOR_PUT(pos, kde); pos += RSN_SELECTOR_LEN; os_memcpy(pos, data, data_len); pos += data_len; return pos;}static void wpa_supplicant_smk_timeout(void *eloop_ctx, void *timeout_ctx){#if 0 struct wpa_sm *sm = eloop_ctx; struct wpa_peerkey *peerkey = timeout_ctx;#endif /* TODO: time out SMK and any STK that was generated using this SMK */}static void wpa_supplicant_peerkey_free(struct wpa_sm *sm, struct wpa_peerkey *peerkey){ eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey); os_free(peerkey);}static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst, const u8 *peer, u16 mui, u16 error_type, int ver){ size_t rlen; struct wpa_eapol_key *err; struct rsn_error_kde error; u8 *rbuf, *pos; size_t kde_len; u16 key_info; kde_len = 2 + RSN_SELECTOR_LEN + sizeof(error); if (peer) kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN; rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, sizeof(*err) + kde_len, &rlen, (void *) &err); if (rbuf == NULL) return -1; err->type = EAPOL_KEY_TYPE_RSN; key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE | WPA_KEY_INFO_ERROR | WPA_KEY_INFO_REQUEST; WPA_PUT_BE16(err->key_info, key_info); WPA_PUT_BE16(err->key_length, 0); os_memcpy(err->replay_counter, sm->request_counter, WPA_REPLAY_COUNTER_LEN); inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); WPA_PUT_BE16(err->key_data_length, (u16) kde_len); pos = (u8 *) (err + 1); if (peer) { /* Peer MAC Address KDE */ pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN); } /* Error KDE */ error.mui = host_to_be16(mui); error.error_type = host_to_be16(error_type); wpa_add_kde(pos, RSN_KEY_DATA_ERROR, (u8 *) &error, sizeof(error)); if (peer) { wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error (peer " MACSTR " mui %d error_type %d)", MAC2STR(peer), mui, error_type); } else { wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error " "(mui %d error_type %d)", mui, error_type); } wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL, rbuf, rlen, err->key_mic); return 0;}static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, int ver, struct wpa_peerkey *peerkey){ size_t rlen; struct wpa_eapol_key *reply; u8 *rbuf, *pos; size_t kde_len; u16 key_info; /* KDEs: Peer RSN IE, Initiator MAC Address, Initiator Nonce */ kde_len = peerkey->rsnie_p_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN + 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN; rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, sizeof(*reply) + kde_len, &rlen, (void *) &reply); if (rbuf == NULL) return -1; reply->type = EAPOL_KEY_TYPE_RSN; key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE; WPA_PUT_BE16(reply->key_info, key_info); WPA_PUT_BE16(reply->key_length, 0); os_memcpy(reply->replay_counter, key->replay_counter, WPA_REPLAY_COUNTER_LEN); os_memcpy(reply->key_nonce, peerkey->pnonce, WPA_NONCE_LEN); WPA_PUT_BE16(reply->key_data_length, (u16) kde_len); pos = (u8 *) (reply + 1); /* Peer RSN IE */ pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len); /* Initiator MAC Address KDE */ pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peerkey->addr, ETH_ALEN); /* Initiator Nonce */ wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN); wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3"); wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL, rbuf, rlen, reply->key_mic); return 0;}static int wpa_supplicant_process_smk_m2( struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, size_t extra_len, int ver){ struct wpa_peerkey *peerkey; struct wpa_eapol_ie_parse kde; struct wpa_ie_data ie; int cipher; struct rsn_ie_hdr *hdr; u8 *pos; wpa_printf(MSG_DEBUG, "RSN: Received SMK M2"); if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for " "the current network"); return -1; } if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) < 0) { wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2"); return -1; } if (kde.rsn_ie == NULL || kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN) { wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in " "SMK M2"); return -1; } wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR, MAC2STR(kde.mac_addr)); if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) { wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK " "M2"); return -1; } if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2"); return -1; } cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher; if (cipher & WPA_CIPHER_CCMP) { wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey"); cipher = WPA_CIPHER_CCMP; } else if (cipher & WPA_CIPHER_TKIP) { wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey"); cipher = WPA_CIPHER_TKIP; } else { wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2"); wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr, STK_MUI_SMK, STK_ERR_CPHR_NS, ver); return -1; } /* TODO: find existing entry and if found, use that instead of adding * a new one; how to handle the case where both ends initiate at the * same time? */ peerkey = os_zalloc(sizeof(*peerkey)); if (peerkey == NULL) return -1; os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN); os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN); os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len); peerkey->rsnie_i_len = kde.rsn_ie_len; peerkey->cipher = cipher;#ifdef CONFIG_IEEE80211W if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 | WPA_KEY_MGMT_PSK_SHA256)) peerkey->use_sha256 = 1;#endif /* CONFIG_IEEE80211W */ if (os_get_random(peerkey->pnonce, WPA_NONCE_LEN)) { wpa_msg(sm->ctx->ctx, MSG_WARNING, "WPA: Failed to get random data for PNonce"); wpa_supplicant_peerkey_free(sm, peerkey); return -1; } hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p; hdr->elem_id = WLAN_EID_RSN; WPA_PUT_LE16(hdr->version, RSN_VERSION); pos = (u8 *) (hdr + 1); /* Group Suite can be anything for SMK RSN IE; receiver will just * ignore it. */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; /* Include only the selected cipher in pairwise cipher suite */ WPA_PUT_LE16(pos, 1); pos += 2; if (cipher == WPA_CIPHER_CCMP) RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); else if (cipher == WPA_CIPHER_TKIP) RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); pos += RSN_SELECTOR_LEN; hdr->len = (pos - peerkey->rsnie_p) - 2; peerkey->rsnie_p_len = pos - peerkey->rsnie_p; wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake", peerkey->rsnie_p, peerkey->rsnie_p_len); wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey); peerkey->next = sm->peerkey; sm->peerkey = peerkey; return 0;}/** * rsn_smkid - Derive SMK identifier * @smk: Station master key (32 bytes) * @pnonce: Peer Nonce * @mac_p: Peer MAC address * @inonce: Initiator Nonce * @mac_i: Initiator MAC address * @use_sha256: Whether to use SHA256-based KDF * * 8.5.1.4 Station to station (STK) key hierarchy * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I) */static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p, const u8 *inonce, const u8 *mac_i, u8 *smkid, int use_sha256){ char *title = "SMK Name"; const u8 *addr[5]; const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN, ETH_ALEN }; unsigned char hash[SHA256_MAC_LEN]; addr[0] = (u8 *) title; addr[1] = pnonce; addr[2] = mac_p; addr[3] = inonce; addr[4] = mac_i;#ifdef CONFIG_IEEE80211W if (use_sha256) hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash); else#endif /* CONFIG_IEEE80211W */ hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash); os_memcpy(smkid, hash, PMKID_LEN);}static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm, struct wpa_peerkey *peerkey){ size_t mlen; struct wpa_eapol_key *msg; u8 *mbuf; size_t kde_len; u16 key_info, ver; kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN; mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, sizeof(*msg) + kde_len, &mlen, (void *) &msg); if (mbuf == NULL) return; msg->type = EAPOL_KEY_TYPE_RSN; if (peerkey->cipher == WPA_CIPHER_CCMP) ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; else ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK; WPA_PUT_BE16(msg->key_info, key_info); if (peerkey->cipher == WPA_CIPHER_CCMP) WPA_PUT_BE16(msg->key_length, 16); else WPA_PUT_BE16(msg->key_length, 32); os_memcpy(msg->replay_counter, peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN); inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN); WPA_PUT_BE16(msg->key_data_length, kde_len); wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID, peerkey->smkid, PMKID_LEN); if (os_get_random(peerkey->inonce, WPA_NONCE_LEN)) { wpa_msg(sm->ctx->ctx, MSG_WARNING, "RSN: Failed to get random data for INonce (STK)"); os_free(mbuf); return; } wpa_hexdump(MSG_DEBUG, "RSN: INonce for STK 4-Way Handshake", peerkey->inonce, WPA_NONCE_LEN); os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN); wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR, MAC2STR(peerkey->addr)); wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL, mbuf, mlen, NULL);}static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm, struct wpa_peerkey *peerkey){ size_t mlen; struct wpa_eapol_key *msg; u8 *mbuf, *pos;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -