1. Add a function to derive the PTK from a PMK and additional data. 2. Add a function to calculate the MIC for a PASN frames. 3. Add a function to compute the hash of an authentication frame body. The above are built only in case that CONFIG_PASN is enabled in build time. Signed-off-by: Ilan Peer <ilan.peer@xxxxxxxxx> --- src/common/defs.h | 3 + src/common/wpa_common.c | 263 +++++++++++++++++++++++++++++++++++++++ src/common/wpa_common.h | 18 +++ wpa_supplicant/Makefile | 8 ++ wpa_supplicant/defconfig | 3 + 5 files changed, 295 insertions(+) diff --git a/src/common/defs.h b/src/common/defs.h index 4faf1c8601..a7082f3116 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -59,6 +59,9 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean; #define WPA_KEY_MGMT_DPP BIT(23) #define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24) +/* TODO: PASN AKM is not yet defined in the spec. */ +#define WPA_KEY_MGMT_PASN BIT(25) + #define WPA_KEY_MGMT_FT (WPA_KEY_MGMT_FT_PSK | \ WPA_KEY_MGMT_FT_IEEE8021X | \ WPA_KEY_MGMT_FT_IEEE8021X_SHA384 | \ diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index 6f602aee42..f47fdf07f8 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -1132,6 +1132,269 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_PASN + +/* + * pasn_use_sha384 - Should SHA384 be used or SHA256 + * + * @akmp: Authentication and Key management protocol + * @cipher: the cipher suite + * + * According to Draft P802.11az_D1.5, section 12.13.7, the hash algorithm to use + * is the hash algorithm defined for the Base AKM (see Table 9-144 (AKM suite + * selectors)). When there is no Base AKM, the hash algorithm is selected based + * on the pairwise Cipher Suite provided in the RSNE provided by the AP in the + * second PASN frame. SHA-256 is used as the hash algorithm, except for the + * ciphers 00-0F-AC:9 and 00-0F-AC:10 for which SHA-384 is used. + */ +static u8 pasn_use_sha384(int akmp, int cipher) +{ + return (akmp == WPA_KEY_MGMT_PASN && (cipher == WPA_CIPHER_CCMP_256 || + cipher == WPA_CIPHER_GCMP)) || + wpa_key_mgmt_sha384(akmp); +} + + +/** + * pasn_pmk_to_ptk - Calculate PASN PTK from PMK, addresses, etc. + * @pmk: Pairwise master key + * @pmk_len: Length of PMK + * @spa: Suppplicant address + * @bssid: AP bssid + * @dhss: is the shared secret derived from the PASN ephemeral key exchange + * encoded as an octet string + * @dhss_len: the length of dhss + * @ptk: Buffer for pairwise transient key + * @akmp: Negotiated AKM + * @cipher: Negotiated pairwise cipher + * @hltk_len: the length in octets that should be derived for HTLK. Can be zero. + * Returns: 0 on success, -1 on failure + */ +int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len, + const u8 *spa, const u8 *bssid, + const u8 *dhss, size_t dhss_len, + struct wpa_ptk *ptk, int akmp, int cipher, + size_t hltk_len) +{ + u8 tmp[WPA_KCK_MAX_LEN + WPA_TK_MAX_LEN + WPA_HLTK_MAX_LEN]; + u8 *data; + size_t data_len, ptk_len; + int ret = -1; + + if (!pmk || !pmk_len) { + wpa_printf(MSG_ERROR, "PASN: No PMK set for PTK derivation"); + return -1; + } + + if (!dhss || !dhss_len) { + wpa_printf(MSG_ERROR, "PASN: No DHSS set for PTK derivation"); + return -1; + } + + /* + * PASN-PTK= PRF-X(PMK, “PASN PTK Derivation”, SPA || BSSID || DHss) + * + * KCK = L(PASN-PTK, 0, 256) + * TK = L(PASN-PTK, 256, Tk_bits) + * HLTK = L(PASN-PTK, 256 + Tk_bits, hltk_len * 8) + */ + data_len = 2 * ETH_ALEN + dhss_len; + data = os_zalloc(data_len); + if (!data) + return -1; + + os_memcpy(data, spa, ETH_ALEN); + os_memcpy(data + ETH_ALEN, bssid, ETH_ALEN); + os_memcpy(data + 2 * ETH_ALEN, dhss, dhss_len); + + ptk->kck_len = WPA_PASN_KCK_LEN; + ptk->tk_len = wpa_cipher_key_len(cipher); + ptk->hltk_len = hltk_len; + ptk->kek_len = 0; + ptk->kek2_len = 0; + ptk->kck2_len = 0; + + if (ptk->tk_len == 0) { + wpa_printf(MSG_ERROR, + "WPA: Unsupported cipher (0x%x) used in PTK derivation", + cipher); + goto err; + } + + ptk_len = ptk->kck_len + ptk->tk_len + ptk->hltk_len; + + if (pasn_use_sha384(akmp, cipher)) { + wpa_printf(MSG_DEBUG, "PASN: PTK derivation using PRF(SHA384)"); + + if (sha384_prf(pmk, pmk_len, "PASN PTK Derivation", + data, data_len, tmp, ptk_len) < 0) + goto err; + } else { + wpa_printf(MSG_DEBUG, "PASN: PTK derivation using PRF(SHA256)"); + + if (sha256_prf(pmk, pmk_len, "PASN PTK Derivation", + data, data_len, tmp, ptk_len) < 0) + goto err; + } + + wpa_printf(MSG_DEBUG, + "PASN: PTK derivation: SPA=" MACSTR " BSSID=" MACSTR, + MAC2STR(spa), MAC2STR(bssid)); + + wpa_hexdump_key(MSG_DEBUG, "PASN: DHss", dhss, dhss_len); + wpa_hexdump_key(MSG_DEBUG, "PASN: PMK", pmk, pmk_len); + wpa_hexdump_key(MSG_DEBUG, "PASN: PASN-PTK", tmp, ptk_len); + + os_memcpy(ptk->kck, tmp, WPA_PASN_KCK_LEN); + wpa_hexdump_key(MSG_DEBUG, "PASN: KCK:", ptk->kck, WPA_PASN_KCK_LEN); + + os_memcpy(ptk->tk, tmp + WPA_PASN_KCK_LEN, ptk->tk_len); + wpa_hexdump_key(MSG_DEBUG, "PASN: TK:", ptk->tk, ptk->tk_len); + + if (hltk_len) { + os_memcpy(ptk->hltk, tmp + WPA_PASN_KCK_LEN + ptk->tk_len, + ptk->hltk_len); + wpa_hexdump_key(MSG_DEBUG, "PASN: HLTK:", ptk->hltk, + ptk->hltk_len); + } + + os_memset(tmp, 0, sizeof(tmp)); + ret = 0; +err: + bin_clear_free(data, data_len); + return ret; +} + + +/* + * pasn_mic_len - Returns the MIC length for PASN authentication + */ +u8 pasn_mic_len(int akmp, int cipher) +{ + if (pasn_use_sha384(akmp, cipher)) + return 24; + + return 16; +} + + +/** + * pasn_mic - Calculate PASN MIC + * @kck: The key confirmation key for the PASN PTKSA + * @akmp: Negotiated AKM + * @cipher: Negotiated pairwise cipher + * @addr1: for the 2nd PASN frame supplicant address; for the 3rd frame the + * BSSID + * @addr2: for the 2nd PASN frame the BSSID; for the 3rd frame the supplicant + * address + * @data: For calculating the MIC for the 2nd PASN frame, this should hold the + * beacon RSN IE. For the calculating the MIC for the 3rd PASN frame, this + * should hold the HASH of body of the PASN 1st frame. + * @data_len: the length of data + * @frame: The body of the PASN frame including the MIC element with the Octets + * in the MIC field of the MIC element set to 0. + * @frame_len: the length of frame + * @mic: buffer to hold the MIC on success. Should be big enough to handle the + * maximal MIC length + * Returns: 0 on success, -1 on failure + */ +int pasn_mic(const u8 *kck, int akmp, int cipher, + const u8 *addr1, const u8 *addr2, + const u8 *data, size_t data_len, + const u8 *frame, size_t frame_len, u8 *mic) +{ + u8 *buf; + u8 hash[SHA384_MAC_LEN]; + size_t buf_len = 2 * ETH_ALEN + data_len + frame_len; + int ret = -1; + + if (!kck) { + wpa_printf(MSG_ERROR, "PASN: No KCK for MIC calculation"); + return -1; + } + + if (!data || !data_len) { + wpa_printf(MSG_ERROR, "PASN: invalid data for MIC calculation"); + return -1; + } + + if (!frame || !frame_len) { + wpa_printf(MSG_ERROR, "PASN: invalid data for MIC calculation"); + return -1; + } + + buf = os_zalloc(buf_len); + if (!buf) + return -1; + + os_memcpy(buf, addr1, ETH_ALEN); + os_memcpy(buf + ETH_ALEN, addr2, ETH_ALEN); + + wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: data: ", data, data_len); + os_memcpy(buf + 2 * ETH_ALEN, data, data_len); + + wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: frame: ", frame, frame_len); + os_memcpy(buf + 2 * ETH_ALEN + data_len, frame, frame_len); + + os_memset(hash, 0, sizeof(hash)); + + wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: KCK: ", kck, WPA_PASN_KCK_LEN); + wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: buf: ", buf, buf_len); + + if (pasn_use_sha384(akmp, cipher)) { + wpa_printf(MSG_DEBUG, "PASN: MIC using HMAC-SHA384"); + + if (hmac_sha384(kck, WPA_PASN_KCK_LEN, buf, buf_len, hash)) + goto err; + + os_memcpy(mic, hash, 24); + wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: mic: ", mic, 24); + } else { + wpa_printf(MSG_DEBUG, "PASN: MIC using HMAC-SHA256"); + + if (hmac_sha256(kck, WPA_PASN_KCK_LEN, buf, buf_len, hash)) + goto err; + + os_memcpy(mic, hash, 16); + wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: mic: ", mic, 16); + } + + ret = 0; +err: + bin_clear_free(buf, buf_len); + return ret; +} + + +/* + * pasn_auth_frame_hash - Computes an hash of an authentication frame body + * + * @akmp: Negotiated AKM + * @cipher: Negotiated pairwise cipher + * @data: pointer to the authentication frame body + * @len: length of the authentication frame body + * @hash: on return would hold the computed hash. Should be big enough to handle + * SHA384. + * Returns: 0 on success, -1 on failure + */ +int pasn_auth_frame_hash(int akmp, int cipher, const u8 *data, size_t len, + u8 *hash) +{ + if (pasn_use_sha384(akmp, cipher)) { + wpa_printf(MSG_DEBUG, "PASN: frame hash using SHA-384"); + + return sha384_vector(1, &data, &len, hash); + + } else { + wpa_printf(MSG_DEBUG, "PASN: frame hash using SHA-256"); + + return sha256_vector(1, &data, &len, hash); + } +} + +#endif /* CONFIG_PASN */ + + static int rsn_selector_to_bitfield(const u8 *s) { if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE) diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 2363b54870..7ac47e1139 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -199,6 +199,8 @@ struct wpa_eapol_key { #define WPA_HLTK_MAX_LEN 32 #define FILS_ICK_MAX_LEN 48 #define FILS_FT_MAX_LEN 48 +#define WPA_PASN_KCK_LEN 32 +#define WPA_PASN_MIC_MAX_LEN 24 /** * struct wpa_ptk - WPA Pairwise Transient Key @@ -548,4 +550,20 @@ int wpa_use_cmac(int akmp); int wpa_use_aes_key_wrap(int akmp); int fils_domain_name_hash(const char *domain, u8 *hash); +int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len, + const u8 *spa, const u8 *bssid, + const u8 *dhss, size_t dhss_len, + struct wpa_ptk *ptk, int akmp, int cipher, + size_t hltk_len); + +u8 pasn_mic_len(int akmp, int cipher); + +int pasn_mic(const u8 *kck, int akmp, int cipher, + const u8 *addr1, const u8 *addr2, + const u8 *data, size_t data_len, + const u8 *frame, size_t frame_len, u8 *mic); + +int pasn_auth_frame_hash(int akmp, int cipher, const u8 *data, size_t len, + u8 *hash); + #endif /* WPA_COMMON_H */ diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index a6329c0995..fea7fc66ff 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -381,6 +381,14 @@ CFLAGS += -DCONFIG_P2P_STRICT endif endif +ifdef CONFIG_PASN +CFLAGS += -DCONFIG_PASN +NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_SHA256=y +NEED_SHA384=y +endif + ifdef CONFIG_WIFI_DISPLAY CFLAGS += -DCONFIG_WIFI_DISPLAY OBJS += wifi_display.o diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index 792ab24eff..ed95bf83b1 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -607,3 +607,6 @@ CONFIG_BGSCAN_SIMPLE=y # Device Provisioning Protocol (DPP) CONFIG_DPP=y + +# Pre Association Security Negotiation (PASN) +#CONFIG_PASN=y -- 2.17.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap