wpa_supplicant: Allow pre-shared (CAK,CKN) pair for MKA

This enables configuring key_mgmt=NONE + mka_ckn + mka_cak.
This allows wpa_supplicant to work in a peer-to-peer mode, where peers
are authenticated by the pre-shared (CAK,CKN) pair. In this mode, peers
can act as key server to distribute keys for the MACsec instances.

This is what some MACsec switches support, and even without HW
support, it's a convenient way to setup a network.

Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
This commit is contained in:
Sabrina Dubroca 2016-11-02 16:38:35 +01:00 committed by Jouni Malinen
parent 5acbf22bb0
commit ad51731abf
7 changed files with 193 additions and 1 deletions

View File

@ -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) },

View File

@ -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);

View File

@ -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

View File

@ -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 */
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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 */