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

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