Blame SOURCES/macsec-0013-wpa_supplicant-Allow-pre-shared-CAK-CKN-pair-for-MKA.patch

6c9f0c
From ad51731abf06efb284d020578eb34e7b1daeb23e Mon Sep 17 00:00:00 2001
6c9f0c
Message-Id: <ad51731abf06efb284d020578eb34e7b1daeb23e.1488376601.git.dcaratti@redhat.com>
6c9f0c
From: Sabrina Dubroca <sd@queasysnail.net>
6c9f0c
Date: Wed, 2 Nov 2016 16:38:35 +0100
6c9f0c
Subject: [PATCH] wpa_supplicant: Allow pre-shared (CAK,CKN) pair for MKA
6c9f0c
6c9f0c
This enables configuring key_mgmt=NONE + mka_ckn + mka_cak.
6c9f0c
This allows wpa_supplicant to work in a peer-to-peer mode, where peers
6c9f0c
are authenticated by the pre-shared (CAK,CKN) pair. In this mode, peers
6c9f0c
can act as key server to distribute keys for the MACsec instances.
6c9f0c
6c9f0c
This is what some MACsec switches support, and even without HW
6c9f0c
support, it's a convenient way to setup a network.
6c9f0c
6c9f0c
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
6c9f0c
---
6c9f0c
 wpa_supplicant/config.c            | 65 ++++++++++++++++++++++++++++++++++++++
6c9f0c
 wpa_supplicant/config_file.c       | 36 +++++++++++++++++++++
6c9f0c
 wpa_supplicant/config_ssid.h       | 20 ++++++++++++
6c9f0c
 wpa_supplicant/wpa_supplicant.c    |  7 +++-
6c9f0c
 wpa_supplicant/wpa_supplicant.conf |  8 +++++
6c9f0c
 wpa_supplicant/wpas_kay.c          | 48 ++++++++++++++++++++++++++++
6c9f0c
 wpa_supplicant/wpas_kay.h          | 10 ++++++
6c9f0c
 7 files changed, 193 insertions(+), 1 deletion(-)
6c9f0c
6c9f0c
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
6c9f0c
index a0b64b2..9011389 100644
6c9f0c
--- a/wpa_supplicant/config.c
6c9f0c
+++ b/wpa_supplicant/config.c
6c9f0c
@@ -1828,6 +1828,69 @@ static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data,
6c9f0c
 #endif /* CONFIG_MESH */
6c9f0c
 
6c9f0c
 
6c9f0c
+#ifdef CONFIG_MACSEC
6c9f0c
+
6c9f0c
+static int wpa_config_parse_mka_cak(const struct parse_data *data,
6c9f0c
+				    struct wpa_ssid *ssid, int line,
6c9f0c
+				    const char *value)
6c9f0c
+{
6c9f0c
+	if (hexstr2bin(value, ssid->mka_cak, MACSEC_CAK_LEN) ||
6c9f0c
+	    value[MACSEC_CAK_LEN * 2] != '\0') {
6c9f0c
+		wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.",
6c9f0c
+			   line, value);
6c9f0c
+		return -1;
6c9f0c
+	}
6c9f0c
+
6c9f0c
+	ssid->mka_psk_set |= MKA_PSK_SET_CAK;
6c9f0c
+
6c9f0c
+	wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak, MACSEC_CAK_LEN);
6c9f0c
+	return 0;
6c9f0c
+}
6c9f0c
+
6c9f0c
+
6c9f0c
+static int wpa_config_parse_mka_ckn(const struct parse_data *data,
6c9f0c
+				    struct wpa_ssid *ssid, int line,
6c9f0c
+				    const char *value)
6c9f0c
+{
6c9f0c
+	if (hexstr2bin(value, ssid->mka_ckn, MACSEC_CKN_LEN) ||
6c9f0c
+	    value[MACSEC_CKN_LEN * 2] != '\0') {
6c9f0c
+		wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
6c9f0c
+			   line, value);
6c9f0c
+		return -1;
6c9f0c
+	}
6c9f0c
+
6c9f0c
+	ssid->mka_psk_set |= MKA_PSK_SET_CKN;
6c9f0c
+
6c9f0c
+	wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn, MACSEC_CKN_LEN);
6c9f0c
+	return 0;
6c9f0c
+}
6c9f0c
+
6c9f0c
+
6c9f0c
+#ifndef NO_CONFIG_WRITE
6c9f0c
+
6c9f0c
+static char * wpa_config_write_mka_cak(const struct parse_data *data,
6c9f0c
+				       struct wpa_ssid *ssid)
6c9f0c
+{
6c9f0c
+	if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
6c9f0c
+		return NULL;
6c9f0c
+
6c9f0c
+	return wpa_config_write_string_hex(ssid->mka_cak, MACSEC_CAK_LEN);
6c9f0c
+}
6c9f0c
+
6c9f0c
+
6c9f0c
+static char * wpa_config_write_mka_ckn(const struct parse_data *data,
6c9f0c
+				       struct wpa_ssid *ssid)
6c9f0c
+{
6c9f0c
+	if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
6c9f0c
+		return NULL;
6c9f0c
+	return wpa_config_write_string_hex(ssid->mka_ckn, MACSEC_CKN_LEN);
6c9f0c
+}
6c9f0c
+
6c9f0c
+#endif /* NO_CONFIG_WRITE */
6c9f0c
+
6c9f0c
+#endif /* CONFIG_MACSEC */
6c9f0c
+
6c9f0c
+
6c9f0c
 /* Helper macros for network block parser */
6c9f0c
 
6c9f0c
 #ifdef OFFSET
6c9f0c
@@ -2062,6 +2125,8 @@ static const struct parse_data ssid_fields[] = {
6c9f0c
 	{ INT(beacon_int) },
6c9f0c
 #ifdef CONFIG_MACSEC
6c9f0c
 	{ INT_RANGE(macsec_policy, 0, 1) },
6c9f0c
+	{ FUNC_KEY(mka_cak) },
6c9f0c
+	{ FUNC_KEY(mka_ckn) },
6c9f0c
 #endif /* CONFIG_MACSEC */
6c9f0c
 #ifdef CONFIG_HS20
6c9f0c
 	{ INT(update_identifier) },
6c9f0c
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
6c9f0c
index 7ae1654..172508e 100644
6c9f0c
--- a/wpa_supplicant/config_file.c
6c9f0c
+++ b/wpa_supplicant/config_file.c
6c9f0c
@@ -662,6 +662,40 @@ static void write_psk_list(FILE *f, struct wpa_ssid *ssid)
6c9f0c
 #endif /* CONFIG_P2P */
6c9f0c
 
6c9f0c
 
6c9f0c
+#ifdef CONFIG_MACSEC
6c9f0c
+
6c9f0c
+static void write_mka_cak(FILE *f, struct wpa_ssid *ssid)
6c9f0c
+{
6c9f0c
+	char *value;
6c9f0c
+
6c9f0c
+	if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
6c9f0c
+		return;
6c9f0c
+
6c9f0c
+	value = wpa_config_get(ssid, "mka_cak");
6c9f0c
+	if (!value)
6c9f0c
+		return;
6c9f0c
+	fprintf(f, "\tmka_cak=%s\n", value);
6c9f0c
+	os_free(value);
6c9f0c
+}
6c9f0c
+
6c9f0c
+
6c9f0c
+static void write_mka_ckn(FILE *f, struct wpa_ssid *ssid)
6c9f0c
+{
6c9f0c
+	char *value;
6c9f0c
+
6c9f0c
+	if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
6c9f0c
+		return;
6c9f0c
+
6c9f0c
+	value = wpa_config_get(ssid, "mka_ckn");
6c9f0c
+	if (!value)
6c9f0c
+		return;
6c9f0c
+	fprintf(f, "\tmka_ckn=%s\n", value);
6c9f0c
+	os_free(value);
6c9f0c
+}
6c9f0c
+
6c9f0c
+#endif /* CONFIG_MACSEC */
6c9f0c
+
6c9f0c
+
6c9f0c
 static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
6c9f0c
 {
6c9f0c
 	int i;
6c9f0c
@@ -772,6 +806,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
6c9f0c
 	INT(beacon_int);
6c9f0c
 #ifdef CONFIG_MACSEC
6c9f0c
 	INT(macsec_policy);
6c9f0c
+	write_mka_cak(f, ssid);
6c9f0c
+	write_mka_ckn(f, ssid);
6c9f0c
 #endif /* CONFIG_MACSEC */
6c9f0c
 #ifdef CONFIG_HS20
6c9f0c
 	INT(update_identifier);
6c9f0c
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
6c9f0c
index 010b594..a530cda 100644
6c9f0c
--- a/wpa_supplicant/config_ssid.h
6c9f0c
+++ b/wpa_supplicant/config_ssid.h
6c9f0c
@@ -728,6 +728,26 @@ struct wpa_ssid {
6c9f0c
 	 *    determine whether to use a secure session or not.
6c9f0c
 	 */
6c9f0c
 	int macsec_policy;
6c9f0c
+
6c9f0c
+	/**
6c9f0c
+	 * mka_ckn - MKA pre-shared CKN
6c9f0c
+	 */
6c9f0c
+#define MACSEC_CKN_LEN 32
6c9f0c
+	u8 mka_ckn[MACSEC_CKN_LEN];
6c9f0c
+
6c9f0c
+	/**
6c9f0c
+	 * mka_cak - MKA pre-shared CAK
6c9f0c
+	 */
6c9f0c
+#define MACSEC_CAK_LEN 16
6c9f0c
+	u8 mka_cak[MACSEC_CAK_LEN];
6c9f0c
+
6c9f0c
+#define MKA_PSK_SET_CKN BIT(0)
6c9f0c
+#define MKA_PSK_SET_CAK BIT(1)
6c9f0c
+#define MKA_PSK_SET (MKA_PSK_SET_CKN | MKA_PSK_SET_CAK)
6c9f0c
+	/**
6c9f0c
+	 * mka_psk_set - Whether mka_ckn and mka_cak are set
6c9f0c
+	 */
6c9f0c
+	u8 mka_psk_set;
6c9f0c
 #endif /* CONFIG_MACSEC */
6c9f0c
 
6c9f0c
 #ifdef CONFIG_HS20
6c9f0c
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
6c9f0c
index 5d6326a..0bfc39d 100644
6c9f0c
--- a/wpa_supplicant/wpa_supplicant.c
6c9f0c
+++ b/wpa_supplicant/wpa_supplicant.c
6c9f0c
@@ -329,7 +329,12 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
6c9f0c
 
6c9f0c
 	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
6c9f0c
 
6c9f0c
-	ieee802_1x_alloc_kay_sm(wpa_s, ssid);
6c9f0c
+#ifdef CONFIG_MACSEC
6c9f0c
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE && ssid->mka_psk_set)
6c9f0c
+		ieee802_1x_create_preshared_mka(wpa_s, ssid);
6c9f0c
+	else
6c9f0c
+		ieee802_1x_alloc_kay_sm(wpa_s, ssid);
6c9f0c
+#endif /* CONFIG_MACSEC */
6c9f0c
 #endif /* IEEE8021X_EAPOL */
6c9f0c
 }
6c9f0c
 
6c9f0c
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
6c9f0c
index 047ca90..8fa740b 100644
6c9f0c
--- a/wpa_supplicant/wpa_supplicant.conf
6c9f0c
+++ b/wpa_supplicant/wpa_supplicant.conf
6c9f0c
@@ -892,6 +892,14 @@ fast_reauth=1
6c9f0c
 # 1: MACsec enabled - Should secure, accept key server's advice to
6c9f0c
 #    determine whether to use a secure session or not.
6c9f0c
 #
6c9f0c
+# mka_cak and mka_ckn: IEEE 802.1X/MACsec pre-shared authentication mode
6c9f0c
+# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
6c9f0c
+# In this mode, instances of wpa_supplicant can act as peers, one of
6c9f0c
+# which will become the key server and start distributing SAKs.
6c9f0c
+# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-bytes (128 bit)
6c9f0c
+# hex-string (32 hex-digits)
6c9f0c
+# mka_ckn (CKN = CAK Name) takes a 32-bytes (256 bit) hex-string (64 hex-digits)
6c9f0c
+#
6c9f0c
 # mixed_cell: This option can be used to configure whether so called mixed
6c9f0c
 # cells, i.e., networks that use both plaintext and encryption in the same
6c9f0c
 # SSID, are allowed when selecting a BSS from scan results.
6c9f0c
diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c
6c9f0c
index e032330..80b98d9 100644
6c9f0c
--- a/wpa_supplicant/wpas_kay.c
6c9f0c
+++ b/wpa_supplicant/wpas_kay.c
6c9f0c
@@ -371,3 +371,51 @@ fail:
6c9f0c
 
6c9f0c
 	return res;
6c9f0c
 }
6c9f0c
+
6c9f0c
+
6c9f0c
+void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
6c9f0c
+				       struct wpa_ssid *ssid)
6c9f0c
+{
6c9f0c
+	struct mka_key *cak;
6c9f0c
+	struct mka_key_name *ckn;
6c9f0c
+	void *res;
6c9f0c
+
6c9f0c
+	if ((ssid->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
6c9f0c
+		return NULL;
6c9f0c
+
6c9f0c
+	if (ieee802_1x_alloc_kay_sm(wpa_s, ssid) < 0)
6c9f0c
+		return NULL;
6c9f0c
+
6c9f0c
+	if (!wpa_s->kay || wpa_s->kay->policy == DO_NOT_SECURE)
6c9f0c
+		return NULL;
6c9f0c
+
6c9f0c
+	ckn = os_zalloc(sizeof(*ckn));
6c9f0c
+	if (!ckn)
6c9f0c
+		goto dealloc;
6c9f0c
+
6c9f0c
+	cak = os_zalloc(sizeof(*cak));
6c9f0c
+	if (!cak)
6c9f0c
+		goto free_ckn;
6c9f0c
+
6c9f0c
+	cak->len = MACSEC_CAK_LEN;
6c9f0c
+	os_memcpy(cak->key, ssid->mka_cak, cak->len);
6c9f0c
+
6c9f0c
+	ckn->len = MACSEC_CKN_LEN;
6c9f0c
+	os_memcpy(ckn->name, ssid->mka_ckn, ckn->len);
6c9f0c
+
6c9f0c
+	res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, FALSE);
6c9f0c
+	if (res)
6c9f0c
+		return res;
6c9f0c
+
6c9f0c
+	/* Failed to create MKA */
6c9f0c
+	os_free(cak);
6c9f0c
+
6c9f0c
+	/* fallthrough */
6c9f0c
+
6c9f0c
+free_ckn:
6c9f0c
+	os_free(ckn);
6c9f0c
+dealloc:
6c9f0c
+	ieee802_1x_dealloc_kay_sm(wpa_s);
6c9f0c
+
6c9f0c
+	return NULL;
6c9f0c
+}
6c9f0c
diff --git a/wpa_supplicant/wpas_kay.h b/wpa_supplicant/wpas_kay.h
6c9f0c
index b7236d0..81f8e0c 100644
6c9f0c
--- a/wpa_supplicant/wpas_kay.h
6c9f0c
+++ b/wpa_supplicant/wpas_kay.h
6c9f0c
@@ -17,6 +17,9 @@ void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s,
6c9f0c
 				      const u8 *peer_addr);
6c9f0c
 void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s);
6c9f0c
 
6c9f0c
+void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
6c9f0c
+				       struct wpa_ssid *ssid);
6c9f0c
+
6c9f0c
 #else /* CONFIG_MACSEC */
6c9f0c
 
6c9f0c
 static inline int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s,
6c9f0c
@@ -36,6 +39,13 @@ static inline void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s)
6c9f0c
 {
6c9f0c
 }
6c9f0c
 
6c9f0c
+static inline void *
6c9f0c
+ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
6c9f0c
+				struct wpa_ssid *ssid)
6c9f0c
+{
6c9f0c
+	return 0;
6c9f0c
+}
6c9f0c
+
6c9f0c
 #endif /* CONFIG_MACSEC */
6c9f0c
 
6c9f0c
 #endif /* WPAS_KAY_H */
6c9f0c
-- 
6c9f0c
2.7.4
6c9f0c