wifi: support WPA2 ad-hoc (ibss-rsn)

If the device supports it, allow usage of WPA2 in ad-hoc networks.

Based-on-patch-by: Nicolas Cavallari <cavallar@lri.fr>

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/issues/184
This commit is contained in:
Beniamino Galvani 2019-08-19 18:04:48 +02:00
parent c97e0ce30b
commit a205eb4aa4
6 changed files with 151 additions and 121 deletions

View file

@ -1214,46 +1214,30 @@ nm_utils_security_valid (NMUtilsSecurityType type,
break;
case NMU_SEC_WPA_PSK:
if (adhoc)
return FALSE; /* FIXME: Kernel WPA Ad-Hoc support is buggy */
return FALSE;
if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
return FALSE;
if (have_ap) {
/* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
* they don't have any pairwise ciphers. */
if (adhoc) {
/* coverity[dead_error_line] */
if ( (ap_wpa & NM_802_11_AP_SEC_GROUP_TKIP)
if (ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
if ( (ap_wpa & NM_802_11_AP_SEC_PAIR_TKIP)
&& (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
return TRUE;
if ( (ap_wpa & NM_802_11_AP_SEC_GROUP_CCMP)
if ( (ap_wpa & NM_802_11_AP_SEC_PAIR_CCMP)
&& (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
return TRUE;
} else {
if (ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
if ( (ap_wpa & NM_802_11_AP_SEC_PAIR_TKIP)
&& (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
return TRUE;
if ( (ap_wpa & NM_802_11_AP_SEC_PAIR_CCMP)
&& (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
return TRUE;
}
}
return FALSE;
}
break;
case NMU_SEC_WPA2_PSK:
if (adhoc)
return FALSE; /* FIXME: Kernel WPA Ad-Hoc support is buggy */
if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
return FALSE;
if (have_ap) {
/* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
* they don't have any pairwise ciphers, nor any RSA flags yet. */
if (adhoc) {
/* coverity[dead_error_line] */
if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
return TRUE;
if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
if (!(wifi_caps & NM_WIFI_DEVICE_CAP_IBSS_RSN))
return FALSE;
if ( (ap_rsn & NM_802_11_AP_SEC_PAIR_CCMP)
&& (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
return TRUE;
} else {
if (ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_PSK) {

View file

@ -1232,7 +1232,7 @@ nm_wifi_ap_new_fake_from_connection (NMConnection *connection)
const char *mode, *band, *key_mgmt;
guint32 channel;
NM80211ApSecurityFlags flags;
gboolean psk = FALSE, eap = FALSE;
gboolean psk = FALSE, eap = FALSE, adhoc = FALSE;
g_return_val_if_fail (connection != NULL, NULL);
@ -1252,9 +1252,10 @@ nm_wifi_ap_new_fake_from_connection (NMConnection *connection)
if (mode) {
if (!strcmp (mode, "infrastructure"))
nm_wifi_ap_set_mode (ap, NM_802_11_MODE_INFRA);
else if (!strcmp (mode, "adhoc"))
else if (!strcmp (mode, "adhoc")) {
nm_wifi_ap_set_mode (ap, NM_802_11_MODE_ADHOC);
else if (!strcmp (mode, "mesh"))
adhoc = TRUE;
} else if (!strcmp (mode, "mesh"))
nm_wifi_ap_set_mode (ap, NM_802_11_MODE_MESH);
else if (!strcmp (mode, "ap")) {
nm_wifi_ap_set_mode (ap, NM_802_11_MODE_INFRA);
@ -1293,7 +1294,7 @@ nm_wifi_ap_new_fake_from_connection (NMConnection *connection)
psk = !strcmp (key_mgmt, "wpa-psk");
eap = !strcmp (key_mgmt, "wpa-eap");
if (psk || eap) {
if (!adhoc && (psk || eap)) {
if (has_proto (s_wireless_sec, PROTO_WPA)) {
flags = priv->wpa_flags | (eap ? NM_802_11_AP_SEC_KEY_MGMT_802_1X : NM_802_11_AP_SEC_KEY_MGMT_PSK);
nm_wifi_ap_set_wpa_flags (ap, flags);
@ -1305,8 +1306,27 @@ nm_wifi_ap_new_fake_from_connection (NMConnection *connection)
add_pair_ciphers (ap, s_wireless_sec);
add_group_ciphers (ap, s_wireless_sec);
}
} else if (adhoc && psk) {
/* Ad-Hoc has special requirements: proto=RSN, pairwise=CCMP and
* group=CCMP.
*/
flags = priv->wpa_flags | NM_802_11_AP_SEC_KEY_MGMT_PSK;
/* Clear ciphers; only CCMP is supported */
flags &= ~( NM_802_11_AP_SEC_PAIR_WEP40
| NM_802_11_AP_SEC_PAIR_WEP104
| NM_802_11_AP_SEC_PAIR_TKIP
| NM_802_11_AP_SEC_GROUP_WEP40
| NM_802_11_AP_SEC_GROUP_WEP104
| NM_802_11_AP_SEC_GROUP_TKIP);
flags |= NM_802_11_AP_SEC_PAIR_CCMP;
flags |= NM_802_11_AP_SEC_GROUP_CCMP;
nm_wifi_ap_set_rsn_flags (ap, flags);
/* Don't use Ad-Hoc WPA (WPA-none) anymore */
nm_wifi_ap_set_wpa_flags (ap, NM_802_11_AP_SEC_NONE);
}
done:
return ap;

View file

@ -302,41 +302,74 @@ verify_wpa_psk (NMSettingWirelessSecurity *s_wsec,
key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
if (key_mgmt) {
if (!strcmp (key_mgmt, "wpa-psk")) {
if (s_8021x) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_SETTING,
_("WPA-PSK authentication is incompatible with 802.1x"));
g_prefix_error (error, "%s: ", NM_SETTING_802_1X_SETTING_NAME);
return FALSE;
}
if (!nm_streq0 (key_mgmt, "wpa-psk"))
return TRUE;
if (auth_alg && strcmp (auth_alg, "open")) {
/* WPA must use "open" authentication */
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("WPA-PSK requires 'open' authentication"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG);
return FALSE;
}
if (s_8021x) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_SETTING,
_("WPA-PSK authentication is incompatible with 802.1x"));
g_prefix_error (error, "%s: ", NM_SETTING_802_1X_SETTING_NAME);
return FALSE;
}
if (auth_alg && !nm_streq (auth_alg, "open")) {
/* WPA must use "open" authentication */
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("WPA-PSK requires 'open' authentication"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG);
return FALSE;
}
/* Make sure the AP's capabilities support WPA-PSK */
if ( !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
&& !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("Access point does not support PSK but setting requires it"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT);
return FALSE;
}
if (adhoc) {
/* Ad-Hoc RSN requires 'rsn' proto, 'ccmp' pairwise, and 'ccmp' group */
if ( nm_setting_wireless_security_get_num_protos (s_wsec) != 1
|| !nm_streq0 (nm_setting_wireless_security_get_proto (s_wsec, 0), "rsn")) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("WPA Ad-Hoc authentication requires 'rsn' protocol"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SETTING_WIRELESS_SECURITY_PROTO);
return FALSE;
}
if (!strcmp (key_mgmt, "wpa-psk")) {
/* Make sure the AP's capabilities support WPA-PSK */
if ( !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
&& !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("Access point does not support PSK but setting requires it"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT);
return FALSE;
}
if ( nm_setting_wireless_security_get_num_pairwise (s_wsec) != 1
|| !nm_streq0 (nm_setting_wireless_security_get_pairwise (s_wsec, 0), "ccmp")) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("WPA Ad-Hoc authentication requires 'ccmp' pairwise cipher"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SETTING_WIRELESS_SECURITY_PAIRWISE);
return FALSE;
}
if ( nm_setting_wireless_security_get_num_groups (s_wsec) != 1
|| !nm_streq0 (nm_setting_wireless_security_get_group (s_wsec, 0), "ccmp")) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("WPA Ad-Hoc requires 'ccmp' group cipher"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SETTING_WIRELESS_SECURITY_GROUP);
return FALSE;
}
}
@ -413,51 +446,52 @@ verify_adhoc (NMSettingWirelessSecurity *s_wsec,
{
const char *key_mgmt = NULL, *leap_username = NULL, *auth_alg = NULL;
if (!adhoc)
return TRUE;
if (s_wsec) {
key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
}
if (adhoc) {
if (key_mgmt && !nm_streq (key_mgmt, "none")) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("Access point mode is Ad-Hoc but setting requires Infrastructure security"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT);
return FALSE;
}
if (key_mgmt && !NM_IN_STRSET (key_mgmt, "none", "wpa-psk")) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("Ad-Hoc mode requires 'none' or 'wpa-psk' key management"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT);
return FALSE;
}
if (s_8021x) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_SETTING,
_("Ad-Hoc mode is incompatible with 802.1x security"));
g_prefix_error (error, "%s: ", NM_SETTING_802_1X_SETTING_NAME);
return FALSE;
}
if (s_8021x) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_SETTING,
_("Ad-Hoc mode is incompatible with 802.1x security"));
g_prefix_error (error, "%s: ", NM_SETTING_802_1X_SETTING_NAME);
return FALSE;
}
if (leap_username) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("Ad-Hoc mode is incompatible with LEAP security"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG);
return FALSE;
}
if (leap_username) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("Ad-Hoc mode is incompatible with LEAP security"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG);
return FALSE;
}
if (auth_alg && strcmp (auth_alg, "open")) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("Ad-Hoc mode requires 'open' authentication"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG);
return FALSE;
}
if (auth_alg && !nm_streq (auth_alg, "open")) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("Ad-Hoc mode requires 'open' authentication"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG);
return FALSE;
}
return TRUE;
@ -713,7 +747,13 @@ nm_wifi_utils_complete_connection (GBytes *ap_ssid,
return FALSE;
if (adhoc) {
/* TODO */
g_object_set (s_wsec,
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk",
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
NULL);
nm_setting_wireless_security_add_proto (s_wsec, "rsn");
nm_setting_wireless_security_add_pairwise (s_wsec, "ccmp");
nm_setting_wireless_security_add_group (s_wsec, "ccmp");
} else if (s_8021x) {
g_object_set (s_wsec,
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap",

View file

@ -2954,22 +2954,6 @@ fill_wpa_ciphers (shvarFile *ifcfg,
list = nm_utils_strsplit_set (p, " ");
for (iter = list; iter && *iter; iter++, i++) {
/* Ad-Hoc configurations cannot have pairwise ciphers, and can only
* have one group cipher. Ignore any additional group ciphers and
* any pairwise ciphers specified.
*/
if (adhoc) {
if (group && (i > 0)) {
PARSE_WARNING ("ignoring group cipher '%s' (only one group cipher allowed "
"in Ad-Hoc mode)", *iter);
continue;
} else if (!group) {
PARSE_WARNING ("ignoring pairwise cipher '%s' (pairwise not used "
"in Ad-Hoc mode)", *iter);
continue;
}
}
if (!strcmp (*iter, "CCMP")) {
if (group)
nm_setting_wireless_security_add_group (wsec, "ccmp");
@ -3644,8 +3628,8 @@ make_wpa_setting (shvarFile *ifcfg,
/* WPA and/or RSN */
if (adhoc) {
/* Ad-Hoc mode only supports WPA proto for now */
nm_setting_wireless_security_add_proto (wsec, "wpa");
/* Ad-Hoc mode only supports RSN proto */
nm_setting_wireless_security_add_proto (wsec, "rsn");
} else {
gs_free char *value2 = NULL;
const char *v2;

View file

@ -12,5 +12,6 @@ USERCTL=yes
PEERDNS=yes
IPV6INIT=no
CIPHER_GROUP=CCMP
CIPHER_PAIRWISE=CCMP
KEY_MGMT=WPA-PSK

View file

@ -3136,14 +3136,14 @@ test_read_wifi_wpa_psk_adhoc (void)
g_assert_cmpstr (nm_setting_wireless_security_get_key_mgmt (s_wsec), ==, "wpa-psk");
g_assert_cmpstr (nm_setting_wireless_security_get_psk (s_wsec), ==, "I wonder what the king is doing tonight?");
/* Pairwise cipher is unused in adhoc mode */
g_assert_cmpint (nm_setting_wireless_security_get_num_pairwise (s_wsec), ==, 0);
g_assert_cmpint (nm_setting_wireless_security_get_num_pairwise (s_wsec), ==, 1);
g_assert_cmpstr (nm_setting_wireless_security_get_pairwise (s_wsec, 0), ==, "ccmp");
g_assert_cmpint (nm_setting_wireless_security_get_num_groups (s_wsec), ==, 1);
g_assert_cmpstr (nm_setting_wireless_security_get_group (s_wsec, 0), ==, "ccmp");
g_assert_cmpint (nm_setting_wireless_security_get_num_protos (s_wsec), ==, 1);
g_assert_cmpstr (nm_setting_wireless_security_get_proto (s_wsec, 0), ==, "wpa");
g_assert_cmpstr (nm_setting_wireless_security_get_proto (s_wsec, 0), ==, "rsn");
/* ===== IPv4 SETTING ===== */
@ -6464,8 +6464,9 @@ test_write_wifi_wpa_psk_adhoc (void)
NM_SETTING_WIRELESS_SECURITY_PSK, "7d308b11df1b4243b0f78e5f3fc68cdbb9a264ed0edf4c188edf329ff5b467f0",
NULL);
nm_setting_wireless_security_add_proto (s_wsec, "wpa");
nm_setting_wireless_security_add_group (s_wsec, "tkip");
nm_setting_wireless_security_add_proto (s_wsec, "rsn");
nm_setting_wireless_security_add_pairwise (s_wsec, "ccmp");
nm_setting_wireless_security_add_group (s_wsec, "ccmp");
/* IP4 setting */
s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();