From patchwork Mon Feb 24 09:15:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Peer, Ilan" X-Patchwork-Id: 1242947 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20170209 header.b=AujFy4EQ; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 48Qxvg61pGz9sPk for ; Mon, 24 Feb 2020 20:43:27 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=1DriNKy4Y4kCCMRBQal+ARQgbTv28I0livvYi2vkyjg=; b=AujFy4EQf8wUXy Rvibev+pq4W3XNSYCKJzZBmVT4oqxyJdVOFmzdy+S6UiEVUOeXxfl7ZtiUY0p8/tN+/CHrnOwUlx7 SwEb2cRvJxBdSLVd3kPyDJnRZLSDUMzT60LKthoevlAgkM0FwTWs8fVndlMprSX0J/rRvC4GSUetX taX7Si/0XmThNlSLFYKYwzGMSv81OQ2XhL/QyPcU2JCDynDzAlMk/QmNJPZGFCc7Ki2HfLxkpW0Ec 5MDOHtSS2v+w8AVBIU8eSk1r+R9jGzljP+nLW7tg5/SBZSbKuR+eFYhS0V4S711yp6es8sWmPMMAh gSEiSlJ9Vh1sEpJzFjtQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1j6AGl-0004Um-QB; Mon, 24 Feb 2020 09:43:19 +0000 Received: from mga17.intel.com ([192.55.52.151]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1j69py-0007oi-BY for hostap@lists.infradead.org; Mon, 24 Feb 2020 09:15:55 +0000 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Feb 2020 01:15:37 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,479,1574150400"; d="scan'208";a="225914440" Received: from jed01681.jer.intel.com ([10.12.190.127]) by orsmga007.jf.intel.com with ESMTP; 24 Feb 2020 01:15:35 -0800 From: Ilan Peer To: hostap@lists.infradead.org Subject: [PATCH 02/14] PASN: Add functions to compute PTK, MIC and hash Date: Mon, 24 Feb 2020 11:15:17 +0200 Message-Id: <20200224091529.15259-3-ilan.peer@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200224091529.15259-1-ilan.peer@intel.com> References: <20200224091529.15259-1-ilan.peer@intel.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200224_011538_478702_8078E783 X-CRM114-Status: GOOD ( 19.65 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.3 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/, medium trust [192.55.52.151 listed in list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Ilan Peer Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org 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 --- src/common/defs.h | 6 + src/common/wpa_common.c | 263 +++++++++++++++++++++++++++++++++++++++ src/common/wpa_common.h | 18 +++ wpa_supplicant/Makefile | 8 ++ wpa_supplicant/defconfig | 3 + 5 files changed, 298 insertions(+) diff --git a/src/common/defs.h b/src/common/defs.h index 1e21ec2de4..736ed7ff09 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -59,6 +59,12 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean; #define WPA_KEY_MGMT_DPP BIT(23) #define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24) +#ifdef CONFIG_PASN +/* TODO: PASN AKM is not yet defined in the spec. */ +#define WPA_KEY_MGMT_PASN BIT(25) +#endif /* CONFIG_PASN */ + + #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 deae2a35f9..1a67f44720 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -1157,6 +1157,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 + * @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 3e9e00558e..3ecb85e8c2 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -208,6 +208,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 @@ -591,4 +593,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 e41464f4d6..d40804d528 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -386,6 +386,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 5308b494b7..847ebebcb2 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -603,3 +603,6 @@ CONFIG_BGSCAN_SIMPLE=y # Device Provisioning Protocol (DPP) CONFIG_DPP=y + +# Pre Association Security Negotiation (PASN) +#CONFIG_PASN=y