| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * WPA Supplicant - WPA state machine and EAPOL-Key processing | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 3 | * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 4 | * | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 5 | * This software may be distributed under the terms of the BSD license. | 
|  | 6 | * See README for more details. | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 7 | */ | 
|  | 8 |  | 
|  | 9 | #include "includes.h" | 
|  | 10 |  | 
|  | 11 | #include "common.h" | 
|  | 12 | #include "crypto/aes_wrap.h" | 
|  | 13 | #include "crypto/crypto.h" | 
|  | 14 | #include "crypto/random.h" | 
|  | 15 | #include "common/ieee802_11_defs.h" | 
|  | 16 | #include "eapol_supp/eapol_supp_sm.h" | 
|  | 17 | #include "wpa.h" | 
|  | 18 | #include "eloop.h" | 
|  | 19 | #include "preauth.h" | 
|  | 20 | #include "pmksa_cache.h" | 
|  | 21 | #include "wpa_i.h" | 
|  | 22 | #include "wpa_ie.h" | 
|  | 23 | #include "peerkey.h" | 
|  | 24 |  | 
|  | 25 |  | 
|  | 26 | /** | 
|  | 27 | * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message | 
|  | 28 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 29 | * @kck: Key Confirmation Key (KCK, part of PTK) | 
|  | 30 | * @ver: Version field from Key Info | 
|  | 31 | * @dest: Destination address for the frame | 
|  | 32 | * @proto: Ethertype (usually ETH_P_EAPOL) | 
|  | 33 | * @msg: EAPOL-Key message | 
|  | 34 | * @msg_len: Length of message | 
|  | 35 | * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written | 
|  | 36 | */ | 
|  | 37 | void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, | 
|  | 38 | int ver, const u8 *dest, u16 proto, | 
|  | 39 | u8 *msg, size_t msg_len, u8 *key_mic) | 
|  | 40 | { | 
|  | 41 | if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) { | 
|  | 42 | /* | 
|  | 43 | * Association event was not yet received; try to fetch | 
|  | 44 | * BSSID from the driver. | 
|  | 45 | */ | 
|  | 46 | if (wpa_sm_get_bssid(sm, sm->bssid) < 0) { | 
|  | 47 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 48 | "WPA: Failed to read BSSID for " | 
|  | 49 | "EAPOL-Key destination address"); | 
|  | 50 | } else { | 
|  | 51 | dest = sm->bssid; | 
|  | 52 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 53 | "WPA: Use BSSID (" MACSTR | 
|  | 54 | ") as the destination for EAPOL-Key", | 
|  | 55 | MAC2STR(dest)); | 
|  | 56 | } | 
|  | 57 | } | 
|  | 58 | if (key_mic && | 
|  | 59 | wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) { | 
|  | 60 | wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, | 
|  | 61 | "WPA: Failed to generate EAPOL-Key " | 
|  | 62 | "version %d MIC", ver); | 
|  | 63 | goto out; | 
|  | 64 | } | 
|  | 65 | wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16); | 
|  | 66 | wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, 16); | 
|  | 67 | wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len); | 
|  | 68 | wpa_sm_ether_send(sm, dest, proto, msg, msg_len); | 
|  | 69 | eapol_sm_notify_tx_eapol_key(sm->eapol); | 
|  | 70 | out: | 
|  | 71 | os_free(msg); | 
|  | 72 | } | 
|  | 73 |  | 
|  | 74 |  | 
|  | 75 | /** | 
|  | 76 | * wpa_sm_key_request - Send EAPOL-Key Request | 
|  | 77 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 78 | * @error: Indicate whether this is an Michael MIC error report | 
|  | 79 | * @pairwise: 1 = error report for pairwise packet, 0 = for group packet | 
|  | 80 | * | 
|  | 81 | * Send an EAPOL-Key Request to the current authenticator. This function is | 
|  | 82 | * used to request rekeying and it is usually called when a local Michael MIC | 
|  | 83 | * failure is detected. | 
|  | 84 | */ | 
|  | 85 | void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) | 
|  | 86 | { | 
|  | 87 | size_t rlen; | 
|  | 88 | struct wpa_eapol_key *reply; | 
|  | 89 | int key_info, ver; | 
|  | 90 | u8 bssid[ETH_ALEN], *rbuf; | 
|  | 91 |  | 
|  | 92 | if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt)) | 
|  | 93 | ver = WPA_KEY_INFO_TYPE_AES_128_CMAC; | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 94 | else if (sm->pairwise_cipher != WPA_CIPHER_TKIP) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 95 | ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; | 
|  | 96 | else | 
|  | 97 | ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; | 
|  | 98 |  | 
|  | 99 | if (wpa_sm_get_bssid(sm, bssid) < 0) { | 
|  | 100 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 101 | "Failed to read BSSID for EAPOL-Key request"); | 
|  | 102 | return; | 
|  | 103 | } | 
|  | 104 |  | 
|  | 105 | rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, | 
|  | 106 | sizeof(*reply), &rlen, (void *) &reply); | 
|  | 107 | if (rbuf == NULL) | 
|  | 108 | return; | 
|  | 109 |  | 
|  | 110 | reply->type = sm->proto == WPA_PROTO_RSN ? | 
|  | 111 | EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; | 
|  | 112 | key_info = WPA_KEY_INFO_REQUEST | ver; | 
|  | 113 | if (sm->ptk_set) | 
|  | 114 | key_info |= WPA_KEY_INFO_MIC; | 
|  | 115 | if (error) | 
|  | 116 | key_info |= WPA_KEY_INFO_ERROR; | 
|  | 117 | if (pairwise) | 
|  | 118 | key_info |= WPA_KEY_INFO_KEY_TYPE; | 
|  | 119 | WPA_PUT_BE16(reply->key_info, key_info); | 
|  | 120 | WPA_PUT_BE16(reply->key_length, 0); | 
|  | 121 | os_memcpy(reply->replay_counter, sm->request_counter, | 
|  | 122 | WPA_REPLAY_COUNTER_LEN); | 
|  | 123 | inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); | 
|  | 124 |  | 
|  | 125 | WPA_PUT_BE16(reply->key_data_length, 0); | 
|  | 126 |  | 
|  | 127 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 128 | "WPA: Sending EAPOL-Key Request (error=%d " | 
|  | 129 | "pairwise=%d ptk_set=%d len=%lu)", | 
|  | 130 | error, pairwise, sm->ptk_set, (unsigned long) rlen); | 
|  | 131 | wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL, | 
|  | 132 | rbuf, rlen, key_info & WPA_KEY_INFO_MIC ? | 
|  | 133 | reply->key_mic : NULL); | 
|  | 134 | } | 
|  | 135 |  | 
|  | 136 |  | 
|  | 137 | static int wpa_supplicant_get_pmk(struct wpa_sm *sm, | 
|  | 138 | const unsigned char *src_addr, | 
|  | 139 | const u8 *pmkid) | 
|  | 140 | { | 
|  | 141 | int abort_cached = 0; | 
|  | 142 |  | 
|  | 143 | if (pmkid && !sm->cur_pmksa) { | 
|  | 144 | /* When using drivers that generate RSN IE, wpa_supplicant may | 
|  | 145 | * not have enough time to get the association information | 
|  | 146 | * event before receiving this 1/4 message, so try to find a | 
|  | 147 | * matching PMKSA cache entry here. */ | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 148 | sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid, | 
|  | 149 | NULL); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 150 | if (sm->cur_pmksa) { | 
|  | 151 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 152 | "RSN: found matching PMKID from PMKSA cache"); | 
|  | 153 | } else { | 
|  | 154 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 155 | "RSN: no matching PMKID found"); | 
|  | 156 | abort_cached = 1; | 
|  | 157 | } | 
|  | 158 | } | 
|  | 159 |  | 
|  | 160 | if (pmkid && sm->cur_pmksa && | 
|  | 161 | os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) { | 
|  | 162 | wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN); | 
|  | 163 | wpa_sm_set_pmk_from_pmksa(sm); | 
|  | 164 | wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache", | 
|  | 165 | sm->pmk, sm->pmk_len); | 
|  | 166 | eapol_sm_notify_cached(sm->eapol); | 
|  | 167 | #ifdef CONFIG_IEEE80211R | 
|  | 168 | sm->xxkey_len = 0; | 
|  | 169 | #endif /* CONFIG_IEEE80211R */ | 
|  | 170 | } else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) { | 
|  | 171 | int res, pmk_len; | 
|  | 172 | pmk_len = PMK_LEN; | 
|  | 173 | res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN); | 
|  | 174 | if (res) { | 
|  | 175 | /* | 
|  | 176 | * EAP-LEAP is an exception from other EAP methods: it | 
|  | 177 | * uses only 16-byte PMK. | 
|  | 178 | */ | 
|  | 179 | res = eapol_sm_get_key(sm->eapol, sm->pmk, 16); | 
|  | 180 | pmk_len = 16; | 
|  | 181 | } else { | 
|  | 182 | #ifdef CONFIG_IEEE80211R | 
|  | 183 | u8 buf[2 * PMK_LEN]; | 
|  | 184 | if (eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0) | 
|  | 185 | { | 
|  | 186 | os_memcpy(sm->xxkey, buf + PMK_LEN, PMK_LEN); | 
|  | 187 | sm->xxkey_len = PMK_LEN; | 
|  | 188 | os_memset(buf, 0, sizeof(buf)); | 
|  | 189 | } | 
|  | 190 | #endif /* CONFIG_IEEE80211R */ | 
|  | 191 | } | 
|  | 192 | if (res == 0) { | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 193 | struct rsn_pmksa_cache_entry *sa = NULL; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 194 | wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state " | 
|  | 195 | "machines", sm->pmk, pmk_len); | 
|  | 196 | sm->pmk_len = pmk_len; | 
| Dmitry Shmidt | c55524a | 2011-07-07 11:18:38 -0700 | [diff] [blame] | 197 | if (sm->proto == WPA_PROTO_RSN && | 
|  | 198 | !wpa_key_mgmt_ft(sm->key_mgmt)) { | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 199 | sa = pmksa_cache_add(sm->pmksa, | 
|  | 200 | sm->pmk, pmk_len, | 
|  | 201 | src_addr, sm->own_addr, | 
|  | 202 | sm->network_ctx, | 
|  | 203 | sm->key_mgmt); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 204 | } | 
|  | 205 | if (!sm->cur_pmksa && pmkid && | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 206 | pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL)) | 
|  | 207 | { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 208 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 209 | "RSN: the new PMK matches with the " | 
|  | 210 | "PMKID"); | 
|  | 211 | abort_cached = 0; | 
|  | 212 | } | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 213 |  | 
|  | 214 | if (!sm->cur_pmksa) | 
|  | 215 | sm->cur_pmksa = sa; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 216 | } else { | 
|  | 217 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 218 | "WPA: Failed to get master session key from " | 
|  | 219 | "EAPOL state machines - key handshake " | 
|  | 220 | "aborted"); | 
|  | 221 | if (sm->cur_pmksa) { | 
|  | 222 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 223 | "RSN: Cancelled PMKSA caching " | 
|  | 224 | "attempt"); | 
|  | 225 | sm->cur_pmksa = NULL; | 
|  | 226 | abort_cached = 1; | 
|  | 227 | } else if (!abort_cached) { | 
|  | 228 | return -1; | 
|  | 229 | } | 
|  | 230 | } | 
|  | 231 | } | 
|  | 232 |  | 
| Dmitry Shmidt | c55524a | 2011-07-07 11:18:38 -0700 | [diff] [blame] | 233 | if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && | 
|  | 234 | !wpa_key_mgmt_ft(sm->key_mgmt)) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 235 | /* Send EAPOL-Start to trigger full EAP authentication. */ | 
|  | 236 | u8 *buf; | 
|  | 237 | size_t buflen; | 
|  | 238 |  | 
|  | 239 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 240 | "RSN: no PMKSA entry found - trigger " | 
|  | 241 | "full EAP authentication"); | 
|  | 242 | buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START, | 
|  | 243 | NULL, 0, &buflen, NULL); | 
|  | 244 | if (buf) { | 
|  | 245 | wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL, | 
|  | 246 | buf, buflen); | 
|  | 247 | os_free(buf); | 
|  | 248 | return -2; | 
|  | 249 | } | 
|  | 250 |  | 
|  | 251 | return -1; | 
|  | 252 | } | 
|  | 253 |  | 
|  | 254 | return 0; | 
|  | 255 | } | 
|  | 256 |  | 
|  | 257 |  | 
|  | 258 | /** | 
|  | 259 | * wpa_supplicant_send_2_of_4 - Send message 2 of WPA/RSN 4-Way Handshake | 
|  | 260 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 261 | * @dst: Destination address for the frame | 
|  | 262 | * @key: Pointer to the EAPOL-Key frame header | 
|  | 263 | * @ver: Version bits from EAPOL-Key Key Info | 
|  | 264 | * @nonce: Nonce value for the EAPOL-Key frame | 
|  | 265 | * @wpa_ie: WPA/RSN IE | 
|  | 266 | * @wpa_ie_len: Length of the WPA/RSN IE | 
|  | 267 | * @ptk: PTK to use for keyed hash and encryption | 
|  | 268 | * Returns: 0 on success, -1 on failure | 
|  | 269 | */ | 
|  | 270 | int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, | 
|  | 271 | const struct wpa_eapol_key *key, | 
|  | 272 | int ver, const u8 *nonce, | 
|  | 273 | const u8 *wpa_ie, size_t wpa_ie_len, | 
|  | 274 | struct wpa_ptk *ptk) | 
|  | 275 | { | 
|  | 276 | size_t rlen; | 
|  | 277 | struct wpa_eapol_key *reply; | 
|  | 278 | u8 *rbuf; | 
|  | 279 | u8 *rsn_ie_buf = NULL; | 
|  | 280 |  | 
|  | 281 | if (wpa_ie == NULL) { | 
|  | 282 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No wpa_ie set - " | 
|  | 283 | "cannot generate msg 2/4"); | 
|  | 284 | return -1; | 
|  | 285 | } | 
|  | 286 |  | 
|  | 287 | #ifdef CONFIG_IEEE80211R | 
|  | 288 | if (wpa_key_mgmt_ft(sm->key_mgmt)) { | 
|  | 289 | int res; | 
|  | 290 |  | 
|  | 291 | /* | 
|  | 292 | * Add PMKR1Name into RSN IE (PMKID-List) and add MDIE and | 
|  | 293 | * FTIE from (Re)Association Response. | 
|  | 294 | */ | 
|  | 295 | rsn_ie_buf = os_malloc(wpa_ie_len + 2 + 2 + PMKID_LEN + | 
|  | 296 | sm->assoc_resp_ies_len); | 
|  | 297 | if (rsn_ie_buf == NULL) | 
|  | 298 | return -1; | 
|  | 299 | os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len); | 
|  | 300 | res = wpa_insert_pmkid(rsn_ie_buf, wpa_ie_len, | 
|  | 301 | sm->pmk_r1_name); | 
|  | 302 | if (res < 0) { | 
|  | 303 | os_free(rsn_ie_buf); | 
|  | 304 | return -1; | 
|  | 305 | } | 
|  | 306 | wpa_ie_len += res; | 
|  | 307 |  | 
|  | 308 | if (sm->assoc_resp_ies) { | 
|  | 309 | os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies, | 
|  | 310 | sm->assoc_resp_ies_len); | 
|  | 311 | wpa_ie_len += sm->assoc_resp_ies_len; | 
|  | 312 | } | 
|  | 313 |  | 
|  | 314 | wpa_ie = rsn_ie_buf; | 
|  | 315 | } | 
|  | 316 | #endif /* CONFIG_IEEE80211R */ | 
|  | 317 |  | 
|  | 318 | wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len); | 
|  | 319 |  | 
|  | 320 | rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, | 
|  | 321 | NULL, sizeof(*reply) + wpa_ie_len, | 
|  | 322 | &rlen, (void *) &reply); | 
|  | 323 | if (rbuf == NULL) { | 
|  | 324 | os_free(rsn_ie_buf); | 
|  | 325 | return -1; | 
|  | 326 | } | 
|  | 327 |  | 
|  | 328 | reply->type = sm->proto == WPA_PROTO_RSN ? | 
|  | 329 | EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; | 
|  | 330 | WPA_PUT_BE16(reply->key_info, | 
|  | 331 | ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC); | 
|  | 332 | if (sm->proto == WPA_PROTO_RSN) | 
|  | 333 | WPA_PUT_BE16(reply->key_length, 0); | 
|  | 334 | else | 
|  | 335 | os_memcpy(reply->key_length, key->key_length, 2); | 
|  | 336 | os_memcpy(reply->replay_counter, key->replay_counter, | 
|  | 337 | WPA_REPLAY_COUNTER_LEN); | 
|  | 338 | wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter, | 
|  | 339 | WPA_REPLAY_COUNTER_LEN); | 
|  | 340 |  | 
|  | 341 | WPA_PUT_BE16(reply->key_data_length, wpa_ie_len); | 
|  | 342 | os_memcpy(reply + 1, wpa_ie, wpa_ie_len); | 
|  | 343 | os_free(rsn_ie_buf); | 
|  | 344 |  | 
|  | 345 | os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); | 
|  | 346 |  | 
|  | 347 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4"); | 
|  | 348 | wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL, | 
|  | 349 | rbuf, rlen, reply->key_mic); | 
|  | 350 |  | 
|  | 351 | return 0; | 
|  | 352 | } | 
|  | 353 |  | 
|  | 354 |  | 
|  | 355 | static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, | 
|  | 356 | const struct wpa_eapol_key *key, | 
|  | 357 | struct wpa_ptk *ptk) | 
|  | 358 | { | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 359 | size_t ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 360 | #ifdef CONFIG_IEEE80211R | 
|  | 361 | if (wpa_key_mgmt_ft(sm->key_mgmt)) | 
|  | 362 | return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len); | 
|  | 363 | #endif /* CONFIG_IEEE80211R */ | 
|  | 364 |  | 
|  | 365 | wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion", | 
|  | 366 | sm->own_addr, sm->bssid, sm->snonce, key->key_nonce, | 
|  | 367 | (u8 *) ptk, ptk_len, | 
|  | 368 | wpa_key_mgmt_sha256(sm->key_mgmt)); | 
|  | 369 | return 0; | 
|  | 370 | } | 
|  | 371 |  | 
|  | 372 |  | 
|  | 373 | static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, | 
|  | 374 | const unsigned char *src_addr, | 
|  | 375 | const struct wpa_eapol_key *key, | 
|  | 376 | u16 ver) | 
|  | 377 | { | 
|  | 378 | struct wpa_eapol_ie_parse ie; | 
|  | 379 | struct wpa_ptk *ptk; | 
|  | 380 | u8 buf[8]; | 
|  | 381 | int res; | 
|  | 382 |  | 
|  | 383 | if (wpa_sm_get_network_ctx(sm) == NULL) { | 
|  | 384 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info " | 
|  | 385 | "found (msg 1 of 4)"); | 
|  | 386 | return; | 
|  | 387 | } | 
|  | 388 |  | 
|  | 389 | wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); | 
|  | 390 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of 4-Way " | 
|  | 391 | "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver); | 
|  | 392 |  | 
|  | 393 | os_memset(&ie, 0, sizeof(ie)); | 
|  | 394 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 395 | if (sm->proto == WPA_PROTO_RSN) { | 
|  | 396 | /* RSN: msg 1/4 should contain PMKID for the selected PMK */ | 
|  | 397 | const u8 *_buf = (const u8 *) (key + 1); | 
|  | 398 | size_t len = WPA_GET_BE16(key->key_data_length); | 
|  | 399 | wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 400 | if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0) | 
|  | 401 | goto failed; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 402 | if (ie.pmkid) { | 
|  | 403 | wpa_hexdump(MSG_DEBUG, "RSN: PMKID from " | 
|  | 404 | "Authenticator", ie.pmkid, PMKID_LEN); | 
|  | 405 | } | 
|  | 406 | } | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 407 |  | 
|  | 408 | res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid); | 
|  | 409 | if (res == -2) { | 
|  | 410 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Do not reply to " | 
|  | 411 | "msg 1/4 - requesting full EAP authentication"); | 
|  | 412 | return; | 
|  | 413 | } | 
|  | 414 | if (res) | 
|  | 415 | goto failed; | 
|  | 416 |  | 
|  | 417 | if (sm->renew_snonce) { | 
|  | 418 | if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) { | 
|  | 419 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 420 | "WPA: Failed to get random data for SNonce"); | 
|  | 421 | goto failed; | 
|  | 422 | } | 
|  | 423 | sm->renew_snonce = 0; | 
|  | 424 | wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce", | 
|  | 425 | sm->snonce, WPA_NONCE_LEN); | 
|  | 426 | } | 
|  | 427 |  | 
|  | 428 | /* Calculate PTK which will be stored as a temporary PTK until it has | 
|  | 429 | * been verified when processing message 3/4. */ | 
|  | 430 | ptk = &sm->tptk; | 
|  | 431 | wpa_derive_ptk(sm, src_addr, key, ptk); | 
|  | 432 | /* Supplicant: swap tx/rx Mic keys */ | 
|  | 433 | os_memcpy(buf, ptk->u.auth.tx_mic_key, 8); | 
|  | 434 | os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8); | 
|  | 435 | os_memcpy(ptk->u.auth.rx_mic_key, buf, 8); | 
|  | 436 | sm->tptk_set = 1; | 
|  | 437 |  | 
|  | 438 | if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce, | 
|  | 439 | sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, | 
|  | 440 | ptk)) | 
|  | 441 | goto failed; | 
|  | 442 |  | 
|  | 443 | os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN); | 
|  | 444 | return; | 
|  | 445 |  | 
|  | 446 | failed: | 
|  | 447 | wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); | 
|  | 448 | } | 
|  | 449 |  | 
|  | 450 |  | 
|  | 451 | static void wpa_sm_start_preauth(void *eloop_ctx, void *timeout_ctx) | 
|  | 452 | { | 
|  | 453 | struct wpa_sm *sm = eloop_ctx; | 
|  | 454 | rsn_preauth_candidate_process(sm); | 
|  | 455 | } | 
|  | 456 |  | 
|  | 457 |  | 
|  | 458 | static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm, | 
|  | 459 | const u8 *addr, int secure) | 
|  | 460 | { | 
|  | 461 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 462 | "WPA: Key negotiation completed with " | 
|  | 463 | MACSTR " [PTK=%s GTK=%s]", MAC2STR(addr), | 
|  | 464 | wpa_cipher_txt(sm->pairwise_cipher), | 
|  | 465 | wpa_cipher_txt(sm->group_cipher)); | 
|  | 466 | wpa_sm_cancel_auth_timeout(sm); | 
|  | 467 | wpa_sm_set_state(sm, WPA_COMPLETED); | 
|  | 468 |  | 
|  | 469 | if (secure) { | 
|  | 470 | wpa_sm_mlme_setprotection( | 
|  | 471 | sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX, | 
|  | 472 | MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); | 
|  | 473 | eapol_sm_notify_portValid(sm->eapol, TRUE); | 
|  | 474 | if (wpa_key_mgmt_wpa_psk(sm->key_mgmt)) | 
|  | 475 | eapol_sm_notify_eap_success(sm->eapol, TRUE); | 
|  | 476 | /* | 
|  | 477 | * Start preauthentication after a short wait to avoid a | 
|  | 478 | * possible race condition between the data receive and key | 
|  | 479 | * configuration after the 4-Way Handshake. This increases the | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 480 | * likelihood of the first preauth EAPOL-Start frame getting to | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 481 | * the target AP. | 
|  | 482 | */ | 
|  | 483 | eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL); | 
|  | 484 | } | 
|  | 485 |  | 
|  | 486 | if (sm->cur_pmksa && sm->cur_pmksa->opportunistic) { | 
|  | 487 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 488 | "RSN: Authenticator accepted " | 
|  | 489 | "opportunistic PMKSA entry - marking it valid"); | 
|  | 490 | sm->cur_pmksa->opportunistic = 0; | 
|  | 491 | } | 
|  | 492 |  | 
|  | 493 | #ifdef CONFIG_IEEE80211R | 
|  | 494 | if (wpa_key_mgmt_ft(sm->key_mgmt)) { | 
|  | 495 | /* Prepare for the next transition */ | 
|  | 496 | wpa_ft_prepare_auth_request(sm, NULL); | 
|  | 497 | } | 
|  | 498 | #endif /* CONFIG_IEEE80211R */ | 
|  | 499 | } | 
|  | 500 |  | 
|  | 501 |  | 
|  | 502 | static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx) | 
|  | 503 | { | 
|  | 504 | struct wpa_sm *sm = eloop_ctx; | 
|  | 505 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Request PTK rekeying"); | 
|  | 506 | wpa_sm_key_request(sm, 0, 1); | 
|  | 507 | } | 
|  | 508 |  | 
|  | 509 |  | 
|  | 510 | static int wpa_supplicant_install_ptk(struct wpa_sm *sm, | 
|  | 511 | const struct wpa_eapol_key *key) | 
|  | 512 | { | 
|  | 513 | int keylen, rsclen; | 
|  | 514 | enum wpa_alg alg; | 
|  | 515 | const u8 *key_rsc; | 
|  | 516 | u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 
|  | 517 |  | 
|  | 518 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 519 | "WPA: Installing PTK to the driver"); | 
|  | 520 |  | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 521 | if (sm->pairwise_cipher == WPA_CIPHER_NONE) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 522 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Pairwise Cipher " | 
|  | 523 | "Suite: NONE - do not use pairwise keys"); | 
|  | 524 | return 0; | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 525 | } | 
|  | 526 |  | 
|  | 527 | if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 528 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 529 | "WPA: Unsupported pairwise cipher %d", | 
|  | 530 | sm->pairwise_cipher); | 
|  | 531 | return -1; | 
|  | 532 | } | 
|  | 533 |  | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 534 | alg = wpa_cipher_to_alg(sm->pairwise_cipher); | 
|  | 535 | keylen = wpa_cipher_key_len(sm->pairwise_cipher); | 
|  | 536 | rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher); | 
|  | 537 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 538 | if (sm->proto == WPA_PROTO_RSN) { | 
|  | 539 | key_rsc = null_rsc; | 
|  | 540 | } else { | 
|  | 541 | key_rsc = key->key_rsc; | 
|  | 542 | wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen); | 
|  | 543 | } | 
|  | 544 |  | 
|  | 545 | if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen, | 
|  | 546 | (u8 *) sm->ptk.tk1, keylen) < 0) { | 
|  | 547 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 548 | "WPA: Failed to set PTK to the " | 
|  | 549 | "driver (alg=%d keylen=%d bssid=" MACSTR ")", | 
|  | 550 | alg, keylen, MAC2STR(sm->bssid)); | 
|  | 551 | return -1; | 
|  | 552 | } | 
|  | 553 |  | 
|  | 554 | if (sm->wpa_ptk_rekey) { | 
|  | 555 | eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); | 
|  | 556 | eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk, | 
|  | 557 | sm, NULL); | 
|  | 558 | } | 
|  | 559 |  | 
|  | 560 | return 0; | 
|  | 561 | } | 
|  | 562 |  | 
|  | 563 |  | 
|  | 564 | static int wpa_supplicant_check_group_cipher(struct wpa_sm *sm, | 
|  | 565 | int group_cipher, | 
|  | 566 | int keylen, int maxkeylen, | 
|  | 567 | int *key_rsc_len, | 
|  | 568 | enum wpa_alg *alg) | 
|  | 569 | { | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 570 | int klen; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 571 |  | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 572 | *alg = wpa_cipher_to_alg(group_cipher); | 
|  | 573 | if (*alg == WPA_ALG_NONE) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 574 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 575 | "WPA: Unsupported Group Cipher %d", | 
|  | 576 | group_cipher); | 
|  | 577 | return -1; | 
|  | 578 | } | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 579 | *key_rsc_len = wpa_cipher_rsc_len(group_cipher); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 580 |  | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 581 | klen = wpa_cipher_key_len(group_cipher); | 
|  | 582 | if (keylen != klen || maxkeylen < klen) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 583 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 584 | "WPA: Unsupported %s Group Cipher key length %d (%d)", | 
|  | 585 | wpa_cipher_txt(group_cipher), keylen, maxkeylen); | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 586 | return -1; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 587 | } | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 588 | return 0; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 589 | } | 
|  | 590 |  | 
|  | 591 |  | 
|  | 592 | struct wpa_gtk_data { | 
|  | 593 | enum wpa_alg alg; | 
|  | 594 | int tx, key_rsc_len, keyidx; | 
|  | 595 | u8 gtk[32]; | 
|  | 596 | int gtk_len; | 
|  | 597 | }; | 
|  | 598 |  | 
|  | 599 |  | 
|  | 600 | static int wpa_supplicant_install_gtk(struct wpa_sm *sm, | 
|  | 601 | const struct wpa_gtk_data *gd, | 
|  | 602 | const u8 *key_rsc) | 
|  | 603 | { | 
|  | 604 | const u8 *_gtk = gd->gtk; | 
|  | 605 | u8 gtk_buf[32]; | 
|  | 606 |  | 
|  | 607 | wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len); | 
|  | 608 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 609 | "WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)", | 
|  | 610 | gd->keyidx, gd->tx, gd->gtk_len); | 
|  | 611 | wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, gd->key_rsc_len); | 
|  | 612 | if (sm->group_cipher == WPA_CIPHER_TKIP) { | 
|  | 613 | /* Swap Tx/Rx keys for Michael MIC */ | 
|  | 614 | os_memcpy(gtk_buf, gd->gtk, 16); | 
|  | 615 | os_memcpy(gtk_buf + 16, gd->gtk + 24, 8); | 
|  | 616 | os_memcpy(gtk_buf + 24, gd->gtk + 16, 8); | 
|  | 617 | _gtk = gtk_buf; | 
|  | 618 | } | 
|  | 619 | if (sm->pairwise_cipher == WPA_CIPHER_NONE) { | 
|  | 620 | if (wpa_sm_set_key(sm, gd->alg, NULL, | 
|  | 621 | gd->keyidx, 1, key_rsc, gd->key_rsc_len, | 
|  | 622 | _gtk, gd->gtk_len) < 0) { | 
|  | 623 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 624 | "WPA: Failed to set GTK to the driver " | 
|  | 625 | "(Group only)"); | 
|  | 626 | return -1; | 
|  | 627 | } | 
|  | 628 | } else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr, | 
|  | 629 | gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len, | 
|  | 630 | _gtk, gd->gtk_len) < 0) { | 
|  | 631 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 632 | "WPA: Failed to set GTK to " | 
|  | 633 | "the driver (alg=%d keylen=%d keyidx=%d)", | 
|  | 634 | gd->alg, gd->gtk_len, gd->keyidx); | 
|  | 635 | return -1; | 
|  | 636 | } | 
|  | 637 |  | 
|  | 638 | return 0; | 
|  | 639 | } | 
|  | 640 |  | 
|  | 641 |  | 
|  | 642 | static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm, | 
|  | 643 | int tx) | 
|  | 644 | { | 
|  | 645 | if (tx && sm->pairwise_cipher != WPA_CIPHER_NONE) { | 
|  | 646 | /* Ignore Tx bit for GTK if a pairwise key is used. One AP | 
|  | 647 | * seemed to set this bit (incorrectly, since Tx is only when | 
|  | 648 | * doing Group Key only APs) and without this workaround, the | 
|  | 649 | * data connection does not work because wpa_supplicant | 
|  | 650 | * configured non-zero keyidx to be used for unicast. */ | 
|  | 651 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 652 | "WPA: Tx bit set for GTK, but pairwise " | 
|  | 653 | "keys are used - ignore Tx bit"); | 
|  | 654 | return 0; | 
|  | 655 | } | 
|  | 656 | return tx; | 
|  | 657 | } | 
|  | 658 |  | 
|  | 659 |  | 
|  | 660 | static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, | 
|  | 661 | const struct wpa_eapol_key *key, | 
|  | 662 | const u8 *gtk, size_t gtk_len, | 
|  | 663 | int key_info) | 
|  | 664 | { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 665 | struct wpa_gtk_data gd; | 
|  | 666 |  | 
|  | 667 | /* | 
|  | 668 | * IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x | 
|  | 669 | * GTK KDE format: | 
|  | 670 | * KeyID[bits 0-1], Tx [bit 2], Reserved [bits 3-7] | 
|  | 671 | * Reserved [bits 0-7] | 
|  | 672 | * GTK | 
|  | 673 | */ | 
|  | 674 |  | 
|  | 675 | os_memset(&gd, 0, sizeof(gd)); | 
|  | 676 | wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in pairwise handshake", | 
|  | 677 | gtk, gtk_len); | 
|  | 678 |  | 
|  | 679 | if (gtk_len < 2 || gtk_len - 2 > sizeof(gd.gtk)) | 
|  | 680 | return -1; | 
|  | 681 |  | 
|  | 682 | gd.keyidx = gtk[0] & 0x3; | 
|  | 683 | gd.tx = wpa_supplicant_gtk_tx_bit_workaround(sm, | 
|  | 684 | !!(gtk[0] & BIT(2))); | 
|  | 685 | gtk += 2; | 
|  | 686 | gtk_len -= 2; | 
|  | 687 |  | 
|  | 688 | os_memcpy(gd.gtk, gtk, gtk_len); | 
|  | 689 | gd.gtk_len = gtk_len; | 
|  | 690 |  | 
|  | 691 | if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, | 
|  | 692 | gtk_len, gtk_len, | 
|  | 693 | &gd.key_rsc_len, &gd.alg) || | 
|  | 694 | wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)) { | 
|  | 695 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 696 | "RSN: Failed to install GTK"); | 
|  | 697 | return -1; | 
|  | 698 | } | 
|  | 699 |  | 
|  | 700 | wpa_supplicant_key_neg_complete(sm, sm->bssid, | 
|  | 701 | key_info & WPA_KEY_INFO_SECURE); | 
|  | 702 | return 0; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 703 | } | 
|  | 704 |  | 
|  | 705 |  | 
|  | 706 | static int ieee80211w_set_keys(struct wpa_sm *sm, | 
|  | 707 | struct wpa_eapol_ie_parse *ie) | 
|  | 708 | { | 
|  | 709 | #ifdef CONFIG_IEEE80211W | 
|  | 710 | if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) | 
|  | 711 | return 0; | 
|  | 712 |  | 
|  | 713 | if (ie->igtk) { | 
|  | 714 | const struct wpa_igtk_kde *igtk; | 
|  | 715 | u16 keyidx; | 
|  | 716 | if (ie->igtk_len != sizeof(*igtk)) | 
|  | 717 | return -1; | 
|  | 718 | igtk = (const struct wpa_igtk_kde *) ie->igtk; | 
|  | 719 | keyidx = WPA_GET_LE16(igtk->keyid); | 
|  | 720 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d " | 
|  | 721 | "pn %02x%02x%02x%02x%02x%02x", | 
|  | 722 | keyidx, MAC2STR(igtk->pn)); | 
|  | 723 | wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", | 
|  | 724 | igtk->igtk, WPA_IGTK_LEN); | 
|  | 725 | if (keyidx > 4095) { | 
|  | 726 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 727 | "WPA: Invalid IGTK KeyID %d", keyidx); | 
|  | 728 | return -1; | 
|  | 729 | } | 
|  | 730 | if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, | 
|  | 731 | keyidx, 0, igtk->pn, sizeof(igtk->pn), | 
|  | 732 | igtk->igtk, WPA_IGTK_LEN) < 0) { | 
|  | 733 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 734 | "WPA: Failed to configure IGTK to the driver"); | 
|  | 735 | return -1; | 
|  | 736 | } | 
|  | 737 | } | 
|  | 738 |  | 
|  | 739 | return 0; | 
|  | 740 | #else /* CONFIG_IEEE80211W */ | 
|  | 741 | return 0; | 
|  | 742 | #endif /* CONFIG_IEEE80211W */ | 
|  | 743 | } | 
|  | 744 |  | 
|  | 745 |  | 
|  | 746 | static void wpa_report_ie_mismatch(struct wpa_sm *sm, | 
|  | 747 | const char *reason, const u8 *src_addr, | 
|  | 748 | const u8 *wpa_ie, size_t wpa_ie_len, | 
|  | 749 | const u8 *rsn_ie, size_t rsn_ie_len) | 
|  | 750 | { | 
|  | 751 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: %s (src=" MACSTR ")", | 
|  | 752 | reason, MAC2STR(src_addr)); | 
|  | 753 |  | 
|  | 754 | if (sm->ap_wpa_ie) { | 
|  | 755 | wpa_hexdump(MSG_INFO, "WPA: WPA IE in Beacon/ProbeResp", | 
|  | 756 | sm->ap_wpa_ie, sm->ap_wpa_ie_len); | 
|  | 757 | } | 
|  | 758 | if (wpa_ie) { | 
|  | 759 | if (!sm->ap_wpa_ie) { | 
|  | 760 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 761 | "WPA: No WPA IE in Beacon/ProbeResp"); | 
|  | 762 | } | 
|  | 763 | wpa_hexdump(MSG_INFO, "WPA: WPA IE in 3/4 msg", | 
|  | 764 | wpa_ie, wpa_ie_len); | 
|  | 765 | } | 
|  | 766 |  | 
|  | 767 | if (sm->ap_rsn_ie) { | 
|  | 768 | wpa_hexdump(MSG_INFO, "WPA: RSN IE in Beacon/ProbeResp", | 
|  | 769 | sm->ap_rsn_ie, sm->ap_rsn_ie_len); | 
|  | 770 | } | 
|  | 771 | if (rsn_ie) { | 
|  | 772 | if (!sm->ap_rsn_ie) { | 
|  | 773 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 774 | "WPA: No RSN IE in Beacon/ProbeResp"); | 
|  | 775 | } | 
|  | 776 | wpa_hexdump(MSG_INFO, "WPA: RSN IE in 3/4 msg", | 
|  | 777 | rsn_ie, rsn_ie_len); | 
|  | 778 | } | 
|  | 779 |  | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 780 | wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 781 | } | 
|  | 782 |  | 
|  | 783 |  | 
|  | 784 | #ifdef CONFIG_IEEE80211R | 
|  | 785 |  | 
|  | 786 | static int ft_validate_mdie(struct wpa_sm *sm, | 
|  | 787 | const unsigned char *src_addr, | 
|  | 788 | struct wpa_eapol_ie_parse *ie, | 
|  | 789 | const u8 *assoc_resp_mdie) | 
|  | 790 | { | 
|  | 791 | struct rsn_mdie *mdie; | 
|  | 792 |  | 
|  | 793 | mdie = (struct rsn_mdie *) (ie->mdie + 2); | 
|  | 794 | if (ie->mdie == NULL || ie->mdie_len < 2 + sizeof(*mdie) || | 
|  | 795 | os_memcmp(mdie->mobility_domain, sm->mobility_domain, | 
|  | 796 | MOBILITY_DOMAIN_ID_LEN) != 0) { | 
|  | 797 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE in msg 3/4 did " | 
|  | 798 | "not match with the current mobility domain"); | 
|  | 799 | return -1; | 
|  | 800 | } | 
|  | 801 |  | 
|  | 802 | if (assoc_resp_mdie && | 
|  | 803 | (assoc_resp_mdie[1] != ie->mdie[1] || | 
|  | 804 | os_memcmp(assoc_resp_mdie, ie->mdie, 2 + ie->mdie[1]) != 0)) { | 
|  | 805 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE mismatch"); | 
|  | 806 | wpa_hexdump(MSG_DEBUG, "FT: MDIE in EAPOL-Key msg 3/4", | 
|  | 807 | ie->mdie, 2 + ie->mdie[1]); | 
|  | 808 | wpa_hexdump(MSG_DEBUG, "FT: MDIE in (Re)Association Response", | 
|  | 809 | assoc_resp_mdie, 2 + assoc_resp_mdie[1]); | 
|  | 810 | return -1; | 
|  | 811 | } | 
|  | 812 |  | 
|  | 813 | return 0; | 
|  | 814 | } | 
|  | 815 |  | 
|  | 816 |  | 
|  | 817 | static int ft_validate_ftie(struct wpa_sm *sm, | 
|  | 818 | const unsigned char *src_addr, | 
|  | 819 | struct wpa_eapol_ie_parse *ie, | 
|  | 820 | const u8 *assoc_resp_ftie) | 
|  | 821 | { | 
|  | 822 | if (ie->ftie == NULL) { | 
|  | 823 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 824 | "FT: No FTIE in EAPOL-Key msg 3/4"); | 
|  | 825 | return -1; | 
|  | 826 | } | 
|  | 827 |  | 
|  | 828 | if (assoc_resp_ftie == NULL) | 
|  | 829 | return 0; | 
|  | 830 |  | 
|  | 831 | if (assoc_resp_ftie[1] != ie->ftie[1] || | 
|  | 832 | os_memcmp(assoc_resp_ftie, ie->ftie, 2 + ie->ftie[1]) != 0) { | 
|  | 833 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: FTIE mismatch"); | 
|  | 834 | wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 3/4", | 
|  | 835 | ie->ftie, 2 + ie->ftie[1]); | 
|  | 836 | wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)Association Response", | 
|  | 837 | assoc_resp_ftie, 2 + assoc_resp_ftie[1]); | 
|  | 838 | return -1; | 
|  | 839 | } | 
|  | 840 |  | 
|  | 841 | return 0; | 
|  | 842 | } | 
|  | 843 |  | 
|  | 844 |  | 
|  | 845 | static int ft_validate_rsnie(struct wpa_sm *sm, | 
|  | 846 | const unsigned char *src_addr, | 
|  | 847 | struct wpa_eapol_ie_parse *ie) | 
|  | 848 | { | 
|  | 849 | struct wpa_ie_data rsn; | 
|  | 850 |  | 
|  | 851 | if (!ie->rsn_ie) | 
|  | 852 | return 0; | 
|  | 853 |  | 
|  | 854 | /* | 
|  | 855 | * Verify that PMKR1Name from EAPOL-Key message 3/4 | 
|  | 856 | * matches with the value we derived. | 
|  | 857 | */ | 
|  | 858 | if (wpa_parse_wpa_ie_rsn(ie->rsn_ie, ie->rsn_ie_len, &rsn) < 0 || | 
|  | 859 | rsn.num_pmkid != 1 || rsn.pmkid == NULL) { | 
|  | 860 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: No PMKR1Name in " | 
|  | 861 | "FT 4-way handshake message 3/4"); | 
|  | 862 | return -1; | 
|  | 863 | } | 
|  | 864 |  | 
|  | 865 | if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) { | 
|  | 866 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 867 | "FT: PMKR1Name mismatch in " | 
|  | 868 | "FT 4-way handshake message 3/4"); | 
|  | 869 | wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Authenticator", | 
|  | 870 | rsn.pmkid, WPA_PMK_NAME_LEN); | 
|  | 871 | wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", | 
|  | 872 | sm->pmk_r1_name, WPA_PMK_NAME_LEN); | 
|  | 873 | return -1; | 
|  | 874 | } | 
|  | 875 |  | 
|  | 876 | return 0; | 
|  | 877 | } | 
|  | 878 |  | 
|  | 879 |  | 
|  | 880 | static int wpa_supplicant_validate_ie_ft(struct wpa_sm *sm, | 
|  | 881 | const unsigned char *src_addr, | 
|  | 882 | struct wpa_eapol_ie_parse *ie) | 
|  | 883 | { | 
|  | 884 | const u8 *pos, *end, *mdie = NULL, *ftie = NULL; | 
|  | 885 |  | 
|  | 886 | if (sm->assoc_resp_ies) { | 
|  | 887 | pos = sm->assoc_resp_ies; | 
|  | 888 | end = pos + sm->assoc_resp_ies_len; | 
|  | 889 | while (pos + 2 < end) { | 
|  | 890 | if (pos + 2 + pos[1] > end) | 
|  | 891 | break; | 
|  | 892 | switch (*pos) { | 
|  | 893 | case WLAN_EID_MOBILITY_DOMAIN: | 
|  | 894 | mdie = pos; | 
|  | 895 | break; | 
|  | 896 | case WLAN_EID_FAST_BSS_TRANSITION: | 
|  | 897 | ftie = pos; | 
|  | 898 | break; | 
|  | 899 | } | 
|  | 900 | pos += 2 + pos[1]; | 
|  | 901 | } | 
|  | 902 | } | 
|  | 903 |  | 
|  | 904 | if (ft_validate_mdie(sm, src_addr, ie, mdie) < 0 || | 
|  | 905 | ft_validate_ftie(sm, src_addr, ie, ftie) < 0 || | 
|  | 906 | ft_validate_rsnie(sm, src_addr, ie) < 0) | 
|  | 907 | return -1; | 
|  | 908 |  | 
|  | 909 | return 0; | 
|  | 910 | } | 
|  | 911 |  | 
|  | 912 | #endif /* CONFIG_IEEE80211R */ | 
|  | 913 |  | 
|  | 914 |  | 
|  | 915 | static int wpa_supplicant_validate_ie(struct wpa_sm *sm, | 
|  | 916 | const unsigned char *src_addr, | 
|  | 917 | struct wpa_eapol_ie_parse *ie) | 
|  | 918 | { | 
|  | 919 | if (sm->ap_wpa_ie == NULL && sm->ap_rsn_ie == NULL) { | 
|  | 920 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 921 | "WPA: No WPA/RSN IE for this AP known. " | 
|  | 922 | "Trying to get from scan results"); | 
|  | 923 | if (wpa_sm_get_beacon_ie(sm) < 0) { | 
|  | 924 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 925 | "WPA: Could not find AP from " | 
|  | 926 | "the scan results"); | 
|  | 927 | } else { | 
|  | 928 | wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 929 | "WPA: Found the current AP from " | 
|  | 930 | "updated scan results"); | 
|  | 931 | } | 
|  | 932 | } | 
|  | 933 |  | 
|  | 934 | if (ie->wpa_ie == NULL && ie->rsn_ie == NULL && | 
|  | 935 | (sm->ap_wpa_ie || sm->ap_rsn_ie)) { | 
|  | 936 | wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match " | 
|  | 937 | "with IE in Beacon/ProbeResp (no IE?)", | 
|  | 938 | src_addr, ie->wpa_ie, ie->wpa_ie_len, | 
|  | 939 | ie->rsn_ie, ie->rsn_ie_len); | 
|  | 940 | return -1; | 
|  | 941 | } | 
|  | 942 |  | 
|  | 943 | if ((ie->wpa_ie && sm->ap_wpa_ie && | 
|  | 944 | (ie->wpa_ie_len != sm->ap_wpa_ie_len || | 
|  | 945 | os_memcmp(ie->wpa_ie, sm->ap_wpa_ie, ie->wpa_ie_len) != 0)) || | 
|  | 946 | (ie->rsn_ie && sm->ap_rsn_ie && | 
|  | 947 | wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt), | 
|  | 948 | sm->ap_rsn_ie, sm->ap_rsn_ie_len, | 
|  | 949 | ie->rsn_ie, ie->rsn_ie_len))) { | 
|  | 950 | wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match " | 
|  | 951 | "with IE in Beacon/ProbeResp", | 
|  | 952 | src_addr, ie->wpa_ie, ie->wpa_ie_len, | 
|  | 953 | ie->rsn_ie, ie->rsn_ie_len); | 
|  | 954 | return -1; | 
|  | 955 | } | 
|  | 956 |  | 
|  | 957 | if (sm->proto == WPA_PROTO_WPA && | 
|  | 958 | ie->rsn_ie && sm->ap_rsn_ie == NULL && sm->rsn_enabled) { | 
|  | 959 | wpa_report_ie_mismatch(sm, "Possible downgrade attack " | 
|  | 960 | "detected - RSN was enabled and RSN IE " | 
|  | 961 | "was in msg 3/4, but not in " | 
|  | 962 | "Beacon/ProbeResp", | 
|  | 963 | src_addr, ie->wpa_ie, ie->wpa_ie_len, | 
|  | 964 | ie->rsn_ie, ie->rsn_ie_len); | 
|  | 965 | return -1; | 
|  | 966 | } | 
|  | 967 |  | 
|  | 968 | #ifdef CONFIG_IEEE80211R | 
|  | 969 | if (wpa_key_mgmt_ft(sm->key_mgmt) && | 
|  | 970 | wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0) | 
|  | 971 | return -1; | 
|  | 972 | #endif /* CONFIG_IEEE80211R */ | 
|  | 973 |  | 
|  | 974 | return 0; | 
|  | 975 | } | 
|  | 976 |  | 
|  | 977 |  | 
|  | 978 | /** | 
|  | 979 | * wpa_supplicant_send_4_of_4 - Send message 4 of WPA/RSN 4-Way Handshake | 
|  | 980 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 981 | * @dst: Destination address for the frame | 
|  | 982 | * @key: Pointer to the EAPOL-Key frame header | 
|  | 983 | * @ver: Version bits from EAPOL-Key Key Info | 
|  | 984 | * @key_info: Key Info | 
|  | 985 | * @kde: KDEs to include the EAPOL-Key frame | 
|  | 986 | * @kde_len: Length of KDEs | 
|  | 987 | * @ptk: PTK to use for keyed hash and encryption | 
|  | 988 | * Returns: 0 on success, -1 on failure | 
|  | 989 | */ | 
|  | 990 | int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, | 
|  | 991 | const struct wpa_eapol_key *key, | 
|  | 992 | u16 ver, u16 key_info, | 
|  | 993 | const u8 *kde, size_t kde_len, | 
|  | 994 | struct wpa_ptk *ptk) | 
|  | 995 | { | 
|  | 996 | size_t rlen; | 
|  | 997 | struct wpa_eapol_key *reply; | 
|  | 998 | u8 *rbuf; | 
|  | 999 |  | 
|  | 1000 | if (kde) | 
|  | 1001 | wpa_hexdump(MSG_DEBUG, "WPA: KDE for msg 4/4", kde, kde_len); | 
|  | 1002 |  | 
|  | 1003 | rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, | 
|  | 1004 | sizeof(*reply) + kde_len, | 
|  | 1005 | &rlen, (void *) &reply); | 
|  | 1006 | if (rbuf == NULL) | 
|  | 1007 | return -1; | 
|  | 1008 |  | 
|  | 1009 | reply->type = sm->proto == WPA_PROTO_RSN ? | 
|  | 1010 | EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; | 
|  | 1011 | key_info &= WPA_KEY_INFO_SECURE; | 
|  | 1012 | key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC; | 
|  | 1013 | WPA_PUT_BE16(reply->key_info, key_info); | 
|  | 1014 | if (sm->proto == WPA_PROTO_RSN) | 
|  | 1015 | WPA_PUT_BE16(reply->key_length, 0); | 
|  | 1016 | else | 
|  | 1017 | os_memcpy(reply->key_length, key->key_length, 2); | 
|  | 1018 | os_memcpy(reply->replay_counter, key->replay_counter, | 
|  | 1019 | WPA_REPLAY_COUNTER_LEN); | 
|  | 1020 |  | 
|  | 1021 | WPA_PUT_BE16(reply->key_data_length, kde_len); | 
|  | 1022 | if (kde) | 
|  | 1023 | os_memcpy(reply + 1, kde, kde_len); | 
|  | 1024 |  | 
|  | 1025 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4"); | 
|  | 1026 | wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL, | 
|  | 1027 | rbuf, rlen, reply->key_mic); | 
|  | 1028 |  | 
|  | 1029 | return 0; | 
|  | 1030 | } | 
|  | 1031 |  | 
|  | 1032 |  | 
|  | 1033 | static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, | 
|  | 1034 | const struct wpa_eapol_key *key, | 
|  | 1035 | u16 ver) | 
|  | 1036 | { | 
|  | 1037 | u16 key_info, keylen, len; | 
|  | 1038 | const u8 *pos; | 
|  | 1039 | struct wpa_eapol_ie_parse ie; | 
|  | 1040 |  | 
|  | 1041 | wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); | 
|  | 1042 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 3 of 4-Way " | 
|  | 1043 | "Handshake from " MACSTR " (ver=%d)", MAC2STR(sm->bssid), ver); | 
|  | 1044 |  | 
|  | 1045 | key_info = WPA_GET_BE16(key->key_info); | 
|  | 1046 |  | 
|  | 1047 | pos = (const u8 *) (key + 1); | 
|  | 1048 | len = WPA_GET_BE16(key->key_data_length); | 
|  | 1049 | wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1050 | if (wpa_supplicant_parse_ies(pos, len, &ie) < 0) | 
|  | 1051 | goto failed; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1052 | if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { | 
|  | 1053 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1054 | "WPA: GTK IE in unencrypted key data"); | 
|  | 1055 | goto failed; | 
|  | 1056 | } | 
|  | 1057 | #ifdef CONFIG_IEEE80211W | 
|  | 1058 | if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { | 
|  | 1059 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1060 | "WPA: IGTK KDE in unencrypted key data"); | 
|  | 1061 | goto failed; | 
|  | 1062 | } | 
|  | 1063 |  | 
|  | 1064 | if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) { | 
|  | 1065 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1066 | "WPA: Invalid IGTK KDE length %lu", | 
|  | 1067 | (unsigned long) ie.igtk_len); | 
|  | 1068 | goto failed; | 
|  | 1069 | } | 
|  | 1070 | #endif /* CONFIG_IEEE80211W */ | 
|  | 1071 |  | 
|  | 1072 | if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0) | 
|  | 1073 | goto failed; | 
|  | 1074 |  | 
|  | 1075 | if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) { | 
|  | 1076 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1077 | "WPA: ANonce from message 1 of 4-Way Handshake " | 
|  | 1078 | "differs from 3 of 4-Way Handshake - drop packet (src=" | 
|  | 1079 | MACSTR ")", MAC2STR(sm->bssid)); | 
|  | 1080 | goto failed; | 
|  | 1081 | } | 
|  | 1082 |  | 
|  | 1083 | keylen = WPA_GET_BE16(key->key_length); | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 1084 | if (keylen != wpa_cipher_key_len(sm->pairwise_cipher)) { | 
|  | 1085 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1086 | "WPA: Invalid %s key length %d (src=" MACSTR | 
|  | 1087 | ")", wpa_cipher_txt(sm->pairwise_cipher), keylen, | 
|  | 1088 | MAC2STR(sm->bssid)); | 
|  | 1089 | goto failed; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1090 | } | 
|  | 1091 |  | 
|  | 1092 | if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info, | 
|  | 1093 | NULL, 0, &sm->ptk)) { | 
|  | 1094 | goto failed; | 
|  | 1095 | } | 
|  | 1096 |  | 
|  | 1097 | /* SNonce was successfully used in msg 3/4, so mark it to be renewed | 
|  | 1098 | * for the next 4-Way Handshake. If msg 3 is received again, the old | 
|  | 1099 | * SNonce will still be used to avoid changing PTK. */ | 
|  | 1100 | sm->renew_snonce = 1; | 
|  | 1101 |  | 
|  | 1102 | if (key_info & WPA_KEY_INFO_INSTALL) { | 
|  | 1103 | if (wpa_supplicant_install_ptk(sm, key)) | 
|  | 1104 | goto failed; | 
|  | 1105 | } | 
|  | 1106 |  | 
|  | 1107 | if (key_info & WPA_KEY_INFO_SECURE) { | 
|  | 1108 | wpa_sm_mlme_setprotection( | 
|  | 1109 | sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX, | 
|  | 1110 | MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); | 
|  | 1111 | eapol_sm_notify_portValid(sm->eapol, TRUE); | 
|  | 1112 | } | 
|  | 1113 | wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); | 
|  | 1114 |  | 
|  | 1115 | if (ie.gtk && | 
|  | 1116 | wpa_supplicant_pairwise_gtk(sm, key, | 
|  | 1117 | ie.gtk, ie.gtk_len, key_info) < 0) { | 
|  | 1118 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1119 | "RSN: Failed to configure GTK"); | 
|  | 1120 | goto failed; | 
|  | 1121 | } | 
|  | 1122 |  | 
|  | 1123 | if (ieee80211w_set_keys(sm, &ie) < 0) { | 
|  | 1124 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1125 | "RSN: Failed to configure IGTK"); | 
|  | 1126 | goto failed; | 
|  | 1127 | } | 
|  | 1128 |  | 
| Dmitry Shmidt | cce0666 | 2013-11-04 18:44:24 -0800 | [diff] [blame] | 1129 | if (ie.gtk) | 
|  | 1130 | wpa_sm_set_rekey_offload(sm); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1131 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1132 | return; | 
|  | 1133 |  | 
|  | 1134 | failed: | 
|  | 1135 | wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); | 
|  | 1136 | } | 
|  | 1137 |  | 
|  | 1138 |  | 
|  | 1139 | static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm, | 
|  | 1140 | const u8 *keydata, | 
|  | 1141 | size_t keydatalen, | 
|  | 1142 | u16 key_info, | 
|  | 1143 | struct wpa_gtk_data *gd) | 
|  | 1144 | { | 
|  | 1145 | int maxkeylen; | 
|  | 1146 | struct wpa_eapol_ie_parse ie; | 
|  | 1147 |  | 
|  | 1148 | wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1149 | if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0) | 
|  | 1150 | return -1; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1151 | if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { | 
|  | 1152 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1153 | "WPA: GTK IE in unencrypted key data"); | 
|  | 1154 | return -1; | 
|  | 1155 | } | 
|  | 1156 | if (ie.gtk == NULL) { | 
|  | 1157 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1158 | "WPA: No GTK IE in Group Key msg 1/2"); | 
|  | 1159 | return -1; | 
|  | 1160 | } | 
|  | 1161 | maxkeylen = gd->gtk_len = ie.gtk_len - 2; | 
|  | 1162 |  | 
|  | 1163 | if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, | 
|  | 1164 | gd->gtk_len, maxkeylen, | 
|  | 1165 | &gd->key_rsc_len, &gd->alg)) | 
|  | 1166 | return -1; | 
|  | 1167 |  | 
|  | 1168 | wpa_hexdump(MSG_DEBUG, "RSN: received GTK in group key handshake", | 
|  | 1169 | ie.gtk, ie.gtk_len); | 
|  | 1170 | gd->keyidx = ie.gtk[0] & 0x3; | 
|  | 1171 | gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm, | 
|  | 1172 | !!(ie.gtk[0] & BIT(2))); | 
|  | 1173 | if (ie.gtk_len - 2 > sizeof(gd->gtk)) { | 
|  | 1174 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1175 | "RSN: Too long GTK in GTK IE (len=%lu)", | 
|  | 1176 | (unsigned long) ie.gtk_len - 2); | 
|  | 1177 | return -1; | 
|  | 1178 | } | 
|  | 1179 | os_memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2); | 
|  | 1180 |  | 
|  | 1181 | if (ieee80211w_set_keys(sm, &ie) < 0) | 
|  | 1182 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1183 | "RSN: Failed to configure IGTK"); | 
|  | 1184 |  | 
|  | 1185 | return 0; | 
|  | 1186 | } | 
|  | 1187 |  | 
|  | 1188 |  | 
|  | 1189 | static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, | 
|  | 1190 | const struct wpa_eapol_key *key, | 
|  | 1191 | size_t keydatalen, int key_info, | 
|  | 1192 | size_t extra_len, u16 ver, | 
|  | 1193 | struct wpa_gtk_data *gd) | 
|  | 1194 | { | 
|  | 1195 | size_t maxkeylen; | 
|  | 1196 | u8 ek[32]; | 
|  | 1197 |  | 
|  | 1198 | gd->gtk_len = WPA_GET_BE16(key->key_length); | 
|  | 1199 | maxkeylen = keydatalen; | 
|  | 1200 | if (keydatalen > extra_len) { | 
|  | 1201 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1202 | "WPA: Truncated EAPOL-Key packet: " | 
|  | 1203 | "key_data_length=%lu > extra_len=%lu", | 
|  | 1204 | (unsigned long) keydatalen, (unsigned long) extra_len); | 
|  | 1205 | return -1; | 
|  | 1206 | } | 
|  | 1207 | if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { | 
|  | 1208 | if (maxkeylen < 8) { | 
|  | 1209 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1210 | "WPA: Too short maxkeylen (%lu)", | 
|  | 1211 | (unsigned long) maxkeylen); | 
|  | 1212 | return -1; | 
|  | 1213 | } | 
|  | 1214 | maxkeylen -= 8; | 
|  | 1215 | } | 
|  | 1216 |  | 
|  | 1217 | if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, | 
|  | 1218 | gd->gtk_len, maxkeylen, | 
|  | 1219 | &gd->key_rsc_len, &gd->alg)) | 
|  | 1220 | return -1; | 
|  | 1221 |  | 
|  | 1222 | gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> | 
|  | 1223 | WPA_KEY_INFO_KEY_INDEX_SHIFT; | 
|  | 1224 | if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { | 
|  | 1225 | os_memcpy(ek, key->key_iv, 16); | 
|  | 1226 | os_memcpy(ek + 16, sm->ptk.kek, 16); | 
|  | 1227 | if (keydatalen > sizeof(gd->gtk)) { | 
|  | 1228 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1229 | "WPA: RC4 key data too long (%lu)", | 
|  | 1230 | (unsigned long) keydatalen); | 
|  | 1231 | return -1; | 
|  | 1232 | } | 
|  | 1233 | os_memcpy(gd->gtk, key + 1, keydatalen); | 
|  | 1234 | if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) { | 
|  | 1235 | wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, | 
|  | 1236 | "WPA: RC4 failed"); | 
|  | 1237 | return -1; | 
|  | 1238 | } | 
|  | 1239 | } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { | 
|  | 1240 | if (keydatalen % 8) { | 
|  | 1241 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1242 | "WPA: Unsupported AES-WRAP len %lu", | 
|  | 1243 | (unsigned long) keydatalen); | 
|  | 1244 | return -1; | 
|  | 1245 | } | 
|  | 1246 | if (maxkeylen > sizeof(gd->gtk)) { | 
|  | 1247 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1248 | "WPA: AES-WRAP key data " | 
|  | 1249 | "too long (keydatalen=%lu maxkeylen=%lu)", | 
|  | 1250 | (unsigned long) keydatalen, | 
|  | 1251 | (unsigned long) maxkeylen); | 
|  | 1252 | return -1; | 
|  | 1253 | } | 
|  | 1254 | if (aes_unwrap(sm->ptk.kek, maxkeylen / 8, | 
|  | 1255 | (const u8 *) (key + 1), gd->gtk)) { | 
|  | 1256 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1257 | "WPA: AES unwrap failed - could not decrypt " | 
|  | 1258 | "GTK"); | 
|  | 1259 | return -1; | 
|  | 1260 | } | 
|  | 1261 | } else { | 
|  | 1262 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1263 | "WPA: Unsupported key_info type %d", ver); | 
|  | 1264 | return -1; | 
|  | 1265 | } | 
|  | 1266 | gd->tx = wpa_supplicant_gtk_tx_bit_workaround( | 
|  | 1267 | sm, !!(key_info & WPA_KEY_INFO_TXRX)); | 
|  | 1268 | return 0; | 
|  | 1269 | } | 
|  | 1270 |  | 
|  | 1271 |  | 
|  | 1272 | static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, | 
|  | 1273 | const struct wpa_eapol_key *key, | 
|  | 1274 | int ver, u16 key_info) | 
|  | 1275 | { | 
|  | 1276 | size_t rlen; | 
|  | 1277 | struct wpa_eapol_key *reply; | 
|  | 1278 | u8 *rbuf; | 
|  | 1279 |  | 
|  | 1280 | rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, | 
|  | 1281 | sizeof(*reply), &rlen, (void *) &reply); | 
|  | 1282 | if (rbuf == NULL) | 
|  | 1283 | return -1; | 
|  | 1284 |  | 
|  | 1285 | reply->type = sm->proto == WPA_PROTO_RSN ? | 
|  | 1286 | EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; | 
|  | 1287 | key_info &= WPA_KEY_INFO_KEY_INDEX_MASK; | 
|  | 1288 | key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE; | 
|  | 1289 | WPA_PUT_BE16(reply->key_info, key_info); | 
|  | 1290 | if (sm->proto == WPA_PROTO_RSN) | 
|  | 1291 | WPA_PUT_BE16(reply->key_length, 0); | 
|  | 1292 | else | 
|  | 1293 | os_memcpy(reply->key_length, key->key_length, 2); | 
|  | 1294 | os_memcpy(reply->replay_counter, key->replay_counter, | 
|  | 1295 | WPA_REPLAY_COUNTER_LEN); | 
|  | 1296 |  | 
|  | 1297 | WPA_PUT_BE16(reply->key_data_length, 0); | 
|  | 1298 |  | 
|  | 1299 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2"); | 
|  | 1300 | wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL, | 
|  | 1301 | rbuf, rlen, reply->key_mic); | 
|  | 1302 |  | 
|  | 1303 | return 0; | 
|  | 1304 | } | 
|  | 1305 |  | 
|  | 1306 |  | 
|  | 1307 | static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, | 
|  | 1308 | const unsigned char *src_addr, | 
|  | 1309 | const struct wpa_eapol_key *key, | 
|  | 1310 | int extra_len, u16 ver) | 
|  | 1311 | { | 
|  | 1312 | u16 key_info, keydatalen; | 
|  | 1313 | int rekey, ret; | 
|  | 1314 | struct wpa_gtk_data gd; | 
|  | 1315 |  | 
|  | 1316 | os_memset(&gd, 0, sizeof(gd)); | 
|  | 1317 |  | 
|  | 1318 | rekey = wpa_sm_get_state(sm) == WPA_COMPLETED; | 
|  | 1319 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of Group Key " | 
|  | 1320 | "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver); | 
|  | 1321 |  | 
|  | 1322 | key_info = WPA_GET_BE16(key->key_info); | 
|  | 1323 | keydatalen = WPA_GET_BE16(key->key_data_length); | 
|  | 1324 |  | 
|  | 1325 | if (sm->proto == WPA_PROTO_RSN) { | 
|  | 1326 | ret = wpa_supplicant_process_1_of_2_rsn(sm, | 
|  | 1327 | (const u8 *) (key + 1), | 
|  | 1328 | keydatalen, key_info, | 
|  | 1329 | &gd); | 
|  | 1330 | } else { | 
|  | 1331 | ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen, | 
|  | 1332 | key_info, extra_len, | 
|  | 1333 | ver, &gd); | 
|  | 1334 | } | 
|  | 1335 |  | 
|  | 1336 | wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); | 
|  | 1337 |  | 
|  | 1338 | if (ret) | 
|  | 1339 | goto failed; | 
|  | 1340 |  | 
|  | 1341 | if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) || | 
|  | 1342 | wpa_supplicant_send_2_of_2(sm, key, ver, key_info)) | 
|  | 1343 | goto failed; | 
|  | 1344 |  | 
|  | 1345 | if (rekey) { | 
|  | 1346 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying " | 
|  | 1347 | "completed with " MACSTR " [GTK=%s]", | 
|  | 1348 | MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher)); | 
|  | 1349 | wpa_sm_cancel_auth_timeout(sm); | 
|  | 1350 | wpa_sm_set_state(sm, WPA_COMPLETED); | 
|  | 1351 | } else { | 
|  | 1352 | wpa_supplicant_key_neg_complete(sm, sm->bssid, | 
|  | 1353 | key_info & | 
|  | 1354 | WPA_KEY_INFO_SECURE); | 
|  | 1355 | } | 
| Dmitry Shmidt | cce0666 | 2013-11-04 18:44:24 -0800 | [diff] [blame] | 1356 |  | 
|  | 1357 | wpa_sm_set_rekey_offload(sm); | 
|  | 1358 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1359 | return; | 
|  | 1360 |  | 
|  | 1361 | failed: | 
|  | 1362 | wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); | 
|  | 1363 | } | 
|  | 1364 |  | 
|  | 1365 |  | 
|  | 1366 | static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm, | 
|  | 1367 | struct wpa_eapol_key *key, | 
|  | 1368 | u16 ver, | 
|  | 1369 | const u8 *buf, size_t len) | 
|  | 1370 | { | 
|  | 1371 | u8 mic[16]; | 
|  | 1372 | int ok = 0; | 
|  | 1373 |  | 
|  | 1374 | os_memcpy(mic, key->key_mic, 16); | 
|  | 1375 | if (sm->tptk_set) { | 
|  | 1376 | os_memset(key->key_mic, 0, 16); | 
|  | 1377 | wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len, | 
|  | 1378 | key->key_mic); | 
|  | 1379 | if (os_memcmp(mic, key->key_mic, 16) != 0) { | 
|  | 1380 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1381 | "WPA: Invalid EAPOL-Key MIC " | 
|  | 1382 | "when using TPTK - ignoring TPTK"); | 
|  | 1383 | } else { | 
|  | 1384 | ok = 1; | 
|  | 1385 | sm->tptk_set = 0; | 
|  | 1386 | sm->ptk_set = 1; | 
|  | 1387 | os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk)); | 
|  | 1388 | } | 
|  | 1389 | } | 
|  | 1390 |  | 
|  | 1391 | if (!ok && sm->ptk_set) { | 
|  | 1392 | os_memset(key->key_mic, 0, 16); | 
|  | 1393 | wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len, | 
|  | 1394 | key->key_mic); | 
|  | 1395 | if (os_memcmp(mic, key->key_mic, 16) != 0) { | 
|  | 1396 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1397 | "WPA: Invalid EAPOL-Key MIC - " | 
|  | 1398 | "dropping packet"); | 
|  | 1399 | return -1; | 
|  | 1400 | } | 
|  | 1401 | ok = 1; | 
|  | 1402 | } | 
|  | 1403 |  | 
|  | 1404 | if (!ok) { | 
|  | 1405 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1406 | "WPA: Could not verify EAPOL-Key MIC - " | 
|  | 1407 | "dropping packet"); | 
|  | 1408 | return -1; | 
|  | 1409 | } | 
|  | 1410 |  | 
|  | 1411 | os_memcpy(sm->rx_replay_counter, key->replay_counter, | 
|  | 1412 | WPA_REPLAY_COUNTER_LEN); | 
|  | 1413 | sm->rx_replay_counter_set = 1; | 
|  | 1414 | return 0; | 
|  | 1415 | } | 
|  | 1416 |  | 
|  | 1417 |  | 
|  | 1418 | /* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */ | 
|  | 1419 | static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, | 
|  | 1420 | struct wpa_eapol_key *key, u16 ver) | 
|  | 1421 | { | 
|  | 1422 | u16 keydatalen = WPA_GET_BE16(key->key_data_length); | 
|  | 1423 |  | 
|  | 1424 | wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data", | 
|  | 1425 | (u8 *) (key + 1), keydatalen); | 
|  | 1426 | if (!sm->ptk_set) { | 
|  | 1427 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1428 | "WPA: PTK not available, cannot decrypt EAPOL-Key Key " | 
|  | 1429 | "Data"); | 
|  | 1430 | return -1; | 
|  | 1431 | } | 
|  | 1432 |  | 
|  | 1433 | /* Decrypt key data here so that this operation does not need | 
|  | 1434 | * to be implemented separately for each message type. */ | 
|  | 1435 | if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { | 
|  | 1436 | u8 ek[32]; | 
|  | 1437 | os_memcpy(ek, key->key_iv, 16); | 
|  | 1438 | os_memcpy(ek + 16, sm->ptk.kek, 16); | 
|  | 1439 | if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) { | 
|  | 1440 | wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, | 
|  | 1441 | "WPA: RC4 failed"); | 
|  | 1442 | return -1; | 
|  | 1443 | } | 
|  | 1444 | } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || | 
|  | 1445 | ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) { | 
|  | 1446 | u8 *buf; | 
|  | 1447 | if (keydatalen % 8) { | 
|  | 1448 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1449 | "WPA: Unsupported AES-WRAP len %d", | 
|  | 1450 | keydatalen); | 
|  | 1451 | return -1; | 
|  | 1452 | } | 
|  | 1453 | keydatalen -= 8; /* AES-WRAP adds 8 bytes */ | 
|  | 1454 | buf = os_malloc(keydatalen); | 
|  | 1455 | if (buf == NULL) { | 
|  | 1456 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1457 | "WPA: No memory for AES-UNWRAP buffer"); | 
|  | 1458 | return -1; | 
|  | 1459 | } | 
|  | 1460 | if (aes_unwrap(sm->ptk.kek, keydatalen / 8, | 
|  | 1461 | (u8 *) (key + 1), buf)) { | 
|  | 1462 | os_free(buf); | 
|  | 1463 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1464 | "WPA: AES unwrap failed - " | 
|  | 1465 | "could not decrypt EAPOL-Key key data"); | 
|  | 1466 | return -1; | 
|  | 1467 | } | 
|  | 1468 | os_memcpy(key + 1, buf, keydatalen); | 
|  | 1469 | os_free(buf); | 
|  | 1470 | WPA_PUT_BE16(key->key_data_length, keydatalen); | 
|  | 1471 | } else { | 
|  | 1472 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1473 | "WPA: Unsupported key_info type %d", ver); | 
|  | 1474 | return -1; | 
|  | 1475 | } | 
|  | 1476 | wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data", | 
|  | 1477 | (u8 *) (key + 1), keydatalen); | 
|  | 1478 | return 0; | 
|  | 1479 | } | 
|  | 1480 |  | 
|  | 1481 |  | 
|  | 1482 | /** | 
|  | 1483 | * wpa_sm_aborted_cached - Notify WPA that PMKSA caching was aborted | 
|  | 1484 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 1485 | */ | 
|  | 1486 | void wpa_sm_aborted_cached(struct wpa_sm *sm) | 
|  | 1487 | { | 
|  | 1488 | if (sm && sm->cur_pmksa) { | 
|  | 1489 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 1490 | "RSN: Cancelling PMKSA caching attempt"); | 
|  | 1491 | sm->cur_pmksa = NULL; | 
|  | 1492 | } | 
|  | 1493 | } | 
|  | 1494 |  | 
|  | 1495 |  | 
|  | 1496 | static void wpa_eapol_key_dump(struct wpa_sm *sm, | 
|  | 1497 | const struct wpa_eapol_key *key) | 
|  | 1498 | { | 
|  | 1499 | #ifndef CONFIG_NO_STDOUT_DEBUG | 
|  | 1500 | u16 key_info = WPA_GET_BE16(key->key_info); | 
|  | 1501 |  | 
|  | 1502 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "  EAPOL-Key type=%d", key->type); | 
|  | 1503 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 1504 | "  key_info 0x%x (ver=%d keyidx=%d rsvd=%d %s%s%s%s%s%s%s%s)", | 
|  | 1505 | key_info, key_info & WPA_KEY_INFO_TYPE_MASK, | 
|  | 1506 | (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> | 
|  | 1507 | WPA_KEY_INFO_KEY_INDEX_SHIFT, | 
|  | 1508 | (key_info & (BIT(13) | BIT(14) | BIT(15))) >> 13, | 
|  | 1509 | key_info & WPA_KEY_INFO_KEY_TYPE ? "Pairwise" : "Group", | 
|  | 1510 | key_info & WPA_KEY_INFO_INSTALL ? " Install" : "", | 
|  | 1511 | key_info & WPA_KEY_INFO_ACK ? " Ack" : "", | 
|  | 1512 | key_info & WPA_KEY_INFO_MIC ? " MIC" : "", | 
|  | 1513 | key_info & WPA_KEY_INFO_SECURE ? " Secure" : "", | 
|  | 1514 | key_info & WPA_KEY_INFO_ERROR ? " Error" : "", | 
|  | 1515 | key_info & WPA_KEY_INFO_REQUEST ? " Request" : "", | 
|  | 1516 | key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : ""); | 
|  | 1517 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 1518 | "  key_length=%u key_data_length=%u", | 
|  | 1519 | WPA_GET_BE16(key->key_length), | 
|  | 1520 | WPA_GET_BE16(key->key_data_length)); | 
|  | 1521 | wpa_hexdump(MSG_DEBUG, "  replay_counter", | 
|  | 1522 | key->replay_counter, WPA_REPLAY_COUNTER_LEN); | 
|  | 1523 | wpa_hexdump(MSG_DEBUG, "  key_nonce", key->key_nonce, WPA_NONCE_LEN); | 
|  | 1524 | wpa_hexdump(MSG_DEBUG, "  key_iv", key->key_iv, 16); | 
|  | 1525 | wpa_hexdump(MSG_DEBUG, "  key_rsc", key->key_rsc, 8); | 
|  | 1526 | wpa_hexdump(MSG_DEBUG, "  key_id (reserved)", key->key_id, 8); | 
|  | 1527 | wpa_hexdump(MSG_DEBUG, "  key_mic", key->key_mic, 16); | 
|  | 1528 | #endif /* CONFIG_NO_STDOUT_DEBUG */ | 
|  | 1529 | } | 
|  | 1530 |  | 
|  | 1531 |  | 
|  | 1532 | /** | 
|  | 1533 | * wpa_sm_rx_eapol - Process received WPA EAPOL frames | 
|  | 1534 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 1535 | * @src_addr: Source MAC address of the EAPOL packet | 
|  | 1536 | * @buf: Pointer to the beginning of the EAPOL data (EAPOL header) | 
|  | 1537 | * @len: Length of the EAPOL frame | 
|  | 1538 | * Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure | 
|  | 1539 | * | 
|  | 1540 | * This function is called for each received EAPOL frame. Other than EAPOL-Key | 
|  | 1541 | * frames can be skipped if filtering is done elsewhere. wpa_sm_rx_eapol() is | 
|  | 1542 | * only processing WPA and WPA2 EAPOL-Key frames. | 
|  | 1543 | * | 
|  | 1544 | * The received EAPOL-Key packets are validated and valid packets are replied | 
|  | 1545 | * to. In addition, key material (PTK, GTK) is configured at the end of a | 
|  | 1546 | * successful key handshake. | 
|  | 1547 | */ | 
|  | 1548 | int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, | 
|  | 1549 | const u8 *buf, size_t len) | 
|  | 1550 | { | 
|  | 1551 | size_t plen, data_len, extra_len; | 
|  | 1552 | struct ieee802_1x_hdr *hdr; | 
|  | 1553 | struct wpa_eapol_key *key; | 
|  | 1554 | u16 key_info, ver; | 
|  | 1555 | u8 *tmp; | 
|  | 1556 | int ret = -1; | 
|  | 1557 | struct wpa_peerkey *peerkey = NULL; | 
|  | 1558 |  | 
|  | 1559 | #ifdef CONFIG_IEEE80211R | 
|  | 1560 | sm->ft_completed = 0; | 
|  | 1561 | #endif /* CONFIG_IEEE80211R */ | 
|  | 1562 |  | 
|  | 1563 | if (len < sizeof(*hdr) + sizeof(*key)) { | 
|  | 1564 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 1565 | "WPA: EAPOL frame too short to be a WPA " | 
|  | 1566 | "EAPOL-Key (len %lu, expecting at least %lu)", | 
|  | 1567 | (unsigned long) len, | 
|  | 1568 | (unsigned long) sizeof(*hdr) + sizeof(*key)); | 
|  | 1569 | return 0; | 
|  | 1570 | } | 
|  | 1571 |  | 
|  | 1572 | tmp = os_malloc(len); | 
|  | 1573 | if (tmp == NULL) | 
|  | 1574 | return -1; | 
|  | 1575 | os_memcpy(tmp, buf, len); | 
|  | 1576 |  | 
|  | 1577 | hdr = (struct ieee802_1x_hdr *) tmp; | 
|  | 1578 | key = (struct wpa_eapol_key *) (hdr + 1); | 
|  | 1579 | plen = be_to_host16(hdr->length); | 
|  | 1580 | data_len = plen + sizeof(*hdr); | 
|  | 1581 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 1582 | "IEEE 802.1X RX: version=%d type=%d length=%lu", | 
|  | 1583 | hdr->version, hdr->type, (unsigned long) plen); | 
|  | 1584 |  | 
|  | 1585 | if (hdr->version < EAPOL_VERSION) { | 
|  | 1586 | /* TODO: backwards compatibility */ | 
|  | 1587 | } | 
|  | 1588 | if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) { | 
|  | 1589 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 1590 | "WPA: EAPOL frame (type %u) discarded, " | 
|  | 1591 | "not a Key frame", hdr->type); | 
|  | 1592 | ret = 0; | 
|  | 1593 | goto out; | 
|  | 1594 | } | 
|  | 1595 | if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) { | 
|  | 1596 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 1597 | "WPA: EAPOL frame payload size %lu " | 
|  | 1598 | "invalid (frame size %lu)", | 
|  | 1599 | (unsigned long) plen, (unsigned long) len); | 
|  | 1600 | ret = 0; | 
|  | 1601 | goto out; | 
|  | 1602 | } | 
|  | 1603 |  | 
|  | 1604 | if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN) | 
|  | 1605 | { | 
|  | 1606 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 1607 | "WPA: EAPOL-Key type (%d) unknown, discarded", | 
|  | 1608 | key->type); | 
|  | 1609 | ret = 0; | 
|  | 1610 | goto out; | 
|  | 1611 | } | 
|  | 1612 | wpa_eapol_key_dump(sm, key); | 
|  | 1613 |  | 
|  | 1614 | eapol_sm_notify_lower_layer_success(sm->eapol, 0); | 
|  | 1615 | wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len); | 
|  | 1616 | if (data_len < len) { | 
|  | 1617 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 1618 | "WPA: ignoring %lu bytes after the IEEE 802.1X data", | 
|  | 1619 | (unsigned long) len - data_len); | 
|  | 1620 | } | 
|  | 1621 | key_info = WPA_GET_BE16(key->key_info); | 
|  | 1622 | ver = key_info & WPA_KEY_INFO_TYPE_MASK; | 
|  | 1623 | if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && | 
|  | 1624 | #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) | 
|  | 1625 | ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && | 
|  | 1626 | #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ | 
|  | 1627 | ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { | 
|  | 1628 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1629 | "WPA: Unsupported EAPOL-Key descriptor version %d", | 
|  | 1630 | ver); | 
|  | 1631 | goto out; | 
|  | 1632 | } | 
|  | 1633 |  | 
|  | 1634 | #ifdef CONFIG_IEEE80211R | 
|  | 1635 | if (wpa_key_mgmt_ft(sm->key_mgmt)) { | 
|  | 1636 | /* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */ | 
|  | 1637 | if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { | 
|  | 1638 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1639 | "FT: AP did not use AES-128-CMAC"); | 
|  | 1640 | goto out; | 
|  | 1641 | } | 
|  | 1642 | } else | 
|  | 1643 | #endif /* CONFIG_IEEE80211R */ | 
|  | 1644 | #ifdef CONFIG_IEEE80211W | 
|  | 1645 | if (wpa_key_mgmt_sha256(sm->key_mgmt)) { | 
|  | 1646 | if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { | 
|  | 1647 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1648 | "WPA: AP did not use the " | 
|  | 1649 | "negotiated AES-128-CMAC"); | 
|  | 1650 | goto out; | 
|  | 1651 | } | 
|  | 1652 | } else | 
|  | 1653 | #endif /* CONFIG_IEEE80211W */ | 
|  | 1654 | if (sm->pairwise_cipher == WPA_CIPHER_CCMP && | 
|  | 1655 | ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { | 
|  | 1656 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1657 | "WPA: CCMP is used, but EAPOL-Key " | 
|  | 1658 | "descriptor version (%d) is not 2", ver); | 
|  | 1659 | if (sm->group_cipher != WPA_CIPHER_CCMP && | 
|  | 1660 | !(key_info & WPA_KEY_INFO_KEY_TYPE)) { | 
|  | 1661 | /* Earlier versions of IEEE 802.11i did not explicitly | 
|  | 1662 | * require version 2 descriptor for all EAPOL-Key | 
|  | 1663 | * packets, so allow group keys to use version 1 if | 
|  | 1664 | * CCMP is not used for them. */ | 
|  | 1665 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1666 | "WPA: Backwards compatibility: allow invalid " | 
|  | 1667 | "version for non-CCMP group keys"); | 
|  | 1668 | } else | 
|  | 1669 | goto out; | 
|  | 1670 | } | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 1671 | if (sm->pairwise_cipher == WPA_CIPHER_GCMP && | 
|  | 1672 | ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { | 
|  | 1673 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1674 | "WPA: GCMP is used, but EAPOL-Key " | 
|  | 1675 | "descriptor version (%d) is not 2", ver); | 
|  | 1676 | goto out; | 
|  | 1677 | } | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1678 |  | 
|  | 1679 | #ifdef CONFIG_PEERKEY | 
|  | 1680 | for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) { | 
|  | 1681 | if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0) | 
|  | 1682 | break; | 
|  | 1683 | } | 
|  | 1684 |  | 
|  | 1685 | if (!(key_info & WPA_KEY_INFO_SMK_MESSAGE) && peerkey) { | 
|  | 1686 | if (!peerkey->initiator && peerkey->replay_counter_set && | 
|  | 1687 | os_memcmp(key->replay_counter, peerkey->replay_counter, | 
|  | 1688 | WPA_REPLAY_COUNTER_LEN) <= 0) { | 
|  | 1689 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1690 | "RSN: EAPOL-Key Replay Counter did not " | 
|  | 1691 | "increase (STK) - dropping packet"); | 
|  | 1692 | goto out; | 
|  | 1693 | } else if (peerkey->initiator) { | 
|  | 1694 | u8 _tmp[WPA_REPLAY_COUNTER_LEN]; | 
|  | 1695 | os_memcpy(_tmp, key->replay_counter, | 
|  | 1696 | WPA_REPLAY_COUNTER_LEN); | 
|  | 1697 | inc_byte_array(_tmp, WPA_REPLAY_COUNTER_LEN); | 
|  | 1698 | if (os_memcmp(_tmp, peerkey->replay_counter, | 
|  | 1699 | WPA_REPLAY_COUNTER_LEN) != 0) { | 
|  | 1700 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 1701 | "RSN: EAPOL-Key Replay " | 
|  | 1702 | "Counter did not match (STK) - " | 
|  | 1703 | "dropping packet"); | 
|  | 1704 | goto out; | 
|  | 1705 | } | 
|  | 1706 | } | 
|  | 1707 | } | 
|  | 1708 |  | 
|  | 1709 | if (peerkey && peerkey->initiator && (key_info & WPA_KEY_INFO_ACK)) { | 
|  | 1710 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1711 | "RSN: Ack bit in key_info from STK peer"); | 
|  | 1712 | goto out; | 
|  | 1713 | } | 
|  | 1714 | #endif /* CONFIG_PEERKEY */ | 
|  | 1715 |  | 
|  | 1716 | if (!peerkey && sm->rx_replay_counter_set && | 
|  | 1717 | os_memcmp(key->replay_counter, sm->rx_replay_counter, | 
|  | 1718 | WPA_REPLAY_COUNTER_LEN) <= 0) { | 
|  | 1719 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1720 | "WPA: EAPOL-Key Replay Counter did not increase - " | 
|  | 1721 | "dropping packet"); | 
|  | 1722 | goto out; | 
|  | 1723 | } | 
|  | 1724 |  | 
|  | 1725 | if (!(key_info & (WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE)) | 
|  | 1726 | #ifdef CONFIG_PEERKEY | 
|  | 1727 | && (peerkey == NULL || !peerkey->initiator) | 
|  | 1728 | #endif /* CONFIG_PEERKEY */ | 
|  | 1729 | ) { | 
|  | 1730 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1731 | "WPA: No Ack bit in key_info"); | 
|  | 1732 | goto out; | 
|  | 1733 | } | 
|  | 1734 |  | 
|  | 1735 | if (key_info & WPA_KEY_INFO_REQUEST) { | 
|  | 1736 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, | 
|  | 1737 | "WPA: EAPOL-Key with Request bit - dropped"); | 
|  | 1738 | goto out; | 
|  | 1739 | } | 
|  | 1740 |  | 
|  | 1741 | if ((key_info & WPA_KEY_INFO_MIC) && !peerkey && | 
|  | 1742 | wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len)) | 
|  | 1743 | goto out; | 
|  | 1744 |  | 
|  | 1745 | #ifdef CONFIG_PEERKEY | 
|  | 1746 | if ((key_info & WPA_KEY_INFO_MIC) && peerkey && | 
|  | 1747 | peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp, data_len)) | 
|  | 1748 | goto out; | 
|  | 1749 | #endif /* CONFIG_PEERKEY */ | 
|  | 1750 |  | 
|  | 1751 | extra_len = data_len - sizeof(*hdr) - sizeof(*key); | 
|  | 1752 |  | 
|  | 1753 | if (WPA_GET_BE16(key->key_data_length) > extra_len) { | 
|  | 1754 | wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key " | 
|  | 1755 | "frame - key_data overflow (%d > %lu)", | 
|  | 1756 | WPA_GET_BE16(key->key_data_length), | 
|  | 1757 | (unsigned long) extra_len); | 
|  | 1758 | goto out; | 
|  | 1759 | } | 
|  | 1760 | extra_len = WPA_GET_BE16(key->key_data_length); | 
|  | 1761 |  | 
|  | 1762 | if (sm->proto == WPA_PROTO_RSN && | 
|  | 1763 | (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { | 
|  | 1764 | if (wpa_supplicant_decrypt_key_data(sm, key, ver)) | 
|  | 1765 | goto out; | 
|  | 1766 | extra_len = WPA_GET_BE16(key->key_data_length); | 
|  | 1767 | } | 
|  | 1768 |  | 
|  | 1769 | if (key_info & WPA_KEY_INFO_KEY_TYPE) { | 
|  | 1770 | if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) { | 
|  | 1771 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1772 | "WPA: Ignored EAPOL-Key (Pairwise) with " | 
|  | 1773 | "non-zero key index"); | 
|  | 1774 | goto out; | 
|  | 1775 | } | 
|  | 1776 | if (peerkey) { | 
|  | 1777 | /* PeerKey 4-Way Handshake */ | 
|  | 1778 | peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver); | 
|  | 1779 | } else if (key_info & WPA_KEY_INFO_MIC) { | 
|  | 1780 | /* 3/4 4-Way Handshake */ | 
|  | 1781 | wpa_supplicant_process_3_of_4(sm, key, ver); | 
|  | 1782 | } else { | 
|  | 1783 | /* 1/4 4-Way Handshake */ | 
|  | 1784 | wpa_supplicant_process_1_of_4(sm, src_addr, key, | 
|  | 1785 | ver); | 
|  | 1786 | } | 
|  | 1787 | } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) { | 
|  | 1788 | /* PeerKey SMK Handshake */ | 
|  | 1789 | peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info, | 
|  | 1790 | ver); | 
|  | 1791 | } else { | 
|  | 1792 | if (key_info & WPA_KEY_INFO_MIC) { | 
|  | 1793 | /* 1/2 Group Key Handshake */ | 
|  | 1794 | wpa_supplicant_process_1_of_2(sm, src_addr, key, | 
|  | 1795 | extra_len, ver); | 
|  | 1796 | } else { | 
|  | 1797 | wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, | 
|  | 1798 | "WPA: EAPOL-Key (Group) without Mic bit - " | 
|  | 1799 | "dropped"); | 
|  | 1800 | } | 
|  | 1801 | } | 
|  | 1802 |  | 
|  | 1803 | ret = 1; | 
|  | 1804 |  | 
|  | 1805 | out: | 
|  | 1806 | os_free(tmp); | 
|  | 1807 | return ret; | 
|  | 1808 | } | 
|  | 1809 |  | 
|  | 1810 |  | 
|  | 1811 | #ifdef CONFIG_CTRL_IFACE | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1812 | static u32 wpa_key_mgmt_suite(struct wpa_sm *sm) | 
|  | 1813 | { | 
|  | 1814 | switch (sm->key_mgmt) { | 
|  | 1815 | case WPA_KEY_MGMT_IEEE8021X: | 
|  | 1816 | return (sm->proto == WPA_PROTO_RSN ? | 
|  | 1817 | RSN_AUTH_KEY_MGMT_UNSPEC_802_1X : | 
|  | 1818 | WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); | 
|  | 1819 | case WPA_KEY_MGMT_PSK: | 
|  | 1820 | return (sm->proto == WPA_PROTO_RSN ? | 
|  | 1821 | RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X : | 
|  | 1822 | WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); | 
|  | 1823 | #ifdef CONFIG_IEEE80211R | 
|  | 1824 | case WPA_KEY_MGMT_FT_IEEE8021X: | 
|  | 1825 | return RSN_AUTH_KEY_MGMT_FT_802_1X; | 
|  | 1826 | case WPA_KEY_MGMT_FT_PSK: | 
|  | 1827 | return RSN_AUTH_KEY_MGMT_FT_PSK; | 
|  | 1828 | #endif /* CONFIG_IEEE80211R */ | 
|  | 1829 | #ifdef CONFIG_IEEE80211W | 
|  | 1830 | case WPA_KEY_MGMT_IEEE8021X_SHA256: | 
|  | 1831 | return RSN_AUTH_KEY_MGMT_802_1X_SHA256; | 
|  | 1832 | case WPA_KEY_MGMT_PSK_SHA256: | 
|  | 1833 | return RSN_AUTH_KEY_MGMT_PSK_SHA256; | 
|  | 1834 | #endif /* CONFIG_IEEE80211W */ | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1835 | case WPA_KEY_MGMT_CCKM: | 
|  | 1836 | return (sm->proto == WPA_PROTO_RSN ? | 
|  | 1837 | RSN_AUTH_KEY_MGMT_CCKM: | 
|  | 1838 | WPA_AUTH_KEY_MGMT_CCKM); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1839 | case WPA_KEY_MGMT_WPA_NONE: | 
|  | 1840 | return WPA_AUTH_KEY_MGMT_NONE; | 
|  | 1841 | default: | 
|  | 1842 | return 0; | 
|  | 1843 | } | 
|  | 1844 | } | 
|  | 1845 |  | 
|  | 1846 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1847 | #define RSN_SUITE "%02x-%02x-%02x-%d" | 
|  | 1848 | #define RSN_SUITE_ARG(s) \ | 
|  | 1849 | ((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff | 
|  | 1850 |  | 
|  | 1851 | /** | 
|  | 1852 | * wpa_sm_get_mib - Dump text list of MIB entries | 
|  | 1853 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 1854 | * @buf: Buffer for the list | 
|  | 1855 | * @buflen: Length of the buffer | 
|  | 1856 | * Returns: Number of bytes written to buffer | 
|  | 1857 | * | 
|  | 1858 | * This function is used fetch dot11 MIB variables. | 
|  | 1859 | */ | 
|  | 1860 | int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen) | 
|  | 1861 | { | 
|  | 1862 | char pmkid_txt[PMKID_LEN * 2 + 1]; | 
|  | 1863 | int rsna, ret; | 
|  | 1864 | size_t len; | 
|  | 1865 |  | 
|  | 1866 | if (sm->cur_pmksa) { | 
|  | 1867 | wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt), | 
|  | 1868 | sm->cur_pmksa->pmkid, PMKID_LEN); | 
|  | 1869 | } else | 
|  | 1870 | pmkid_txt[0] = '\0'; | 
|  | 1871 |  | 
|  | 1872 | if ((wpa_key_mgmt_wpa_psk(sm->key_mgmt) || | 
|  | 1873 | wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) && | 
|  | 1874 | sm->proto == WPA_PROTO_RSN) | 
|  | 1875 | rsna = 1; | 
|  | 1876 | else | 
|  | 1877 | rsna = 0; | 
|  | 1878 |  | 
|  | 1879 | ret = os_snprintf(buf, buflen, | 
|  | 1880 | "dot11RSNAOptionImplemented=TRUE\n" | 
|  | 1881 | "dot11RSNAPreauthenticationImplemented=TRUE\n" | 
|  | 1882 | "dot11RSNAEnabled=%s\n" | 
|  | 1883 | "dot11RSNAPreauthenticationEnabled=%s\n" | 
|  | 1884 | "dot11RSNAConfigVersion=%d\n" | 
|  | 1885 | "dot11RSNAConfigPairwiseKeysSupported=5\n" | 
|  | 1886 | "dot11RSNAConfigGroupCipherSize=%d\n" | 
|  | 1887 | "dot11RSNAConfigPMKLifetime=%d\n" | 
|  | 1888 | "dot11RSNAConfigPMKReauthThreshold=%d\n" | 
|  | 1889 | "dot11RSNAConfigNumberOfPTKSAReplayCounters=1\n" | 
|  | 1890 | "dot11RSNAConfigSATimeout=%d\n", | 
|  | 1891 | rsna ? "TRUE" : "FALSE", | 
|  | 1892 | rsna ? "TRUE" : "FALSE", | 
|  | 1893 | RSN_VERSION, | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 1894 | wpa_cipher_key_len(sm->group_cipher) * 8, | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1895 | sm->dot11RSNAConfigPMKLifetime, | 
|  | 1896 | sm->dot11RSNAConfigPMKReauthThreshold, | 
|  | 1897 | sm->dot11RSNAConfigSATimeout); | 
|  | 1898 | if (ret < 0 || (size_t) ret >= buflen) | 
|  | 1899 | return 0; | 
|  | 1900 | len = ret; | 
|  | 1901 |  | 
|  | 1902 | ret = os_snprintf( | 
|  | 1903 | buf + len, buflen - len, | 
|  | 1904 | "dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n" | 
|  | 1905 | "dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n" | 
|  | 1906 | "dot11RSNAGroupCipherSelected=" RSN_SUITE "\n" | 
|  | 1907 | "dot11RSNAPMKIDUsed=%s\n" | 
|  | 1908 | "dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n" | 
|  | 1909 | "dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n" | 
|  | 1910 | "dot11RSNAGroupCipherRequested=" RSN_SUITE "\n" | 
|  | 1911 | "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n" | 
|  | 1912 | "dot11RSNA4WayHandshakeFailures=%u\n", | 
|  | 1913 | RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)), | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 1914 | RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto, | 
|  | 1915 | sm->pairwise_cipher)), | 
|  | 1916 | RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto, | 
|  | 1917 | sm->group_cipher)), | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1918 | pmkid_txt, | 
|  | 1919 | RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)), | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 1920 | RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto, | 
|  | 1921 | sm->pairwise_cipher)), | 
|  | 1922 | RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto, | 
|  | 1923 | sm->group_cipher)), | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1924 | sm->dot11RSNA4WayHandshakeFailures); | 
|  | 1925 | if (ret >= 0 && (size_t) ret < buflen) | 
|  | 1926 | len += ret; | 
|  | 1927 |  | 
|  | 1928 | return (int) len; | 
|  | 1929 | } | 
|  | 1930 | #endif /* CONFIG_CTRL_IFACE */ | 
|  | 1931 |  | 
|  | 1932 |  | 
|  | 1933 | static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry, | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1934 | void *ctx, enum pmksa_free_reason reason) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1935 | { | 
|  | 1936 | struct wpa_sm *sm = ctx; | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1937 | int deauth = 0; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1938 |  | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1939 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA cache entry free_cb: " | 
|  | 1940 | MACSTR " reason=%d", MAC2STR(entry->aa), reason); | 
|  | 1941 |  | 
|  | 1942 | if (sm->cur_pmksa == entry) { | 
|  | 1943 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 1944 | "RSN: %s current PMKSA entry", | 
|  | 1945 | reason == PMKSA_REPLACE ? "replaced" : "removed"); | 
|  | 1946 | pmksa_cache_clear_current(sm); | 
|  | 1947 |  | 
|  | 1948 | /* | 
|  | 1949 | * If an entry is simply being replaced, there's no need to | 
|  | 1950 | * deauthenticate because it will be immediately re-added. | 
|  | 1951 | * This happens when EAP authentication is completed again | 
|  | 1952 | * (reauth or failed PMKSA caching attempt). | 
|  | 1953 | */ | 
|  | 1954 | if (reason != PMKSA_REPLACE) | 
|  | 1955 | deauth = 1; | 
|  | 1956 | } | 
|  | 1957 |  | 
|  | 1958 | if (reason == PMKSA_EXPIRE && | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1959 | (sm->pmk_len == entry->pmk_len && | 
|  | 1960 | os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) { | 
|  | 1961 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1962 | "RSN: deauthenticating due to expired PMK"); | 
|  | 1963 | pmksa_cache_clear_current(sm); | 
|  | 1964 | deauth = 1; | 
|  | 1965 | } | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1966 |  | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1967 | if (deauth) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1968 | os_memset(sm->pmk, 0, sizeof(sm->pmk)); | 
|  | 1969 | wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); | 
|  | 1970 | } | 
|  | 1971 | } | 
|  | 1972 |  | 
|  | 1973 |  | 
|  | 1974 | /** | 
|  | 1975 | * wpa_sm_init - Initialize WPA state machine | 
|  | 1976 | * @ctx: Context pointer for callbacks; this needs to be an allocated buffer | 
|  | 1977 | * Returns: Pointer to the allocated WPA state machine data | 
|  | 1978 | * | 
|  | 1979 | * This function is used to allocate a new WPA state machine and the returned | 
|  | 1980 | * value is passed to all WPA state machine calls. | 
|  | 1981 | */ | 
|  | 1982 | struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx) | 
|  | 1983 | { | 
|  | 1984 | struct wpa_sm *sm; | 
|  | 1985 |  | 
|  | 1986 | sm = os_zalloc(sizeof(*sm)); | 
|  | 1987 | if (sm == NULL) | 
|  | 1988 | return NULL; | 
|  | 1989 | dl_list_init(&sm->pmksa_candidates); | 
|  | 1990 | sm->renew_snonce = 1; | 
|  | 1991 | sm->ctx = ctx; | 
|  | 1992 |  | 
|  | 1993 | sm->dot11RSNAConfigPMKLifetime = 43200; | 
|  | 1994 | sm->dot11RSNAConfigPMKReauthThreshold = 70; | 
|  | 1995 | sm->dot11RSNAConfigSATimeout = 60; | 
|  | 1996 |  | 
|  | 1997 | sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm); | 
|  | 1998 | if (sm->pmksa == NULL) { | 
|  | 1999 | wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, | 
|  | 2000 | "RSN: PMKSA cache initialization failed"); | 
|  | 2001 | os_free(sm); | 
|  | 2002 | return NULL; | 
|  | 2003 | } | 
|  | 2004 |  | 
|  | 2005 | return sm; | 
|  | 2006 | } | 
|  | 2007 |  | 
|  | 2008 |  | 
|  | 2009 | /** | 
|  | 2010 | * wpa_sm_deinit - Deinitialize WPA state machine | 
|  | 2011 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2012 | */ | 
|  | 2013 | void wpa_sm_deinit(struct wpa_sm *sm) | 
|  | 2014 | { | 
|  | 2015 | if (sm == NULL) | 
|  | 2016 | return; | 
|  | 2017 | pmksa_cache_deinit(sm->pmksa); | 
|  | 2018 | eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL); | 
|  | 2019 | eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); | 
|  | 2020 | os_free(sm->assoc_wpa_ie); | 
|  | 2021 | os_free(sm->ap_wpa_ie); | 
|  | 2022 | os_free(sm->ap_rsn_ie); | 
|  | 2023 | os_free(sm->ctx); | 
|  | 2024 | peerkey_deinit(sm); | 
|  | 2025 | #ifdef CONFIG_IEEE80211R | 
|  | 2026 | os_free(sm->assoc_resp_ies); | 
|  | 2027 | #endif /* CONFIG_IEEE80211R */ | 
|  | 2028 | os_free(sm); | 
|  | 2029 | } | 
|  | 2030 |  | 
|  | 2031 |  | 
|  | 2032 | /** | 
|  | 2033 | * wpa_sm_notify_assoc - Notify WPA state machine about association | 
|  | 2034 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2035 | * @bssid: The BSSID of the new association | 
|  | 2036 | * | 
|  | 2037 | * This function is called to let WPA state machine know that the connection | 
|  | 2038 | * was established. | 
|  | 2039 | */ | 
|  | 2040 | void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) | 
|  | 2041 | { | 
|  | 2042 | int clear_ptk = 1; | 
|  | 2043 |  | 
|  | 2044 | if (sm == NULL) | 
|  | 2045 | return; | 
|  | 2046 |  | 
|  | 2047 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 2048 | "WPA: Association event - clear replay counter"); | 
|  | 2049 | os_memcpy(sm->bssid, bssid, ETH_ALEN); | 
|  | 2050 | os_memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN); | 
|  | 2051 | sm->rx_replay_counter_set = 0; | 
|  | 2052 | sm->renew_snonce = 1; | 
|  | 2053 | if (os_memcmp(sm->preauth_bssid, bssid, ETH_ALEN) == 0) | 
|  | 2054 | rsn_preauth_deinit(sm); | 
|  | 2055 |  | 
|  | 2056 | #ifdef CONFIG_IEEE80211R | 
|  | 2057 | if (wpa_ft_is_completed(sm)) { | 
|  | 2058 | /* | 
|  | 2059 | * Clear portValid to kick EAPOL state machine to re-enter | 
|  | 2060 | * AUTHENTICATED state to get the EAPOL port Authorized. | 
|  | 2061 | */ | 
|  | 2062 | eapol_sm_notify_portValid(sm->eapol, FALSE); | 
|  | 2063 | wpa_supplicant_key_neg_complete(sm, sm->bssid, 1); | 
|  | 2064 |  | 
|  | 2065 | /* Prepare for the next transition */ | 
|  | 2066 | wpa_ft_prepare_auth_request(sm, NULL); | 
|  | 2067 |  | 
|  | 2068 | clear_ptk = 0; | 
|  | 2069 | } | 
|  | 2070 | #endif /* CONFIG_IEEE80211R */ | 
|  | 2071 |  | 
|  | 2072 | if (clear_ptk) { | 
|  | 2073 | /* | 
|  | 2074 | * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if | 
|  | 2075 | * this is not part of a Fast BSS Transition. | 
|  | 2076 | */ | 
|  | 2077 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PTK"); | 
|  | 2078 | sm->ptk_set = 0; | 
|  | 2079 | sm->tptk_set = 0; | 
|  | 2080 | } | 
|  | 2081 |  | 
|  | 2082 | #ifdef CONFIG_TDLS | 
|  | 2083 | wpa_tdls_assoc(sm); | 
|  | 2084 | #endif /* CONFIG_TDLS */ | 
|  | 2085 | } | 
|  | 2086 |  | 
|  | 2087 |  | 
|  | 2088 | /** | 
|  | 2089 | * wpa_sm_notify_disassoc - Notify WPA state machine about disassociation | 
|  | 2090 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2091 | * | 
|  | 2092 | * This function is called to let WPA state machine know that the connection | 
|  | 2093 | * was lost. This will abort any existing pre-authentication session. | 
|  | 2094 | */ | 
|  | 2095 | void wpa_sm_notify_disassoc(struct wpa_sm *sm) | 
|  | 2096 | { | 
|  | 2097 | rsn_preauth_deinit(sm); | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 2098 | pmksa_cache_clear_current(sm); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2099 | if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE) | 
|  | 2100 | sm->dot11RSNA4WayHandshakeFailures++; | 
|  | 2101 | #ifdef CONFIG_TDLS | 
|  | 2102 | wpa_tdls_disassoc(sm); | 
|  | 2103 | #endif /* CONFIG_TDLS */ | 
|  | 2104 | } | 
|  | 2105 |  | 
|  | 2106 |  | 
|  | 2107 | /** | 
|  | 2108 | * wpa_sm_set_pmk - Set PMK | 
|  | 2109 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2110 | * @pmk: The new PMK | 
|  | 2111 | * @pmk_len: The length of the new PMK in bytes | 
|  | 2112 | * | 
|  | 2113 | * Configure the PMK for WPA state machine. | 
|  | 2114 | */ | 
|  | 2115 | void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len) | 
|  | 2116 | { | 
|  | 2117 | if (sm == NULL) | 
|  | 2118 | return; | 
|  | 2119 |  | 
|  | 2120 | sm->pmk_len = pmk_len; | 
|  | 2121 | os_memcpy(sm->pmk, pmk, pmk_len); | 
|  | 2122 |  | 
|  | 2123 | #ifdef CONFIG_IEEE80211R | 
|  | 2124 | /* Set XXKey to be PSK for FT key derivation */ | 
|  | 2125 | sm->xxkey_len = pmk_len; | 
|  | 2126 | os_memcpy(sm->xxkey, pmk, pmk_len); | 
|  | 2127 | #endif /* CONFIG_IEEE80211R */ | 
|  | 2128 | } | 
|  | 2129 |  | 
|  | 2130 |  | 
|  | 2131 | /** | 
|  | 2132 | * wpa_sm_set_pmk_from_pmksa - Set PMK based on the current PMKSA | 
|  | 2133 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2134 | * | 
|  | 2135 | * Take the PMK from the current PMKSA into use. If no PMKSA is active, the PMK | 
|  | 2136 | * will be cleared. | 
|  | 2137 | */ | 
|  | 2138 | void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm) | 
|  | 2139 | { | 
|  | 2140 | if (sm == NULL) | 
|  | 2141 | return; | 
|  | 2142 |  | 
|  | 2143 | if (sm->cur_pmksa) { | 
|  | 2144 | sm->pmk_len = sm->cur_pmksa->pmk_len; | 
|  | 2145 | os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len); | 
|  | 2146 | } else { | 
|  | 2147 | sm->pmk_len = PMK_LEN; | 
|  | 2148 | os_memset(sm->pmk, 0, PMK_LEN); | 
|  | 2149 | } | 
|  | 2150 | } | 
|  | 2151 |  | 
|  | 2152 |  | 
|  | 2153 | /** | 
|  | 2154 | * wpa_sm_set_fast_reauth - Set fast reauthentication (EAP) enabled/disabled | 
|  | 2155 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2156 | * @fast_reauth: Whether fast reauthentication (EAP) is allowed | 
|  | 2157 | */ | 
|  | 2158 | void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth) | 
|  | 2159 | { | 
|  | 2160 | if (sm) | 
|  | 2161 | sm->fast_reauth = fast_reauth; | 
|  | 2162 | } | 
|  | 2163 |  | 
|  | 2164 |  | 
|  | 2165 | /** | 
|  | 2166 | * wpa_sm_set_scard_ctx - Set context pointer for smartcard callbacks | 
|  | 2167 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2168 | * @scard_ctx: Context pointer for smartcard related callback functions | 
|  | 2169 | */ | 
|  | 2170 | void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx) | 
|  | 2171 | { | 
|  | 2172 | if (sm == NULL) | 
|  | 2173 | return; | 
|  | 2174 | sm->scard_ctx = scard_ctx; | 
|  | 2175 | if (sm->preauth_eapol) | 
|  | 2176 | eapol_sm_register_scard_ctx(sm->preauth_eapol, scard_ctx); | 
|  | 2177 | } | 
|  | 2178 |  | 
|  | 2179 |  | 
|  | 2180 | /** | 
|  | 2181 | * wpa_sm_set_config - Notification of current configration change | 
|  | 2182 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2183 | * @config: Pointer to current network configuration | 
|  | 2184 | * | 
|  | 2185 | * Notify WPA state machine that configuration has changed. config will be | 
|  | 2186 | * stored as a backpointer to network configuration. This can be %NULL to clear | 
|  | 2187 | * the stored pointed. | 
|  | 2188 | */ | 
|  | 2189 | void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) | 
|  | 2190 | { | 
|  | 2191 | if (!sm) | 
|  | 2192 | return; | 
|  | 2193 |  | 
|  | 2194 | if (config) { | 
|  | 2195 | sm->network_ctx = config->network_ctx; | 
|  | 2196 | sm->peerkey_enabled = config->peerkey_enabled; | 
|  | 2197 | sm->allowed_pairwise_cipher = config->allowed_pairwise_cipher; | 
|  | 2198 | sm->proactive_key_caching = config->proactive_key_caching; | 
|  | 2199 | sm->eap_workaround = config->eap_workaround; | 
|  | 2200 | sm->eap_conf_ctx = config->eap_conf_ctx; | 
|  | 2201 | if (config->ssid) { | 
|  | 2202 | os_memcpy(sm->ssid, config->ssid, config->ssid_len); | 
|  | 2203 | sm->ssid_len = config->ssid_len; | 
|  | 2204 | } else | 
|  | 2205 | sm->ssid_len = 0; | 
|  | 2206 | sm->wpa_ptk_rekey = config->wpa_ptk_rekey; | 
|  | 2207 | } else { | 
|  | 2208 | sm->network_ctx = NULL; | 
|  | 2209 | sm->peerkey_enabled = 0; | 
|  | 2210 | sm->allowed_pairwise_cipher = 0; | 
|  | 2211 | sm->proactive_key_caching = 0; | 
|  | 2212 | sm->eap_workaround = 0; | 
|  | 2213 | sm->eap_conf_ctx = NULL; | 
|  | 2214 | sm->ssid_len = 0; | 
|  | 2215 | sm->wpa_ptk_rekey = 0; | 
|  | 2216 | } | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2217 | } | 
|  | 2218 |  | 
|  | 2219 |  | 
|  | 2220 | /** | 
|  | 2221 | * wpa_sm_set_own_addr - Set own MAC address | 
|  | 2222 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2223 | * @addr: Own MAC address | 
|  | 2224 | */ | 
|  | 2225 | void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr) | 
|  | 2226 | { | 
|  | 2227 | if (sm) | 
|  | 2228 | os_memcpy(sm->own_addr, addr, ETH_ALEN); | 
|  | 2229 | } | 
|  | 2230 |  | 
|  | 2231 |  | 
|  | 2232 | /** | 
|  | 2233 | * wpa_sm_set_ifname - Set network interface name | 
|  | 2234 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2235 | * @ifname: Interface name | 
|  | 2236 | * @bridge_ifname: Optional bridge interface name (for pre-auth) | 
|  | 2237 | */ | 
|  | 2238 | void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname, | 
|  | 2239 | const char *bridge_ifname) | 
|  | 2240 | { | 
|  | 2241 | if (sm) { | 
|  | 2242 | sm->ifname = ifname; | 
|  | 2243 | sm->bridge_ifname = bridge_ifname; | 
|  | 2244 | } | 
|  | 2245 | } | 
|  | 2246 |  | 
|  | 2247 |  | 
|  | 2248 | /** | 
|  | 2249 | * wpa_sm_set_eapol - Set EAPOL state machine pointer | 
|  | 2250 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2251 | * @eapol: Pointer to EAPOL state machine allocated with eapol_sm_init() | 
|  | 2252 | */ | 
|  | 2253 | void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol) | 
|  | 2254 | { | 
|  | 2255 | if (sm) | 
|  | 2256 | sm->eapol = eapol; | 
|  | 2257 | } | 
|  | 2258 |  | 
|  | 2259 |  | 
|  | 2260 | /** | 
|  | 2261 | * wpa_sm_set_param - Set WPA state machine parameters | 
|  | 2262 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2263 | * @param: Parameter field | 
|  | 2264 | * @value: Parameter value | 
|  | 2265 | * Returns: 0 on success, -1 on failure | 
|  | 2266 | */ | 
|  | 2267 | int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, | 
|  | 2268 | unsigned int value) | 
|  | 2269 | { | 
|  | 2270 | int ret = 0; | 
|  | 2271 |  | 
|  | 2272 | if (sm == NULL) | 
|  | 2273 | return -1; | 
|  | 2274 |  | 
|  | 2275 | switch (param) { | 
|  | 2276 | case RSNA_PMK_LIFETIME: | 
|  | 2277 | if (value > 0) | 
|  | 2278 | sm->dot11RSNAConfigPMKLifetime = value; | 
|  | 2279 | else | 
|  | 2280 | ret = -1; | 
|  | 2281 | break; | 
|  | 2282 | case RSNA_PMK_REAUTH_THRESHOLD: | 
|  | 2283 | if (value > 0 && value <= 100) | 
|  | 2284 | sm->dot11RSNAConfigPMKReauthThreshold = value; | 
|  | 2285 | else | 
|  | 2286 | ret = -1; | 
|  | 2287 | break; | 
|  | 2288 | case RSNA_SA_TIMEOUT: | 
|  | 2289 | if (value > 0) | 
|  | 2290 | sm->dot11RSNAConfigSATimeout = value; | 
|  | 2291 | else | 
|  | 2292 | ret = -1; | 
|  | 2293 | break; | 
|  | 2294 | case WPA_PARAM_PROTO: | 
|  | 2295 | sm->proto = value; | 
|  | 2296 | break; | 
|  | 2297 | case WPA_PARAM_PAIRWISE: | 
|  | 2298 | sm->pairwise_cipher = value; | 
|  | 2299 | break; | 
|  | 2300 | case WPA_PARAM_GROUP: | 
|  | 2301 | sm->group_cipher = value; | 
|  | 2302 | break; | 
|  | 2303 | case WPA_PARAM_KEY_MGMT: | 
|  | 2304 | sm->key_mgmt = value; | 
|  | 2305 | break; | 
|  | 2306 | #ifdef CONFIG_IEEE80211W | 
|  | 2307 | case WPA_PARAM_MGMT_GROUP: | 
|  | 2308 | sm->mgmt_group_cipher = value; | 
|  | 2309 | break; | 
|  | 2310 | #endif /* CONFIG_IEEE80211W */ | 
|  | 2311 | case WPA_PARAM_RSN_ENABLED: | 
|  | 2312 | sm->rsn_enabled = value; | 
|  | 2313 | break; | 
|  | 2314 | case WPA_PARAM_MFP: | 
|  | 2315 | sm->mfp = value; | 
|  | 2316 | break; | 
|  | 2317 | default: | 
|  | 2318 | break; | 
|  | 2319 | } | 
|  | 2320 |  | 
|  | 2321 | return ret; | 
|  | 2322 | } | 
|  | 2323 |  | 
|  | 2324 |  | 
|  | 2325 | /** | 
|  | 2326 | * wpa_sm_get_param - Get WPA state machine parameters | 
|  | 2327 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2328 | * @param: Parameter field | 
|  | 2329 | * Returns: Parameter value | 
|  | 2330 | */ | 
|  | 2331 | unsigned int wpa_sm_get_param(struct wpa_sm *sm, enum wpa_sm_conf_params param) | 
|  | 2332 | { | 
|  | 2333 | if (sm == NULL) | 
|  | 2334 | return 0; | 
|  | 2335 |  | 
|  | 2336 | switch (param) { | 
|  | 2337 | case RSNA_PMK_LIFETIME: | 
|  | 2338 | return sm->dot11RSNAConfigPMKLifetime; | 
|  | 2339 | case RSNA_PMK_REAUTH_THRESHOLD: | 
|  | 2340 | return sm->dot11RSNAConfigPMKReauthThreshold; | 
|  | 2341 | case RSNA_SA_TIMEOUT: | 
|  | 2342 | return sm->dot11RSNAConfigSATimeout; | 
|  | 2343 | case WPA_PARAM_PROTO: | 
|  | 2344 | return sm->proto; | 
|  | 2345 | case WPA_PARAM_PAIRWISE: | 
|  | 2346 | return sm->pairwise_cipher; | 
|  | 2347 | case WPA_PARAM_GROUP: | 
|  | 2348 | return sm->group_cipher; | 
|  | 2349 | case WPA_PARAM_KEY_MGMT: | 
|  | 2350 | return sm->key_mgmt; | 
|  | 2351 | #ifdef CONFIG_IEEE80211W | 
|  | 2352 | case WPA_PARAM_MGMT_GROUP: | 
|  | 2353 | return sm->mgmt_group_cipher; | 
|  | 2354 | #endif /* CONFIG_IEEE80211W */ | 
|  | 2355 | case WPA_PARAM_RSN_ENABLED: | 
|  | 2356 | return sm->rsn_enabled; | 
|  | 2357 | default: | 
|  | 2358 | return 0; | 
|  | 2359 | } | 
|  | 2360 | } | 
|  | 2361 |  | 
|  | 2362 |  | 
|  | 2363 | /** | 
|  | 2364 | * wpa_sm_get_status - Get WPA state machine | 
|  | 2365 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2366 | * @buf: Buffer for status information | 
|  | 2367 | * @buflen: Maximum buffer length | 
|  | 2368 | * @verbose: Whether to include verbose status information | 
|  | 2369 | * Returns: Number of bytes written to buf. | 
|  | 2370 | * | 
|  | 2371 | * Query WPA state machine for status information. This function fills in | 
|  | 2372 | * a text area with current status information. If the buffer (buf) is not | 
|  | 2373 | * large enough, status information will be truncated to fit the buffer. | 
|  | 2374 | */ | 
|  | 2375 | int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen, | 
|  | 2376 | int verbose) | 
|  | 2377 | { | 
|  | 2378 | char *pos = buf, *end = buf + buflen; | 
|  | 2379 | int ret; | 
|  | 2380 |  | 
|  | 2381 | ret = os_snprintf(pos, end - pos, | 
|  | 2382 | "pairwise_cipher=%s\n" | 
|  | 2383 | "group_cipher=%s\n" | 
|  | 2384 | "key_mgmt=%s\n", | 
|  | 2385 | wpa_cipher_txt(sm->pairwise_cipher), | 
|  | 2386 | wpa_cipher_txt(sm->group_cipher), | 
|  | 2387 | wpa_key_mgmt_txt(sm->key_mgmt, sm->proto)); | 
|  | 2388 | if (ret < 0 || ret >= end - pos) | 
|  | 2389 | return pos - buf; | 
|  | 2390 | pos += ret; | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 2391 |  | 
|  | 2392 | if (sm->mfp != NO_MGMT_FRAME_PROTECTION && sm->ap_rsn_ie) { | 
|  | 2393 | struct wpa_ie_data rsn; | 
|  | 2394 | if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn) | 
|  | 2395 | >= 0 && | 
|  | 2396 | rsn.capabilities & (WPA_CAPABILITY_MFPR | | 
|  | 2397 | WPA_CAPABILITY_MFPC)) { | 
|  | 2398 | ret = os_snprintf(pos, end - pos, "pmf=%d\n", | 
|  | 2399 | (rsn.capabilities & | 
|  | 2400 | WPA_CAPABILITY_MFPR) ? 2 : 1); | 
|  | 2401 | if (ret < 0 || ret >= end - pos) | 
|  | 2402 | return pos - buf; | 
|  | 2403 | pos += ret; | 
|  | 2404 | } | 
|  | 2405 | } | 
|  | 2406 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2407 | return pos - buf; | 
|  | 2408 | } | 
|  | 2409 |  | 
|  | 2410 |  | 
| Dmitry Shmidt | f7e0a99 | 2013-05-23 11:03:10 -0700 | [diff] [blame] | 2411 | int wpa_sm_pmf_enabled(struct wpa_sm *sm) | 
|  | 2412 | { | 
|  | 2413 | struct wpa_ie_data rsn; | 
|  | 2414 |  | 
|  | 2415 | if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !sm->ap_rsn_ie) | 
|  | 2416 | return 0; | 
|  | 2417 |  | 
|  | 2418 | if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn) >= 0 && | 
|  | 2419 | rsn.capabilities & (WPA_CAPABILITY_MFPR | WPA_CAPABILITY_MFPC)) | 
|  | 2420 | return 1; | 
|  | 2421 |  | 
|  | 2422 | return 0; | 
|  | 2423 | } | 
|  | 2424 |  | 
|  | 2425 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2426 | /** | 
|  | 2427 | * wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration | 
|  | 2428 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2429 | * @wpa_ie: Pointer to buffer for WPA/RSN IE | 
|  | 2430 | * @wpa_ie_len: Pointer to the length of the wpa_ie buffer | 
|  | 2431 | * Returns: 0 on success, -1 on failure | 
|  | 2432 | */ | 
|  | 2433 | int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie, | 
|  | 2434 | size_t *wpa_ie_len) | 
|  | 2435 | { | 
|  | 2436 | int res; | 
|  | 2437 |  | 
|  | 2438 | if (sm == NULL) | 
|  | 2439 | return -1; | 
|  | 2440 |  | 
|  | 2441 | res = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len); | 
|  | 2442 | if (res < 0) | 
|  | 2443 | return -1; | 
|  | 2444 | *wpa_ie_len = res; | 
|  | 2445 |  | 
|  | 2446 | wpa_hexdump(MSG_DEBUG, "WPA: Set own WPA IE default", | 
|  | 2447 | wpa_ie, *wpa_ie_len); | 
|  | 2448 |  | 
|  | 2449 | if (sm->assoc_wpa_ie == NULL) { | 
|  | 2450 | /* | 
|  | 2451 | * Make a copy of the WPA/RSN IE so that 4-Way Handshake gets | 
|  | 2452 | * the correct version of the IE even if PMKSA caching is | 
|  | 2453 | * aborted (which would remove PMKID from IE generation). | 
|  | 2454 | */ | 
|  | 2455 | sm->assoc_wpa_ie = os_malloc(*wpa_ie_len); | 
|  | 2456 | if (sm->assoc_wpa_ie == NULL) | 
|  | 2457 | return -1; | 
|  | 2458 |  | 
|  | 2459 | os_memcpy(sm->assoc_wpa_ie, wpa_ie, *wpa_ie_len); | 
|  | 2460 | sm->assoc_wpa_ie_len = *wpa_ie_len; | 
|  | 2461 | } | 
|  | 2462 |  | 
|  | 2463 | return 0; | 
|  | 2464 | } | 
|  | 2465 |  | 
|  | 2466 |  | 
|  | 2467 | /** | 
|  | 2468 | * wpa_sm_set_assoc_wpa_ie - Set own WPA/RSN IE from (Re)AssocReq | 
|  | 2469 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2470 | * @ie: Pointer to IE data (starting from id) | 
|  | 2471 | * @len: IE length | 
|  | 2472 | * Returns: 0 on success, -1 on failure | 
|  | 2473 | * | 
|  | 2474 | * Inform WPA state machine about the WPA/RSN IE used in (Re)Association | 
|  | 2475 | * Request frame. The IE will be used to override the default value generated | 
|  | 2476 | * with wpa_sm_set_assoc_wpa_ie_default(). | 
|  | 2477 | */ | 
|  | 2478 | int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len) | 
|  | 2479 | { | 
|  | 2480 | if (sm == NULL) | 
|  | 2481 | return -1; | 
|  | 2482 |  | 
|  | 2483 | os_free(sm->assoc_wpa_ie); | 
|  | 2484 | if (ie == NULL || len == 0) { | 
|  | 2485 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 2486 | "WPA: clearing own WPA/RSN IE"); | 
|  | 2487 | sm->assoc_wpa_ie = NULL; | 
|  | 2488 | sm->assoc_wpa_ie_len = 0; | 
|  | 2489 | } else { | 
|  | 2490 | wpa_hexdump(MSG_DEBUG, "WPA: set own WPA/RSN IE", ie, len); | 
|  | 2491 | sm->assoc_wpa_ie = os_malloc(len); | 
|  | 2492 | if (sm->assoc_wpa_ie == NULL) | 
|  | 2493 | return -1; | 
|  | 2494 |  | 
|  | 2495 | os_memcpy(sm->assoc_wpa_ie, ie, len); | 
|  | 2496 | sm->assoc_wpa_ie_len = len; | 
|  | 2497 | } | 
|  | 2498 |  | 
|  | 2499 | return 0; | 
|  | 2500 | } | 
|  | 2501 |  | 
|  | 2502 |  | 
|  | 2503 | /** | 
|  | 2504 | * wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp | 
|  | 2505 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2506 | * @ie: Pointer to IE data (starting from id) | 
|  | 2507 | * @len: IE length | 
|  | 2508 | * Returns: 0 on success, -1 on failure | 
|  | 2509 | * | 
|  | 2510 | * Inform WPA state machine about the WPA IE used in Beacon / Probe Response | 
|  | 2511 | * frame. | 
|  | 2512 | */ | 
|  | 2513 | int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len) | 
|  | 2514 | { | 
|  | 2515 | if (sm == NULL) | 
|  | 2516 | return -1; | 
|  | 2517 |  | 
|  | 2518 | os_free(sm->ap_wpa_ie); | 
|  | 2519 | if (ie == NULL || len == 0) { | 
|  | 2520 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 2521 | "WPA: clearing AP WPA IE"); | 
|  | 2522 | sm->ap_wpa_ie = NULL; | 
|  | 2523 | sm->ap_wpa_ie_len = 0; | 
|  | 2524 | } else { | 
|  | 2525 | wpa_hexdump(MSG_DEBUG, "WPA: set AP WPA IE", ie, len); | 
|  | 2526 | sm->ap_wpa_ie = os_malloc(len); | 
|  | 2527 | if (sm->ap_wpa_ie == NULL) | 
|  | 2528 | return -1; | 
|  | 2529 |  | 
|  | 2530 | os_memcpy(sm->ap_wpa_ie, ie, len); | 
|  | 2531 | sm->ap_wpa_ie_len = len; | 
|  | 2532 | } | 
|  | 2533 |  | 
|  | 2534 | return 0; | 
|  | 2535 | } | 
|  | 2536 |  | 
|  | 2537 |  | 
|  | 2538 | /** | 
|  | 2539 | * wpa_sm_set_ap_rsn_ie - Set AP RSN IE from Beacon/ProbeResp | 
|  | 2540 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2541 | * @ie: Pointer to IE data (starting from id) | 
|  | 2542 | * @len: IE length | 
|  | 2543 | * Returns: 0 on success, -1 on failure | 
|  | 2544 | * | 
|  | 2545 | * Inform WPA state machine about the RSN IE used in Beacon / Probe Response | 
|  | 2546 | * frame. | 
|  | 2547 | */ | 
|  | 2548 | int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len) | 
|  | 2549 | { | 
|  | 2550 | if (sm == NULL) | 
|  | 2551 | return -1; | 
|  | 2552 |  | 
|  | 2553 | os_free(sm->ap_rsn_ie); | 
|  | 2554 | if (ie == NULL || len == 0) { | 
|  | 2555 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 2556 | "WPA: clearing AP RSN IE"); | 
|  | 2557 | sm->ap_rsn_ie = NULL; | 
|  | 2558 | sm->ap_rsn_ie_len = 0; | 
|  | 2559 | } else { | 
|  | 2560 | wpa_hexdump(MSG_DEBUG, "WPA: set AP RSN IE", ie, len); | 
|  | 2561 | sm->ap_rsn_ie = os_malloc(len); | 
|  | 2562 | if (sm->ap_rsn_ie == NULL) | 
|  | 2563 | return -1; | 
|  | 2564 |  | 
|  | 2565 | os_memcpy(sm->ap_rsn_ie, ie, len); | 
|  | 2566 | sm->ap_rsn_ie_len = len; | 
|  | 2567 | } | 
|  | 2568 |  | 
|  | 2569 | return 0; | 
|  | 2570 | } | 
|  | 2571 |  | 
|  | 2572 |  | 
|  | 2573 | /** | 
|  | 2574 | * wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE | 
|  | 2575 | * @sm: Pointer to WPA state machine data from wpa_sm_init() | 
|  | 2576 | * @data: Pointer to data area for parsing results | 
|  | 2577 | * Returns: 0 on success, -1 if IE is not known, or -2 on parsing failure | 
|  | 2578 | * | 
|  | 2579 | * Parse the contents of the own WPA or RSN IE from (Re)AssocReq and write the | 
|  | 2580 | * parsed data into data. | 
|  | 2581 | */ | 
|  | 2582 | int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data) | 
|  | 2583 | { | 
|  | 2584 | if (sm == NULL) | 
|  | 2585 | return -1; | 
|  | 2586 |  | 
|  | 2587 | if (sm->assoc_wpa_ie == NULL) { | 
|  | 2588 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, | 
|  | 2589 | "WPA: No WPA/RSN IE available from association info"); | 
|  | 2590 | return -1; | 
|  | 2591 | } | 
|  | 2592 | if (wpa_parse_wpa_ie(sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, data)) | 
|  | 2593 | return -2; | 
|  | 2594 | return 0; | 
|  | 2595 | } | 
|  | 2596 |  | 
|  | 2597 |  | 
|  | 2598 | int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len) | 
|  | 2599 | { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2600 | return pmksa_cache_list(sm->pmksa, buf, len); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2601 | } | 
|  | 2602 |  | 
|  | 2603 |  | 
|  | 2604 | void wpa_sm_drop_sa(struct wpa_sm *sm) | 
|  | 2605 | { | 
|  | 2606 | wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK"); | 
|  | 2607 | sm->ptk_set = 0; | 
|  | 2608 | sm->tptk_set = 0; | 
|  | 2609 | os_memset(sm->pmk, 0, sizeof(sm->pmk)); | 
|  | 2610 | os_memset(&sm->ptk, 0, sizeof(sm->ptk)); | 
|  | 2611 | os_memset(&sm->tptk, 0, sizeof(sm->tptk)); | 
|  | 2612 | } | 
|  | 2613 |  | 
|  | 2614 |  | 
|  | 2615 | int wpa_sm_has_ptk(struct wpa_sm *sm) | 
|  | 2616 | { | 
|  | 2617 | if (sm == NULL) | 
|  | 2618 | return 0; | 
|  | 2619 | return sm->ptk_set; | 
|  | 2620 | } | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2621 |  | 
|  | 2622 |  | 
|  | 2623 | void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr) | 
|  | 2624 | { | 
|  | 2625 | os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN); | 
|  | 2626 | } | 
|  | 2627 |  | 
|  | 2628 |  | 
|  | 2629 | void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx) | 
|  | 2630 | { | 
| Dmitry Shmidt | f7e0a99 | 2013-05-23 11:03:10 -0700 | [diff] [blame] | 2631 | pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2632 | } | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 2633 |  | 
|  | 2634 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 2635 | #ifdef CONFIG_WNM | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 2636 | int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) | 
|  | 2637 | { | 
|  | 2638 | struct wpa_gtk_data gd; | 
|  | 2639 | #ifdef CONFIG_IEEE80211W | 
|  | 2640 | struct wpa_igtk_kde igd; | 
|  | 2641 | u16 keyidx; | 
|  | 2642 | #endif /* CONFIG_IEEE80211W */ | 
|  | 2643 | u16 keyinfo; | 
|  | 2644 | u8 keylen;  /* plaintext key len */ | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 2645 | u8 *key_rsc; | 
|  | 2646 |  | 
|  | 2647 | os_memset(&gd, 0, sizeof(gd)); | 
|  | 2648 | #ifdef CONFIG_IEEE80211W | 
|  | 2649 | os_memset(&igd, 0, sizeof(igd)); | 
|  | 2650 | #endif /* CONFIG_IEEE80211W */ | 
|  | 2651 |  | 
| Dmitry Shmidt | 4530cfd | 2012-09-09 15:20:40 -0700 | [diff] [blame] | 2652 | keylen = wpa_cipher_key_len(sm->group_cipher); | 
|  | 2653 | gd.key_rsc_len = wpa_cipher_rsc_len(sm->group_cipher); | 
|  | 2654 | gd.alg = wpa_cipher_to_alg(sm->group_cipher); | 
|  | 2655 | if (gd.alg == WPA_ALG_NONE) { | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 2656 | wpa_printf(MSG_DEBUG, "Unsupported group cipher suite"); | 
|  | 2657 | return -1; | 
|  | 2658 | } | 
|  | 2659 |  | 
|  | 2660 | if (subelem_id == WNM_SLEEP_SUBELEM_GTK) { | 
|  | 2661 | key_rsc = buf + 5; | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 2662 | keyinfo = WPA_GET_LE16(buf + 2); | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 2663 | gd.gtk_len = keylen; | 
|  | 2664 | if (gd.gtk_len != buf[4]) { | 
|  | 2665 | wpa_printf(MSG_DEBUG, "GTK len mismatch len %d vs %d", | 
|  | 2666 | gd.gtk_len, buf[4]); | 
|  | 2667 | return -1; | 
|  | 2668 | } | 
|  | 2669 | gd.keyidx = keyinfo & 0x03; /* B0 - B1 */ | 
|  | 2670 | gd.tx = wpa_supplicant_gtk_tx_bit_workaround( | 
|  | 2671 | sm, !!(keyinfo & WPA_KEY_INFO_TXRX)); | 
|  | 2672 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 2673 | os_memcpy(gd.gtk, buf + 13, gd.gtk_len); | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 2674 |  | 
|  | 2675 | wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)", | 
|  | 2676 | gd.gtk, gd.gtk_len); | 
|  | 2677 | if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) { | 
|  | 2678 | wpa_printf(MSG_DEBUG, "Failed to install the GTK in " | 
|  | 2679 | "WNM mode"); | 
|  | 2680 | return -1; | 
|  | 2681 | } | 
|  | 2682 | #ifdef CONFIG_IEEE80211W | 
|  | 2683 | } else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) { | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 2684 | os_memcpy(igd.keyid, buf + 2, 2); | 
|  | 2685 | os_memcpy(igd.pn, buf + 4, 6); | 
|  | 2686 |  | 
|  | 2687 | keyidx = WPA_GET_LE16(igd.keyid); | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 2688 | os_memcpy(igd.igtk, buf + 10, WPA_IGTK_LEN); | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 2689 |  | 
|  | 2690 | wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)", | 
|  | 2691 | igd.igtk, WPA_IGTK_LEN); | 
|  | 2692 | if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, | 
|  | 2693 | keyidx, 0, igd.pn, sizeof(igd.pn), | 
|  | 2694 | igd.igtk, WPA_IGTK_LEN) < 0) { | 
|  | 2695 | wpa_printf(MSG_DEBUG, "Failed to install the IGTK in " | 
|  | 2696 | "WNM mode"); | 
|  | 2697 | return -1; | 
|  | 2698 | } | 
|  | 2699 | #endif /* CONFIG_IEEE80211W */ | 
|  | 2700 | } else { | 
|  | 2701 | wpa_printf(MSG_DEBUG, "Unknown element id"); | 
|  | 2702 | return -1; | 
|  | 2703 | } | 
|  | 2704 |  | 
|  | 2705 | return 0; | 
|  | 2706 | } | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 2707 | #endif /* CONFIG_WNM */ |