[PATCHv4 4/7] FT: new rrb message format
Michael Braun
michael-dev at fami-braun.de
Thu Mar 23 04:57:20 PDT 2017
Convert FT RRB into new TLV based format.
Use AES+SIV as AED cipher.
This needs at least 32 byte long keys. These can be provided either
by a config filee change or letting a KDF derive the 32 byte key used
from the 16 byte key given.
This breaks backward compatiblity.
Signed-off-by: Michael Braun <michael-dev at fami-braun.de>
--
v5:
- configuration file fallback for short keys
- add authenticated-only packet area
v4:
- AES-SIV
v3:
- use new extended OUI ethertype
- use encrypt-then-mac with aes+sha256 as AED
- use different keys for encryption and mac using hmac_sha256_kdf
---
hostapd/Makefile | 3 +
hostapd/config_file.c | 24 +-
hostapd/hostapd.conf | 12 +-
src/ap/hostapd.h | 2 +
src/ap/wpa_auth.h | 99 ++--
src/ap/wpa_auth_ft.c | 1052 ++++++++++++++++++++++++++++++-----------
src/ap/wpa_auth_glue.c | 2 +-
src/ap/wpa_auth_i.h | 2 +-
tests/hwsim/test_ap_ft.py | 40 +-
tests/hwsim/test_hapd_ctrl.py | 12 +-
10 files changed, 903 insertions(+), 345 deletions(-)
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 298019e..ab144e2 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -295,7 +295,10 @@ OBJS += ../src/ap/wpa_auth_ft.o
NEED_SHA256=y
NEED_AES_OMAC1=y
NEED_AES_UNWRAP=y
+NEED_AES_SIV=y
NEED_ETH_P_OUI=y
+NEED_SHA256=y
+NEED_HMAC_SHA256_KDF=y
endif
ifdef NEED_ETH_P_OUI
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 7b43806..2070a74 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -20,6 +20,7 @@
#include "ap/wpa_auth.h"
#include "ap/ap_config.h"
#include "config_file.h"
+#include "crypto/sha256.h"
#ifndef CONFIG_NO_RADIUS
@@ -1000,6 +1001,25 @@ static int hostapd_config_tx_queue(struct hostapd_config *conf,
#ifdef CONFIG_IEEE80211R_AP
+static int rkh_dervice_key(const char *pos, u8 *key, size_t key_len)
+{
+ u8 oldkey[16];
+
+ if (!hexstr2bin(pos, key, key_len))
+ return 0;
+
+ /* try to use old short key for backward compatibility */
+ if (hexstr2bin(pos, oldkey, sizeof(oldkey)))
+ return -1;
+
+ if (hmac_sha256_kdf(oldkey, sizeof(oldkey), "FT OLDKEY", NULL, 0,
+ key, key_len) < 0)
+ return -1;
+
+ return 0;
+}
+
+
static int add_r0kh(struct hostapd_bss_config *bss, char *value)
{
struct ft_remote_r0kh *r0kh;
@@ -1033,7 +1053,7 @@ static int add_r0kh(struct hostapd_bss_config *bss, char *value)
os_memcpy(r0kh->id, pos, r0kh->id_len);
pos = next;
- if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) {
+ if (rkh_dervice_key(pos, r0kh->key, sizeof(r0kh->key)) < 0) {
wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos);
os_free(r0kh);
return -1;
@@ -1078,7 +1098,7 @@ static int add_r1kh(struct hostapd_bss_config *bss, char *value)
}
pos = next;
- if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) {
+ if (rkh_dervice_key(pos, r1kh->key, sizeof(r1kh->key)) < 0) {
wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos);
os_free(r1kh);
return -1;
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 18c330b..7e61d1c 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1452,21 +1452,21 @@ own_ip_addr=127.0.0.1
#reassociation_deadline=1000
# List of R0KHs in the same Mobility Domain
-# format: <MAC address> <NAS Identifier> <128-bit key as hex string>
+# format: <MAC address> <NAS Identifier> <256-bit key as hex string>
# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC
# address when requesting PMK-R1 key from the R0KH that the STA used during the
# Initial Mobility Domain Association.
-#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f
-#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff
+#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
+#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
# And so on.. One line per R0KH.
# List of R1KHs in the same Mobility Domain
-# format: <MAC address> <R1KH-ID> <128-bit key as hex string>
+# format: <MAC address> <R1KH-ID> <256-bit key as hex string>
# This list is used to map R1KH-ID to a destination MAC address when sending
# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD
# that can request PMK-R1 keys.
-#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f
-#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff
+#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
+#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
# And so on.. One line per R1KH.
# Whether PMK-R1 push is enabled at R0KH
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 452ca1e..e7c65f7 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -195,6 +195,8 @@ struct hostapd_data {
struct eth_p_oui_ctx *oui_pull;
struct eth_p_oui_ctx *oui_resp;
struct eth_p_oui_ctx *oui_push;
+ struct eth_p_oui_ctx *oui_sreq;
+ struct eth_p_oui_ctx *oui_sresp;
#endif /* CONFIG_IEEE80211R_AP */
struct wps_context *wps;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 22c2093..9bf5884 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -44,54 +44,61 @@ struct ft_rrb_frame {
#define FT_PACKET_R0KH_R1KH_RESP 0x02
#define FT_PACKET_R0KH_R1KH_PUSH 0x03
-#define FT_R0KH_R1KH_PULL_NONCE_LEN 16
-#define FT_R0KH_R1KH_PULL_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \
- WPA_PMK_NAME_LEN + FT_R1KH_ID_LEN + \
- ETH_ALEN)
-#define FT_R0KH_R1KH_PULL_PAD_LEN ((8 - FT_R0KH_R1KH_PULL_DATA_LEN % 8) % 8)
-
-struct ft_r0kh_r1kh_pull_frame {
- u8 nonce[FT_R0KH_R1KH_PULL_NONCE_LEN];
- u8 pmk_r0_name[WPA_PMK_NAME_LEN];
- u8 r1kh_id[FT_R1KH_ID_LEN];
- u8 s1kh_id[ETH_ALEN];
- u8 pad[FT_R0KH_R1KH_PULL_PAD_LEN]; /* 8-octet boundary for AES block */
- u8 key_wrap_extra[8];
-} STRUCT_PACKED;
+/* packet layout
+ * IEEE 802 extended OUI ethertype frame header
+ * u16 authlen
+ * multiple of of struct ft_rrb_tlv (authenticated only, length = authlen)
+ * multiple of of struct ft_rrb_tlv (aes-siv encrypted, all-zero padded to
+ * blocksize, aes-siv needs an extra
+ * blocksize length)
+ */
-#define FT_R0KH_R1KH_RESP_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \
- FT_R1KH_ID_LEN + ETH_ALEN + PMK_LEN + \
- WPA_PMK_NAME_LEN + 2)
-#define FT_R0KH_R1KH_RESP_PAD_LEN ((8 - FT_R0KH_R1KH_RESP_DATA_LEN % 8) % 8)
-struct ft_r0kh_r1kh_resp_frame {
- u8 nonce[FT_R0KH_R1KH_PULL_NONCE_LEN]; /* copied from pull */
- u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */
- u8 s1kh_id[ETH_ALEN]; /* copied from pull */
- u8 pmk_r1[PMK_LEN];
- u8 pmk_r1_name[WPA_PMK_NAME_LEN];
- le16 pairwise;
- u8 pad[FT_R0KH_R1KH_RESP_PAD_LEN]; /* 8-octet boundary for AES block */
- u8 key_wrap_extra[8];
-} STRUCT_PACKED;
+#define FT_RRB_NONCE_LEN 16
+
+#define FT_RRB_LAST_EMPTY 0 /* placeholder or padding */
+
+#define FT_RRB_NONCE 2 /* size FT_RRB_NONCE_LEN */
+#define FT_RRB_TIMESTAMP 3 /* le32 unix seconds */
+
+#define FT_RRB_R0KH_ID 4 /* FT_R0KH_ID_MAX_LEN */
+#define FT_RRB_R1KH_ID 5 /* FT_R1KH_ID_LEN */
+#define FT_RRB_S1KH_ID 6 /* ETH_ALEN */
+
+#define FT_RRB_PMK_R0_NAME 7 /* WPA_PMK_NAME_LEN */
+#define FT_RRB_PMK_R0 8 /* PMK_LEN */
+#define FT_RRB_PMK_R1_NAME 9 /* WPA_PMK_NAME_LEN */
+#define FT_RRB_PMK_R1 10 /* PMK_LEN */
-#define FT_R0KH_R1KH_PUSH_DATA_LEN (4 + FT_R1KH_ID_LEN + ETH_ALEN + \
- WPA_PMK_NAME_LEN + PMK_LEN + \
- WPA_PMK_NAME_LEN + 2)
-#define FT_R0KH_R1KH_PUSH_PAD_LEN ((8 - FT_R0KH_R1KH_PUSH_DATA_LEN % 8) % 8)
-struct ft_r0kh_r1kh_push_frame {
- /* Encrypted with AES key-wrap */
- u8 timestamp[4]; /* current time in seconds since unix epoch, little
- * endian */
- u8 r1kh_id[FT_R1KH_ID_LEN];
- u8 s1kh_id[ETH_ALEN];
- u8 pmk_r0_name[WPA_PMK_NAME_LEN];
- u8 pmk_r1[PMK_LEN];
- u8 pmk_r1_name[WPA_PMK_NAME_LEN];
- le16 pairwise;
- u8 pad[FT_R0KH_R1KH_PUSH_PAD_LEN]; /* 8-octet boundary for AES block */
- u8 key_wrap_extra[8];
+#define FT_RRB_PAIRWISE 11 /* le16 */
+
+struct ft_rrb_tlv {
+ le16 type;
+ le16 len;
+ /* followed by data of length len */
} STRUCT_PACKED;
+/* session TLVs:
+ * required: PMK_R1, PMK_R1_NAME, PAIRWISE
+ *
+ * pull frame TLVs:
+ * auth:
+ * required: NONCE, R0KH_ID, R1KH_ID
+ * encrypted:
+ * required: PMK_R0_NAME, S1KH_ID
+ *
+ * response frame TLVs:
+ * auth:
+ * required: NONCE, R0KH_ID, R1KH_ID
+ * encrypted:
+ * required: S1KH_ID, session TLVs
+ *
+ * push frame TLVs:
+ * auth:
+ * required: TIMESTAMP, R0KH_ID, R1KH_ID
+ * encrypted:
+ * required: S1KH_ID, PMK_R0_NAME, session TLVs
+ */
+
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
@@ -110,7 +117,7 @@ struct ft_remote_r0kh {
u8 addr[ETH_ALEN];
u8 id[FT_R0KH_ID_MAX_LEN];
size_t id_len;
- u8 key[16];
+ u8 key[32];
};
@@ -118,7 +125,7 @@ struct ft_remote_r1kh {
struct ft_remote_r1kh *next;
u8 addr[ETH_ALEN];
u8 id[FT_R1KH_ID_LEN];
- u8 key[16];
+ u8 key[32];
};
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 1d4c519..d0e58e3 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -13,6 +13,8 @@
#include "utils/list.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
#include "crypto/aes_wrap.h"
#include "crypto/random.h"
#include "ap_config.h"
@@ -24,11 +26,379 @@
#ifdef CONFIG_IEEE80211R_AP
+static const char *ft_rrb_ad = "hostapd FT RRB";
+
static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
const u8 *current_ap, const u8 *sta_addr,
u16 status, const u8 *resp_ies,
size_t resp_ies_len);
+struct tlv_list {
+ int type;
+ int len;
+ const u8 *data;
+};
+
+
+/**
+ * decrypt message
+ * @data full packet
+ * @key encryption and mac key
+ * @plain pointer to store pointer for plaintext
+ * (only action_length many bytes)
+ * needs to be freed by caller if not null
+ * will only be returned on success
+ * @return 0 on success, -1 on error
+ */
+static int wpa_ft_rrb_decrypt(const u8 *key, const size_t key_len,
+ const u8 *enc, const size_t enc_len,
+ const u8 *auth, const size_t auth_len,
+ const u8 *src_addr, const u8 type,
+ u8 **plain, size_t *plain_size)
+{
+ size_t len;
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: decrypt using key", key, key_len);
+
+ if (!key) { /* skip decryption */
+ *plain = os_memdup(enc, enc_len);
+ if (enc_len > 0 && !*plain)
+ goto err;
+
+ *plain_size = enc_len;
+
+ return 0;
+ }
+
+ *plain = NULL;
+
+ /* siv overhead */
+ if (enc_len < AES_BLOCK_SIZE)
+ goto err;
+
+ /* len of plaintext + AES-SIV overhead
+ * remember: tlv type 0x0000 is reserved or padding and termination */
+ len = enc_len - AES_BLOCK_SIZE;
+
+ /* length a multiple of blocksize? */
+ if (len % AES_BLOCK_SIZE != 0)
+ goto err;
+
+ *plain = os_zalloc(enc_len);
+ if (!*plain)
+ goto err;
+
+ const u8 *ad[4] = { src_addr, auth, &type, (u8 *) ft_rrb_ad };
+ size_t ad_len[4] = { ETH_ALEN, auth_len, sizeof(type),
+ os_strlen(ft_rrb_ad) };
+ if (aes_siv_decrypt(key, key_len, enc, enc_len, 4, ad, ad_len,
+ *plain) < 0)
+ goto err;
+
+ *plain_size = len;
+ return 0;
+err:
+ os_free(*plain);
+ *plain = NULL;
+ *plain_size = 0;
+
+ wpa_printf(MSG_ERROR, "FT: Failed to decrypt");
+
+ return -1;
+}
+
+
+/* get first tlv record in packet matching type
+ * @data (decrypted) packet
+ * @return 0 on success else -1
+ */
+static int wpa_ft_rrb_get_tlv(const u8 *plain, const size_t plain_len,
+ int type, size_t *tlv_len, const u8 **tlv_data)
+{
+ struct ft_rrb_tlv *f;
+ size_t left;
+ le16 type16;
+ size_t len;
+
+ left = plain_len;
+ type16 = host_to_le16(type);
+
+ while (left >= sizeof(*f)) {
+ f = (struct ft_rrb_tlv *) plain;
+
+ left -= sizeof(*f);
+ plain += sizeof(*f);
+ len = le_to_host16(f->len);
+
+ if (left < len) {
+ wpa_printf(MSG_DEBUG, "FT: RRB message truncated");
+ break;
+ }
+
+ if (f->type == type16) {
+ *tlv_len = len;
+ *tlv_data = plain;
+ return 0;
+ }
+
+ left -= len;
+ plain += len;
+ }
+
+ return -1;
+}
+
+
+static void wpa_ft_rrb_dump(const u8 *plain, const size_t plain_len)
+{
+ struct ft_rrb_tlv *f;
+ size_t left;
+ size_t len;
+
+ left = plain_len;
+
+ wpa_printf(MSG_DEBUG, "FT: RRB dump message");
+ while (left >= sizeof(*f)) {
+ f = (struct ft_rrb_tlv *) plain;
+
+ left -= sizeof(*f);
+ plain += sizeof(*f);
+ len = le_to_host16(f->len);
+
+ wpa_printf(MSG_DEBUG, "FT: RRB TLV type = %d, len = %zu",
+ le_to_host16(f->type), len);
+
+ if (left < len) {
+ wpa_printf(MSG_DEBUG, "FT: RRB message truncated: left"
+ " %zu bytes, need %zu", left, len);
+ break;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "FT: RRB TLV data", plain, len);
+
+ left -= len;
+ plain += len;
+ }
+
+ if (left > 0)
+ wpa_hexdump(MSG_DEBUG, "FT: RRB TLV padding", plain, left);
+
+ wpa_printf(MSG_DEBUG, "FT: RRB dump message end");
+}
+
+
+static inline size_t wpa_ft_tlv_len(const struct tlv_list *tlvs)
+{
+ size_t tlv_len = 0;
+ int i;
+
+ if (!tlvs)
+ return 0;
+
+ for (i = 0; tlvs[i].type != FT_RRB_LAST_EMPTY; i++) {
+ tlv_len += sizeof(struct ft_rrb_tlv);
+ tlv_len += tlvs[i].len;
+ }
+
+ return tlv_len;
+}
+
+
+static inline size_t wpa_ft_tlv_lin(const struct tlv_list *tlvs, u8 *start,
+ u8 *endpos)
+{
+ int i;
+ size_t tlv_len;
+ struct ft_rrb_tlv *hdr;
+ u8 *pos = start;
+
+ if (!tlvs)
+ return 0;
+
+ tlv_len = 0;
+ pos = start + tlv_len;
+ for (i = 0; tlvs[i].type != FT_RRB_LAST_EMPTY; i++) {
+ tlv_len += sizeof(*hdr);
+ if (start + tlv_len > endpos)
+ return tlv_len;
+ hdr = (struct ft_rrb_tlv *) pos;
+ hdr->type = host_to_le16(tlvs[i].type);
+ hdr->len = host_to_le16(tlvs[i].len);
+ pos = start + tlv_len;
+
+ tlv_len += tlvs[i].len;
+ if (start + tlv_len > endpos)
+ return tlv_len;
+ os_memcpy(pos, tlvs[i].data, tlvs[i].len);
+ pos = start + tlv_len;
+ }
+
+ return tlv_len;
+}
+
+
+static int wpa_ft_rrb_lin(const struct tlv_list *tlvs1,
+ const struct tlv_list *tlvs2,
+ int pad, u8 **plain, size_t *plain_len)
+{
+ u8 *pos, *endpos;
+ size_t tlv_len, pad_len;
+
+ tlv_len = 0;
+ tlv_len += wpa_ft_tlv_len(tlvs1);
+ tlv_len += wpa_ft_tlv_len(tlvs2);
+
+ pad_len = 0;
+ if (pad && (tlv_len % AES_BLOCK_SIZE != 0))
+ pad_len = AES_BLOCK_SIZE - (tlv_len % AES_BLOCK_SIZE);
+
+ *plain_len = tlv_len + pad_len;
+ *plain = os_zalloc(*plain_len);
+ if (*plain == NULL) {
+ wpa_printf(MSG_ERROR, "FT: Failed to allocate plaintext");
+ goto err;
+ }
+
+ pos = *plain;
+ endpos = *plain + tlv_len;
+ pos += wpa_ft_tlv_lin(tlvs1, pos, endpos);
+ pos += wpa_ft_tlv_lin(tlvs2, pos, endpos);
+
+ /* sanity check */
+ if (pos != endpos) {
+ wpa_printf(MSG_ERROR, "FT: length error building RRB");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ os_free(*plain);
+ *plain = NULL;
+ *plain_len = 0;
+ return -1;
+}
+
+
+static int wpa_ft_rrb_encrypt(const u8 *key, const size_t key_len,
+ const u8 *plain, const size_t plain_len,
+ const u8 *auth, const size_t auth_len,
+ const u8 *src_addr, const u8 type, u8 *enc)
+{
+ const u8 *ad[4] = { src_addr, auth, &type, (u8 *) ft_rrb_ad };
+ size_t ad_len[4] = { ETH_ALEN, auth_len, sizeof(type),
+ os_strlen(ft_rrb_ad) };
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: encrypt using key", key, key_len);
+
+ if (!key)
+ /* encryption not needed, return plaintext as packet */
+ os_memcpy(enc, plain, plain_len);
+ else if (aes_siv_encrypt(key, key_len, plain, plain_len, 4, ad,
+ ad_len, enc) < 0) {
+ wpa_printf(MSG_ERROR, "FT: Failed to encrypt RRB-OUI message");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * encrypt message
+ * @frame ft_rrb_frame
+ * @key encryption and mac key
+ * @packet pointer to store pointer for ciphertext
+ * (only action_length many bytes)
+ * needs to be freed by caller if not null
+ * will only be returned on success
+ * @return 0 on success, -1 on error
+ */
+static int wpa_ft_rrb_build(const u8 *key, const size_t key_len,
+ const struct tlv_list *tlvs_enc0,
+ const struct tlv_list *tlvs_enc1,
+ const struct tlv_list *tlvs_auth,
+ const u8 *src_addr, const u8 type,
+ u8 **packet, size_t *packet_len)
+{
+ u8 *plain = NULL, *auth = NULL, *enc;
+ size_t plain_len, auth_len;
+ u16 *head;
+ int ret = -1;
+
+ if (wpa_ft_rrb_lin(tlvs_enc0, tlvs_enc1, key ? 1 : 0,
+ &plain, &plain_len) < 0)
+ goto out;
+
+ if (wpa_ft_rrb_lin(tlvs_auth, NULL, 0, &auth, &auth_len) < 0)
+ goto out;
+
+ *packet_len = sizeof(*head) + auth_len + plain_len;
+ if (key)
+ *packet_len += AES_BLOCK_SIZE;
+ *packet = os_zalloc(*packet_len);
+
+ if (*packet == NULL)
+ goto out;
+
+ enc = *packet + sizeof(*head) + auth_len;
+ if (wpa_ft_rrb_encrypt(key, key_len, plain, plain_len, auth,
+ auth_len, src_addr, type, enc) < 0)
+ goto out;
+
+ os_memcpy(*packet + sizeof(*head), auth, auth_len);
+
+ head = (u16 *) *packet;
+ *head = host_to_le16(auth_len);
+
+ ret = 0;
+
+out:
+ os_free(plain);
+ os_free(auth);
+
+ if (ret) {
+ wpa_printf(MSG_ERROR, "FT: Failed to build RRB-OUI message");
+ os_free(*packet);
+ *packet = NULL;
+ *packet_len = 0;
+ }
+
+ return ret;
+}
+
+
+#define RRB_GET_SRC(srcfield, type, field, txt, checklength) do { \
+ if (wpa_ft_rrb_get_tlv(srcfield, srcfield##_len, type, \
+ &f_##field##_len, &f_##field) < 0 || \
+ (checklength > 0 && ((size_t) checklength) != f_##field##_len)) { \
+ wpa_printf(MSG_DEBUG, "FT: Missing required " #field " in " \
+ "%s from " MACSTR, txt, MAC2STR(src_addr)); \
+ wpa_ft_rrb_dump(srcfield, srcfield##_len); \
+ goto out; \
+ } \
+} while (0)
+
+#define RRB_GET(type, field, txt, checklength) \
+ RRB_GET_SRC(plain, type, field, txt, checklength)
+#define RRB_GET_AUTH(type, field, txt, checklength) \
+ RRB_GET_SRC(auth, type, field, txt, checklength)
+
+#define RRB_GET_OPTIONAL_SRC(srcfield, type, field, txt, checklength) do { \
+ if (wpa_ft_rrb_get_tlv(srcfield, srcfield##_len, type, \
+ &f_##field##_len, &f_##field) < 0 || \
+ (checklength > 0 && ((size_t) checklength) != f_##field##_len)) { \
+ wpa_printf(MSG_DEBUG, "FT: Missing optional " #field " in " \
+ "%s from " MACSTR, txt, MAC2STR(src_addr)); \
+ f_##field##_len = 0; \
+ f_##field = NULL; \
+ } \
+} while (0)
+
+#define RRB_GET_OPTIONAL(type, field, txt, checklength) \
+ RRB_GET_OPTIONAL_SRC(plain, type, field, txt, checklength)
+#define RRB_GET_OPTIONAL_AUTH(type, field, txt, checklength) \
+ RRB_GET_OPTIONAL_SRC(auth, type, field, txt, checklength)
static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
const u8 *data, size_t data_len)
@@ -252,7 +622,7 @@ static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
const u8 *spa, const u8 *pmk_r0_name,
- u8 *pmk_r0, int *pairwise)
+ const struct wpa_ft_pmk_r0_sa **r0_out)
{
struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
struct wpa_ft_pmk_r0_sa *r0;
@@ -262,15 +632,14 @@ static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
os_memcmp_const(r0->pmk_r0_name, pmk_r0_name,
WPA_PMK_NAME_LEN) == 0) {
- os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN);
- if (pairwise)
- *pairwise = r0->pairwise;
+ *r0_out = r0;
return 0;
}
r0 = r0->next;
}
+ *r0_out = NULL;
return -1;
}
@@ -325,48 +694,125 @@ static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
}
+static void wpa_ft_rrb_lookup_r0kh(struct wpa_authenticator *wpa_auth,
+ const u8 *src_addr, const u8 *f_r0kh_id,
+ size_t f_r0kh_id_len,
+ struct ft_remote_r0kh **r0kh_out)
+{
+ struct ft_remote_r0kh *r0kh;
+
+ r0kh = wpa_auth->conf.r0kh_list;
+ for (; r0kh; r0kh = r0kh->next) {
+ if (src_addr && os_memcmp(r0kh->addr, src_addr, ETH_ALEN))
+ continue;
+ if (f_r0kh_id && (r0kh->id_len != f_r0kh_id_len ||
+ os_memcmp_const(f_r0kh_id, r0kh->id, f_r0kh_id_len)))
+ continue;
+ break;
+ }
+
+ if (!r0kh)
+ wpa_printf(MSG_DEBUG, "FT: No matching R0KH found");
+
+ *r0kh_out = r0kh;
+}
+
+
+static void wpa_ft_rrb_lookup_r1kh(struct wpa_authenticator *wpa_auth,
+ const u8 *src_addr, const u8 *f_r1kh_id,
+ struct ft_remote_r1kh **r1kh_out)
+{
+ struct ft_remote_r1kh *r1kh;
+
+ r1kh = wpa_auth->conf.r1kh_list;
+ for (; r1kh; r1kh = r1kh->next) {
+ if (src_addr && os_memcmp(r1kh->addr, src_addr, ETH_ALEN))
+ continue;
+ if (f_r1kh_id &&
+ os_memcmp_const(r1kh->id, f_r1kh_id, FT_R1KH_ID_LEN))
+ continue;
+ break;
+ }
+
+ if (!r1kh)
+ wpa_printf(MSG_DEBUG, "FT: No matching R1KH found");
+
+ *r1kh_out = r1kh;
+}
+
+
+static int wpa_ft_rrb_check_r0kh(struct wpa_authenticator *wpa_auth,
+ const u8 *f_r0kh_id, size_t f_r0kh_id_len)
+{
+ if (f_r0kh_id_len != wpa_auth->conf.r0_key_holder_len ||
+ os_memcmp_const(f_r0kh_id, wpa_auth->conf.r0_key_holder,
+ f_r0kh_id_len) != 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int wpa_ft_rrb_check_r1kh(struct wpa_authenticator *wpa_auth,
+ const u8 *f_r1kh_id)
+{
+ if (os_memcmp_const(f_r1kh_id, wpa_auth->conf.r1_key_holder,
+ FT_R1KH_ID_LEN) != 0)
+ return -1;
+
+ return 0;
+}
+
+
static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
const u8 *ies, size_t ies_len,
const u8 *pmk_r0_name)
{
struct ft_remote_r0kh *r0kh;
- struct ft_r0kh_r1kh_pull_frame frame, f;
+ u8 *packet = NULL;
+ const u8 *key;
+ size_t packet_len, key_len;
- r0kh = sm->wpa_auth->conf.r0kh_list;
- while (r0kh) {
- if (r0kh->id_len == sm->r0kh_id_len &&
- os_memcmp_const(r0kh->id, sm->r0kh_id, sm->r0kh_id_len) ==
- 0)
- break;
- r0kh = r0kh->next;
- }
+ wpa_ft_rrb_lookup_r0kh(sm->wpa_auth, NULL, sm->r0kh_id, sm->r0kh_id_len,
+ &r0kh);
if (r0kh == NULL) {
wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID",
sm->r0kh_id, sm->r0kh_id_len);
return -1;
}
+ key = r0kh->key;
+ key_len = sizeof(r0kh->key);
- wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
- "address " MACSTR, MAC2STR(r0kh->addr));
+ wpa_printf(MSG_DEBUG, "FT: Send pull request to remote R0KH address "
+ MACSTR, MAC2STR(r0kh->addr));
- os_memset(&frame, 0, sizeof(frame));
- /* aes_wrap() does not support inplace encryption, so use a temporary
- * buffer for the data. */
- if (random_get_bytes(f.nonce, FT_R0KH_R1KH_PULL_NONCE_LEN)) {
+ if (random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
"nonce");
return -1;
}
- os_memcpy(sm->ft_pending_pull_nonce, f.nonce,
- FT_R0KH_R1KH_PULL_NONCE_LEN);
- os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
- os_memcpy(f.r1kh_id, sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
- os_memcpy(f.s1kh_id, sm->addr, ETH_ALEN);
- os_memset(f.pad, 0, sizeof(f.pad));
- if (aes_wrap(r0kh->key, sizeof(r0kh->key),
- (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
- f.nonce, frame.nonce) < 0)
+ struct tlv_list req_enc[] = {
+ { .type = FT_RRB_PMK_R0_NAME, .len = WPA_PMK_NAME_LEN,
+ .data = pmk_r0_name },
+ { .type = FT_RRB_S1KH_ID, .len = ETH_ALEN,
+ .data = sm->addr },
+ { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
+ };
+
+ struct tlv_list req_auth[] = {
+ { .type = FT_RRB_NONCE, .len = FT_RRB_NONCE_LEN,
+ .data = sm->ft_pending_pull_nonce },
+ { .type = FT_RRB_R0KH_ID, .len = sm->r0kh_id_len,
+ .data = sm->r0kh_id },
+ { .type = FT_RRB_R1KH_ID, .len = FT_R1KH_ID_LEN,
+ .data = sm->wpa_auth->conf.r1_key_holder },
+ { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
+ };
+
+ if (wpa_ft_rrb_build(key, key_len, req_enc, NULL, req_auth,
+ sm->wpa_auth->addr, FT_PACKET_R0KH_R1KH_PULL,
+ &packet, &packet_len) < 0)
return -1;
wpabuf_free(sm->ft_pending_req_ies);
@@ -375,7 +821,10 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
return -1;
wpa_ft_rrb_oui_send(sm->wpa_auth, r0kh->addr, FT_PACKET_R0KH_R1KH_PULL,
- (u8 *) &frame, sizeof(frame));
+ packet, packet_len);
+
+ os_free(packet);
+ packet = NULL;
return 0;
}
@@ -1422,99 +1871,215 @@ static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
}
+static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len,
+ const struct tlv_list *tlvs,
+ const struct wpa_ft_pmk_r0_sa *pmk_r0,
+ const u8 *r1kh_id, const u8 *s1kh_id,
+ const struct tlv_list *tlv_auth,
+ const u8 *src_addr, const u8 type,
+ u8 **packet, size_t *packet_len)
+{
+ u8 pmk_r1[PMK_LEN];
+ u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+ u8 f_pairwise[sizeof(le16)];
+ int ret;
+
+ if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh_id,
+ s1kh_id, pmk_r1, pmk_r1_name) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
+ WPA_PUT_LE16(f_pairwise, pmk_r0->pairwise);
+
+ struct tlv_list sess_tlv[] = {
+ { .type = FT_RRB_PMK_R1, .len = sizeof(pmk_r1),
+ .data = pmk_r1 },
+ { .type = FT_RRB_PMK_R1_NAME, .len = sizeof(pmk_r1_name),
+ .data = pmk_r1_name },
+ { .type = FT_RRB_PAIRWISE, .len = sizeof(f_pairwise),
+ .data = f_pairwise },
+ { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
+ };
+
+ ret = wpa_ft_rrb_build(key, key_len, tlvs, sess_tlv, tlv_auth,
+ src_addr, type, packet, packet_len);
+
+ os_memset(pmk_r1, 0, sizeof(pmk_r1));
+
+ return ret;
+
+}
+
+
static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
const u8 *src_addr,
- const u8 *data, size_t data_len)
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len)
{
- struct ft_r0kh_r1kh_pull_frame f;
- const u8 *crypt;
- u8 *plain;
+ const char *msgtype = "pull request";
+ const int type = FT_PACKET_R0KH_R1KH_PULL;
+ u8 *plain = NULL, *packet = NULL;
+ size_t plain_len = 0, packet_len = 0;
struct ft_remote_r1kh *r1kh;
- struct ft_r0kh_r1kh_resp_frame resp, r;
- u8 pmk_r0[PMK_LEN];
+ const u8 *key = NULL;
+ size_t key_len = 0;
+ const u8 *f_nonce, *f_r0kh_id, *f_r1kh_id, *f_s1kh_id, *f_pmk_r0_name;
+ size_t f_nonce_len, f_r0kh_id_len, f_r1kh_id_len, f_s1kh_id_len;
+ size_t f_pmk_r0_name_len;
+ const struct wpa_ft_pmk_r0_sa *r0;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, "FT: Received %s from " MACSTR,
+ msgtype, MAC2STR(src_addr));
+
+ RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, msgtype, -1);
+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", f_r0kh_id, f_r0kh_id_len);
+
+ if (wpa_ft_rrb_check_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len)) {
+ wpa_printf(MSG_DEBUG, "FT: R0KH-ID mismatch");
+ goto out;
+ }
+
+ RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, msgtype, FT_R1KH_ID_LEN);
+ wpa_printf(MSG_DEBUG, "FT: R1KH-ID=" MACSTR, MAC2STR(f_r1kh_id));
+
+ wpa_ft_rrb_lookup_r1kh(wpa_auth, src_addr, f_r1kh_id, &r1kh);
+ if (r1kh == NULL)
+ goto out;
+ key = r1kh->key;
+ key_len = sizeof(r1kh->key);
+
+ RRB_GET_AUTH(FT_RRB_NONCE, nonce, "pull request", FT_RRB_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: nonce", f_nonce, f_nonce_len);
+
+ if (wpa_ft_rrb_decrypt(key, key_len, enc, enc_len, auth, auth_len,
+ src_addr, type, &plain, &plain_len) < 0)
+ goto out;
+
+ RRB_GET(FT_RRB_PMK_R0_NAME, pmk_r0_name, msgtype, WPA_PMK_NAME_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", f_pmk_r0_name,
+ f_pmk_r0_name_len);
+
+ RRB_GET(FT_RRB_S1KH_ID, s1kh_id, msgtype, ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "FT: S1KH-ID=" MACSTR, MAC2STR(f_s1kh_id));
+
+ struct tlv_list resp[] = {
+ { .type = FT_RRB_S1KH_ID, .len = f_s1kh_id_len,
+ .data = f_s1kh_id },
+ { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
+ };
+ struct tlv_list resp_auth[] = {
+ { .type = FT_RRB_NONCE, .len = f_nonce_len,
+ .data = f_nonce },
+ { .type = FT_RRB_R0KH_ID, .len = f_r0kh_id_len,
+ .data = f_r0kh_id },
+ { .type = FT_RRB_R1KH_ID, .len = f_r1kh_id_len,
+ .data = f_r1kh_id },
+ { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
+ };
+
+ if (wpa_ft_fetch_pmk_r0(wpa_auth, f_s1kh_id, f_pmk_r0_name, &r0) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: No matching PMK-R0-Name found");
+ goto out;
+ }
+
+ ret = wpa_ft_rrb_build_r0(key, key_len, resp, r0, f_r1kh_id, f_s1kh_id,
+ resp_auth, wpa_auth->addr,
+ FT_PACKET_R0KH_R1KH_RESP,
+ &packet, &packet_len);
+
+ if (!ret)
+ wpa_ft_rrb_oui_send(wpa_auth, src_addr,
+ FT_PACKET_R0KH_R1KH_RESP, packet,
+ packet_len);
+
+out:
+ os_free(plain); plain = NULL;
+ os_free(packet); packet = NULL;
+
+ return 0;
+}
+
+
+/* @returns 0 on success
+ * -1 on error
+ */
+static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth,
+ const u8 *src_addr, const u8 type,
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len,
+ const char *msgtype, u8 *s1kh_id_out)
+{
+ u8 *plain = NULL;
+ size_t plain_len = 0;
+ struct ft_remote_r0kh *r0kh;
+ const u8 *key;
+ size_t key_len;
+ const u8 *f_r1kh_id, *f_s1kh_id, *f_r0kh_id;
+ const u8 *f_pmk_r1_name, *f_pairwise, *f_pmk_r1;
+ size_t f_r1kh_id_len, f_s1kh_id_len, f_r0kh_id_len;
+ size_t f_pmk_r1_name_len, f_pairwise_len, f_pmk_r1_len;
int pairwise;
+ int ret = -1;
- wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
+ RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, msgtype, -1);
+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", f_r0kh_id, f_r0kh_id_len);
- if (data_len < sizeof(f))
- return -1;
+ RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, msgtype, FT_R1KH_ID_LEN);
+ wpa_printf(MSG_DEBUG, "FT: R1KH-ID=" MACSTR, MAC2STR(f_r1kh_id));
- r1kh = wpa_auth->conf.r1kh_list;
- while (r1kh) {
- if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0)
- break;
- r1kh = r1kh->next;
- }
- if (r1kh == NULL) {
- wpa_printf(MSG_DEBUG, "FT: No matching R1KH address found for "
- "PMK-R1 pull source address " MACSTR,
- MAC2STR(src_addr));
- return -1;
+ if (wpa_ft_rrb_check_r1kh(wpa_auth, f_r1kh_id)) {
+ wpa_printf(MSG_DEBUG, "FT: R1KH-ID mismatch");
+ goto out;
}
- crypt = data + offsetof(struct ft_r0kh_r1kh_pull_frame, nonce);
- os_memset(&f, 0, sizeof(f));
- plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_pull_frame, nonce);
- /* aes_unwrap() does not support inplace decryption, so use a temporary
- * buffer for the data. */
- if (aes_unwrap(r1kh->key, sizeof(r1kh->key),
- (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
- crypt, plain) < 0) {
- wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
- "request from " MACSTR, MAC2STR(src_addr));
- return -1;
- }
+ wpa_ft_rrb_lookup_r0kh(wpa_auth, src_addr, f_r0kh_id, f_r0kh_id_len,
+ &r0kh);
+ if (r0kh == NULL)
+ goto out;
+ key = r0kh->key;
+ key_len = sizeof(r0kh->key);
- wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
- f.nonce, sizeof(f.nonce));
- wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name",
- f.pmk_r0_name, WPA_PMK_NAME_LEN);
- wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
- MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
-
- os_memset(&resp, 0, sizeof(resp));
- /* aes_wrap() does not support inplace encryption, so use a temporary
- * buffer for the data. */
- os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
- os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN);
- os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN);
- if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0,
- &pairwise) < 0) {
- wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for "
- "PMK-R1 pull");
- return -1;
- }
+ if (wpa_ft_rrb_decrypt(key, key_len, enc, enc_len, auth, auth_len,
+ src_addr, type, &plain, &plain_len) < 0)
+ goto out;
- if (wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
- r.pmk_r1, r.pmk_r1_name) < 0) {
- os_memset(pmk_r0, 0, PMK_LEN);
- return -1;
- }
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
- WPA_PMK_NAME_LEN);
- r.pairwise = host_to_le16(pairwise);
- os_memset(r.pad, 0, sizeof(r.pad));
+ RRB_GET(FT_RRB_S1KH_ID, s1kh_id, msgtype, ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "FT: S1KH-ID=" MACSTR, MAC2STR(f_s1kh_id));
- if (aes_wrap(r1kh->key, sizeof(r1kh->key),
- (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
- r.nonce, resp.nonce) < 0) {
- os_memset(pmk_r0, 0, PMK_LEN);
- return -1;
- }
+ if (s1kh_id_out)
+ os_memcpy(s1kh_id_out, f_s1kh_id, ETH_ALEN);
- os_memset(pmk_r0, 0, PMK_LEN);
+ RRB_GET(FT_RRB_PAIRWISE, pairwise, msgtype, sizeof(le16));
+ wpa_hexdump(MSG_DEBUG, "FT: pairwise", f_pairwise, f_pairwise_len);
- wpa_ft_rrb_oui_send(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_RESP,
- (u8 *) &resp, sizeof(resp));
+ RRB_GET(FT_RRB_PMK_R1_NAME, pmk_r1_name, msgtype, WPA_PMK_NAME_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
+ f_pmk_r1_name, WPA_PMK_NAME_LEN);
+
+ RRB_GET(FT_RRB_PMK_R1, pmk_r1, msgtype, PMK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f_pmk_r1, PMK_LEN);
+
+ pairwise = WPA_GET_LE16(f_pairwise);
+
+ if (wpa_ft_store_pmk_r1(wpa_auth, f_s1kh_id, f_pmk_r1, f_pmk_r1_name,
+ pairwise) < 0)
+ goto out;
+
+ ret = 0;
+out:
+ if (plain) {
+ os_memset(plain, 0, plain_len);
+ os_free(plain); plain = NULL;
+ }
+
+ return ret;
- return 0;
}
-static void ft_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx)
+static void ft_finish_pull(struct wpa_state_machine *sm)
{
- struct wpa_state_machine *sm = eloop_ctx;
int res;
u8 *resp_ies;
size_t resp_ies_len;
@@ -1538,169 +2103,106 @@ static void ft_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx)
}
-static int ft_pull_resp_cb(struct wpa_state_machine *sm, void *ctx)
+struct ft_get_sta_ctx {
+ const u8 *nonce;
+ const u8 *s1kh_id;
+ struct wpa_state_machine *sm;
+};
+
+
+static int ft_get_sta_cb(struct wpa_state_machine *sm, void *ctx)
{
- struct ft_r0kh_r1kh_resp_frame *frame = ctx;
+ struct ft_get_sta_ctx *info = ctx;
- if (os_memcmp(frame->s1kh_id, sm->addr, ETH_ALEN) != 0 ||
- os_memcmp(frame->nonce, sm->ft_pending_pull_nonce,
- FT_R0KH_R1KH_PULL_NONCE_LEN) != 0 ||
+ if ((info->s1kh_id && os_memcmp(info->s1kh_id, sm->addr, ETH_ALEN)) ||
+ os_memcmp(info->nonce, sm->ft_pending_pull_nonce,
+ FT_RRB_NONCE_LEN) != 0 ||
sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
return 0;
- wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for "
- MACSTR " - process from timeout", MAC2STR(sm->addr));
- eloop_register_timeout(0, 0, ft_pull_resp_cb_finish, sm, NULL);
+ info->sm = sm;
+
return 1;
}
static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
const u8 *src_addr,
- const u8 *data, size_t data_len)
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len)
{
- struct ft_r0kh_r1kh_resp_frame f;
- const u8 *crypt;
- u8 *plain;
- struct ft_remote_r0kh *r0kh;
- int pairwise, res;
-
- wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
-
- if (data_len < sizeof(f))
- return -1;
-
- r0kh = wpa_auth->conf.r0kh_list;
- while (r0kh) {
- if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
- break;
- r0kh = r0kh->next;
- }
- if (r0kh == NULL) {
- wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
- "PMK-R0 pull response source address " MACSTR,
- MAC2STR(src_addr));
+ const char *msgtype = "pull response";
+ const int type = FT_PACKET_R0KH_R1KH_RESP;
+ int ret = -1;
+ struct ft_get_sta_ctx ctx;
+ u8 s1kh_id[ETH_ALEN];
+ const u8 *f_nonce;
+ size_t f_nonce_len;
+
+ wpa_printf(MSG_DEBUG, "FT: Received %s", msgtype);
+
+ RRB_GET_AUTH(FT_RRB_NONCE, nonce, msgtype, FT_RRB_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: nonce", f_nonce, f_nonce_len);
+
+ os_memset(&ctx, 0, sizeof(ctx));
+ ctx.nonce = f_nonce;
+ if (!wpa_auth_for_each_sta(wpa_auth, ft_get_sta_cb, &ctx)) {
+ /* nonce not found */
+ wpa_printf(MSG_DEBUG, "FT: Invalid nonce");
return -1;
}
- crypt = data + offsetof(struct ft_r0kh_r1kh_resp_frame, nonce);
- os_memset(&f, 0, sizeof(f));
- plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_resp_frame, nonce);
- /* aes_unwrap() does not support inplace decryption, so use a temporary
- * buffer for the data. */
- if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
- (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
- crypt, plain) < 0) {
- wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
- "response from " MACSTR, MAC2STR(src_addr));
+ ret = wpa_ft_rrb_rx_r1(wpa_auth, src_addr, type, enc, enc_len, auth,
+ auth_len, msgtype, s1kh_id);
+ if (ret < 0)
return -1;
- }
- if (os_memcmp_const(f.r1kh_id, wpa_auth->conf.r1_key_holder,
- FT_R1KH_ID_LEN) != 0) {
- wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a "
- "matching R1KH-ID");
- return -1;
+ ctx.s1kh_id = s1kh_id;
+ if (!ret && wpa_auth_for_each_sta(wpa_auth, ft_get_sta_cb, &ctx)) {
+ wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request "
+ "for " MACSTR " - process from timeout",
+ MAC2STR(ctx.sm->addr));
+ ft_finish_pull(ctx.sm);
}
- pairwise = le_to_host16(f.pairwise);
- wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
- f.nonce, sizeof(f.nonce));
- wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
- MACSTR " pairwise=0x%x",
- MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1",
- f.pmk_r1, PMK_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name",
- f.pmk_r1_name, WPA_PMK_NAME_LEN);
-
- res = wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
- pairwise);
- wpa_printf(MSG_DEBUG, "FT: Look for pending pull request");
- wpa_auth_for_each_sta(wpa_auth, ft_pull_resp_cb, &f);
- os_memset(f.pmk_r1, 0, PMK_LEN);
-
- return res ? 0 : -1;
+out:
+ return ret;
}
static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
const u8 *src_addr,
- const u8 *data, size_t data_len)
+ const u8 *enc, size_t enc_len,
+ const u8 *auth, size_t auth_len)
{
- struct ft_r0kh_r1kh_push_frame f;
- const u8 *crypt;
- u8 *plain;
- struct ft_remote_r0kh *r0kh;
+ const char *msgtype = "push";
+ const int type = FT_PACKET_R0KH_R1KH_PUSH;
struct os_time now;
- os_time_t tsend;
- int pairwise;
-
- wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
-
- if (data_len < sizeof(f))
- return -1;
-
- r0kh = wpa_auth->conf.r0kh_list;
- while (r0kh) {
- if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
- break;
- r0kh = r0kh->next;
- }
- if (r0kh == NULL) {
- wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
- "PMK-R0 push source address " MACSTR,
- MAC2STR(src_addr));
- return -1;
- }
+ struct os_time tsend;
+ const u8 *f_timestamp;
+ size_t f_timestamp_len;
- crypt = data + offsetof(struct ft_r0kh_r1kh_push_frame, timestamp);
- os_memset(&f, 0, sizeof(f));
- plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_push_frame,
- timestamp);
- /* aes_unwrap() does not support inplace decryption, so use a temporary
- * buffer for the data. */
- if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
- (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
- crypt, plain) < 0) {
- wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
- MACSTR, MAC2STR(src_addr));
- return -1;
- }
+ wpa_printf(MSG_DEBUG, "FT: Received %s", msgtype);
+ RRB_GET_AUTH(FT_RRB_TIMESTAMP, timestamp, msgtype, sizeof(le32));
+ tsend.sec = WPA_GET_LE32(f_timestamp);
+ wpa_printf(MSG_DEBUG, "FT: timestamp=%ld", tsend.sec);
os_get_time(&now);
- tsend = WPA_GET_LE32(f.timestamp);
- if ((now.sec > tsend && now.sec - tsend > 60) ||
- (now.sec < tsend && tsend - now.sec > 60)) {
- wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not have a valid "
- "timestamp: sender time %d own time %d\n",
- (int) tsend, (int) now.sec);
+ if ((now.sec > tsend.sec && now.sec - tsend.sec > 60) ||
+ (now.sec < tsend.sec && tsend.sec - now.sec > 60)) {
+ wpa_printf(MSG_DEBUG, "FT: did not have a valid "
+ "timestamp: sender time %ld own time %ld\n",
+ tsend.sec, now.sec);
return -1;
}
- if (os_memcmp_const(f.r1kh_id, wpa_auth->conf.r1_key_holder,
- FT_R1KH_ID_LEN) != 0) {
- wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching "
- "R1KH-ID (received " MACSTR " own " MACSTR ")",
- MAC2STR(f.r1kh_id),
- MAC2STR(wpa_auth->conf.r1_key_holder));
+ if (wpa_ft_rrb_rx_r1(wpa_auth, src_addr, type, enc, enc_len, auth,
+ auth_len, msgtype, NULL) < 0)
return -1;
- }
-
- pairwise = le_to_host16(f.pairwise);
- wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID="
- MACSTR " pairwise=0x%x",
- MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1",
- f.pmk_r1, PMK_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name",
- f.pmk_r1_name, WPA_PMK_NAME_LEN);
-
- wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
- pairwise);
- os_memset(f.pmk_r1, 0, PMK_LEN);
return 0;
+out:
+ return -1;
}
@@ -1826,6 +2328,10 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
const u8 *dst_addr, u8 oui_suffix, const u8 *data,
size_t data_len)
{
+ const u16 *head;
+ const u8 *auth, *enc;
+ size_t alen, elen;
+
wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP "
MACSTR, MAC2STR(src_addr));
wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix);
@@ -1845,15 +2351,31 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
return;
}
+ head = (u16 *) data;
+ if (data_len < sizeof(*head)) {
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame too short");
+ return;
+ }
+
+ alen = le_to_host16(*head);
+ if (data_len < sizeof(*head) + alen) {
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame too short");
+ return;
+ }
+
+ auth = data + sizeof(*head);
+ enc = data + sizeof(*head) + alen;
+ elen = data_len - sizeof(*head) - alen;
+
switch (oui_suffix) {
case FT_PACKET_R0KH_R1KH_PULL:
- wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len);
+ wpa_ft_rrb_rx_pull(wpa_auth, src_addr, enc, elen, auth, alen);
break;
case FT_PACKET_R0KH_R1KH_RESP:
- wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len);
+ wpa_ft_rrb_rx_resp(wpa_auth, src_addr, enc, elen, auth, alen);
break;
case FT_PACKET_R0KH_R1KH_PUSH:
- wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len);
+ wpa_ft_rrb_rx_push(wpa_auth, src_addr, enc, elen, auth, alen);
break;
}
}
@@ -1862,41 +2384,45 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
struct wpa_ft_pmk_r0_sa *pmk_r0,
struct ft_remote_r1kh *r1kh,
- const u8 *s1kh_id, int pairwise)
+ const u8 *s1kh_id)
{
- struct ft_r0kh_r1kh_push_frame frame, f;
struct os_time now;
- const u8 *plain;
- u8 *crypt;
-
- os_memset(&frame, 0, sizeof(frame));
- /* aes_wrap() does not support inplace encryption, so use a temporary
- * buffer for the data. */
- os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
- os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
- os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN);
- if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
- s1kh_id, f.pmk_r1, f.pmk_r1_name) < 0)
- return -1;
- wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id));
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name,
- WPA_PMK_NAME_LEN);
+ u8 *packet;
+ size_t packet_len;
+ u8 f_timestamp[sizeof(le32)];
+
os_get_time(&now);
- WPA_PUT_LE32(f.timestamp, now.sec);
- f.pairwise = host_to_le16(pairwise);
- os_memset(f.pad, 0, sizeof(f.pad));
- plain = ((const u8 *) &f) + offsetof(struct ft_r0kh_r1kh_push_frame,
- timestamp);
- crypt = ((u8 *) &frame) + offsetof(struct ft_r0kh_r1kh_push_frame,
- timestamp);
- if (aes_wrap(r1kh->key, sizeof(r1kh->key),
- (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
- plain, crypt) < 0)
+ WPA_PUT_LE32(f_timestamp, now.sec);
+
+ struct tlv_list push[] = {
+ { .type = FT_RRB_S1KH_ID, .len = ETH_ALEN,
+ .data = s1kh_id },
+ { .type = FT_RRB_PMK_R0_NAME, .len = WPA_PMK_NAME_LEN,
+ .data = pmk_r0->pmk_r0_name },
+ { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
+ };
+ struct tlv_list push_auth[] = {
+ { .type = FT_RRB_TIMESTAMP, .len = sizeof(f_timestamp),
+ .data = f_timestamp },
+ { .type = FT_RRB_R0KH_ID,
+ .len = wpa_auth->conf.r0_key_holder_len,
+ .data = wpa_auth->conf.r0_key_holder },
+ { .type = FT_RRB_R1KH_ID, .len = FT_R1KH_ID_LEN,
+ .data = r1kh->id },
+ { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
+ };
+
+ if (wpa_ft_rrb_build_r0(r1kh->key, sizeof(r1kh->key), push, pmk_r0,
+ r1kh->id, s1kh_id, push_auth, wpa_auth->addr,
+ FT_PACKET_R0KH_R1KH_PUSH,
+ &packet, &packet_len) < 0)
return -1;
wpa_ft_rrb_oui_send(wpa_auth, r1kh->addr, FT_PACKET_R0KH_R1KH_PUSH,
- (u8 *) &frame, sizeof(frame));
+ packet, packet_len);
+
+ os_free(packet);
+ packet = NULL;
return 0;
}
@@ -1925,7 +2451,7 @@ void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
r1kh = wpa_auth->conf.r1kh_list;
while (r1kh) {
- wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr, r0->pairwise);
+ wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr);
r1kh = r1kh->next;
}
}
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 6f06f43..f9b3c07 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -800,7 +800,7 @@ static void hostapd_rrb_oui_receive(void *ctx, const u8 *src_addr,
{
struct hostapd_data *hapd = ctx;
- wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI received packet " MACSTR " -> "
MACSTR, MAC2STR(src_addr), MAC2STR(dst_addr));
if (!is_multicast_ether_addr(dst_addr) &&
os_memcmp(hapd->own_addr, dst_addr, ETH_ALEN) != 0)
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 90318d8..3279ad4 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -121,7 +121,7 @@ struct wpa_state_machine {
const u8 *ies, size_t ies_len);
void *ft_pending_cb_ctx;
struct wpabuf *ft_pending_req_ies;
- u8 ft_pending_pull_nonce[FT_R0KH_R1KH_PULL_NONCE_LEN];
+ u8 ft_pending_pull_nonce[FT_RRB_NONCE_LEN];
u8 ft_pending_auth_transaction;
u8 ft_pending_current_ap[ETH_ALEN];
#endif /* CONFIG_IEEE80211R_AP */
diff --git a/tests/hwsim/test_ap_ft.py b/tests/hwsim/test_ap_ft.py
index 298fd82..f73cc89 100644
--- a/tests/hwsim/test_ap_ft.py
+++ b/tests/hwsim/test_ap_ft.py
@@ -55,9 +55,9 @@ def ft_params1a(rsn=True, ssid=None, passphrase=None):
def ft_params1(rsn=True, ssid=None, passphrase=None):
params = ft_params1a(rsn, ssid, passphrase)
- params['r0kh'] = [ "02:00:00:00:03:00 nas1.w1.fi 100102030405060708090a0b0c0d0e0f",
- "02:00:00:00:04:00 nas2.w1.fi 300102030405060708090a0b0c0d0e0f" ]
- params['r1kh'] = "02:00:00:00:04:00 00:01:02:03:04:06 200102030405060708090a0b0c0d0e0f"
+ params['r0kh'] = [ "02:00:00:00:03:00 nas1.w1.fi 100102030405060708090a0b0c0d0e0f100102030405060708090a0b0c0d0e0f",
+ "02:00:00:00:04:00 nas2.w1.fi 300102030405060708090a0b0c0d0e0f300102030405060708090a0b0c0d0e0f" ]
+ params['r1kh'] = "02:00:00:00:04:00 00:01:02:03:04:06 200102030405060708090a0b0c0d0e0f200102030405060708090a0b0c0d0e0f"
return params
def ft_params2a(rsn=True, ssid=None, passphrase=None):
@@ -68,36 +68,36 @@ def ft_params2a(rsn=True, ssid=None, passphrase=None):
def ft_params2(rsn=True, ssid=None, passphrase=None):
params = ft_params2a(rsn, ssid, passphrase)
- params['r0kh'] = [ "02:00:00:00:03:00 nas1.w1.fi 200102030405060708090a0b0c0d0e0f",
- "02:00:00:00:04:00 nas2.w1.fi 000102030405060708090a0b0c0d0e0f" ]
- params['r1kh'] = "02:00:00:00:03:00 00:01:02:03:04:05 300102030405060708090a0b0c0d0e0f"
+ params['r0kh'] = [ "02:00:00:00:03:00 nas1.w1.fi 200102030405060708090a0b0c0d0e0f200102030405060708090a0b0c0d0e0f",
+ "02:00:00:00:04:00 nas2.w1.fi 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f" ]
+ params['r1kh'] = "02:00:00:00:03:00 00:01:02:03:04:05 300102030405060708090a0b0c0d0e0f300102030405060708090a0b0c0d0e0f"
return params
def ft_params1_r0kh_mismatch(rsn=True, ssid=None, passphrase=None):
params = ft_params(rsn, ssid, passphrase)
params['nas_identifier'] = "nas1.w1.fi"
params['r1_key_holder'] = "000102030405"
- params['r0kh'] = [ "02:00:00:00:03:00 nas1.w1.fi 100102030405060708090a0b0c0d0e0f",
- "12:00:00:00:04:00 nas2.w1.fi 300102030405060708090a0b0c0d0e0f" ]
- params['r1kh'] = "12:00:00:00:04:00 10:01:02:03:04:06 200102030405060708090a0b0c0d0e0f"
+ params['r0kh'] = [ "02:00:00:00:03:00 nas1.w1.fi 100102030405060708090a0b0c0d0e0f100102030405060708090a0b0c0d0e0f",
+ "12:00:00:00:04:00 nas2.w1.fi 300102030405060708090a0b0c0d0e0f300102030405060708090a0b0c0d0e0f" ]
+ params['r1kh'] = "12:00:00:00:04:00 10:01:02:03:04:06 200102030405060708090a0b0c0d0e0f200102030405060708090a0b0c0d0e0f"
return params
def ft_params2_incorrect_rrb_key(rsn=True, ssid=None, passphrase=None):
params = ft_params(rsn, ssid, passphrase)
params['nas_identifier'] = "nas2.w1.fi"
params['r1_key_holder'] = "000102030406"
- params['r0kh'] = [ "02:00:00:00:03:00 nas1.w1.fi 200102030405060708090a0b0c0d0ef1",
- "02:00:00:00:04:00 nas2.w1.fi 000102030405060708090a0b0c0d0ef2" ]
- params['r1kh'] = "02:00:00:00:03:00 00:01:02:03:04:05 300102030405060708090a0b0c0d0ef3"
+ params['r0kh'] = [ "02:00:00:00:03:00 nas1.w1.fi 200102030405060708090a0b0c0d0ef1200102030405060708090a0b0c0d0ef1",
+ "02:00:00:00:04:00 nas2.w1.fi 000102030405060708090a0b0c0d0ef2000102030405060708090a0b0c0d0ef2" ]
+ params['r1kh'] = "02:00:00:00:03:00 00:01:02:03:04:05 300102030405060708090a0b0c0d0ef3300102030405060708090a0b0c0d0ef3"
return params
def ft_params2_r0kh_mismatch(rsn=True, ssid=None, passphrase=None):
params = ft_params(rsn, ssid, passphrase)
params['nas_identifier'] = "nas2.w1.fi"
params['r1_key_holder'] = "000102030406"
- params['r0kh'] = [ "12:00:00:00:03:00 nas1.w1.fi 200102030405060708090a0b0c0d0e0f",
- "02:00:00:00:04:00 nas2.w1.fi 000102030405060708090a0b0c0d0e0f" ]
- params['r1kh'] = "12:00:00:00:03:00 10:01:02:03:04:05 300102030405060708090a0b0c0d0e0f"
+ params['r0kh'] = [ "12:00:00:00:03:00 nas1.w1.fi 200102030405060708090a0b0c0d0e0f200102030405060708090a0b0c0d0e0f",
+ "02:00:00:00:04:00 nas2.w1.fi 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f" ]
+ params['r1kh'] = "12:00:00:00:03:00 10:01:02:03:04:05 300102030405060708090a0b0c0d0e0f300102030405060708090a0b0c0d0e0f"
return params
def run_roams(dev, apdev, hapd0, hapd1, ssid, passphrase, over_ds=False,
@@ -1037,7 +1037,7 @@ def test_ap_ft_ap_oom3(dev, apdev):
# This will fail due to not being able to send out PMK-R1 pull request
dev[0].roam(bssid1)
- with fail_test(hapd1, 1, "aes_wrap;wpa_ft_pull_pmk_r1"):
+ with fail_test(hapd1, 1, "aes_siv_encrypt;wpa_ft_pull_pmk_r1"):
# This will fail due to not being able to send out PMK-R1 pull request
dev[0].roam(bssid1)
@@ -1246,7 +1246,7 @@ def test_ap_ft_ap_oom10(dev, apdev):
bssid1 = hapd1.own_addr()
dev[0].scan_for_bss(bssid1, freq="2412")
- with fail_test(hapd0, 1, "aes_unwrap;wpa_ft_rrb_rx_pull"):
+ with fail_test(hapd0, 1, "aes_siv_decrypt;wpa_ft_rrb_rx_pull"):
# This will fail to roam
if "OK" not in dev[0].request("FT_DS " + bssid1):
raise Exception("FT_DS failed")
@@ -1258,13 +1258,13 @@ def test_ap_ft_ap_oom10(dev, apdev):
raise Exception("FT_DS failed")
wait_fail_trigger(hapd0, "GET_FAIL")
- with fail_test(hapd0, 1, "aes_wrap;wpa_ft_rrb_rx_pull"):
+ with fail_test(hapd0, 1, "aes_siv_encrypt;wpa_ft_rrb_rx_pull"):
# This will fail to roam
if "OK" not in dev[0].request("FT_DS " + bssid1):
raise Exception("FT_DS failed")
wait_fail_trigger(hapd0, "GET_FAIL")
- with fail_test(hapd1, 1, "aes_unwrap;wpa_ft_rrb_rx_resp"):
+ with fail_test(hapd1, 1, "aes_siv_decrypt;wpa_ft_rrb_rx_resp"):
# This will fail to roam
if "OK" not in dev[0].request("FT_DS " + bssid1):
raise Exception("FT_DS failed")
@@ -1286,7 +1286,7 @@ def test_ap_ft_ap_oom11(dev, apdev):
wait_fail_trigger(hapd0, "GET_FAIL")
dev[1].scan_for_bss(bssid0, freq="2412")
- with fail_test(hapd0, 1, "aes_wrap;wpa_ft_generate_pmk_r1"):
+ with fail_test(hapd0, 1, "aes_siv_encrypt;wpa_ft_generate_pmk_r1"):
dev[1].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
scan_freq="2412")
wait_fail_trigger(hapd0, "GET_FAIL")
diff --git a/tests/hwsim/test_hapd_ctrl.py b/tests/hwsim/test_hapd_ctrl.py
index d18a6b4..0a32fda 100644
--- a/tests/hwsim/test_hapd_ctrl.py
+++ b/tests/hwsim/test_hapd_ctrl.py
@@ -295,12 +295,12 @@ def test_hapd_ctrl_set_error_cases(dev, apdev):
"wep_key_len_broadcast 20",
"wep_rekey_period -1",
"wep_default_key 4",
- "r0kh 02:00:00:00:03:0q nas1.w1.fi 100102030405060708090a0b0c0d0e0f",
- "r0kh 02:00:00:00:03:00 12345678901234567890123456789012345678901234567890.nas1.w1.fi 100102030405060708090a0b0c0d0e0f",
- "r0kh 02:00:00:00:03:00 nas1.w1.fi 100q02030405060708090a0b0c0d0e0f",
- "r1kh 02:00:00:00:04:q0 00:01:02:03:04:06 200102030405060708090a0b0c0d0e0f",
- "r1kh 02:00:00:00:04:00 00:01:02:03:04:q6 200102030405060708090a0b0c0d0e0f",
- "r1kh 02:00:00:00:04:00 00:01:02:03:04:06 2q0102030405060708090a0b0c0d0e0f",
+ "r0kh 02:00:00:00:03:0q nas1.w1.fi 100102030405060708090a0b0c0d0e0f100102030405060708090a0b0c0d0e0f",
+ "r0kh 02:00:00:00:03:00 12345678901234567890123456789012345678901234567890.nas1.w1.fi 100102030405060708090a0b0c0d0e0f100102030405060708090a0b0c0d0e0f",
+ "r0kh 02:00:00:00:03:00 nas1.w1.fi 100q02030405060708090a0b0c0d0e0f100q02030405060708090a0b0c0d0e0f",
+ "r1kh 02:00:00:00:04:q0 00:01:02:03:04:06 200102030405060708090a0b0c0d0e0f200102030405060708090a0b0c0d0e0f",
+ "r1kh 02:00:00:00:04:00 00:01:02:03:04:q6 200102030405060708090a0b0c0d0e0f200102030405060708090a0b0c0d0e0f",
+ "r1kh 02:00:00:00:04:00 00:01:02:03:04:06 2q0102030405060708090a0b0c0d0e0f2q0102030405060708090a0b0c0d0e0f",
"roaming_consortium 1",
"roaming_consortium 12",
"roaming_consortium 112233445566778899aabbccddeeff00",
--
2.1.4
More information about the Hostap
mailing list