From 4e3f6b847a0c8734d9b8bcad77c071742ec99730 Mon Sep 17 00:00:00 2001 From: Henry Ptasinski Date: Wed, 10 Jan 2024 17:20:55 -0800 Subject: [PATCH] wlantest: Add test vectors for S1G BIP - CMAC and GMAC modes - 128-bit and 256-bit modes - normal BIP and BIP using BCE - test vectors with minimum and optional additional header elements in S1G beacon frames - S1G Beacon Compatibility element in some cases, no other beacon body components Signed-off-by: Henry Ptasinski Signed-off-by: Andrew Pope Signed-off-by: David Goodall --- src/common/ieee802_11_defs.h | 38 +++ wlantest/bip.c | 242 ++++++++++++++ wlantest/test_vectors.c | 604 +++++++++++++++++++++++++++++++++++ wlantest/wlantest.h | 6 + 4 files changed, 890 insertions(+) diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 12137dcf4..8fb230340 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -24,6 +24,13 @@ #define WLAN_FC_ISWEP 0x4000 #define WLAN_FC_HTC 0x8000 +#define WLAN_FC_S1G_BEACON_NEXT_TBTT 0x0100 +#define WLAN_FC_S1G_BEACON_COMP_SSID 0x0200 +#define WLAN_FC_S1G_BEACON_ANO 0x0400 +#define WLAN_FC_S1G_BEACON_BSS_BW 0x3800 +#define WLAN_FC_S1G_BEACON_SECURITY 0x4000 +#define WLAN_FC_S1G_BEACON_AP_PM 0x8000 + #define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2) #define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4) @@ -36,6 +43,7 @@ #define WLAN_FC_TYPE_MGMT 0 #define WLAN_FC_TYPE_CTRL 1 #define WLAN_FC_TYPE_DATA 2 +#define WLAN_FC_TYPE_EXT 3 /* management */ #define WLAN_FC_STYPE_ASSOC_REQ 0 @@ -77,6 +85,10 @@ #define WLAN_FC_STYPE_QOS_CFPOLL 14 #define WLAN_FC_STYPE_QOS_CFACKPOLL 15 +/* extension */ +#define WLAN_FC_STYPE_DMG_BEACON 0 +#define WLAN_FC_STYPE_S1G_BEACON 1 + /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 #define WLAN_AUTH_SHARED_KEY 1 @@ -954,6 +966,23 @@ struct ieee80211_hdr { #define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr)) +struct ieee80211_hdr_s1g_beacon { + le16 frame_control; + le16 duration_id; + u8 sa[6]; + u8 timestamp[4]; + u8 change_seq[1]; + /* followed by: + * 'u8 next_tbtt[3];' if the Next TBTT Present field in the + * Frame Control field is 1 + * 'u8 compressed_ssid[4];' if the Compressed SSID Present field in + * the Frame Control is 1 + * 'u8 ano[1];' if the ANO field in the Frame Control field is 1 + */ +} STRUCT_PACKED; + +#define IEEE80211_HDRLEN_S1G_BEACON (sizeof(struct ieee80211_hdr_s1g_beacon)) + #define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4)) struct ieee80211_mgmt { @@ -3007,6 +3036,15 @@ struct ieee80211_neighbor_ap_info { u8 data[0]; } STRUCT_PACKED; +/* S1G Beacon Compatibility element */ +struct ieee80211_s1g_beacon_compat { + u8 element_id; + u8 length; + le16 compat_info; + le16 beacon_interval; + le32 tsf_completion; +} STRUCT_PACKED; + #ifdef _MSC_VER #pragma pack(pop) #endif /* _MSC_VER */ diff --git a/wlantest/bip.c b/wlantest/bip.c index c73a15c98..9dd145ac3 100644 --- a/wlantest/bip.c +++ b/wlantest/bip.c @@ -67,6 +67,124 @@ u8 * bip_protect(const u8 *igtk, size_t igtk_len, u8 *frame, size_t len, } +#define MME_LEN_LESS_MIC 10 +#define MIC_ELEM_LEN_LESS_MIC 2 + +u8 * bip_protect_s1g_beacon(const u8 *igtk, size_t igtk_len, const u8 *frame, + size_t len, const u8 *ipn, int keyid, bool bce, + size_t *prot_len) +{ + u8 *prot, *pos, *buf; + u8 mic[16]; + u16 fc; + struct ieee80211_hdr_s1g_beacon *hdr; + struct ieee80211_s1g_beacon_compat *bc; + size_t plen, mic_len, element_len, buf_len; + size_t hdr_add_len = 0, bce_add_len = 0; + + mic_len = igtk_len == 32 ? 16 : 8; + if (bce) + element_len = MIC_ELEM_LEN_LESS_MIC + mic_len; + else + element_len = MME_LEN_LESS_MIC + mic_len; + + plen = len + element_len; /* add element length */ + prot = os_malloc(plen); + if (!prot) + return NULL; + os_memcpy(prot, frame, len); + pos = prot + len; + + /* Add MME/MIC element to the end of the frame */ + if (bce) { + bce_add_len = 6; /* AAD increases by 6 bytes for BCE */ + *pos++ = WLAN_EID_MIC; /* Element ID */ + *pos++ = element_len - 2; /* Length field */ + } else { + *pos++ = WLAN_EID_MMIE; /* Element ID */ + *pos++ = element_len - 2; /* Length field */ + WPA_PUT_LE16(pos, keyid); /* KeyID */ + pos += 2; + os_memcpy(pos, ipn, 6); /* BIPN */ + pos += 6; + } + os_memset(pos, 0, mic_len); /* MIC */ + + /* Duration (2) and Timestamp (4) are omitted from AAD, BIPN (6) is + * added if BCE is used */ + buf_len = plen - 6 + bce_add_len; + buf = os_malloc(buf_len); + if (!buf) { + os_free(prot); + return NULL; + } + + /* BIP AAD: FC SA ChangeSeq NextTBTT(if present) + * CompressedSSID(if present) ANO(if present), BIPN(if using BCE) */ + hdr = (struct ieee80211_hdr_s1g_beacon *) frame; + fc = le_to_host16(hdr->frame_control); + if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_EXT || + WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_S1G_BEACON) { + wpa_printf(MSG_ERROR, "Frame is not an S1G Beacon"); + os_free(prot); + os_free(buf); + return NULL; + } + + WPA_PUT_LE16(buf, fc); + os_memcpy(buf + 2, hdr->sa, ETH_ALEN); + os_memcpy(buf + 8, hdr->change_seq, 1); + if (fc & WLAN_FC_S1G_BEACON_NEXT_TBTT) + hdr_add_len += 3; + if (fc & WLAN_FC_S1G_BEACON_COMP_SSID) + hdr_add_len += 4; + if (fc & WLAN_FC_S1G_BEACON_ANO) + hdr_add_len++; + os_memcpy(buf + 9, prot + IEEE80211_HDRLEN_S1G_BEACON, hdr_add_len); + if (bce) + os_memcpy(buf + 9 + hdr_add_len, ipn, bce_add_len); + os_memcpy(buf + 9 + hdr_add_len + bce_add_len, + prot + IEEE80211_HDRLEN_S1G_BEACON + hdr_add_len, + plen - (IEEE80211_HDRLEN_S1G_BEACON + hdr_add_len)); + /* The S1G Beacon Compatibility element, when present, is the first + * element in the S1G Beacon frame body */ + if (len >= IEEE80211_HDRLEN_S1G_BEACON + hdr_add_len + + sizeof(struct ieee80211_s1g_beacon_compat)) { + bc = (struct ieee80211_s1g_beacon_compat *) + (buf + 9 + hdr_add_len + bce_add_len); + if (bc->element_id == WLAN_EID_S1G_BCN_COMPAT) { + wpa_printf(MSG_DEBUG, + "S1G Beacon Compatibility element found, masking TSF Completion field"); + os_memset(&bc->tsf_completion, 0, + sizeof(bc->tsf_completion)); + if (bce && keyid - 6 != (bc->compat_info & 0x80) >> 7) { + wpa_printf(MSG_ERROR, + "Key ID does not match BIGTK Key ID Index in S1G Beacon Compatibility element"); + os_free(prot); + os_free(buf); + return NULL; + } + } + } + + wpa_hexdump(MSG_MSGDUMP, "S1G BIP-CMAC AAD|Body(masked)", buf, buf_len); + + /* MIC = L(AES-128-CMAC(AAD || Frame Body), 0, 64) */ + if (omac1_aes_128(igtk, buf, buf_len, mic) < 0) { + os_free(prot); + os_free(buf); + return NULL; + } + os_free(buf); + + os_memcpy(pos, mic, mic_len); + wpa_hexdump(MSG_DEBUG, "S1G BIP-CMAC MIC", pos, mic_len); + + *prot_len = plen; + return prot; +} + + u8 * bip_gmac_protect(const u8 *igtk, size_t igtk_len, u8 *frame, size_t len, u8 *ipn, int keyid, size_t *prot_len) { @@ -131,3 +249,127 @@ u8 * bip_gmac_protect(const u8 *igtk, size_t igtk_len, u8 *frame, size_t len, *prot_len = plen; return prot; } + + +u8 * bip_gmac_protect_s1g_beacon(const u8 *igtk, size_t igtk_len, + const u8 *frame, size_t len, const u8 *ipn, + int keyid, bool bce, size_t *prot_len) +{ + u8 *prot, *pos, *buf; + u16 fc; + struct ieee80211_hdr_s1g_beacon *hdr; + struct ieee80211_s1g_beacon_compat *bc; + size_t plen, mic_len, element_len, buf_len; + size_t hdr_add_len = 0, bce_add_len = 0; + u8 nonce[12], *npos; + + mic_len = 16; + if (bce) + element_len = MIC_ELEM_LEN_LESS_MIC + mic_len; + else + element_len = MME_LEN_LESS_MIC + mic_len; + + plen = len + element_len; /* add element length */ + prot = os_malloc(plen); + if (!prot) + return NULL; + os_memcpy(prot, frame, len); + pos = prot + len; + /* Add MME/MIC element to the end of the frame */ + if (bce) { + bce_add_len = 6; + *pos++ = WLAN_EID_MIC; /* Element ID */ + *pos++ = element_len - 2; /* Length field */ + } else { + *pos++ = WLAN_EID_MMIE; /* Element ID */ + *pos++ = element_len - 2; /* Length field */ + WPA_PUT_LE16(pos, keyid); /* KeyID */ + pos += 2; + os_memcpy(pos, ipn, 6); /* BIPN */ + pos += 6; + } + os_memset(pos, 0, mic_len); /* MIC */ + + /* Duration (2) and Timestamp (4) are omitted from AAD, + * BIPN (6) is added if BCE is used */ + buf_len = plen - 6 + bce_add_len; + buf = os_malloc(buf_len); + if (!buf) { + os_free(prot); + return NULL; + } + + /* BIP AAD: FC SA ChangeSeq NextTBTT(if present) + * CompressedSSID(if present) ANO(if present) */ + hdr = (struct ieee80211_hdr_s1g_beacon *) frame; + fc = le_to_host16(hdr->frame_control); + if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_EXT || + WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_S1G_BEACON) { + wpa_printf(MSG_ERROR, "Frame is not an S1G Beacon"); + os_free(prot); + os_free(buf); + return NULL; + } + + WPA_PUT_LE16(buf, fc); + os_memcpy(buf + 2, hdr->sa, ETH_ALEN); + os_memcpy(buf + 8, hdr->change_seq, 1); + if (fc & WLAN_FC_S1G_BEACON_NEXT_TBTT) + hdr_add_len += 3; + if (fc & WLAN_FC_S1G_BEACON_COMP_SSID) + hdr_add_len += 4; + if (fc & WLAN_FC_S1G_BEACON_ANO) + hdr_add_len++; + os_memcpy(buf + 9, prot + IEEE80211_HDRLEN_S1G_BEACON, hdr_add_len); + if (bce) + os_memcpy(buf + 9 + hdr_add_len, ipn, bce_add_len); + os_memcpy(buf + 9 + hdr_add_len + bce_add_len, + prot + IEEE80211_HDRLEN_S1G_BEACON + hdr_add_len, + plen - (IEEE80211_HDRLEN_S1G_BEACON + hdr_add_len)); + /* The S1G Beacon Compatibility element, when present, is the first + * element in the S1G Beacon frame body */ + if (len >= IEEE80211_HDRLEN_S1G_BEACON + hdr_add_len + + sizeof(struct ieee80211_s1g_beacon_compat)) { + bc = (struct ieee80211_s1g_beacon_compat *) + (buf + 9 + hdr_add_len + bce_add_len); + if (bc->element_id == WLAN_EID_S1G_BCN_COMPAT) { + wpa_printf(MSG_DEBUG, + "S1G Beacon Compatibility element found, masking TSF Completion field"); + os_memset(&bc->tsf_completion, 0, + sizeof(bc->tsf_completion)); + if (bce && keyid - 6 != (bc->compat_info & 0x80) >> 7) { + wpa_printf(MSG_ERROR, + "Key ID does not match BIGTK Key ID Index in S1G Beacon Compatibility element"); + os_free(prot); + os_free(buf); + return NULL; + } + } + } + wpa_hexdump(MSG_MSGDUMP, "S1G BIP-GMAC AAD|Body(masked)", buf, buf_len); + + /* Nonce: SA | IPN */ + os_memcpy(nonce, hdr->sa, ETH_ALEN); + npos = nonce + ETH_ALEN; + *npos++ = ipn[5]; + *npos++ = ipn[4]; + *npos++ = ipn[3]; + *npos++ = ipn[2]; + *npos++ = ipn[1]; + *npos++ = ipn[0]; + wpa_hexdump(MSG_EXCESSIVE, "S1G BIP-GMAC Nonce", nonce, sizeof(nonce)); + + /* MIC = AES-GMAC(AAD || Frame Body) */ + if (aes_gmac(igtk, igtk_len, nonce, sizeof(nonce), buf, buf_len, pos) < + 0) { + os_free(prot); + os_free(buf); + return NULL; + } + os_free(buf); + + wpa_hexdump(MSG_DEBUG, "S1G BIP-GMAC MIC", pos, 16); + + *prot_len = plen; + return prot; +} diff --git a/wlantest/test_vectors.c b/wlantest/test_vectors.c index 3ee53ae24..350c9d319 100644 --- a/wlantest/test_vectors.c +++ b/wlantest/test_vectors.c @@ -381,6 +381,166 @@ static void test_vector_bip(void) } +static void test_vector_bip_s1g_beacon(void) +{ + const u8 igtk[] = { + 0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e, + 0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf + }; + const u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }; + /* FC 2 Dur 2 SA 6 Time 4 CS 1 Next 0/3 Comp 0/4 ANO 0/1 + * FC: prot 2 type 2 subtype 4 next 1 comp 1 ano 1 bss bw 3 sec 1 ap + * pm 1 + * S1G Beacon, no extra header fields, S1G Beacon Compatibility element + */ + const u8 frame[] = { + 0x1c, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, + 0x08, 0x80, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, + 0x78 + }; + u8 *prot; + size_t prot_len; + + wpa_printf(MSG_INFO, + "\nIEEE P802.11REVme/D4.0, J.9.2 S1G Beacon frame with BIP-CMAC-128, no optional header fields, S1G Beacon Compatibility element in body\n"); + + wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk)); + wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn)); + wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame)); + + prot = bip_protect_s1g_beacon(igtk, sizeof(igtk), frame, sizeof(frame), + ipn, 7, false, &prot_len); + if (!prot) { + wpa_printf(MSG_ERROR, + "Failed to protect S1G Beacon frame with BIP-CMAC-128"); + return; + } + + wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len); + os_free(prot); +} + + +static void test_vector_bip_s1g_beacon_ext(void) +{ + const u8 igtk[] = { + 0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e, + 0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf + }; + const u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }; + /* FC 2 Dur 2 SA 6 Time 4 CS 1 Next 0/3 Comp 0/4 ANO 0/1 + * FC: prot 2 type 2 subtype 4 next 1 comp 1 ano 1 bss bw 3 sec 1 ap + * pm 1 + * S1G Beacon, all possible extra header fields, no body fields */ + const u8 frame[] = { + 0x1c, 0x47, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + u8 *prot; + size_t prot_len; + + wpa_printf(MSG_INFO, + "\nIEEE P802.11REVme/D4.0, J.9.2 S1G Beacon frame with BIP-CMAC-128, all optional header fields, no body elements\n"); + + wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk)); + wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn)); + wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame)); + + prot = bip_protect_s1g_beacon(igtk, sizeof(igtk), frame, sizeof(frame), + ipn, 6, false, &prot_len); + if (!prot) { + wpa_printf(MSG_ERROR, + "Failed to protect S1G Beacon frame with BIP-CMAC-128"); + return; + } + + wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len); + os_free(prot); +} + + +static void test_vector_bip_s1g_beacon_bce(void) +{ + const u8 igtk[] = { + 0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e, + 0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf + }; + const u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }; + /* FC 2 Dur 2 SA 6 Time 4 CS 1 Next 0/3 Comp 0/4 ANO 0/1 + * FC: prot 2 type 2 subtype 4 next 1 comp 1 ano 1 bss bw 3 sec 1 ap + * pm 1 + * S1G Beacon, no extra header fields, S1G Beacon Compatibility element + */ + const u8 frame[] = { + 0x1c, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, + 0x08, 0x80, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, + 0x78 + }; + u8 *prot; + size_t prot_len; + + wpa_printf(MSG_INFO, + "\nIEEE P802.11REVme/D4.0, J.9.2 S1G Beacon frame with BIP-CMAC-128 using BCE, no optional header fields, S1G Beacon Compatibility element in body\n"); + + wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk)); + wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn)); + wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame)); + + prot = bip_protect_s1g_beacon(igtk, sizeof(igtk), frame, sizeof(frame), + ipn, 7, true, &prot_len); + if (!prot) { + wpa_printf(MSG_ERROR, + "Failed to protect S1G Beacon frame with BIP using BCE-CMAC-128"); + return; + } + + wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len); + os_free(prot); +} + + +static void test_vector_bip_s1g_beacon_bce_ext(void) +{ + const u8 igtk[] = { + 0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e, + 0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf + }; + const u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }; + /* FC 2 Dur 2 SA 6 Time 4 CS 1 Next 0/3 Comp 0/4 ANO 0/1 + * FC: prot 2 type 2 subtype 4 next 1 comp 1 ano 1 bss bw 3 sec 1 ap + * pm 1 + * S1G Beacon, all possible extra header fields, no body fields */ + const u8 frame[] = { + 0x1c, 0x47, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + u8 *prot; + size_t prot_len; + + wpa_printf(MSG_INFO, + "\nIEEE P802.11REVme/D4.0, J.9.2 S1G Beacon frame with BIP-CMAC-128 using BCE, all optional header fields, no body elements\n"); + + wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk)); + wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn)); + wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame)); + + prot = bip_protect_s1g_beacon(igtk, sizeof(igtk), frame, sizeof(frame), + ipn, 6, true, &prot_len); + if (!prot) { + wpa_printf(MSG_ERROR, + "Failed to protect S1G Beacon frame with BIP using BCE-CMAC-128"); + return; + } + + wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len); + os_free(prot); +} + + static void test_vector_ccmp_mgmt(void) { u8 tk[] = { 0x66, 0xed, 0x21, 0x04, 0x2f, 0x9f, 0x26, 0xd7, @@ -863,6 +1023,218 @@ static int test_vector_bip_gmac_128(void) } +static int test_vector_bip_gmac_128_s1g_beacon(void) +{ + const u8 igtk[] = { + 0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e, + 0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf + }; + const u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const u8 frame[] = { + 0x1c, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, + 0x78 + }; + const u8 res[] = { + 0x1c, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd5, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, + 0x78, 0x4c, 0x18, 0x06, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xa5, 0xb2, 0x42, 0xc1, 0xc1, + 0x1e, 0xab, 0x10, 0xc5, 0xa4, 0xe8, 0xb9, 0x53, + 0x66, 0x19, 0x38 + }; + u8 *prot; + size_t prot_len; + int err = 0; + + wpa_printf(MSG_INFO, + "\nIEEE P802.11REVme/D4.0, J.9.2 S1G Beacon frame with BIP-GMAC-128, no optional header fields, S1G Beacon Compatibility element in body\n"); + + wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk)); + wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn)); + wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame)); + + prot = bip_gmac_protect_s1g_beacon(igtk, sizeof(igtk), frame, + sizeof(frame), ipn, 6, false, + &prot_len); + if (!prot) { + wpa_printf(MSG_ERROR, + "Failed to protect S1G Beacon frame with BIP-GMAC-128"); + return 1; + } + + wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len); + if (prot_len != sizeof(res) || os_memcmp(res, prot, prot_len) != 0) { + wpa_printf(MSG_ERROR, + "S1G Beacon frame with BIP-GMAC-128 test vector mismatch"); + err++; + } + os_free(prot); + + return err; +} + + +static int test_vector_bip_gmac_128_s1g_beacon_ext(void) +{ + const u8 igtk[] = { + 0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e, + 0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf + }; + const u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const u8 frame[] = { + 0x1c, 0x47, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const u8 res[] = { + 0x1c, 0x47, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, + 0x18, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x39, 0xd0, 0x0c, 0xc2, 0xee, 0xd7, 0x4c, + 0x2a, 0xb7, 0x41, 0xcc, 0xf8, 0x08, 0x9b, 0x5b, + 0x08 + }; + u8 *prot; + size_t prot_len; + int err = 0; + + wpa_printf(MSG_INFO, + "\nIEEE P802.11REVme/D4.0, J.9.2 S1G Beacon frame with BIP-GMAC-128, all optional header fields, no body elements\n"); + + wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk)); + wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn)); + wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame)); + + prot = bip_gmac_protect_s1g_beacon(igtk, sizeof(igtk), frame, + sizeof(frame), ipn, 7, false, + &prot_len); + if (!prot) { + wpa_printf(MSG_ERROR, + "Failed to protect S1G Beacon frame with BIP-GMAC-128"); + return 1; + } + + wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len); + if (prot_len != sizeof(res) || os_memcmp(res, prot, prot_len) != 0) { + wpa_printf(MSG_ERROR, + "S1G Beacon frame with BIP-GMAC-128 test vector mismatch"); + err++; + } + os_free(prot); + + return err; +} + + +static int test_vector_bip_gmac_128_s1g_beacon_bce(void) +{ + const u8 igtk[] = { + 0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e, + 0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf + }; + const u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const u8 frame[] = { + 0x1c, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, + 0x78 + }; + const u8 res[] = { + 0x1c, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd5, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, + 0x78, 0x8c, 0x10, 0xa2, 0x5b, 0x7e, 0x67, 0x76, + 0xf0, 0x11, 0x57, 0xa4, 0xfb, 0x4a, 0x2d, 0x66, + 0xd0, 0x17, 0x66 + }; + u8 *prot; + size_t prot_len; + int err = 0; + + wpa_printf(MSG_INFO, + "\nIEEE P802.11REVme/D4.0, J.9.2 S1G Beacon frame with BIP-GMAC-128 using BCE, no optional header fields, S1G Beacon Compatibility element in body\n"); + + wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk)); + wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn)); + wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame)); + + prot = bip_gmac_protect_s1g_beacon(igtk, sizeof(igtk), frame, + sizeof(frame), ipn, 6, true, + &prot_len); + if (!prot) { + wpa_printf(MSG_ERROR, + "Failed to protect S1G Beacon frame with BIP-GMAC-128 using BCE"); + return 1; + } + + wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len); + if (prot_len != sizeof(res) || os_memcmp(res, prot, prot_len) != 0) { + wpa_printf(MSG_ERROR, + "S1G Beacon frame with BIP-GMAC-128 using BCE test vector mismatch"); + err++; + } + os_free(prot); + + return err; +} + + +static int test_vector_bip_gmac_128_s1g_beacon_bce_ext(void) +{ + const u8 igtk[] = { + 0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e, + 0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf + }; + const u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const u8 frame[] = { + 0x1c, 0x47, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const u8 res[] = { + 0x1c, 0x47, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, + 0x10, 0x86, 0xdd, 0xb6, 0xc0, 0x56, 0x21, 0x30, + 0x9d, 0x3e, 0xbd, 0x25, 0x96, 0x67, 0x5b, 0xdd, + 0xc3 + }; + u8 *prot; + size_t prot_len; + int err = 0; + + wpa_printf(MSG_INFO, + "\nIEEE P802.11REVme/D4.0, J.9.2 S1G Beacon frame with BIP-GMAC-128 using BCE, all optional header fields, no body elements\n"); + + wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk)); + wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn)); + wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame)); + + prot = bip_gmac_protect_s1g_beacon(igtk, sizeof(igtk), frame, + sizeof(frame), ipn, 7, true, + &prot_len); + if (!prot) { + wpa_printf(MSG_ERROR, + "Failed to protect S1G Beacon frame with BIP-GMAC-128 using BCE"); + return 1; + } + + wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len); + if (prot_len != sizeof(res) || os_memcmp(res, prot, prot_len) != 0) { + wpa_printf(MSG_ERROR, + "S1G Beacon frame with BIP-GMAC-128 using BCE test vector mismatch"); + err++; + } + os_free(prot); + + return err; +} + + static int test_vector_bip_gmac_256(void) { u8 igtk[] = { @@ -915,6 +1287,226 @@ static int test_vector_bip_gmac_256(void) } +static int test_vector_bip_gmac_256_s1g_beacon(void) +{ + const u8 igtk[] = { + 0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e, + 0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + const u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const u8 frame[] = { + 0x1c, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, + 0x08, 0x80, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, + 0x78 + }; + const u8 res[] = { + 0x1c, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd5, + 0x08, 0x80, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, + 0x78, 0x4c, 0x18, 0x07, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x33, 0xa2, 0x6f, 0xc6, 0x7e, + 0xbf, 0xfd, 0xa0, 0xac, 0x9b, 0x29, 0xaa, 0x70, + 0xda, 0x3f, 0x51 + }; + u8 *prot; + size_t prot_len; + int err = 0; + + wpa_printf(MSG_INFO, + "\nIEEE P802.11REVme/D4.0, J.9.2 S1G Beacon frame with BIP-GMAC-256, no optional header fields, S1G Beacon Compatibility element in body\n"); + + wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk)); + wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn)); + wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame)); + + prot = bip_gmac_protect_s1g_beacon(igtk, sizeof(igtk), frame, + sizeof(frame), ipn, 7, false, + &prot_len); + if (!prot) { + wpa_printf(MSG_ERROR, + "Failed to protect S1G Beacon frame with BIP-GMAC-256"); + return 1; + } + + wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len); + if (prot_len != sizeof(res) || os_memcmp(res, prot, prot_len) != 0) { + wpa_printf(MSG_ERROR, + "S1G Beacon frame with BIP-GMAC-256 test vector mismatch"); + err++; + } + os_free(prot); + + return err; +} + + +static int test_vector_bip_gmac_256_s1g_beacon_ext(void) +{ + const u8 igtk[] = { + 0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e, + 0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + const u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const u8 frame[] = { + 0x1c, 0x47, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const u8 res[] = { + 0x1c, 0x47, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, + 0x18, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0a, 0x5f, 0xa0, 0xf4, 0x71, 0xdf, 0x73, + 0x9e, 0x61, 0x4d, 0xcf, 0x5d, 0xbb, 0x36, 0xf9, + 0x65 + }; + u8 *prot; + size_t prot_len; + int err = 0; + + wpa_printf(MSG_INFO, + "\nIEEE P802.11REVme/D4.0, J.9.2 S1G Beacon frame with BIP-GMAC-256, all optional header fields, no body elements\n"); + + wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk)); + wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn)); + wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame)); + + prot = bip_gmac_protect_s1g_beacon(igtk, sizeof(igtk), frame, + sizeof(frame), ipn, 6, false, + &prot_len); + if (!prot) { + wpa_printf(MSG_ERROR, + "Failed to protect S1B Beacon frame with BIP-GMAC-256"); + return 1; + } + + wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len); + if (prot_len != sizeof(res) || os_memcmp(res, prot, prot_len) != 0) { + wpa_printf(MSG_ERROR, + "S1G Beacon frame with BIP-GMAC-256 test vector mismatch"); + err++; + } + os_free(prot); + + return err; +} + + +static int test_vector_bip_gmac_256_s1g_beacon_bce(void) +{ + const u8 igtk[] = { + 0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e, + 0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + const u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const u8 frame[] = { + 0x1c, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, + 0x08, 0x80, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, + 0x78 + }; + const u8 res[] = { + 0x1c, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd5, + 0x08, 0x80, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, + 0x78, 0x8c, 0x10, 0xf8, 0x76, 0x22, 0x80, 0x3d, + 0x9c, 0x22, 0x8a, 0xcb, 0x3c, 0x55, 0x8a, 0x33, + 0x2e, 0x94, 0x13 + }; + u8 *prot; + size_t prot_len; + int err = 0; + + wpa_printf(MSG_INFO, + "\nIEEE P802.11REVme/D4.0, J.9.2 S1G Beacon frame with BIP-GMAC-256 using BCE, no optional header fields, S1G Beacon Compatibility element in body\n"); + + wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk)); + wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn)); + wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame)); + + prot = bip_gmac_protect_s1g_beacon(igtk, sizeof(igtk), frame, + sizeof(frame), ipn, 7, true, + &prot_len); + if (!prot) { + wpa_printf(MSG_ERROR, + "Failed to protect S1G Beacon frame with BIP-GMAC-256 using BCE"); + return 1; + } + + wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len); + if (prot_len != sizeof(res) || os_memcmp(res, prot, prot_len) != 0) { + wpa_printf(MSG_ERROR, + "S1G Beacon frame with BIP-GMAC-256 using BCE test vector mismatch"); + err++; + } + os_free(prot); + + return err; +} + + +static int test_vector_bip_gmac_256_s1g_beacon_bce_ext(void) +{ + const u8 igtk[] = { + 0x4e, 0xa9, 0x54, 0x3e, 0x09, 0xcf, 0x2b, 0x1e, + 0xca, 0x66, 0xff, 0xc5, 0x8b, 0xde, 0xcb, 0xcf, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + const u8 ipn[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const u8 frame[] = { + 0x1c, 0x47, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const u8 res[] = { + 0x1c, 0x47, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, + 0x10, 0x3c, 0x80, 0x49, 0xbe, 0x8c, 0x23, 0x34, + 0x1f, 0x5c, 0x2f, 0x9c, 0xd6, 0x03, 0xe3, 0x7a, + 0x5b + }; + u8 *prot; + size_t prot_len; + int err = 0; + + wpa_printf(MSG_INFO, + "\nIEEE P802.11REVme/D4.0, J.9.2 S1G Beacon frame with BIP-GMAC-256 using BCE, all optional header fields, no body elements\n"); + + wpa_hexdump(MSG_INFO, "IGTK", igtk, sizeof(igtk)); + wpa_hexdump(MSG_INFO, "IPN", ipn, sizeof(ipn)); + wpa_hexdump(MSG_INFO, "Plaintext frame", frame, sizeof(frame)); + + prot = bip_gmac_protect_s1g_beacon(igtk, sizeof(igtk), frame, + sizeof(frame), ipn, 6, true, + &prot_len); + if (!prot) { + wpa_printf(MSG_ERROR, + "Failed to protect S1B Beacon frame with BIP-GMAC-256 using BCE"); + return 1; + } + + wpa_hexdump(MSG_INFO, "Protected MPDU (without FCS)", prot, prot_len); + if (prot_len != sizeof(res) || os_memcmp(res, prot, prot_len) != 0) { + wpa_printf(MSG_ERROR, + "S1G Beacon frame with BIP-GMAC-256 using BCE test vector mismatch"); + err++; + } + os_free(prot); + + return err; +} + + int main(int argc, char *argv[]) { int errors = 0; @@ -929,12 +1521,24 @@ int main(int argc, char *argv[]) test_vector_ccmp(); test_vector_ccmp_pv1(); test_vector_bip(); + test_vector_bip_s1g_beacon(); + test_vector_bip_s1g_beacon_ext(); + test_vector_bip_s1g_beacon_bce(); + test_vector_bip_s1g_beacon_bce_ext(); test_vector_ccmp_mgmt(); errors += test_vector_gcmp(); errors += test_vector_gcmp_256(); errors += test_vector_ccmp_256(); errors += test_vector_bip_gmac_128(); + errors += test_vector_bip_gmac_128_s1g_beacon(); + errors += test_vector_bip_gmac_128_s1g_beacon_ext(); + errors += test_vector_bip_gmac_128_s1g_beacon_bce(); + errors += test_vector_bip_gmac_128_s1g_beacon_bce_ext(); errors += test_vector_bip_gmac_256(); + errors += test_vector_bip_gmac_256_s1g_beacon(); + errors += test_vector_bip_gmac_256_s1g_beacon_ext(); + errors += test_vector_bip_gmac_256_s1g_beacon_bce(); + errors += test_vector_bip_gmac_256_s1g_beacon_bce_ext(); if (errors) wpa_printf(MSG_INFO, "One or more test vectors failed"); diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h index 65ae74cb4..ec1e3bb48 100644 --- a/wlantest/wlantest.h +++ b/wlantest/wlantest.h @@ -353,8 +353,14 @@ u8 * wep_decrypt(struct wlantest *wt, const struct ieee80211_hdr *hdr, u8 * bip_protect(const u8 *igtk, size_t igtk_len, u8 *frame, size_t len, u8 *ipn, int keyid, size_t *prot_len); +u8 * bip_protect_s1g_beacon(const u8 *igtk, size_t igtk_len, const u8 *frame, + size_t len, const u8 *ipn, int keyid, bool bce, + size_t *prot_len); u8 * bip_gmac_protect(const u8 *igtk, size_t igtk_len, u8 *frame, size_t len, u8 *ipn, int keyid, size_t *prot_len); +u8 * bip_gmac_protect_s1g_beacon(const u8 *igtk, size_t igtk_len, + const u8 *frame, size_t len, const u8 *ipn, + int keyid, bool bce, size_t *prot_len); u8 * gcmp_decrypt(const u8 *tk, size_t tk_len, const struct ieee80211_hdr *hdr, const u8 *a1, const u8 *a2, const u8 *a3,