diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index a0b64b22a..9011389ea 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1828,6 +1828,69 @@ static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data, #endif /* CONFIG_MESH */ +#ifdef CONFIG_MACSEC + +static int wpa_config_parse_mka_cak(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + if (hexstr2bin(value, ssid->mka_cak, MACSEC_CAK_LEN) || + value[MACSEC_CAK_LEN * 2] != '\0') { + wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.", + line, value); + return -1; + } + + ssid->mka_psk_set |= MKA_PSK_SET_CAK; + + wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak, MACSEC_CAK_LEN); + return 0; +} + + +static int wpa_config_parse_mka_ckn(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + if (hexstr2bin(value, ssid->mka_ckn, MACSEC_CKN_LEN) || + value[MACSEC_CKN_LEN * 2] != '\0') { + wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.", + line, value); + return -1; + } + + ssid->mka_psk_set |= MKA_PSK_SET_CKN; + + wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn, MACSEC_CKN_LEN); + return 0; +} + + +#ifndef NO_CONFIG_WRITE + +static char * wpa_config_write_mka_cak(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK)) + return NULL; + + return wpa_config_write_string_hex(ssid->mka_cak, MACSEC_CAK_LEN); +} + + +static char * wpa_config_write_mka_ckn(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN)) + return NULL; + return wpa_config_write_string_hex(ssid->mka_ckn, MACSEC_CKN_LEN); +} + +#endif /* NO_CONFIG_WRITE */ + +#endif /* CONFIG_MACSEC */ + + /* Helper macros for network block parser */ #ifdef OFFSET @@ -2062,6 +2125,8 @@ static const struct parse_data ssid_fields[] = { { INT(beacon_int) }, #ifdef CONFIG_MACSEC { INT_RANGE(macsec_policy, 0, 1) }, + { FUNC_KEY(mka_cak) }, + { FUNC_KEY(mka_ckn) }, #endif /* CONFIG_MACSEC */ #ifdef CONFIG_HS20 { INT(update_identifier) }, diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 7ae16545b..172508e85 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -662,6 +662,40 @@ static void write_psk_list(FILE *f, struct wpa_ssid *ssid) #endif /* CONFIG_P2P */ +#ifdef CONFIG_MACSEC + +static void write_mka_cak(FILE *f, struct wpa_ssid *ssid) +{ + char *value; + + if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK)) + return; + + value = wpa_config_get(ssid, "mka_cak"); + if (!value) + return; + fprintf(f, "\tmka_cak=%s\n", value); + os_free(value); +} + + +static void write_mka_ckn(FILE *f, struct wpa_ssid *ssid) +{ + char *value; + + if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN)) + return; + + value = wpa_config_get(ssid, "mka_ckn"); + if (!value) + return; + fprintf(f, "\tmka_ckn=%s\n", value); + os_free(value); +} + +#endif /* CONFIG_MACSEC */ + + static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) { int i; @@ -772,6 +806,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT(beacon_int); #ifdef CONFIG_MACSEC INT(macsec_policy); + write_mka_cak(f, ssid); + write_mka_ckn(f, ssid); #endif /* CONFIG_MACSEC */ #ifdef CONFIG_HS20 INT(update_identifier); diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 010b594af..a530cda6a 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -728,6 +728,26 @@ struct wpa_ssid { * determine whether to use a secure session or not. */ int macsec_policy; + + /** + * mka_ckn - MKA pre-shared CKN + */ +#define MACSEC_CKN_LEN 32 + u8 mka_ckn[MACSEC_CKN_LEN]; + + /** + * mka_cak - MKA pre-shared CAK + */ +#define MACSEC_CAK_LEN 16 + u8 mka_cak[MACSEC_CAK_LEN]; + +#define MKA_PSK_SET_CKN BIT(0) +#define MKA_PSK_SET_CAK BIT(1) +#define MKA_PSK_SET (MKA_PSK_SET_CKN | MKA_PSK_SET_CAK) + /** + * mka_psk_set - Whether mka_ckn and mka_cak are set + */ + u8 mka_psk_set; #endif /* CONFIG_MACSEC */ #ifdef CONFIG_HS20 diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 5d6326a5d..0bfc39ddb 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -329,7 +329,12 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s) eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf); - ieee802_1x_alloc_kay_sm(wpa_s, ssid); +#ifdef CONFIG_MACSEC + if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE && ssid->mka_psk_set) + ieee802_1x_create_preshared_mka(wpa_s, ssid); + else + ieee802_1x_alloc_kay_sm(wpa_s, ssid); +#endif /* CONFIG_MACSEC */ #endif /* IEEE8021X_EAPOL */ } diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 047ca9001..8fa740b19 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -892,6 +892,14 @@ fast_reauth=1 # 1: MACsec enabled - Should secure, accept key server's advice to # determine whether to use a secure session or not. # +# mka_cak and mka_ckn: IEEE 802.1X/MACsec pre-shared authentication mode +# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair. +# In this mode, instances of wpa_supplicant can act as peers, one of +# which will become the key server and start distributing SAKs. +# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-bytes (128 bit) +# hex-string (32 hex-digits) +# mka_ckn (CKN = CAK Name) takes a 32-bytes (256 bit) hex-string (64 hex-digits) +# # mixed_cell: This option can be used to configure whether so called mixed # cells, i.e., networks that use both plaintext and encryption in the same # SSID, are allowed when selecting a BSS from scan results. diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c index e03233003..80b98d995 100644 --- a/wpa_supplicant/wpas_kay.c +++ b/wpa_supplicant/wpas_kay.c @@ -371,3 +371,51 @@ fail: return res; } + + +void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + struct mka_key *cak; + struct mka_key_name *ckn; + void *res; + + if ((ssid->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET) + return NULL; + + if (ieee802_1x_alloc_kay_sm(wpa_s, ssid) < 0) + return NULL; + + if (!wpa_s->kay || wpa_s->kay->policy == DO_NOT_SECURE) + return NULL; + + ckn = os_zalloc(sizeof(*ckn)); + if (!ckn) + goto dealloc; + + cak = os_zalloc(sizeof(*cak)); + if (!cak) + goto free_ckn; + + cak->len = MACSEC_CAK_LEN; + os_memcpy(cak->key, ssid->mka_cak, cak->len); + + ckn->len = MACSEC_CKN_LEN; + os_memcpy(ckn->name, ssid->mka_ckn, ckn->len); + + res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, FALSE); + if (res) + return res; + + /* Failed to create MKA */ + os_free(cak); + + /* fallthrough */ + +free_ckn: + os_free(ckn); +dealloc: + ieee802_1x_dealloc_kay_sm(wpa_s); + + return NULL; +} diff --git a/wpa_supplicant/wpas_kay.h b/wpa_supplicant/wpas_kay.h index b7236d077..81f8e0ce3 100644 --- a/wpa_supplicant/wpas_kay.h +++ b/wpa_supplicant/wpas_kay.h @@ -17,6 +17,9 @@ void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s, const u8 *peer_addr); void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s); +void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + #else /* CONFIG_MACSEC */ static inline int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, @@ -36,6 +39,13 @@ static inline void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s) { } +static inline void * +ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + return 0; +} + #endif /* CONFIG_MACSEC */ #endif /* WPAS_KAY_H */