Home | History | Annotate | Download | only in ap
      1 /*
      2  * hostapd - PeerKey for Direct Link Setup (DLS)
      3  * Copyright (c) 2006-2009, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "utils/includes.h"
     10 
     11 #include "utils/common.h"
     12 #include "utils/eloop.h"
     13 #include "crypto/sha1.h"
     14 #include "crypto/sha256.h"
     15 #include "crypto/random.h"
     16 #include "wpa_auth.h"
     17 #include "wpa_auth_i.h"
     18 #include "wpa_auth_ie.h"
     19 
     20 #ifdef CONFIG_PEERKEY
     21 
     22 struct wpa_stsl_search {
     23 	const u8 *addr;
     24 	struct wpa_state_machine *sm;
     25 };
     26 
     27 
     28 static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
     29 {
     30 	struct wpa_stsl_search *search = ctx;
     31 	if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
     32 		search->sm = sm;
     33 		return 1;
     34 	}
     35 	return 0;
     36 }
     37 
     38 
     39 static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
     40 			       struct wpa_state_machine *sm, const u8 *peer,
     41 			       u16 mui, u16 error_type)
     42 {
     43 	u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
     44 	       2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
     45 	u8 *pos;
     46 	struct rsn_error_kde error;
     47 
     48 	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
     49 			"Sending SMK Error");
     50 
     51 	pos = kde;
     52 
     53 	if (peer) {
     54 		pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
     55 				  NULL, 0);
     56 	}
     57 
     58 	error.mui = host_to_be16(mui);
     59 	error.error_type = host_to_be16(error_type);
     60 	pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
     61 			  (u8 *) &error, sizeof(error), NULL, 0);
     62 
     63 	__wpa_send_eapol(wpa_auth, sm,
     64 			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
     65 			 WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
     66 			 NULL, NULL, kde, pos - kde, 0, 0, 0);
     67 }
     68 
     69 
     70 void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
     71 		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
     72 		const u8 *key_data, size_t key_data_len)
     73 {
     74 	struct wpa_eapol_ie_parse kde;
     75 	struct wpa_stsl_search search;
     76 	u8 *buf, *pos;
     77 	size_t buf_len;
     78 
     79 	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
     80 		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
     81 		return;
     82 	}
     83 
     84 	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
     85 	    kde.mac_addr_len < ETH_ALEN) {
     86 		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
     87 			   "SMK M1");
     88 		return;
     89 	}
     90 
     91 	/* Initiator = sm->addr; Peer = kde.mac_addr */
     92 
     93 	search.addr = kde.mac_addr;
     94 	search.sm = NULL;
     95 	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
     96 	    0 || search.sm == NULL) {
     97 		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
     98 			   " aborted - STA not associated anymore",
     99 			   MAC2STR(kde.mac_addr));
    100 		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
    101 				   STK_ERR_STA_NR);
    102 		return;
    103 	}
    104 
    105 	buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
    106 	buf = os_malloc(buf_len);
    107 	if (buf == NULL)
    108 		return;
    109 	/* Initiator RSN IE */
    110 	os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
    111 	pos = buf + kde.rsn_ie_len;
    112 	/* Initiator MAC Address */
    113 	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
    114 			  NULL, 0);
    115 
    116 	/* SMK M2:
    117 	 * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
    118 	 *           MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
    119 	 */
    120 
    121 	wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
    122 			"Sending SMK M2");
    123 
    124 	__wpa_send_eapol(wpa_auth, search.sm,
    125 			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
    126 			 WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
    127 			 NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
    128 
    129 	os_free(buf);
    130 }
    131 
    132 
    133 static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
    134 			    struct wpa_state_machine *sm,
    135 			    struct wpa_eapol_key *key,
    136 			    struct wpa_eapol_ie_parse *kde,
    137 			    const u8 *smk)
    138 {
    139 	u8 *buf, *pos;
    140 	size_t buf_len;
    141 	u32 lifetime;
    142 
    143 	/* SMK M4:
    144 	 * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
    145 	 *           MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
    146 	 *           Lifetime KDE)
    147 	 */
    148 
    149 	buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
    150 		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
    151 		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
    152 		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
    153 	pos = buf = os_malloc(buf_len);
    154 	if (buf == NULL)
    155 		return;
    156 
    157 	/* Initiator MAC Address */
    158 	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
    159 			  NULL, 0);
    160 
    161 	/* Initiator Nonce */
    162 	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
    163 			  NULL, 0);
    164 
    165 	/* SMK with PNonce */
    166 	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
    167 			  key->key_nonce, WPA_NONCE_LEN);
    168 
    169 	/* Lifetime */
    170 	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
    171 	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
    172 			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
    173 
    174 	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
    175 			"Sending SMK M4");
    176 
    177 	__wpa_send_eapol(wpa_auth, sm,
    178 			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
    179 			 WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
    180 			 NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
    181 
    182 	os_free(buf);
    183 }
    184 
    185 
    186 static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
    187 			    struct wpa_state_machine *sm,
    188 			    struct wpa_eapol_key *key,
    189 			    struct wpa_eapol_ie_parse *kde,
    190 			    const u8 *smk, const u8 *peer)
    191 {
    192 	u8 *buf, *pos;
    193 	size_t buf_len;
    194 	u32 lifetime;
    195 
    196 	/* SMK M5:
    197 	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
    198 	 *           MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
    199 	 *                             Lifetime KDE))
    200 	 */
    201 
    202 	buf_len = kde->rsn_ie_len +
    203 		2 + RSN_SELECTOR_LEN + ETH_ALEN +
    204 		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
    205 		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
    206 		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
    207 	pos = buf = os_malloc(buf_len);
    208 	if (buf == NULL)
    209 		return;
    210 
    211 	/* Peer RSN IE */
    212 	os_memcpy(pos, kde->rsn_ie, kde->rsn_ie_len);
    213 	pos += kde->rsn_ie_len;
    214 
    215 	/* Peer MAC Address */
    216 	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
    217 
    218 	/* PNonce */
    219 	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
    220 			  WPA_NONCE_LEN, NULL, 0);
    221 
    222 	/* SMK and INonce */
    223 	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
    224 			  kde->nonce, WPA_NONCE_LEN);
    225 
    226 	/* Lifetime */
    227 	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
    228 	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
    229 			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
    230 
    231 	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
    232 			"Sending SMK M5");
    233 
    234 	__wpa_send_eapol(wpa_auth, sm,
    235 			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
    236 			 WPA_KEY_INFO_SMK_MESSAGE,
    237 			 NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
    238 
    239 	os_free(buf);
    240 }
    241 
    242 
    243 void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
    244 		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
    245 		const u8 *key_data, size_t key_data_len)
    246 {
    247 	struct wpa_eapol_ie_parse kde;
    248 	struct wpa_stsl_search search;
    249 	u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
    250 
    251 	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
    252 		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
    253 		return;
    254 	}
    255 
    256 	if (kde.rsn_ie == NULL ||
    257 	    kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
    258 	    kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
    259 		wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
    260 			   "Nonce KDE in SMK M3");
    261 		return;
    262 	}
    263 
    264 	/* Peer = sm->addr; Initiator = kde.mac_addr;
    265 	 * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
    266 
    267 	search.addr = kde.mac_addr;
    268 	search.sm = NULL;
    269 	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
    270 	    0 || search.sm == NULL) {
    271 		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
    272 			   " aborted - STA not associated anymore",
    273 			   MAC2STR(kde.mac_addr));
    274 		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
    275 				   STK_ERR_STA_NR);
    276 		return;
    277 	}
    278 
    279 	if (random_get_bytes(smk, PMK_LEN)) {
    280 		wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
    281 		return;
    282 	}
    283 
    284 	/* SMK = PRF-256(Random number, "SMK Derivation",
    285 	 *               AA || Time || INonce || PNonce)
    286 	 */
    287 	os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
    288 	pos = buf + ETH_ALEN;
    289 	wpa_get_ntp_timestamp(pos);
    290 	pos += 8;
    291 	os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
    292 	pos += WPA_NONCE_LEN;
    293 	os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
    294 #ifdef CONFIG_IEEE80211W
    295 	sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
    296 		   smk, PMK_LEN);
    297 #else /* CONFIG_IEEE80211W */
    298 	sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
    299 		 smk, PMK_LEN);
    300 #endif /* CONFIG_IEEE80211W */
    301 
    302 	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
    303 
    304 	wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
    305 	wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
    306 
    307 	/* Authenticator does not need SMK anymore and it is required to forget
    308 	 * it. */
    309 	os_memset(smk, 0, sizeof(*smk));
    310 }
    311 
    312 
    313 void wpa_smk_error(struct wpa_authenticator *wpa_auth,
    314 		   struct wpa_state_machine *sm,
    315 		   const u8 *key_data, size_t key_data_len)
    316 {
    317 	struct wpa_eapol_ie_parse kde;
    318 	struct wpa_stsl_search search;
    319 	struct rsn_error_kde error;
    320 	u16 mui, error_type;
    321 
    322 	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
    323 		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
    324 		return;
    325 	}
    326 
    327 	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
    328 	    kde.error == NULL || kde.error_len < sizeof(error)) {
    329 		wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
    330 			   "SMK Error");
    331 		return;
    332 	}
    333 
    334 	search.addr = kde.mac_addr;
    335 	search.sm = NULL;
    336 	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
    337 	    0 || search.sm == NULL) {
    338 		wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
    339 			   "associated for SMK Error message from " MACSTR,
    340 			   MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
    341 		return;
    342 	}
    343 
    344 	os_memcpy(&error, kde.error, sizeof(error));
    345 	mui = be_to_host16(error.mui);
    346 	error_type = be_to_host16(error.error_type);
    347 	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
    348 			 "STA reported SMK Error: Peer " MACSTR
    349 			 " MUI %d Error Type %d",
    350 			 MAC2STR(kde.mac_addr), mui, error_type);
    351 
    352 	wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
    353 }
    354 
    355 #endif /* CONFIG_PEERKEY */
    356