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

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