[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