]>
git.ipfire.org Git - thirdparty/hostap.git/blob - wpa_supplicant/mesh_rsn.c
2 * WPA Supplicant - Mesh RSN routines
3 * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
11 #include "utils/common.h"
12 #include "utils/eloop.h"
13 #include "crypto/sha256.h"
14 #include "crypto/random.h"
15 #include "crypto/aes.h"
16 #include "crypto/aes_siv.h"
17 #include "rsn_supp/wpa.h"
18 #include "ap/hostapd.h"
19 #include "ap/wpa_auth.h"
20 #include "ap/sta_info.h"
21 #include "ap/ieee802_11.h"
22 #include "wpa_supplicant_i.h"
24 #include "wpas_glue.h"
28 #define MESH_AUTH_TIMEOUT 10
29 #define MESH_AUTH_RETRY 3
31 void mesh_auth_timer(void *eloop_ctx
, void *user_data
)
33 struct wpa_supplicant
*wpa_s
= eloop_ctx
;
34 struct sta_info
*sta
= user_data
;
36 if (sta
->sae
->state
!= SAE_ACCEPTED
) {
37 wpa_printf(MSG_DEBUG
, "AUTH: Re-authenticate with " MACSTR
39 MAC2STR(sta
->addr
), sta
->sae_auth_retry
);
40 if (sta
->sae_auth_retry
< MESH_AUTH_RETRY
) {
41 mesh_rsn_auth_sae_sta(wpa_s
, sta
);
43 /* block the STA if exceeded the number of attempts */
44 sta
->plink_state
= PLINK_BLOCKED
;
45 sta
->sae
->state
= SAE_NOTHING
;
47 sta
->sae_auth_retry
++;
52 static void auth_logger(void *ctx
, const u8
*addr
, logger_level level
,
56 wpa_printf(MSG_DEBUG
, "AUTH: " MACSTR
" - %s",
59 wpa_printf(MSG_DEBUG
, "AUTH: %s", txt
);
63 static const u8
*auth_get_psk(void *ctx
, const u8
*addr
,
64 const u8
*p2p_dev_addr
, const u8
*prev_psk
)
66 struct mesh_rsn
*mesh_rsn
= ctx
;
67 struct hostapd_data
*hapd
= mesh_rsn
->wpa_s
->ifmsh
->bss
[0];
68 struct sta_info
*sta
= ap_get_sta(hapd
, addr
);
70 wpa_printf(MSG_DEBUG
, "AUTH: %s (addr=" MACSTR
" prev_psk=%p)",
71 __func__
, MAC2STR(addr
), prev_psk
);
73 if (sta
&& sta
->auth_alg
== WLAN_AUTH_SAE
) {
74 if (!sta
->sae
|| prev_psk
)
83 static int auth_set_key(void *ctx
, int vlan_id
, enum wpa_alg alg
,
84 const u8
*addr
, int idx
, u8
*key
, size_t key_len
)
86 struct mesh_rsn
*mesh_rsn
= ctx
;
89 os_memset(seq
, 0, sizeof(seq
));
92 wpa_printf(MSG_DEBUG
, "AUTH: %s(alg=%d addr=" MACSTR
94 __func__
, alg
, MAC2STR(addr
), idx
);
96 wpa_printf(MSG_DEBUG
, "AUTH: %s(alg=%d key_idx=%d)",
99 wpa_hexdump_key(MSG_DEBUG
, "AUTH: set_key - key", key
, key_len
);
101 return wpa_drv_set_key(mesh_rsn
->wpa_s
, alg
, addr
, idx
,
102 1, seq
, 6, key
, key_len
);
106 static int auth_start_ampe(void *ctx
, const u8
*addr
)
108 struct mesh_rsn
*mesh_rsn
= ctx
;
109 struct hostapd_data
*hapd
;
110 struct sta_info
*sta
;
112 if (mesh_rsn
->wpa_s
->current_ssid
->mode
!= WPAS_MODE_MESH
)
115 hapd
= mesh_rsn
->wpa_s
->ifmsh
->bss
[0];
116 sta
= ap_get_sta(hapd
, addr
);
118 eloop_cancel_timeout(mesh_auth_timer
, mesh_rsn
->wpa_s
, sta
);
120 mesh_mpm_auth_peer(mesh_rsn
->wpa_s
, addr
);
125 static int __mesh_rsn_auth_init(struct mesh_rsn
*rsn
, const u8
*addr
)
127 struct wpa_auth_config conf
;
128 struct wpa_auth_callbacks cb
;
131 wpa_printf(MSG_DEBUG
, "AUTH: Initializing group state machine");
133 os_memset(&conf
, 0, sizeof(conf
));
135 conf
.wpa_key_mgmt
= WPA_KEY_MGMT_SAE
;
136 conf
.wpa_pairwise
= WPA_CIPHER_CCMP
;
137 conf
.rsn_pairwise
= WPA_CIPHER_CCMP
;
138 conf
.wpa_group
= WPA_CIPHER_CCMP
;
139 conf
.eapol_version
= 0;
140 conf
.wpa_group_rekey
= -1;
142 os_memset(&cb
, 0, sizeof(cb
));
144 cb
.logger
= auth_logger
;
145 cb
.get_psk
= auth_get_psk
;
146 cb
.set_key
= auth_set_key
;
147 cb
.start_ampe
= auth_start_ampe
;
149 rsn
->auth
= wpa_init(addr
, &conf
, &cb
);
150 if (rsn
->auth
== NULL
) {
151 wpa_printf(MSG_DEBUG
, "AUTH: wpa_init() failed");
155 /* TODO: support rekeying */
156 if (random_get_bytes(rsn
->mgtk
, 16) < 0) {
157 wpa_deinit(rsn
->auth
);
162 wpa_drv_set_key(rsn
->wpa_s
, WPA_ALG_IGTK
, NULL
, 4, 1,
163 seq
, sizeof(seq
), rsn
->mgtk
, sizeof(rsn
->mgtk
));
165 /* group privacy / data frames */
166 wpa_drv_set_key(rsn
->wpa_s
, WPA_ALG_CCMP
, NULL
, 1, 1,
167 seq
, sizeof(seq
), rsn
->mgtk
, sizeof(rsn
->mgtk
));
173 static void mesh_rsn_deinit(struct mesh_rsn
*rsn
)
175 os_memset(rsn
->mgtk
, 0, sizeof(rsn
->mgtk
));
176 wpa_deinit(rsn
->auth
);
180 struct mesh_rsn
*mesh_rsn_auth_init(struct wpa_supplicant
*wpa_s
,
181 struct mesh_conf
*conf
)
183 struct mesh_rsn
*mesh_rsn
;
184 struct hostapd_data
*bss
= wpa_s
->ifmsh
->bss
[0];
188 mesh_rsn
= os_zalloc(sizeof(*mesh_rsn
));
189 if (mesh_rsn
== NULL
)
191 mesh_rsn
->wpa_s
= wpa_s
;
193 if (__mesh_rsn_auth_init(mesh_rsn
, wpa_s
->own_addr
) < 0) {
194 mesh_rsn_deinit(mesh_rsn
);
198 bss
->wpa_auth
= mesh_rsn
->auth
;
200 ie
= wpa_auth_get_wpa_ie(mesh_rsn
->auth
, &ie_len
);
201 conf
->ies
= (u8
*) ie
;
202 conf
->ie_len
= ie_len
;
204 wpa_supplicant_rsn_supp_set_config(wpa_s
, wpa_s
->current_ssid
);
210 static int index_within_array(const int *array
, int idx
)
214 for (i
= 0; i
< idx
; i
++) {
223 static int mesh_rsn_sae_group(struct wpa_supplicant
*wpa_s
,
224 struct sae_data
*sae
)
226 int *groups
= wpa_s
->ifmsh
->bss
[0]->conf
->sae_groups
;
228 /* Configuration may have changed, so validate current index */
229 if (!index_within_array(groups
, wpa_s
->mesh_rsn
->sae_group_index
))
233 int group
= groups
[wpa_s
->mesh_rsn
->sae_group_index
];
237 if (sae_set_group(sae
, group
) == 0) {
238 wpa_dbg(wpa_s
, MSG_DEBUG
, "SME: Selected SAE group %d",
242 wpa_s
->mesh_rsn
->sae_group_index
++;
249 static int mesh_rsn_build_sae_commit(struct wpa_supplicant
*wpa_s
,
250 struct wpa_ssid
*ssid
,
251 struct sta_info
*sta
)
253 if (ssid
->passphrase
== NULL
) {
254 wpa_msg(wpa_s
, MSG_DEBUG
, "SAE: No password available");
258 if (mesh_rsn_sae_group(wpa_s
, sta
->sae
) < 0) {
259 wpa_msg(wpa_s
, MSG_DEBUG
, "SAE: Failed to select group");
263 return sae_prepare_commit(wpa_s
->own_addr
, sta
->addr
,
264 (u8
*) ssid
->passphrase
,
265 os_strlen(ssid
->passphrase
), sta
->sae
);
269 /* initiate new SAE authentication with sta */
270 int mesh_rsn_auth_sae_sta(struct wpa_supplicant
*wpa_s
,
271 struct sta_info
*sta
)
273 struct hostapd_data
*hapd
= wpa_s
->ifmsh
->bss
[0];
274 struct wpa_ssid
*ssid
= wpa_s
->current_ssid
;
279 wpa_msg(wpa_s
, MSG_DEBUG
,
280 "AUTH: No current_ssid known to initiate new SAE");
285 sta
->sae
= os_zalloc(sizeof(*sta
->sae
));
286 if (sta
->sae
== NULL
)
290 if (mesh_rsn_build_sae_commit(wpa_s
, ssid
, sta
))
293 wpa_msg(wpa_s
, MSG_DEBUG
,
294 "AUTH: started authentication with SAE peer: " MACSTR
,
297 wpa_supplicant_set_state(wpa_s
, WPA_AUTHENTICATING
);
298 ret
= auth_sae_init_committed(hapd
, sta
);
302 rnd
= rand() % MESH_AUTH_TIMEOUT
;
303 eloop_register_timeout(MESH_AUTH_TIMEOUT
+ rnd
, 0, mesh_auth_timer
,
309 void mesh_rsn_get_pmkid(struct mesh_rsn
*rsn
, struct sta_info
*sta
, u8
*pmkid
)
311 /* don't expect wpa auth to cache the pmkid for now */
312 rsn_pmkid(sta
->sae
->pmk
, PMK_LEN
, rsn
->wpa_s
->own_addr
,
314 wpa_key_mgmt_sha256(wpa_auth_sta_key_mgmt(sta
->wpa_sm
)));
319 mesh_rsn_derive_aek(struct mesh_rsn
*rsn
, struct sta_info
*sta
)
321 u8
*myaddr
= rsn
->wpa_s
->own_addr
;
322 u8
*peer
= sta
->addr
;
323 u8
*addr1
= peer
, *addr2
= myaddr
;
324 u8 context
[AES_BLOCK_SIZE
];
327 RSN_SELECTOR_PUT(context
, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP
));
329 if (os_memcmp(myaddr
, peer
, ETH_ALEN
) < 0) {
333 os_memcpy(context
+ 4, addr1
, ETH_ALEN
);
334 os_memcpy(context
+ 10, addr2
, ETH_ALEN
);
336 sha256_prf(sta
->sae
->pmk
, sizeof(sta
->sae
->pmk
), "AEK Derivation",
337 context
, sizeof(context
), sta
->aek
, sizeof(sta
->aek
));
341 /* derive mesh temporal key from pmk */
342 int mesh_rsn_derive_mtk(struct wpa_supplicant
*wpa_s
, struct sta_info
*sta
)
346 u16 min_lid
, max_lid
;
347 size_t nonce_len
= sizeof(sta
->my_nonce
);
348 size_t lid_len
= sizeof(sta
->my_lid
);
349 u8
*myaddr
= wpa_s
->own_addr
;
350 u8
*peer
= sta
->addr
;
351 /* 2 nonces, 2 linkids, akm suite, 2 mac addrs */
352 u8 context
[64 + 4 + 4 + 12];
355 if (os_memcmp(sta
->my_nonce
, sta
->peer_nonce
, nonce_len
) < 0) {
357 max
= sta
->peer_nonce
;
359 min
= sta
->peer_nonce
;
362 os_memcpy(ptr
, min
, nonce_len
);
363 os_memcpy(ptr
+ nonce_len
, max
, nonce_len
);
364 ptr
+= 2 * nonce_len
;
366 if (sta
->my_lid
< sta
->peer_lid
) {
367 min_lid
= host_to_le16(sta
->my_lid
);
368 max_lid
= host_to_le16(sta
->peer_lid
);
370 min_lid
= host_to_le16(sta
->peer_lid
);
371 max_lid
= host_to_le16(sta
->my_lid
);
373 os_memcpy(ptr
, &min_lid
, lid_len
);
374 os_memcpy(ptr
+ lid_len
, &max_lid
, lid_len
);
378 RSN_SELECTOR_PUT(ptr
, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP
));
381 if (os_memcmp(myaddr
, peer
, ETH_ALEN
) < 0) {
388 os_memcpy(ptr
, min
, ETH_ALEN
);
389 os_memcpy(ptr
+ ETH_ALEN
, max
, ETH_ALEN
);
391 sha256_prf(sta
->sae
->pmk
, sizeof(sta
->sae
->pmk
),
392 "Temporal Key Derivation", context
, sizeof(context
),
393 sta
->mtk
, sizeof(sta
->mtk
));
398 void mesh_rsn_init_ampe_sta(struct wpa_supplicant
*wpa_s
, struct sta_info
*sta
)
400 if (random_get_bytes(sta
->my_nonce
, 32) < 0) {
401 wpa_printf(MSG_INFO
, "mesh: Failed to derive random nonce");
402 /* TODO: How to handle this more cleanly? */
404 os_memset(sta
->peer_nonce
, 0, 32);
405 mesh_rsn_derive_aek(wpa_s
->mesh_rsn
, sta
);
409 /* insert AMPE and encrypted MIC at @ie.
410 * @mesh_rsn: mesh RSN context
411 * @sta: STA we're sending to
412 * @cat: pointer to category code in frame header.
413 * @buf: wpabuf to add encrypted AMPE and MIC to.
415 int mesh_rsn_protect_frame(struct mesh_rsn
*rsn
, struct sta_info
*sta
,
416 const u8
*cat
, struct wpabuf
*buf
)
418 struct ieee80211_ampe_ie
*ampe
;
419 u8
const *ie
= wpabuf_head_u8(buf
) + wpabuf_len(buf
);
420 u8
*ampe_ie
= NULL
, *mic_ie
= NULL
, *mic_payload
;
421 const u8
*aad
[] = { rsn
->wpa_s
->own_addr
, sta
->addr
, cat
};
422 const size_t aad_len
[] = { ETH_ALEN
, ETH_ALEN
, ie
- cat
};
425 if (AES_BLOCK_SIZE
+ 2 + sizeof(*ampe
) + 2 > wpabuf_tailroom(buf
)) {
426 wpa_printf(MSG_ERROR
, "protect frame: buffer too small");
430 ampe_ie
= os_zalloc(2 + sizeof(*ampe
));
432 wpa_printf(MSG_ERROR
, "protect frame: out of memory");
436 mic_ie
= os_zalloc(2 + AES_BLOCK_SIZE
);
438 wpa_printf(MSG_ERROR
, "protect frame: out of memory");
444 ampe_ie
[0] = WLAN_EID_AMPE
;
445 ampe_ie
[1] = sizeof(*ampe
);
446 ampe
= (struct ieee80211_ampe_ie
*) (ampe_ie
+ 2);
448 RSN_SELECTOR_PUT(ampe
->selected_pairwise_suite
,
449 wpa_cipher_to_suite(WPA_PROTO_RSN
, WPA_CIPHER_CCMP
));
450 os_memcpy(ampe
->local_nonce
, sta
->my_nonce
, 32);
451 os_memcpy(ampe
->peer_nonce
, sta
->peer_nonce
, 32);
452 /* incomplete: see 13.5.4 */
453 /* TODO: static mgtk for now since we don't support rekeying! */
454 os_memcpy(ampe
->mgtk
, rsn
->mgtk
, 16);
455 /* TODO: Populate Key RSC */
456 /* expire in 13 decades or so */
457 os_memset(ampe
->key_expiration
, 0xff, 4);
460 mic_ie
[0] = WLAN_EID_MIC
;
461 mic_ie
[1] = AES_BLOCK_SIZE
;
462 wpabuf_put_data(buf
, mic_ie
, 2);
463 /* MIC field is output ciphertext */
465 /* encrypt after MIC */
466 mic_payload
= (u8
*) wpabuf_put(buf
, 2 + sizeof(*ampe
) +
469 if (aes_siv_encrypt(sta
->aek
, ampe_ie
, 2 + sizeof(*ampe
), 3,
470 aad
, aad_len
, mic_payload
)) {
471 wpa_printf(MSG_ERROR
, "protect frame: failed to encrypt");
484 int mesh_rsn_process_ampe(struct wpa_supplicant
*wpa_s
, struct sta_info
*sta
,
485 struct ieee802_11_elems
*elems
, const u8
*cat
,
486 const u8
*start
, size_t elems_len
)
489 struct ieee80211_ampe_ie
*ampe
;
490 u8 null_nonce
[32] = {};
493 u8
*ampe_buf
, *crypt
= NULL
;
495 const u8
*aad
[] = { sta
->addr
, wpa_s
->own_addr
, cat
};
496 const size_t aad_len
[] = { ETH_ALEN
, ETH_ALEN
,
497 (elems
->mic
- 2) - cat
};
499 if (!elems
->mic
|| elems
->mic_len
< AES_BLOCK_SIZE
) {
500 wpa_msg(wpa_s
, MSG_DEBUG
, "Mesh RSN: missing mic ie");
504 ampe_buf
= (u8
*) elems
->mic
+ elems
->mic_len
;
505 if ((int) elems_len
< ampe_buf
- start
)
508 crypt_len
= elems_len
- (elems
->mic
- start
);
510 wpa_msg(wpa_s
, MSG_DEBUG
, "Mesh RSN: missing ampe ie");
514 /* crypt is modified by siv_decrypt */
515 crypt
= os_zalloc(crypt_len
);
517 wpa_printf(MSG_ERROR
, "Mesh RSN: out of memory");
522 os_memcpy(crypt
, elems
->mic
, crypt_len
);
524 if (aes_siv_decrypt(sta
->aek
, crypt
, crypt_len
, 3,
525 aad
, aad_len
, ampe_buf
)) {
526 wpa_printf(MSG_ERROR
, "Mesh RSN: frame verification failed!");
531 ampe_eid
= *ampe_buf
++;
532 ampe_ie_len
= *ampe_buf
++;
534 if (ampe_eid
!= WLAN_EID_AMPE
||
535 ampe_ie_len
< sizeof(struct ieee80211_ampe_ie
)) {
536 wpa_msg(wpa_s
, MSG_DEBUG
, "Mesh RSN: invalid ampe ie");
541 ampe
= (struct ieee80211_ampe_ie
*) ampe_buf
;
542 if (os_memcmp(ampe
->peer_nonce
, null_nonce
, 32) != 0 &&
543 os_memcmp(ampe
->peer_nonce
, sta
->my_nonce
, 32) != 0) {
544 wpa_msg(wpa_s
, MSG_DEBUG
, "Mesh RSN: invalid peer nonce");
548 os_memcpy(sta
->peer_nonce
, ampe
->local_nonce
,
549 sizeof(ampe
->local_nonce
));
550 os_memcpy(sta
->mgtk
, ampe
->mgtk
, sizeof(ampe
->mgtk
));
552 /* todo parse mgtk expiration */