From 8e04a17bc53ea2fb2ca1740ae4783515b10973d7 Mon Sep 17 00:00:00 2001 From: Harald Milz Date: Fri, 2 May 2025 09:29:14 +0200 Subject: [PATCH 1/9] esp32: Set disable_time_check default to False. Signed-off-by: Harald Milz --- docs/library/network.WLAN.rst | 74 +++++++++++++++ ports/esp32/network_wlan.c | 170 ++++++++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+) diff --git a/docs/library/network.WLAN.rst b/docs/library/network.WLAN.rst index ee0ef490fda84..62c011ca73b32 100644 --- a/docs/library/network.WLAN.rst +++ b/docs/library/network.WLAN.rst @@ -147,6 +147,80 @@ Methods pm WiFi Power Management setting (see below for allowed values) ============= =========== +.. method:: WLAN.eap_connect(param=value, ...) + + Connect to the specified wireless network, using WPA-Enterprise authentication and + the specified parameters. ESP32 port only. The EAP methods provided are EAP-PWD, EAP-PEAP, + EAP-TTLS, and EAP-TLS. EAP-TLS is UNTESTED and thus EXPERIMENTAL. + + Common parameters: + + * ssid -- WiFi access point name, (string, e.g. `eduroam`) + * eap_method -- EAP method to use (string) + + EAP-PWD parameters + + * username -- your network username (string) + * password -- your network password (string) + + EAP-PEAP parameters: + + * username -- your network username (string) + * password -- your network password (string) + * identity -- anonymous identity (string) + * ca_cert -- the CA certificate (filename, string) + + EAP-TTLS parameters: + + * username -- your network username (string) + * password -- your network password (string) + * identity -- anonymous identity (string) + * ca_cert -- the CA certificate (filename, string) + * ttls_phase2_method -- TTLS Phase 2 method (integer) + + EAP-TTLS supports the following TTLS Phase 2 methods: + + * 0 -- PWD + * 1 -- MSCHAPv2 (default) + * 2 -- MSCHAP + * 3 -- PAP + * 4 -- CHAP + + Please note that MSCHAPv2 and CHAP have known security issues and should be avoided. + + EAP-TLS parameters: + + * client_cert -- client certificate filename (string) + * private_key -- private key filename (string) + * private_key_password -- private key password (string, optional) + * disable_time_check -- suppress the validity check for the local client certificate when using EAP-TLS (boolean, default False) + + `disable_time_check` is only included for the sake of completeness. In practice, + you want to renew the client certificate before expiry. + + Certificate files need to be uploaded first, e.g.:: + + mpremote cp : + + EAP-PWD should be used whenever possible. It connects swiftly and uses the least resources. + When using one of the other methods, make sure the system time is correct to prevent + certificate validation errors. Best practice is to use a battery buffered RTC and to set + the system time using NTP regularly. A temporary workaround if no battery buffered RTC is + available is to set the system time to the image build time, like: + + import sys + import machine + (year, month, day) = sys.version.split(" on ")[1].split("-") + rtc = machine.RTC() + date_time = (int(year), int(month), int(day), 0, 0, 0, 0, 0) + rtc.init(date_time) + + + + + + + Constants --------- diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c index e85d1328fdc2b..ac1f37f663ff0 100644 --- a/ports/esp32/network_wlan.c +++ b/ports/esp32/network_wlan.c @@ -732,6 +732,176 @@ static mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_ } MP_DEFINE_CONST_FUN_OBJ_KW(network_wlan_config_obj, 1, network_wlan_config); +<<<<<<< HEAD +======= +// WPA2 Enterprise Connect + +// there are no official constants so far +#define WIFI_AUTH_EAP_PWD 0 +#define WIFI_AUTH_EAP_PEAP 1 +#define WIFI_AUTH_EAP_TTLS 2 +#define WIFI_AUTH_EAP_TLS 3 + +static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_ssid, ARG_eap_method, ARG_username, ARG_password, + ARG_identity, ARG_ca_cert, ARG_ttls_phase2_method, + ARG_client_cert, ARG_private_key, ARG_private_key_password, ARG_disable_time_check }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_eap_method, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, // default EAP-PWD + { MP_QSTR_username, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_password, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_identity, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_ca_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_ttls_phase2_method, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, // default MSCHAPV2 + { MP_QSTR_client_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_private_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_private_key_password, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, +<<<<<<< HEAD + { MP_QSTR_disable_time_check, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, // beware! +======= + { MP_QSTR_disable_time_check, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, +>>>>>>> 0517049d7 (ports/esp32: Set disable_time_check default to False.) + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + wifi_config_t wifi_sta_config = {0}; + int16_t eap_method = (int16_t)args[ARG_eap_method].u_int; + size_t len; + const char *p; + + // TODO check if the IF is in STA mode, else bail out. + + // parameter check + if (eap_method < WIFI_AUTH_EAP_PWD || eap_method > WIFI_AUTH_EAP_TLS) { + mp_raise_ValueError(MP_ERROR_TEXT("unknown config value for eap_method")); + } + + // this is mandatory and should not be None. + if (args[ARG_ssid].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len); + memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid))); + } + esp_exceptions(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config)); + + if (eap_method == WIFI_AUTH_EAP_PWD || eap_method == WIFI_AUTH_EAP_PEAP || eap_method == WIFI_AUTH_EAP_TTLS) { + // use username and password + if (args[ARG_username].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_username].u_obj, &len); + esp_exceptions(esp_eap_client_set_username((const unsigned char *) p, len)); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("missing config param username")); + } + if (args[ARG_password].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_password].u_obj, &len); + esp_exceptions(esp_eap_client_set_password((const unsigned char *) p, len)); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("missing config param password")); + } + } + + if (eap_method == WIFI_AUTH_EAP_PEAP || eap_method == WIFI_AUTH_EAP_TTLS) { + // additionally use identity and ca_cert + if (args[ARG_identity].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_identity].u_obj, &len); + esp_exceptions(esp_eap_client_set_identity((const unsigned char *) p, len)); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("missing config param identity")); + } + if (args[ARG_ca_cert].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_ca_cert].u_obj, &len); + // see comment (1) below. + esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *) p, len+1)); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("missing config param ca_cert")); + } + } + + if (eap_method == WIFI_AUTH_EAP_TTLS) { + // additionally use ttls_phase2_method, defaulting to MSCHAPV2 (and then very similar to EAP-PEAP) + // tested and verified with all 5 supported phase 2 methods. + if (args[ARG_ttls_phase2_method].u_obj != mp_const_none) { + int16_t ttls_phase2_method = (int16_t)args[ARG_ttls_phase2_method].u_int; + if (ttls_phase2_method < ESP_EAP_TTLS_PHASE2_EAP || ttls_phase2_method > ESP_EAP_TTLS_PHASE2_CHAP) { + mp_raise_ValueError(MP_ERROR_TEXT("unknown config value for ttls_phase2_method")); + } + mp_printf(&mp_plat_print, "ttls_phase2_method: \"%d\"\n", ttls_phase2_method); + esp_exceptions(esp_eap_client_set_ttls_phase2_method(ttls_phase2_method)); + } + } + + if (eap_method == WIFI_AUTH_EAP_TLS) { + // UNTESTED! + // EAP-TLS uses client cert, private key, and (optionally) private key password, and (optionally) ca_cert + size_t client_cert_len = 0; + const char *client_cert = NULL; + size_t private_key_len = 0; + const char *private_key = NULL; + size_t private_key_password_len = 0; + const char *private_key_password = NULL; + + mp_printf(&mp_plat_print, "\nPlease note that EAP-TLS is so far UNTESTED and thus EXPERIMENTAL.\nUse at your own risk!\n\n"); + if (args[ARG_client_cert].u_obj != mp_const_none) { + client_cert = mp_obj_str_get_data(args[ARG_client_cert].u_obj, &client_cert_len); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("missing config param client_cert")); + } + if (args[ARG_private_key].u_obj != mp_const_none) { + private_key = mp_obj_str_get_data(args[ARG_private_key].u_obj, &private_key_len); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("missing config param private_key")); + } + if (args[ARG_private_key_password].u_obj != mp_const_none) { // password is optional + private_key_password = mp_obj_str_get_data(args[ARG_private_key_password].u_obj, &private_key_password_len); + } + // disable time check or not + if (args[ARG_disable_time_check].u_bool == true) { + esp_exceptions(esp_eap_client_set_disable_time_check(true)); + mp_printf(&mp_plat_print, "disable_time_check: true\n"); + } + + // (1) the documentation for esp_eap_client_set_certificate_and_key() says, + // "2. The client_cert, private_key, and private_key_password should be zero-terminated." + // so we copy 1 byte more to include the null. + // in the esp-idf wifi_enterprise example, the null is appended when converting the cert files to byte arrays. + esp_exceptions(esp_eap_client_set_certificate_and_key( + (const unsigned char *) client_cert, client_cert_len+1, + (const unsigned char *) private_key, private_key_len+1, + (const unsigned char *) private_key_password, private_key_password_len+1) + ); + // according to the esp-idf wifi_enterprise example, the ca_cert is optional for EAP-TLS + if (args[ARG_ca_cert].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_ca_cert].u_obj, &len); + const mp_obj_type_t *type = mp_obj_get_type(args[ARG_ca_cert].u_obj); + esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *) p, len+1)); + } + } + + esp_exceptions(esp_netif_set_hostname(wlan_sta_obj.netif, mod_network_hostname_data)); + + // eap_enable & start + esp_exceptions(esp_wifi_sta_enterprise_enable()); + // TODO Maybe we need to add esp_wifi_sta_enterprise_disable() to wlan.active(False)? + // or separate function + if (!wifi_started) { + esp_exceptions(esp_wifi_start()); + } + + wifi_sta_reconnects = 0; + // connect to the WiFi AP + MP_THREAD_GIL_EXIT(); + esp_exceptions(esp_wifi_connect()); + MP_THREAD_GIL_ENTER(); + wifi_sta_connect_requested = true; + + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_KW(network_wlan_eap_connect_obj, 1, network_wlan_eap_connect); + +>>>>>>> 3ec881cdd (ports/esp32: Set disable_time_check default to False.) static const mp_rom_map_elem_t wlan_if_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_wlan_active_obj) }, { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&network_wlan_connect_obj) }, From 6edd762b97159c1b4b2a0fa052528f56786cd031 Mon Sep 17 00:00:00 2001 From: Harald Milz Date: Fri, 2 May 2025 10:47:19 +0200 Subject: [PATCH 2/9] esp32: Formatting corrections. Signed-off-by: Harald Milz --- docs/library/network.WLAN.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/library/network.WLAN.rst b/docs/library/network.WLAN.rst index 62c011ca73b32..1abb0b993dd1b 100644 --- a/docs/library/network.WLAN.rst +++ b/docs/library/network.WLAN.rst @@ -155,7 +155,7 @@ Methods Common parameters: - * ssid -- WiFi access point name, (string, e.g. `eduroam`) + * ssid -- WiFi access point name, (string, e.g. "eduroam") * eap_method -- EAP method to use (string) EAP-PWD parameters @@ -195,7 +195,7 @@ Methods * private_key_password -- private key password (string, optional) * disable_time_check -- suppress the validity check for the local client certificate when using EAP-TLS (boolean, default False) - `disable_time_check` is only included for the sake of completeness. In practice, + disable_time_check is only included for the sake of completeness. In practice, you want to renew the client certificate before expiry. Certificate files need to be uploaded first, e.g.:: From c7d318bdd45cf2d6a9f290ccde91634d3e930f6f Mon Sep 17 00:00:00 2001 From: Harald Milz Date: Fri, 2 May 2025 11:00:03 +0200 Subject: [PATCH 3/9] esp32: Formatting corrections. Signed-off-by: Harald Milz --- ports/esp32/network_wlan.c | 61 +++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c index ac1f37f663ff0..b450be015aff1 100644 --- a/ports/esp32/network_wlan.c +++ b/ports/esp32/network_wlan.c @@ -732,8 +732,7 @@ static mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_ } MP_DEFINE_CONST_FUN_OBJ_KW(network_wlan_config_obj, 1, network_wlan_config); -<<<<<<< HEAD -======= + // WPA2 Enterprise Connect // there are no official constants so far @@ -757,11 +756,7 @@ static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args { MP_QSTR_client_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_private_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_private_key_password, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, -<<<<<<< HEAD - { MP_QSTR_disable_time_check, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, // beware! -======= { MP_QSTR_disable_time_check, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, ->>>>>>> 0517049d7 (ports/esp32: Set disable_time_check default to False.) }; // parse args @@ -773,31 +768,29 @@ static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args size_t len; const char *p; - // TODO check if the IF is in STA mode, else bail out. - // parameter check if (eap_method < WIFI_AUTH_EAP_PWD || eap_method > WIFI_AUTH_EAP_TLS) { mp_raise_ValueError(MP_ERROR_TEXT("unknown config value for eap_method")); } - - // this is mandatory and should not be None. + + // this is mandatory and should not be None if (args[ARG_ssid].u_obj != mp_const_none) { p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len); memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid))); } esp_exceptions(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config)); - + if (eap_method == WIFI_AUTH_EAP_PWD || eap_method == WIFI_AUTH_EAP_PEAP || eap_method == WIFI_AUTH_EAP_TTLS) { // use username and password if (args[ARG_username].u_obj != mp_const_none) { p = mp_obj_str_get_data(args[ARG_username].u_obj, &len); - esp_exceptions(esp_eap_client_set_username((const unsigned char *) p, len)); + esp_exceptions(esp_eap_client_set_username((const unsigned char *)p, len)); } else { mp_raise_ValueError(MP_ERROR_TEXT("missing config param username")); } if (args[ARG_password].u_obj != mp_const_none) { p = mp_obj_str_get_data(args[ARG_password].u_obj, &len); - esp_exceptions(esp_eap_client_set_password((const unsigned char *) p, len)); + esp_exceptions(esp_eap_client_set_password((const unsigned char *)p, len)); } else { mp_raise_ValueError(MP_ERROR_TEXT("missing config param password")); } @@ -807,14 +800,14 @@ static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args // additionally use identity and ca_cert if (args[ARG_identity].u_obj != mp_const_none) { p = mp_obj_str_get_data(args[ARG_identity].u_obj, &len); - esp_exceptions(esp_eap_client_set_identity((const unsigned char *) p, len)); + esp_exceptions(esp_eap_client_set_identity((const unsigned char *)p, len)); } else { mp_raise_ValueError(MP_ERROR_TEXT("missing config param identity")); } if (args[ARG_ca_cert].u_obj != mp_const_none) { p = mp_obj_str_get_data(args[ARG_ca_cert].u_obj, &len); // see comment (1) below. - esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *) p, len+1)); + esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *)p, len+1)); } else { mp_raise_ValueError(MP_ERROR_TEXT("missing config param ca_cert")); } @@ -828,11 +821,11 @@ static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args if (ttls_phase2_method < ESP_EAP_TTLS_PHASE2_EAP || ttls_phase2_method > ESP_EAP_TTLS_PHASE2_CHAP) { mp_raise_ValueError(MP_ERROR_TEXT("unknown config value for ttls_phase2_method")); } - mp_printf(&mp_plat_print, "ttls_phase2_method: \"%d\"\n", ttls_phase2_method); + mp_printf(&mp_plat_print, "ttls_phase2_method: \"%d\"\n", ttls_phase2_method); esp_exceptions(esp_eap_client_set_ttls_phase2_method(ttls_phase2_method)); } - } - + } + if (eap_method == WIFI_AUTH_EAP_TLS) { // UNTESTED! // EAP-TLS uses client cert, private key, and (optionally) private key password, and (optionally) ca_cert @@ -860,23 +853,23 @@ static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args // disable time check or not if (args[ARG_disable_time_check].u_bool == true) { esp_exceptions(esp_eap_client_set_disable_time_check(true)); - mp_printf(&mp_plat_print, "disable_time_check: true\n"); + mp_printf(&mp_plat_print, "disable_time_check: true\n"); } - // (1) the documentation for esp_eap_client_set_certificate_and_key() says, + // (1) the documentation for esp_eap_client_set_certificate_and_key() says, // "2. The client_cert, private_key, and private_key_password should be zero-terminated." // so we copy 1 byte more to include the null. // in the esp-idf wifi_enterprise example, the null is appended when converting the cert files to byte arrays. esp_exceptions(esp_eap_client_set_certificate_and_key( - (const unsigned char *) client_cert, client_cert_len+1, - (const unsigned char *) private_key, private_key_len+1, - (const unsigned char *) private_key_password, private_key_password_len+1) - ); + (const unsigned char *) client_cert, client_cert_len+1, + (const unsigned char *) private_key, private_key_len+1, + (const unsigned char *) private_key_password, private_key_password_len+1) + ); // according to the esp-idf wifi_enterprise example, the ca_cert is optional for EAP-TLS if (args[ARG_ca_cert].u_obj != mp_const_none) { p = mp_obj_str_get_data(args[ARG_ca_cert].u_obj, &len); const mp_obj_type_t *type = mp_obj_get_type(args[ARG_ca_cert].u_obj); - esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *) p, len+1)); + esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *)p, len+1)); } } @@ -884,10 +877,8 @@ static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args // eap_enable & start esp_exceptions(esp_wifi_sta_enterprise_enable()); - // TODO Maybe we need to add esp_wifi_sta_enterprise_disable() to wlan.active(False)? - // or separate function - if (!wifi_started) { - esp_exceptions(esp_wifi_start()); + if (!wifi_started) { + esp_exceptions(esp_wifi_start()); } wifi_sta_reconnects = 0; @@ -901,7 +892,6 @@ static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args } static MP_DEFINE_CONST_FUN_OBJ_KW(network_wlan_eap_connect_obj, 1, network_wlan_eap_connect); ->>>>>>> 3ec881cdd (ports/esp32: Set disable_time_check default to False.) static const mp_rom_map_elem_t wlan_if_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_wlan_active_obj) }, { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&network_wlan_connect_obj) }, @@ -938,6 +928,17 @@ static const mp_rom_map_elem_t wlan_if_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_SEC_WPA2_WPA3_ENT), MP_ROM_INT(WIFI_AUTH_WPA2_WPA3_ENTERPRISE) }, #endif + { MP_ROM_QSTR(MP_QSTR_EAP_PWD), MP_ROM_INT(WIFI_AUTH_EAP_PWD) }, + { MP_ROM_QSTR(MP_QSTR_EAP_PEAP), MP_ROM_INT(WIFI_AUTH_EAP_PEAP) }, + { MP_ROM_QSTR(MP_QSTR_EAP_TTLS), MP_ROM_INT(WIFI_AUTH_EAP_TTLS) }, + { MP_ROM_QSTR(MP_QSTR_EAP_TLS), MP_ROM_INT(WIFI_AUTH_EAP_TLS) }, + + { MP_ROM_QSTR(MP_QSTR_EAP_TTLS_PHASE2_EAP), MP_ROM_INT(ESP_EAP_TTLS_PHASE2_EAP) }, + { MP_ROM_QSTR(MP_QSTR_EAP_TTLS_PHASE2_MSCHAPV2), MP_ROM_INT(ESP_EAP_TTLS_PHASE2_MSCHAPV2) }, + { MP_ROM_QSTR(MP_QSTR_EAP_TTLS_PHASE2_MSCHAP), MP_ROM_INT(ESP_EAP_TTLS_PHASE2_MSCHAP) }, + { MP_ROM_QSTR(MP_QSTR_EAP_TTLS_PHASE2_PAP), MP_ROM_INT(ESP_EAP_TTLS_PHASE2_PAP) }, + { MP_ROM_QSTR(MP_QSTR_EAP_TTLS_PHASE2_CHAP), MP_ROM_INT(ESP_EAP_TTLS_PHASE2_CHAP) }, + { MP_ROM_QSTR(MP_QSTR_PM_NONE), MP_ROM_INT(WIFI_PS_NONE) }, { MP_ROM_QSTR(MP_QSTR_PM_PERFORMANCE), MP_ROM_INT(WIFI_PS_MIN_MODEM) }, { MP_ROM_QSTR(MP_QSTR_PM_POWERSAVE), MP_ROM_INT(WIFI_PS_MAX_MODEM) }, From f7c986cb1f63d3f9aac3599e6e88e2aef4e6f838 Mon Sep 17 00:00:00 2001 From: Harald Milz Date: Fri, 2 May 2025 11:04:22 +0200 Subject: [PATCH 4/9] esp32: Formatting corrections. Signed-off-by: Harald Milz --- ports/esp32/network_wlan.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c index b450be015aff1..e02a4b1cca7e3 100644 --- a/ports/esp32/network_wlan.c +++ b/ports/esp32/network_wlan.c @@ -742,7 +742,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(network_wlan_config_obj, 1, network_wlan_config); #define WIFI_AUTH_EAP_TLS 3 static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_ssid, ARG_eap_method, ARG_username, ARG_password, + enum { ARG_ssid, ARG_eap_method, ARG_username, ARG_password, ARG_identity, ARG_ca_cert, ARG_ttls_phase2_method, ARG_client_cert, ARG_private_key, ARG_private_key_password, ARG_disable_time_check }; static const mp_arg_t allowed_args[] = { @@ -756,7 +756,7 @@ static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args { MP_QSTR_client_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_private_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_private_key_password, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_disable_time_check, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_disable_time_check, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; // parse args @@ -767,7 +767,7 @@ static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args int16_t eap_method = (int16_t)args[ARG_eap_method].u_int; size_t len; const char *p; - + // parameter check if (eap_method < WIFI_AUTH_EAP_PWD || eap_method > WIFI_AUTH_EAP_TLS) { mp_raise_ValueError(MP_ERROR_TEXT("unknown config value for eap_method")); @@ -806,8 +806,8 @@ static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args } if (args[ARG_ca_cert].u_obj != mp_const_none) { p = mp_obj_str_get_data(args[ARG_ca_cert].u_obj, &len); - // see comment (1) below. - esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *)p, len+1)); + // see comment (1) below. + esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *)p, len + 1)); } else { mp_raise_ValueError(MP_ERROR_TEXT("missing config param ca_cert")); } @@ -824,7 +824,7 @@ static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args mp_printf(&mp_plat_print, "ttls_phase2_method: \"%d\"\n", ttls_phase2_method); esp_exceptions(esp_eap_client_set_ttls_phase2_method(ttls_phase2_method)); } - } + } if (eap_method == WIFI_AUTH_EAP_TLS) { // UNTESTED! @@ -861,15 +861,15 @@ static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args // so we copy 1 byte more to include the null. // in the esp-idf wifi_enterprise example, the null is appended when converting the cert files to byte arrays. esp_exceptions(esp_eap_client_set_certificate_and_key( - (const unsigned char *) client_cert, client_cert_len+1, - (const unsigned char *) private_key, private_key_len+1, - (const unsigned char *) private_key_password, private_key_password_len+1) + (const unsigned char *) client_cert, client_cert_len + 1, + (const unsigned char *) private_key, private_key_len + 1, + (const unsigned char *) private_key_password, private_key_password_len + 1) ); // according to the esp-idf wifi_enterprise example, the ca_cert is optional for EAP-TLS if (args[ARG_ca_cert].u_obj != mp_const_none) { p = mp_obj_str_get_data(args[ARG_ca_cert].u_obj, &len); const mp_obj_type_t *type = mp_obj_get_type(args[ARG_ca_cert].u_obj); - esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *)p, len+1)); + esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *)p, len + 1)); } } From bb675c637e3732791b4c7775acdffbecc6607478 Mon Sep 17 00:00:00 2001 From: Harald Milz Date: Fri, 2 May 2025 11:06:03 +0200 Subject: [PATCH 5/9] esp32: Formatting corrections. Signed-off-by: Harald Milz --- ports/esp32/network_wlan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c index e02a4b1cca7e3..d58fc63eac042 100644 --- a/ports/esp32/network_wlan.c +++ b/ports/esp32/network_wlan.c @@ -861,9 +861,9 @@ static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args // so we copy 1 byte more to include the null. // in the esp-idf wifi_enterprise example, the null is appended when converting the cert files to byte arrays. esp_exceptions(esp_eap_client_set_certificate_and_key( - (const unsigned char *) client_cert, client_cert_len + 1, - (const unsigned char *) private_key, private_key_len + 1, - (const unsigned char *) private_key_password, private_key_password_len + 1) + (const unsigned char *)client_cert, client_cert_len + 1, + (const unsigned char *)private_key, private_key_len + 1, + (const unsigned char *)private_key_password, private_key_password_len + 1) ); // according to the esp-idf wifi_enterprise example, the ca_cert is optional for EAP-TLS if (args[ARG_ca_cert].u_obj != mp_const_none) { From 536b393f0fcb9d289cc29f9fdf8a67bc286c0445 Mon Sep 17 00:00:00 2001 From: Harald Milz Date: Thu, 12 Jun 2025 15:38:22 +0200 Subject: [PATCH 6/9] esp32: Added WPA-Enterprise. Signed-off-by: Harald Milz --- docs/library/network.WLAN.rst | 140 ++++++------- ports/esp32/esp32_common.cmake | 1 + ports/esp32/network_wlan.c | 358 ++++++++++++++++----------------- 3 files changed, 251 insertions(+), 248 deletions(-) diff --git a/docs/library/network.WLAN.rst b/docs/library/network.WLAN.rst index 1abb0b993dd1b..8f8f3ba059aa3 100644 --- a/docs/library/network.WLAN.rst +++ b/docs/library/network.WLAN.rst @@ -32,12 +32,82 @@ Methods argument is passed. Otherwise, query current state if no argument is provided. Most other methods require active interface. -.. method:: WLAN.connect(ssid=None, key=None, *, bssid=None) +.. method:: WLAN.connect(ssid=None, key=None, *, bssid=None, wpa3=False, param=value, ...) Connect to the specified wireless network, using the specified key. If *bssid* is given then the connection will be restricted to the access-point with that MAC address (the *ssid* must also be specified - in this case). + in this case). *wpa3* enforces WPA3 authentication and will reject the + network if WPA3 is not supported. + + WPA Enterprise (ESP32 port only) + + * eap_method -- EAP method to use (string) + + Connect to the specified wireless network, using WPA-Enterprise authentication and + the specified parameters. The EAP methods provided are EAP-PWD, EAP-PEAP, + EAP-TTLS, and EAP-TLS. EAP-TLS is UNTESTED and thus EXPERIMENTAL. + + Common parameters: + + * ssid -- WiFi access point name, (string, e.g. "eduroam") + + EAP-PWD parameters + + * username -- your network username (string) + * password -- your network password (string) + + EAP-PEAP parameters: + + * username -- your network username (string) + * password -- your network password (string) + * identity -- anonymous identity (string) + * ca_cert -- the CA certificate (filename, string) + + EAP-TTLS parameters: + + * username -- your network username (string) + * password -- your network password (string) + * identity -- anonymous identity (string) + * ca_cert -- the CA certificate (filename, string) + * ttls_phase2_method -- TTLS Phase 2 method (integer) + + EAP-TTLS supports the following TTLS Phase 2 methods: + + * 0 -- PWD + * 1 -- MSCHAPv2 (default) + * 2 -- MSCHAP + * 3 -- PAP + * 4 -- CHAP + + Please note that MSCHAPv2 and CHAP have known security issues and should be avoided. + + EAP-TLS parameters: + + * client_cert -- client certificate filename (string) + * private_key -- private key filename (string) + * private_key_password -- private key password (string, optional) + * disable_time_check -- suppress the validity check for the local client certificate when using EAP-TLS (boolean, default False) + + disable_time_check is only included for the sake of completeness. In practice, + you want to renew the client certificate before expiry. + + Certificate files need to be uploaded first, e.g.:: + + mpremote cp : + + EAP-PWD should be used whenever possible. It connects swiftly and uses the least resources. + When using one of the other methods, make sure the system time is correct to prevent + certificate validation errors. Best practice is to use a battery buffered RTC and to set + the system time using NTP regularly. A temporary workaround if no battery buffered RTC is + available is to set the system time to the image build time, like: + + import sys + import machine + (year, month, day) = sys.version.split(" on ")[1].split("-") + rtc = machine.RTC() + date_time = (int(year), int(month), int(day), 0, 0, 0, 0, 0) + rtc.init(date_time) .. method:: WLAN.disconnect() @@ -149,72 +219,6 @@ Methods .. method:: WLAN.eap_connect(param=value, ...) - Connect to the specified wireless network, using WPA-Enterprise authentication and - the specified parameters. ESP32 port only. The EAP methods provided are EAP-PWD, EAP-PEAP, - EAP-TTLS, and EAP-TLS. EAP-TLS is UNTESTED and thus EXPERIMENTAL. - - Common parameters: - - * ssid -- WiFi access point name, (string, e.g. "eduroam") - * eap_method -- EAP method to use (string) - - EAP-PWD parameters - - * username -- your network username (string) - * password -- your network password (string) - - EAP-PEAP parameters: - - * username -- your network username (string) - * password -- your network password (string) - * identity -- anonymous identity (string) - * ca_cert -- the CA certificate (filename, string) - - EAP-TTLS parameters: - - * username -- your network username (string) - * password -- your network password (string) - * identity -- anonymous identity (string) - * ca_cert -- the CA certificate (filename, string) - * ttls_phase2_method -- TTLS Phase 2 method (integer) - - EAP-TTLS supports the following TTLS Phase 2 methods: - - * 0 -- PWD - * 1 -- MSCHAPv2 (default) - * 2 -- MSCHAP - * 3 -- PAP - * 4 -- CHAP - - Please note that MSCHAPv2 and CHAP have known security issues and should be avoided. - - EAP-TLS parameters: - - * client_cert -- client certificate filename (string) - * private_key -- private key filename (string) - * private_key_password -- private key password (string, optional) - * disable_time_check -- suppress the validity check for the local client certificate when using EAP-TLS (boolean, default False) - - disable_time_check is only included for the sake of completeness. In practice, - you want to renew the client certificate before expiry. - - Certificate files need to be uploaded first, e.g.:: - - mpremote cp : - - EAP-PWD should be used whenever possible. It connects swiftly and uses the least resources. - When using one of the other methods, make sure the system time is correct to prevent - certificate validation errors. Best practice is to use a battery buffered RTC and to set - the system time using NTP regularly. A temporary workaround if no battery buffered RTC is - available is to set the system time to the image build time, like: - - import sys - import machine - (year, month, day) = sys.version.split(" on ")[1].split("-") - rtc = machine.RTC() - date_time = (int(year), int(month), int(day), 0, 0, 0, 0, 0) - rtc.init(date_time) - diff --git a/ports/esp32/esp32_common.cmake b/ports/esp32/esp32_common.cmake index dedef6d782cae..592056c69a0de 100644 --- a/ports/esp32/esp32_common.cmake +++ b/ports/esp32/esp32_common.cmake @@ -190,6 +190,7 @@ list(APPEND IDF_COMPONENTS ulp usb vfs + wpa_supplicant ) # Provide the default LD fragment if not set diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c index d58fc63eac042..3da9239fc2367 100644 --- a/ports/esp32/network_wlan.c +++ b/ports/esp32/network_wlan.c @@ -40,6 +40,7 @@ #include "modnetwork.h" #include "esp_wifi.h" +#include "esp_eap_client.h" #include "esp_log.h" #include "esp_psram.h" @@ -298,12 +299,35 @@ static mp_obj_t network_wlan_active(size_t n_args, const mp_obj_t *args) { } static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_wlan_active_obj, 1, 2, network_wlan_active); +// WLAN connect including WPA2/WPA3 Enterprise Connect +// there are no official constants in ESP-IDF for this so far +#define WIFI_AUTH_EAP_NONE 0 +#define WIFI_AUTH_EAP_PWD 1 +#define WIFI_AUTH_EAP_PEAP 2 +#define WIFI_AUTH_EAP_TTLS 3 +#define WIFI_AUTH_EAP_TLS 4 + static mp_obj_t network_wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_ssid, ARG_key, ARG_bssid }; + enum { ARG_ssid, ARG_key, ARG_bssid, + ARG_eap_method, ARG_username, ARG_password, + ARG_identity, ARG_ca_cert, ARG_ttls_phase2_method, + ARG_client_cert, ARG_private_key, ARG_private_key_password, ARG_disable_time_check, + ARG_wpa3 }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_eap_method, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = WIFI_AUTH_EAP_NONE} }, // default PSK + { MP_QSTR_username, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_password, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_identity, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_ca_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_ttls_phase2_method, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ESP_EAP_TTLS_PHASE2_MSCHAPV2} }, // default MSCHAPV2 + { MP_QSTR_client_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_private_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_private_key_password, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_disable_time_check, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_wpa3, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} } // if true, enforces WPA3-SAE or WPA3 Enterprise }; // parse args @@ -311,32 +335,162 @@ static mp_obj_t network_wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); wifi_config_t wifi_sta_config = {0}; + int16_t eap_method = (int16_t)args[ARG_eap_method].u_int; + size_t len; + const char *p; - // configure any parameters that are given - if (n_args > 1) { - size_t len; - const char *p; - if (args[ARG_ssid].u_obj != mp_const_none) { - p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len); - memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid))); - } - if (args[ARG_key].u_obj != mp_const_none) { - p = mp_obj_str_get_data(args[ARG_key].u_obj, &len); - memcpy(wifi_sta_config.sta.password, p, MIN(len, sizeof(wifi_sta_config.sta.password))); - } - if (args[ARG_bssid].u_obj != mp_const_none) { - p = mp_obj_str_get_data(args[ARG_bssid].u_obj, &len); - if (len != sizeof(wifi_sta_config.sta.bssid)) { - mp_raise_ValueError(NULL); + // parameter check + if (eap_method < WIFI_AUTH_EAP_NONE || eap_method > WIFI_AUTH_EAP_TLS) { + mp_raise_ValueError(MP_ERROR_TEXT("unknown config value for eap_method")); + } + + // this is mandatory and should not be None + if (args[ARG_ssid].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len); + memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid))); + } + + if (args[ARG_key].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_key].u_obj, &len); + memcpy(wifi_sta_config.sta.password, p, MIN(len, sizeof(wifi_sta_config.sta.password))); + } + + if (args[ARG_bssid].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_bssid].u_obj, &len); + if (len != sizeof(wifi_sta_config.sta.bssid)) { + mp_raise_ValueError(NULL); + } + wifi_sta_config.sta.bssid_set = 1; + memcpy(wifi_sta_config.sta.bssid, p, sizeof(wifi_sta_config.sta.bssid)); + } + + if (eap_method == WIFI_AUTH_EAP_NONE) { + // WPA2 or WPA3 PSK + if (args[ARG_wpa3].u_bool == true) { + // this will only affect WPA3-personal, not enterprise. + wifi_sta_config.sta.threshold.authmode = WIFI_AUTH_WPA3_PSK; + } + } else { + // WPA2/3 Enterprise + // At the moment (using ESP-IDF 5.4), setting WIFI_AUTH_WPA3_ENTERPRISE in eduroam networks will + // actually default to WPA2 because suite B compatibility is not implemented. + // The reason is outlined here: https://eduroam.org/eduroam-and-wpa3/ + if (args[ARG_wpa3].u_bool == true) { + wifi_sta_config.sta.threshold.authmode = WIFI_AUTH_WPA3_ENTERPRISE; + } else { + wifi_sta_config.sta.threshold.authmode = WIFI_AUTH_WPA2_WPA3_ENTERPRISE; + } + } + + esp_exceptions(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config)); + + if (eap_method == WIFI_AUTH_EAP_PWD || eap_method == WIFI_AUTH_EAP_PEAP || eap_method == WIFI_AUTH_EAP_TTLS) { + // use username and password + if (args[ARG_username].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_username].u_obj, &len); + esp_exceptions(esp_eap_client_set_username((const unsigned char *)p, len)); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("missing config param username")); + } + if (args[ARG_password].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_password].u_obj, &len); + esp_exceptions(esp_eap_client_set_password((const unsigned char *)p, len)); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("missing config param password")); + } + } + + if (eap_method == WIFI_AUTH_EAP_PEAP || eap_method == WIFI_AUTH_EAP_TTLS) { + // additionally use identity and ca_cert + if (args[ARG_identity].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_identity].u_obj, &len); + esp_exceptions(esp_eap_client_set_identity((const unsigned char *)p, len)); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("missing config param identity")); + } + if (args[ARG_ca_cert].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_ca_cert].u_obj, &len); + // see comment (1) below. + esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *)p, len + 1)); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("missing config param ca_cert")); + } + } + + if (eap_method == WIFI_AUTH_EAP_TTLS) { + // additionally use ttls_phase2_method, defaulting to MSCHAPV2 (and then very similar to EAP-PEAP) + // tested and verified with all 5 supported phase 2 methods. + if (args[ARG_ttls_phase2_method].u_obj != mp_const_none) { + int16_t ttls_phase2_method = (int16_t)args[ARG_ttls_phase2_method].u_int; + if (ttls_phase2_method < ESP_EAP_TTLS_PHASE2_EAP || ttls_phase2_method > ESP_EAP_TTLS_PHASE2_CHAP) { + mp_raise_ValueError(MP_ERROR_TEXT("unknown config value for ttls_phase2_method")); } - wifi_sta_config.sta.bssid_set = 1; - memcpy(wifi_sta_config.sta.bssid, p, sizeof(wifi_sta_config.sta.bssid)); + mp_printf(&mp_plat_print, "ttls_phase2_method: \"%d\"\n", ttls_phase2_method); + esp_exceptions(esp_eap_client_set_ttls_phase2_method(ttls_phase2_method)); + } + } + + if (eap_method == WIFI_AUTH_EAP_TLS) { + // UNTESTED! + // EAP-TLS uses client cert, private key, and (optionally) private key password, and (optionally) ca_cert + // please note that this release does not implement WIFI_AUTH_WPA3_ENT_192 + // The reason is outlined here: https://eduroam.org/eduroam-and-wpa3/ + size_t client_cert_len = 0; + const char *client_cert = NULL; + size_t private_key_len = 0; + const char *private_key = NULL; + size_t private_key_password_len = 0; + const char *private_key_password = NULL; + + mp_printf(&mp_plat_print, "\nPlease note that EAP-TLS is so far UNTESTED and thus EXPERIMENTAL.\nUse at your own risk!\n\n"); + if (args[ARG_client_cert].u_obj != mp_const_none) { + client_cert = mp_obj_str_get_data(args[ARG_client_cert].u_obj, &client_cert_len); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("missing config param client_cert")); + } + if (args[ARG_private_key].u_obj != mp_const_none) { + private_key = mp_obj_str_get_data(args[ARG_private_key].u_obj, &private_key_len); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("missing config param private_key")); + } + if (args[ARG_private_key_password].u_obj != mp_const_none) { // password is optional + private_key_password = mp_obj_str_get_data(args[ARG_private_key_password].u_obj, &private_key_password_len); + } + // disable time check or not + if (args[ARG_disable_time_check].u_bool == true) { + esp_exceptions(esp_eap_client_set_disable_time_check(true)); + mp_printf(&mp_plat_print, "disable_time_check: true\n"); + } + + // (1) the documentation for esp_eap_client_set_certificate_and_key() says, + // "2. The client_cert, private_key, and private_key_password should be zero-terminated." + // so we copy 1 byte more to include the null. + // in the esp-idf wifi_enterprise example, the null is appended when converting the cert files to byte arrays. + esp_exceptions(esp_eap_client_set_certificate_and_key( + (const unsigned char *)client_cert, client_cert_len + 1, + (const unsigned char *)private_key, private_key_len + 1, + (const unsigned char *)private_key_password, private_key_password_len + 1) + ); + // according to the esp-idf wifi_enterprise example, the ca_cert is optional for EAP-TLS + if (args[ARG_ca_cert].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_ca_cert].u_obj, &len); + // const mp_obj_type_t *type = mp_obj_get_type(args[ARG_ca_cert].u_obj); + esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *)p, len + 1)); } - esp_exceptions(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config)); } esp_exceptions(esp_netif_set_hostname(wlan_sta_obj.netif, mod_network_hostname_data)); + // eap_enable if requested & start + if (eap_method == WIFI_AUTH_EAP_NONE) { + esp_exceptions(esp_wifi_sta_enterprise_disable()); + } else { + esp_exceptions(esp_wifi_sta_enterprise_enable()); + } + if (!wifi_started) { + esp_exceptions(esp_wifi_start()); + } + wifi_sta_reconnects = 0; // connect to the WiFi AP MP_THREAD_GIL_EXIT(); @@ -348,9 +502,11 @@ static mp_obj_t network_wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp } static MP_DEFINE_CONST_FUN_OBJ_KW(network_wlan_connect_obj, 1, network_wlan_connect); + static mp_obj_t network_wlan_disconnect(mp_obj_t self_in) { wifi_sta_connect_requested = false; esp_exceptions(esp_wifi_disconnect()); + esp_exceptions(esp_wifi_sta_enterprise_disable()); return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_1(network_wlan_disconnect_obj, network_wlan_disconnect); @@ -732,166 +888,6 @@ static mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_ } MP_DEFINE_CONST_FUN_OBJ_KW(network_wlan_config_obj, 1, network_wlan_config); - -// WPA2 Enterprise Connect - -// there are no official constants so far -#define WIFI_AUTH_EAP_PWD 0 -#define WIFI_AUTH_EAP_PEAP 1 -#define WIFI_AUTH_EAP_TTLS 2 -#define WIFI_AUTH_EAP_TLS 3 - -static mp_obj_t network_wlan_eap_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_ssid, ARG_eap_method, ARG_username, ARG_password, - ARG_identity, ARG_ca_cert, ARG_ttls_phase2_method, - ARG_client_cert, ARG_private_key, ARG_private_key_password, ARG_disable_time_check }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_eap_method, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, // default EAP-PWD - { MP_QSTR_username, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_password, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_identity, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_ca_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_ttls_phase2_method, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, // default MSCHAPV2 - { MP_QSTR_client_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_private_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_private_key_password, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_disable_time_check, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - }; - - // parse args - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - wifi_config_t wifi_sta_config = {0}; - int16_t eap_method = (int16_t)args[ARG_eap_method].u_int; - size_t len; - const char *p; - - // parameter check - if (eap_method < WIFI_AUTH_EAP_PWD || eap_method > WIFI_AUTH_EAP_TLS) { - mp_raise_ValueError(MP_ERROR_TEXT("unknown config value for eap_method")); - } - - // this is mandatory and should not be None - if (args[ARG_ssid].u_obj != mp_const_none) { - p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len); - memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid))); - } - esp_exceptions(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config)); - - if (eap_method == WIFI_AUTH_EAP_PWD || eap_method == WIFI_AUTH_EAP_PEAP || eap_method == WIFI_AUTH_EAP_TTLS) { - // use username and password - if (args[ARG_username].u_obj != mp_const_none) { - p = mp_obj_str_get_data(args[ARG_username].u_obj, &len); - esp_exceptions(esp_eap_client_set_username((const unsigned char *)p, len)); - } else { - mp_raise_ValueError(MP_ERROR_TEXT("missing config param username")); - } - if (args[ARG_password].u_obj != mp_const_none) { - p = mp_obj_str_get_data(args[ARG_password].u_obj, &len); - esp_exceptions(esp_eap_client_set_password((const unsigned char *)p, len)); - } else { - mp_raise_ValueError(MP_ERROR_TEXT("missing config param password")); - } - } - - if (eap_method == WIFI_AUTH_EAP_PEAP || eap_method == WIFI_AUTH_EAP_TTLS) { - // additionally use identity and ca_cert - if (args[ARG_identity].u_obj != mp_const_none) { - p = mp_obj_str_get_data(args[ARG_identity].u_obj, &len); - esp_exceptions(esp_eap_client_set_identity((const unsigned char *)p, len)); - } else { - mp_raise_ValueError(MP_ERROR_TEXT("missing config param identity")); - } - if (args[ARG_ca_cert].u_obj != mp_const_none) { - p = mp_obj_str_get_data(args[ARG_ca_cert].u_obj, &len); - // see comment (1) below. - esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *)p, len + 1)); - } else { - mp_raise_ValueError(MP_ERROR_TEXT("missing config param ca_cert")); - } - } - - if (eap_method == WIFI_AUTH_EAP_TTLS) { - // additionally use ttls_phase2_method, defaulting to MSCHAPV2 (and then very similar to EAP-PEAP) - // tested and verified with all 5 supported phase 2 methods. - if (args[ARG_ttls_phase2_method].u_obj != mp_const_none) { - int16_t ttls_phase2_method = (int16_t)args[ARG_ttls_phase2_method].u_int; - if (ttls_phase2_method < ESP_EAP_TTLS_PHASE2_EAP || ttls_phase2_method > ESP_EAP_TTLS_PHASE2_CHAP) { - mp_raise_ValueError(MP_ERROR_TEXT("unknown config value for ttls_phase2_method")); - } - mp_printf(&mp_plat_print, "ttls_phase2_method: \"%d\"\n", ttls_phase2_method); - esp_exceptions(esp_eap_client_set_ttls_phase2_method(ttls_phase2_method)); - } - } - - if (eap_method == WIFI_AUTH_EAP_TLS) { - // UNTESTED! - // EAP-TLS uses client cert, private key, and (optionally) private key password, and (optionally) ca_cert - size_t client_cert_len = 0; - const char *client_cert = NULL; - size_t private_key_len = 0; - const char *private_key = NULL; - size_t private_key_password_len = 0; - const char *private_key_password = NULL; - - mp_printf(&mp_plat_print, "\nPlease note that EAP-TLS is so far UNTESTED and thus EXPERIMENTAL.\nUse at your own risk!\n\n"); - if (args[ARG_client_cert].u_obj != mp_const_none) { - client_cert = mp_obj_str_get_data(args[ARG_client_cert].u_obj, &client_cert_len); - } else { - mp_raise_ValueError(MP_ERROR_TEXT("missing config param client_cert")); - } - if (args[ARG_private_key].u_obj != mp_const_none) { - private_key = mp_obj_str_get_data(args[ARG_private_key].u_obj, &private_key_len); - } else { - mp_raise_ValueError(MP_ERROR_TEXT("missing config param private_key")); - } - if (args[ARG_private_key_password].u_obj != mp_const_none) { // password is optional - private_key_password = mp_obj_str_get_data(args[ARG_private_key_password].u_obj, &private_key_password_len); - } - // disable time check or not - if (args[ARG_disable_time_check].u_bool == true) { - esp_exceptions(esp_eap_client_set_disable_time_check(true)); - mp_printf(&mp_plat_print, "disable_time_check: true\n"); - } - - // (1) the documentation for esp_eap_client_set_certificate_and_key() says, - // "2. The client_cert, private_key, and private_key_password should be zero-terminated." - // so we copy 1 byte more to include the null. - // in the esp-idf wifi_enterprise example, the null is appended when converting the cert files to byte arrays. - esp_exceptions(esp_eap_client_set_certificate_and_key( - (const unsigned char *)client_cert, client_cert_len + 1, - (const unsigned char *)private_key, private_key_len + 1, - (const unsigned char *)private_key_password, private_key_password_len + 1) - ); - // according to the esp-idf wifi_enterprise example, the ca_cert is optional for EAP-TLS - if (args[ARG_ca_cert].u_obj != mp_const_none) { - p = mp_obj_str_get_data(args[ARG_ca_cert].u_obj, &len); - const mp_obj_type_t *type = mp_obj_get_type(args[ARG_ca_cert].u_obj); - esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *)p, len + 1)); - } - } - - esp_exceptions(esp_netif_set_hostname(wlan_sta_obj.netif, mod_network_hostname_data)); - - // eap_enable & start - esp_exceptions(esp_wifi_sta_enterprise_enable()); - if (!wifi_started) { - esp_exceptions(esp_wifi_start()); - } - - wifi_sta_reconnects = 0; - // connect to the WiFi AP - MP_THREAD_GIL_EXIT(); - esp_exceptions(esp_wifi_connect()); - MP_THREAD_GIL_ENTER(); - wifi_sta_connect_requested = true; - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_KW(network_wlan_eap_connect_obj, 1, network_wlan_eap_connect); - static const mp_rom_map_elem_t wlan_if_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_wlan_active_obj) }, { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&network_wlan_connect_obj) }, @@ -928,6 +924,7 @@ static const mp_rom_map_elem_t wlan_if_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_SEC_WPA2_WPA3_ENT), MP_ROM_INT(WIFI_AUTH_WPA2_WPA3_ENTERPRISE) }, #endif + { MP_ROM_QSTR(MP_QSTR_EAP_NONE), MP_ROM_INT(WIFI_AUTH_EAP_NONE) }, { MP_ROM_QSTR(MP_QSTR_EAP_PWD), MP_ROM_INT(WIFI_AUTH_EAP_PWD) }, { MP_ROM_QSTR(MP_QSTR_EAP_PEAP), MP_ROM_INT(WIFI_AUTH_EAP_PEAP) }, { MP_ROM_QSTR(MP_QSTR_EAP_TTLS), MP_ROM_INT(WIFI_AUTH_EAP_TTLS) }, @@ -964,3 +961,4 @@ MP_DEFINE_CONST_OBJ_TYPE( ); #endif // MICROPY_PY_NETWORK_WLAN + From 4f7d830823edbb2977c1818c40bf1c6b184a3a00 Mon Sep 17 00:00:00 2001 From: Harald Milz Date: Thu, 12 Jun 2025 15:43:45 +0200 Subject: [PATCH 7/9] esp32: Added WPA-Enterprise. Signed-off-by: Harald Milz --- ports/esp32/network_wlan.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c index 3da9239fc2367..8d0b081b995d2 100644 --- a/ports/esp32/network_wlan.c +++ b/ports/esp32/network_wlan.c @@ -349,7 +349,7 @@ static mp_obj_t network_wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len); memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid))); } - + if (args[ARG_key].u_obj != mp_const_none) { p = mp_obj_str_get_data(args[ARG_key].u_obj, &len); memcpy(wifi_sta_config.sta.password, p, MIN(len, sizeof(wifi_sta_config.sta.password))); @@ -367,13 +367,13 @@ static mp_obj_t network_wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp if (eap_method == WIFI_AUTH_EAP_NONE) { // WPA2 or WPA3 PSK if (args[ARG_wpa3].u_bool == true) { - // this will only affect WPA3-personal, not enterprise. + // this will only affect WPA3-personal, not enterprise wifi_sta_config.sta.threshold.authmode = WIFI_AUTH_WPA3_PSK; } } else { // WPA2/3 Enterprise // At the moment (using ESP-IDF 5.4), setting WIFI_AUTH_WPA3_ENTERPRISE in eduroam networks will - // actually default to WPA2 because suite B compatibility is not implemented. + // actually default to WPA2 because suite B compatibility is not implemented // The reason is outlined here: https://eduroam.org/eduroam-and-wpa3/ if (args[ARG_wpa3].u_bool == true) { wifi_sta_config.sta.threshold.authmode = WIFI_AUTH_WPA3_ENTERPRISE; @@ -419,7 +419,7 @@ static mp_obj_t network_wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp if (eap_method == WIFI_AUTH_EAP_TTLS) { // additionally use ttls_phase2_method, defaulting to MSCHAPV2 (and then very similar to EAP-PEAP) - // tested and verified with all 5 supported phase 2 methods. + // tested and verified with all 5 supported phase 2 methods if (args[ARG_ttls_phase2_method].u_obj != mp_const_none) { int16_t ttls_phase2_method = (int16_t)args[ARG_ttls_phase2_method].u_int; if (ttls_phase2_method < ESP_EAP_TTLS_PHASE2_EAP || ttls_phase2_method > ESP_EAP_TTLS_PHASE2_CHAP) { @@ -464,8 +464,8 @@ static mp_obj_t network_wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp // (1) the documentation for esp_eap_client_set_certificate_and_key() says, // "2. The client_cert, private_key, and private_key_password should be zero-terminated." - // so we copy 1 byte more to include the null. - // in the esp-idf wifi_enterprise example, the null is appended when converting the cert files to byte arrays. + // so we copy 1 byte more to include the null + // in the esp-idf wifi_enterprise example, the null is appended when converting the cert files to byte arrays esp_exceptions(esp_eap_client_set_certificate_and_key( (const unsigned char *)client_cert, client_cert_len + 1, (const unsigned char *)private_key, private_key_len + 1, @@ -474,7 +474,6 @@ static mp_obj_t network_wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp // according to the esp-idf wifi_enterprise example, the ca_cert is optional for EAP-TLS if (args[ARG_ca_cert].u_obj != mp_const_none) { p = mp_obj_str_get_data(args[ARG_ca_cert].u_obj, &len); - // const mp_obj_type_t *type = mp_obj_get_type(args[ARG_ca_cert].u_obj); esp_exceptions(esp_eap_client_set_ca_cert((const unsigned char *)p, len + 1)); } } From 085a8ab26314946f0a553d37addaae5f7b667b96 Mon Sep 17 00:00:00 2001 From: Harald Milz Date: Thu, 12 Jun 2025 15:48:36 +0200 Subject: [PATCH 8/9] esp32: Added WPA-Enterprise. Signed-off-by: Harald Milz --- ports/esp32/network_wlan.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c index 8d0b081b995d2..77a77d52fb90e 100644 --- a/ports/esp32/network_wlan.c +++ b/ports/esp32/network_wlan.c @@ -370,9 +370,9 @@ static mp_obj_t network_wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp // this will only affect WPA3-personal, not enterprise wifi_sta_config.sta.threshold.authmode = WIFI_AUTH_WPA3_PSK; } - } else { + } else { // WPA2/3 Enterprise - // At the moment (using ESP-IDF 5.4), setting WIFI_AUTH_WPA3_ENTERPRISE in eduroam networks will + // At the moment (using ESP-IDF 5.4), setting WIFI_AUTH_WPA3_ENTERPRISE in eduroam networks will // actually default to WPA2 because suite B compatibility is not implemented // The reason is outlined here: https://eduroam.org/eduroam-and-wpa3/ if (args[ARG_wpa3].u_bool == true) { @@ -960,4 +960,3 @@ MP_DEFINE_CONST_OBJ_TYPE( ); #endif // MICROPY_PY_NETWORK_WLAN - From 7943e82555d96c8482935ee0b64da4046d10f8f8 Mon Sep 17 00:00:00 2001 From: Harald Milz Date: Fri, 13 Jun 2025 11:55:46 +0200 Subject: [PATCH 9/9] esp32: Added WPA-Enterprise. Signed-off-by: Harald Milz --- docs/library/network.WLAN.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/library/network.WLAN.rst b/docs/library/network.WLAN.rst index 8f8f3ba059aa3..bf42cb952a966 100644 --- a/docs/library/network.WLAN.rst +++ b/docs/library/network.WLAN.rst @@ -217,12 +217,6 @@ Methods pm WiFi Power Management setting (see below for allowed values) ============= =========== -.. method:: WLAN.eap_connect(param=value, ...) - - - - - Constants pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy