[PATCH 09/15] handshake: Add pmksa setter & stealer

James Prestwood <[email protected]>
Newsgroups dev.linux.lists.iwd
Message-ID <[email protected]>
From: Denis Kenzior <[email protected]>

The majority of this patch was authored by Denis Kenzior, but
I have appended setting the PMK inside handshake_state_set_pmksa
as well as checking if the pmkid exists in
handshake_state_steal_pmkid.

Authored-by: Denis Kenzior <[email protected]>
Authored-by: James Prestwood <[email protected]>
---
 Makefile.am     |  4 +++
 src/handshake.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/handshake.h | 11 ++++++-
 3 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/Makefile.am b/Makefile.am
index 598b8f90..89198289 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -458,6 +458,7 @@ unit_test_eap_sim_SOURCES = unit/test-eap-sim.c \
 		src/eapol.h src/eapol.c \
 		src/eapolutil.h src/eapolutil.c \
 		src/handshake.h src/handshake.c \
+		src/pmksa.h src/pmksa.c \
 		src/eap.h src/eap.c src/eap-private.h \
 		src/util.h src/util.c \
 		src/simauth.h src/simauth.c \
@@ -517,6 +518,7 @@ unit_test_eapol_SOURCES = unit/test-eapol.c \
 				src/eapol.h src/eapol.c \
 				src/eapolutil.h src/eapolutil.c \
 				src/handshake.h src/handshake.c \
+				src/pmksa.h src/pmksa.c \
 				src/eap.h src/eap.c src/eap-private.h \
 				src/eap-tls.c src/eap-ttls.c \
 				src/eap-md5.c src/util.c \
@@ -547,6 +549,7 @@ unit_test_wsc_SOURCES = unit/test-wsc.c src/wscutil.h src/wscutil.c \
 				src/eapol.h src/eapol.c \
 				src/eapolutil.h src/eapolutil.c \
 				src/handshake.h src/handshake.c \
+				src/pmksa.h src/pmksa.c \
 				src/eap.h src/eap.c src/eap-private.h \
 				src/util.h src/util.c \
 				src/erp.h src/erp.c \
@@ -565,6 +568,7 @@ unit_test_sae_SOURCES = unit/test-sae.c \
 				src/crypto.h src/crypto.c \
 				src/ie.h src/ie.c \
 				src/handshake.h src/handshake.c \
+				src/pmksa.h src/pmksa.c \
 				src/erp.h src/erp.c \
 				src/band.h src/band.c \
 				src/util.h src/util.c \
diff --git a/src/handshake.c b/src/handshake.c
index 7fb75dc4..a93143d1 100644
--- a/src/handshake.c
+++ b/src/handshake.c
@@ -43,6 +43,7 @@
 #include "src/handshake.h"
 #include "src/erp.h"
 #include "src/band.h"
+#include "src/pmksa.h"
 
 static inline unsigned int n_ecc_groups(void)
 {
@@ -138,6 +139,9 @@ void handshake_state_unref(struct handshake_state *s)
 	l_free(s->fils_ip_resp_ie);
 	l_free(s->vendor_ies);
 
+	if (s->have_pmksa)
+		l_free(s->pmksa);
+
 	if (s->erp_cache)
 		erp_cache_put(s->erp_cache);
 
@@ -701,6 +705,11 @@ void handshake_state_install_ptk(struct handshake_state *s)
 {
 	s->ptk_complete = true;
 
+	if (!s->have_pmksa && IE_AKM_IS_SAE(s->akm_suite)) {
+		l_debug("Adding PMKSA expiration");
+		s->expiration = l_time_now() + pmksa_lifetime();
+	}
+
 	if (install_tk) {
 		uint32_t cipher = ie_rsn_cipher_suite_to_cipher(
 							s->pairwise_cipher);
@@ -1203,3 +1212,71 @@ done:
 
 	return r;
 }
+
+bool handshake_state_set_pmksa(struct handshake_state *s,
+					struct pmksa *pmksa)
+{
+	/* checks for both expiration || pmksa being set */
+	if (s->expiration)
+		return false;
+
+	s->pmksa = pmksa;
+	s->have_pmksa = true;
+
+	handshake_state_set_pmkid(s, pmksa->pmkid);
+	handshake_state_set_pmk(s, pmksa->pmk, pmksa->pmk_len);
+
+	return true;
+}
+
+static struct pmksa *handshake_state_steal_pmksa(struct handshake_state *s)
+{
+	struct pmksa *pmksa;
+	uint64_t now = l_time_now();
+
+	if (s->have_pmksa) {
+		pmksa = l_steal_ptr(s->pmksa);
+		s->have_pmksa = false;
+
+		if (l_time_after(now, pmksa->expiration)) {
+			l_free(pmksa);
+			pmksa = NULL;
+		}
+
+		return pmksa;
+	}
+
+	if (s->expiration && l_time_after(now, s->expiration)) {
+		s->expiration = 0;
+		return NULL;
+	}
+
+	if (!s->have_pmkid)
+		return NULL;
+
+	pmksa = l_new(struct pmksa, 1);
+	pmksa->expiration = s->expiration;
+	memcpy(pmksa->spa, s->spa, sizeof(s->spa));
+	memcpy(pmksa->aa, s->aa, sizeof(s->aa));
+	memcpy(pmksa->ssid, s->ssid, s->ssid_len);
+	pmksa->ssid_len = s->ssid_len;
+	pmksa->akm = s->akm_suite;
+	memcpy(pmksa->pmkid, s->pmkid, sizeof(s->pmkid));
+	pmksa->pmk_len = s->pmk_len;
+	memcpy(pmksa->pmk, s->pmk, s->pmk_len);
+
+	return pmksa;
+}
+
+void handshake_state_cache_pmksa(struct handshake_state *s)
+{
+	struct pmksa *pmksa = handshake_state_steal_pmksa(s);
+
+	l_debug("%p", pmksa);
+
+	if (!pmksa)
+		return;
+
+	if (L_WARN_ON(pmksa_cache_put(pmksa) < 0))
+		l_free(pmksa);
+}
diff --git a/src/handshake.h b/src/handshake.h
index 6c0946d4..cf7dc48c 100644
--- a/src/handshake.h
+++ b/src/handshake.h
@@ -29,6 +29,7 @@
 struct handshake_state;
 enum crypto_cipher;
 struct eapol_frame;
+struct pmksa;
 
 enum handshake_kde {
 	/* 802.11-2020 Table 12-9 in section 12.7.2 */
@@ -141,7 +142,12 @@ struct handshake_state {
 	bool supplicant_ocvc : 1;
 	bool ext_key_id_capable : 1;
 	bool force_default_ecc_group : 1;
-	uint8_t ssid[SSID_MAX_SIZE];
+	bool have_pmksa : 1;
+	union {
+		struct pmksa *pmksa;
+		uint64_t expiration;
+	};
+	uint8_t ssid[32];
 	size_t ssid_len;
 	char *passphrase;
 	char *password_identifier;
@@ -302,6 +308,9 @@ void handshake_state_set_chandef(struct handshake_state *s,
 int handshake_state_verify_oci(struct handshake_state *s, const uint8_t *oci,
 				size_t oci_len);
 
+bool handshake_state_set_pmksa(struct handshake_state *s, struct pmksa *pmksa);
+void handshake_state_cache_pmksa(struct handshake_state *s);
+
 bool handshake_util_ap_ie_matches(const struct ie_rsn_info *msg_info,
 					const uint8_t *scan_ie, bool is_wpa);
 
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.