Skip to content

Commit

Permalink
netplan: add support for WPA3-Enterprise and PMF
Browse files Browse the repository at this point in the history
These changes introduce support for enabling PMF (Protected Management
Frames) through Netplan configuration.

PMF is required by WPA3 and was previously implicitly set to "required"
for WPA3-Personal (via SAE).

There are occasions where the user might not want to restrict the
configuration to WPA3-only (WPA3-Enterprise transition mode)

Network Manager will enable different EAP methods simultaneously when we
set it to "eap", such as WPA-EAP and WPA-EAP-SHA256. NM doesn't allow
the user to set the method as "eap-sha256" only.
As we want to allow the user to use WPA-EAP-SHA256 to enable WPA3, we can't
set the PMF to required or it will break WPA2. We could set it
implicitly to "optional" but it would change the default configuration
we generate.

Because of that, a new key was added to Netplan to enable users to set
the PMF mode manually.

These changes also add two new EAP methods to Netplan: "eap-sha256" and
"eap-suite-b-192". They are both used with WPA3-Enterprise.

PMF is mandatory when using "eap-suite-b-192" so it's implicitly set to
"required".
  • Loading branch information
daniloegea committed Aug 22, 2023
1 parent 3e6783f commit 4ab8e4c
Show file tree
Hide file tree
Showing 12 changed files with 589 additions and 11 deletions.
14 changes: 11 additions & 3 deletions doc/netplan-yaml.md
Original file line number Diff line number Diff line change
Expand Up @@ -850,8 +850,9 @@ interfaces, as well as individual wifi networks, by means of the `auth` block.

> The supported key management modes are `none` (no key management);
> `psk` (WPA with pre-shared key, common for home wifi); `eap` (WPA
> with EAP, common for enterprise wifi); `sae` (used by WPA3); and `802.1x`
> (used primarily for wired Ethernet connections).
> with EAP, common for enterprise wifi); `eap-sha256` (used with WPA3-Enterprise);
> `eap-suite-b-192` (used with WPA3-Enterprise); `sae` (used by WPA3);
> and `802.1x` (used primarily for wired Ethernet connections).

- **password** (scalar)

Expand All @@ -863,7 +864,14 @@ interfaces, as well as individual wifi networks, by means of the `auth` block.
- **method** (scalar)

> The EAP method to use. The supported EAP methods are `tls` (TLS),
> `peap` (Protected EAP), and `ttls` (Tunneled TLS).
> `peap` (Protected EAP), and `ttls` (Tunneled TLS).

- **pmf** (scalar)

> Protected Management Frames (802.11w) mode. Valid values are `optional` and `required`.
> PMF is required by WPA3 and will be set to `required` by default when
> `key-management` is set to `sae` or `eap-suite-b-192`. WPA3-Enterprise with
> `eap-sha256` also requires PMF and must be enabled manually.

- **identity** (scalar)

Expand Down
10 changes: 10 additions & 0 deletions src/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ typedef enum {
NETPLAN_AUTH_KEY_MANAGEMENT_NONE,
NETPLAN_AUTH_KEY_MANAGEMENT_WPA_PSK,
NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAP,
NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAPSHA256,
NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAPSUITE_B_192,
NETPLAN_AUTH_KEY_MANAGEMENT_8021X,
NETPLAN_AUTH_KEY_MANAGEMENT_WPA_SAE,
NETPLAN_AUTH_KEY_MANAGEMENT_MAX,
Expand All @@ -119,9 +121,17 @@ typedef enum {
NETPLAN_AUTH_EAP_METHOD_MAX,
} NetplanAuthEAPMethod;

typedef enum {
NETPLAN_AUTH_PMF_MODE_DISABLED,
NETPLAN_AUTH_PMF_MODE_OPTIONAL,
NETPLAN_AUTH_PMF_MODE_REQUIRED,
NETPLAN_AUTH_PMF_MODE_MAX,
} NetplanAuthPMFMode;

typedef struct authentication_settings {
NetplanAuthKeyManagementType key_management;
NetplanAuthEAPMethod eap_method;
NetplanAuthPMFMode pmf_mode;
char* identity;
char* anonymous_identity;
char* password;
Expand Down
10 changes: 10 additions & 0 deletions src/names.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ netplan_auth_key_management_type_to_str[NETPLAN_AUTH_KEY_MANAGEMENT_MAX] = {
[NETPLAN_AUTH_KEY_MANAGEMENT_NONE] = "none",
[NETPLAN_AUTH_KEY_MANAGEMENT_WPA_PSK] = "psk",
[NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAP] = "eap",
[NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAPSHA256] = "eap-sha256",
[NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAPSUITE_B_192] = "eap-suite-b-192",
[NETPLAN_AUTH_KEY_MANAGEMENT_WPA_SAE] = "sae",
[NETPLAN_AUTH_KEY_MANAGEMENT_8021X] = "802.1x",
};
Expand All @@ -72,6 +74,13 @@ netplan_auth_eap_method_to_str[NETPLAN_AUTH_EAP_METHOD_MAX] = {
[NETPLAN_AUTH_EAP_TTLS] = "ttls",
};

static const char* const
netplan_auth_pmf_mode_to_str[NETPLAN_AUTH_PMF_MODE_MAX] = {
[NETPLAN_AUTH_PMF_MODE_DISABLED] = NULL,
[NETPLAN_AUTH_PMF_MODE_OPTIONAL] = "optional",
[NETPLAN_AUTH_PMF_MODE_REQUIRED] = "required",
};

static const char* const
netplan_tunnel_mode_to_str[NETPLAN_TUNNEL_MODE_MAX_] = {
[NETPLAN_TUNNEL_MODE_UNKNOWN] = NULL,
Expand Down Expand Up @@ -129,6 +138,7 @@ NAME_FUNCTION(backend, NetplanBackend);
NAME_FUNCTION(def_type, NetplanDefType);
NAME_FUNCTION(auth_key_management_type, NetplanAuthKeyManagementType);
NAME_FUNCTION(auth_eap_method, NetplanAuthEAPMethod);
NAME_FUNCTION(auth_pmf_mode, NetplanAuthPMFMode);
NAME_FUNCTION(tunnel_mode, NetplanTunnelMode);
NAME_FUNCTION(addr_gen_mode, NetplanAddrGenMode);
NAME_FUNCTION(wifi_mode, NetplanWifiMode);
Expand Down
3 changes: 3 additions & 0 deletions src/names.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ netplan_auth_key_management_type_name(NetplanAuthKeyManagementType val);
const char*
netplan_auth_eap_method_name(NetplanAuthEAPMethod val);

const char*
netplan_auth_pmf_mode_name(NetplanAuthPMFMode val);

const char*
netplan_tunnel_mode_name(NetplanTunnelMode val);

Expand Down
1 change: 1 addition & 0 deletions src/netplan.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ write_auth(yaml_event_t* event, yaml_emitter_t* emitter, NetplanAuthenticationSe
YAML_MAPPING_OPEN(event, emitter);
YAML_NONNULL_STRING(event, emitter, "key-management", netplan_auth_key_management_type_name(auth.key_management));
YAML_NONNULL_STRING(event, emitter, "method", netplan_auth_eap_method_name(auth.eap_method));
YAML_NONNULL_STRING(event, emitter, "pmf", netplan_auth_pmf_mode_name(auth.pmf_mode));
YAML_NONNULL_STRING(event, emitter, "anonymous-identity", auth.anonymous_identity);
YAML_NONNULL_STRING(event, emitter, "identity", auth.identity);
YAML_NONNULL_STRING(event, emitter, "ca-certificate", auth.ca_certificate);
Expand Down
28 changes: 23 additions & 5 deletions src/networkd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1049,13 +1049,16 @@ append_wpa_auth_conf(GString* s, const NetplanAuthenticationSettings* auth, cons
g_string_append(s, " key_mgmt=WPA-EAP\n");
break;

case NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAPSHA256:
g_string_append(s, " key_mgmt=WPA-EAP-SHA256\n");
break;

case NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAPSUITE_B_192:
g_string_append(s, " key_mgmt=WPA-EAP-SUITE-B-192\n");
break;

case NETPLAN_AUTH_KEY_MANAGEMENT_WPA_SAE:
/*
* SAE is used by WPA3 and Management Frame Protection
* (ieee80211w) is mandatory.
*/
g_string_append(s, " key_mgmt=SAE\n");
g_string_append(s, " ieee80211w=2\n");
break;

case NETPLAN_AUTH_KEY_MANAGEMENT_8021X:
Expand Down Expand Up @@ -1084,6 +1087,21 @@ append_wpa_auth_conf(GString* s, const NetplanAuthenticationSettings* auth, cons
default: break; // LCOV_EXCL_LINE
}

switch (auth->pmf_mode) {
case NETPLAN_AUTH_PMF_MODE_DISABLED:
break;

case NETPLAN_AUTH_PMF_MODE_OPTIONAL:
g_string_append(s, " ieee80211w=1\n");
break;

case NETPLAN_AUTH_PMF_MODE_REQUIRED:
g_string_append(s, " ieee80211w=2\n");
break;

default: break; // LCOV_EXCL_LINE
}

if (auth->identity) {
g_string_append_printf(s, " identity=\"%s\"\n", auth->identity);
}
Expand Down
22 changes: 22 additions & 0 deletions src/nm.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,13 @@ write_wifi_auth_parameters(const NetplanAuthenticationSettings* auth, GKeyFile *
case NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAP:
g_key_file_set_string(kf, "wifi-security", "key-mgmt", "wpa-eap");
break;
case NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAPSHA256:
/* NM uses "wpa-eap" to enable both EAP and EAP-SHA256 */
g_key_file_set_string(kf, "wifi-security", "key-mgmt", "wpa-eap");
break;
case NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAPSUITE_B_192:
g_key_file_set_string(kf, "wifi-security", "key-mgmt", "wpa-eap-suite-b-192");
break;
case NETPLAN_AUTH_KEY_MANAGEMENT_WPA_SAE:
g_key_file_set_string(kf, "wifi-security", "key-mgmt", "sae");
break;
Expand All @@ -458,6 +465,21 @@ write_wifi_auth_parameters(const NetplanAuthenticationSettings* auth, GKeyFile *
default: break; // LCOV_EXCL_LINE
}

switch (auth->pmf_mode) {
case NETPLAN_AUTH_PMF_MODE_DISABLED:
break;

case NETPLAN_AUTH_PMF_MODE_OPTIONAL:
g_key_file_set_string(kf, "wifi-security", "pmf", "2");
break;

case NETPLAN_AUTH_PMF_MODE_REQUIRED:
g_key_file_set_string(kf, "wifi-security", "pmf", "3");
break;

default: break; // LCOV_EXCL_LINE
}

if (auth->eap_method != NETPLAN_AUTH_EAP_NONE)
write_dot1x_auth_parameters(auth, kf);
else if (auth->password)
Expand Down
20 changes: 20 additions & 0 deletions src/parse-nm.c
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ netplan_parser_load_keyfile(NetplanParser* npp, const char* filename, GError** e
g_autofree gchar* netdef_id = NULL;
ssize_t netdef_id_size = 0;
gchar *tmp_str = NULL;
gint pmf = 0;
NetplanNetDefinition* nd = NULL;
NetplanWifiAccessPoint* ap = NULL;
g_autoptr(GKeyFile) kf = g_key_file_new();
Expand Down Expand Up @@ -970,6 +971,10 @@ netplan_parser_load_keyfile(NetplanParser* npp, const char* filename, GError** e
ap->auth.key_management = NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAP;
ap->has_auth = TRUE;
_kf_clear_key(kf, "wifi-security", "key-mgmt");
} else if (tmp_str && g_strcmp0(tmp_str, "wpa-eap-suite-b-192") == 0) {
ap->auth.key_management = NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAPSUITE_B_192;
ap->has_auth = TRUE;
_kf_clear_key(kf, "wifi-security", "key-mgmt");
} else if (tmp_str && g_strcmp0(tmp_str, "sae") == 0) {
ap->auth.key_management = NETPLAN_AUTH_KEY_MANAGEMENT_WPA_SAE;
ap->has_auth = TRUE;
Expand All @@ -981,6 +986,21 @@ netplan_parser_load_keyfile(NetplanParser* npp, const char* filename, GError** e
}
g_free(tmp_str);

pmf = g_key_file_get_integer(kf, "wifi-security", "pmf", NULL);
switch (pmf) {
case 2:
ap->auth.pmf_mode = NETPLAN_AUTH_PMF_MODE_OPTIONAL;
_kf_clear_key(kf, "wifi-security", "pmf");
break;

case 3:
ap->auth.pmf_mode = NETPLAN_AUTH_PMF_MODE_REQUIRED;
_kf_clear_key(kf, "wifi-security", "pmf");
break;

default: break;
}

keyfile_handle_generic_str(kf, "wifi-security", "psk", &ap->auth.password);
if (ap->auth.password)
ap->has_auth = TRUE;
Expand Down
31 changes: 30 additions & 1 deletion src/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -915,8 +915,22 @@ handle_auth_key_management(NetplanParser* npp, yaml_node_t* node, __unused const
auth->key_management = NETPLAN_AUTH_KEY_MANAGEMENT_WPA_PSK;
else if (strcmp(scalar(node), "eap") == 0)
auth->key_management = NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAP;
else if (strcmp(scalar(node), "sae") == 0)
else if (strcmp(scalar(node), "eap-sha256") == 0)
auth->key_management = NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAPSHA256;
else if (strcmp(scalar(node), "eap-suite-b-192") == 0) {
/* Settings for WPA3-Enterprise for sensitive enterprise environments.
* Management Frame Protection (ieee80211w) is mandatory.
*/
auth->key_management = NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAPSUITE_B_192;
auth->pmf_mode = NETPLAN_AUTH_PMF_MODE_REQUIRED;
}
else if (strcmp(scalar(node), "sae") == 0) {
/* SAE is used by WPA3 and Management Frame Protection
* (ieee80211w) is mandatory.
*/
auth->key_management = NETPLAN_AUTH_KEY_MANAGEMENT_WPA_SAE;
auth->pmf_mode = NETPLAN_AUTH_PMF_MODE_REQUIRED;
}
else if (strcmp(scalar(node), "802.1x") == 0)
auth->key_management = NETPLAN_AUTH_KEY_MANAGEMENT_8021X;
else
Expand All @@ -940,9 +954,24 @@ handle_auth_method(NetplanParser* npp, yaml_node_t* node, __unused const void* _
return TRUE;
}

static gboolean
handle_pmf_mode(NetplanParser* npp, yaml_node_t* node, __unused const void* _, GError** error)
{
NetplanAuthenticationSettings* auth = npp->current.auth;
g_assert(auth);
if (strcmp(scalar(node), "optional") == 0)
auth->pmf_mode = NETPLAN_AUTH_PMF_MODE_OPTIONAL;
else if (strcmp(scalar(node), "required") == 0)
auth->pmf_mode = NETPLAN_AUTH_PMF_MODE_REQUIRED;
else
return yaml_error(npp, node, error, "unknown PMF mode '%s'. Valid entries are \"optional\" and \"disabled\"", scalar(node));
return TRUE;
}

static const mapping_entry_handler auth_handlers[] = {
{"key-management", YAML_SCALAR_NODE, {.generic=handle_auth_key_management}, NULL},
{"method", YAML_SCALAR_NODE, {.generic=handle_auth_method}, NULL},
{"pmf", YAML_SCALAR_NODE, {.generic=handle_pmf_mode}, NULL},
{"identity", YAML_SCALAR_NODE, {.generic=handle_auth_str}, auth_offset(identity)},
{"anonymous-identity", YAML_SCALAR_NODE, {.generic=handle_auth_str}, auth_offset(anonymous_identity)},
{"password", YAML_SCALAR_NODE, {.generic=handle_auth_str}, auth_offset(password)},
Expand Down
1 change: 1 addition & 0 deletions src/types.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ reset_auth_settings(NetplanAuthenticationSettings* auth)
FREE_AND_NULLIFY(auth->phase2_auth);
auth->key_management = NETPLAN_AUTH_KEY_MANAGEMENT_NONE;
auth->eap_method = NETPLAN_AUTH_EAP_NONE;
auth->pmf_mode = NETPLAN_AUTH_PMF_MODE_DISABLED;
}

void
Expand Down
Loading

0 comments on commit 4ab8e4c

Please sign in to comment.