[PATCH v2 08/20] PASN: Add functions to compute PTK, MIC and hash

Ilan Peer ilan.peer at intel.com
Wed Dec 16 06:00:21 EST 2020


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 at intel.com>
---
 src/common/defs.h        |   2 +
 src/common/wpa_common.c  | 263 +++++++++++++++++++++++++++++++++++++++
 src/common/wpa_common.h  |  18 +++
 wpa_supplicant/Makefile  |   8 ++
 wpa_supplicant/defconfig |   3 +
 5 files changed, 294 insertions(+)

diff --git a/src/common/defs.h b/src/common/defs.h
index b01ab03b65..a58eff5f71 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -49,6 +49,8 @@
 #define WPA_KEY_MGMT_OWE BIT(22)
 #define WPA_KEY_MGMT_DPP BIT(23)
 #define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24)
+#define WPA_KEY_MGMT_PASN BIT(25)
+
 
 #define WPA_KEY_MGMT_FT (WPA_KEY_MGMT_FT_PSK | \
 			 WPA_KEY_MGMT_FT_IEEE8021X | \
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 092960cc25..f8b38eab90 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1166,6 +1166,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_D2.0, 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
+ * @kdk_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 kdk_len)
+{
+	u8 tmp[WPA_KCK_MAX_LEN + WPA_TK_MAX_LEN + WPA_KDK_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)
+	 * KDK = L(PASN-PTK, 256 + Tk_bits, kdk_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->kdk_len = kdk_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->kdk_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 (kdk_len) {
+		os_memcpy(ptk->kdk, tmp + WPA_PASN_KCK_LEN + ptk->tk_len,
+			  ptk->kdk_len);
+		wpa_hexdump_key(MSG_DEBUG, "PASN: KDK:", ptk->kdk,
+				ptk->kdk_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 f6d2d48ee8..0117ae719e 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -219,6 +219,8 @@ struct wpa_eapol_key {
 #define WPA_KDK_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
@@ -617,4 +619,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 kdk_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 9adadf141e..ef7e99e745 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -385,6 +385,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 a0fe94e679..ce542c1316 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -620,3 +620,6 @@ CONFIG_DPP=y
 # support for this by default, but that functionality is subject to be removed
 # in the future.
 #CONFIG_NO_TKIP=y
+
+# Pre Association Security Negotiation (PASN)
+#CONFIG_PASN=y
-- 
2.17.1




More information about the Hostap mailing list