From cac01d369adfc7b35c3a8bdfb4251c1cf7394de3 Mon Sep 17 00:00:00 2001 From: "John P. Swensen" Date: Tue, 8 Mar 2022 19:57:10 -0800 Subject: [PATCH 1/3] Added another overloaded WiFiSTAClass::begin() function that provides an easy way of creating a WPA2 Enterprise connection. --- libraries/WiFi/src/WiFiGeneric.h | 6 +++ libraries/WiFi/src/WiFiSTA.cpp | 72 ++++++++++++++++++++++++++++++++ libraries/WiFi/src/WiFiSTA.h | 3 ++ 3 files changed, 81 insertions(+) diff --git a/libraries/WiFi/src/WiFiGeneric.h b/libraries/WiFi/src/WiFiGeneric.h index 62642b43dc7..ea2abc2aff6 100644 --- a/libraries/WiFi/src/WiFiGeneric.h +++ b/libraries/WiFi/src/WiFiGeneric.h @@ -31,6 +31,12 @@ #include "esp_smartconfig.h" #include "wifi_provisioning/manager.h" +#ifdef ENABLE_WPA2_AUTHENTICATION +#include +#include +#include "esp_wpa2.h" +#endif + ESP_EVENT_DECLARE_BASE(ARDUINO_EVENTS); typedef enum { diff --git a/libraries/WiFi/src/WiFiSTA.cpp b/libraries/WiFi/src/WiFiSTA.cpp index c75405bb4f3..7ab34cafef2 100644 --- a/libraries/WiFi/src/WiFiSTA.cpp +++ b/libraries/WiFi/src/WiFiSTA.cpp @@ -145,6 +145,78 @@ wl_status_t WiFiSTAClass::status() return (wl_status_t)xEventGroupClearBits(_sta_status_group, 0); } + +#ifdef ENABLE_WPA2_AUTHENTICATION +static WiFiClientSecure client_secure; + +/** + * Start Wifi connection with a WPA2 Enterprise AP + * if passphrase is set the most secure supported mode will be automatically selected + * @param ssid const char* Pointer to the SSID string. + * @param wpa2_identity const char* Pointer to the entity + * @param wpa2_username const char* Pointer to the username + * @param password const char * Pinter to the password. + * @param root_ca const char* Optional. Pointer to the root certificate string. + * @param client_cert const char* Optional. Pointer to the client certificate string. + * @param client_key const char* Optional. Pointer to the client key. + * @param bssid uint8_t[6] Optional. BSSID / MAC of AP + * @param channel Optional. Channel of AP + * @param connect Optional. call connect + * @return + */ +wl_status_t WiFiSTAClass::begin(const char* wpa2_ssid, const char* wpa2_identity, const char* wpa2_username, const char *wpa2_password, const char* root_ca, const char* client_cert, const char* client_key, int32_t channel, const uint8_t* bssid, bool connect) +{ + if(!WiFi.enableSTA(true)) { + log_e("STA enable failed!"); + return WL_CONNECT_FAILED; + } + + if(!wpa2_ssid || *wpa2_ssid == 0x00 || strlen(wpa2_ssid) > 32) { + log_e("SSID too long or missing!"); + return WL_CONNECT_FAILED; + } + + if(wpa2_identity && strlen(wpa2_identity) > 64) { + log_e("identity too long!"); + return WL_CONNECT_FAILED; + } + + if(wpa2_username && strlen(wpa2_username) > 64) { + log_e("username too long!"); + return WL_CONNECT_FAILED; + } + + if(wpa2_password && strlen(wpa2_password) > 64) { + log_e("password too long!"); + } + + esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)wpa2_identity, strlen(wpa2_identity)); + esp_wifi_sta_wpa2_ent_set_username((uint8_t *)wpa2_username, strlen(wpa2_username)); + esp_wifi_sta_wpa2_ent_set_password((uint8_t *)wpa2_password, strlen(wpa2_password)); + esp_wifi_sta_wpa2_ent_enable(); //set config settings to enable function + WiFi.begin(wpa2_ssid); //connect to wifi + + int cert_count = (root_ca != NULL) + (client_cert != NULL) + (client_key != NULL); + if ( cert_count > 1 ) { + log_e("only one cert method allowed!"); + return WL_CONNECT_FAILED; + } + + if (root_ca != NULL) { + client_secure.setCACert(root_ca); + } + else if (client_cert != NULL) { + client_secure.setCertificate(client_cert); + } + else if (client_key != NULL) { + client_secure.setPrivateKey(client_key); + } + return status(); +} +#endif + + + /** * Start Wifi connection * if passphrase is set the most secure supported mode will be automatically selected diff --git a/libraries/WiFi/src/WiFiSTA.h b/libraries/WiFi/src/WiFiSTA.h index e49273f0176..8d39d1f9f9f 100644 --- a/libraries/WiFi/src/WiFiSTA.h +++ b/libraries/WiFi/src/WiFiSTA.h @@ -39,6 +39,9 @@ class WiFiSTAClass public: +#ifdef ENABLE_WPA2_AUTHENTICATION + wl_status_t begin(const char* wpa2_ssid, const char* wpa2_identity, const char* wpa2_username, const char *wpa2_password, const char* root_ca=NULL, const char* client_cert=NULL, const char* client_key=NULL,int32_t channel=0, const uint8_t* bssid=0, bool connect=true); +#endif wl_status_t begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); wl_status_t begin(char* ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); wl_status_t begin(); From 47fa2317ac976cdd2577107fdf93b540630d3861 Mon Sep 17 00:00:00 2001 From: "John P. Swensen" Date: Thu, 10 Mar 2022 10:32:36 -0800 Subject: [PATCH 2/3] Updates requested in pull request discussion to remove guards and fix #include locations --- libraries/WiFi/src/WiFiGeneric.h | 6 ------ libraries/WiFi/src/WiFiSTA.cpp | 6 ++---- libraries/WiFi/src/WiFiSTA.h | 2 -- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/libraries/WiFi/src/WiFiGeneric.h b/libraries/WiFi/src/WiFiGeneric.h index ea2abc2aff6..62642b43dc7 100644 --- a/libraries/WiFi/src/WiFiGeneric.h +++ b/libraries/WiFi/src/WiFiGeneric.h @@ -31,12 +31,6 @@ #include "esp_smartconfig.h" #include "wifi_provisioning/manager.h" -#ifdef ENABLE_WPA2_AUTHENTICATION -#include -#include -#include "esp_wpa2.h" -#endif - ESP_EVENT_DECLARE_BASE(ARDUINO_EVENTS); typedef enum { diff --git a/libraries/WiFi/src/WiFiSTA.cpp b/libraries/WiFi/src/WiFiSTA.cpp index 7ab34cafef2..e320ece8a98 100644 --- a/libraries/WiFi/src/WiFiSTA.cpp +++ b/libraries/WiFi/src/WiFiSTA.cpp @@ -25,6 +25,7 @@ #include "WiFi.h" #include "WiFiGeneric.h" #include "WiFiSTA.h" +#include extern "C" { #include @@ -42,6 +43,7 @@ extern "C" { #include "lwip/dns.h" #include #include +#include "esp_wpa2.h" } // ----------------------------------------------------------------------------------------------------------------------- @@ -146,7 +148,6 @@ wl_status_t WiFiSTAClass::status() } -#ifdef ENABLE_WPA2_AUTHENTICATION static WiFiClientSecure client_secure; /** @@ -213,9 +214,6 @@ wl_status_t WiFiSTAClass::begin(const char* wpa2_ssid, const char* wpa2_identity } return status(); } -#endif - - /** * Start Wifi connection diff --git a/libraries/WiFi/src/WiFiSTA.h b/libraries/WiFi/src/WiFiSTA.h index 8d39d1f9f9f..f159c41c131 100644 --- a/libraries/WiFi/src/WiFiSTA.h +++ b/libraries/WiFi/src/WiFiSTA.h @@ -39,9 +39,7 @@ class WiFiSTAClass public: -#ifdef ENABLE_WPA2_AUTHENTICATION wl_status_t begin(const char* wpa2_ssid, const char* wpa2_identity, const char* wpa2_username, const char *wpa2_password, const char* root_ca=NULL, const char* client_cert=NULL, const char* client_key=NULL,int32_t channel=0, const uint8_t* bssid=0, bool connect=true); -#endif wl_status_t begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); wl_status_t begin(char* ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); wl_status_t begin(); From 42c901073152aa772e39d8e2f34ca04063afb1a9 Mon Sep 17 00:00:00 2001 From: "John P. Swensen" Date: Thu, 10 Mar 2022 11:49:29 -0800 Subject: [PATCH 3/3] Updates to fix several issues. (1) I was doing cert files wrong and went back to the esp-edf wpa2 example to get this corrected. (2) I updated the WiFiClientEnterprise example to use this new method and to add a bunch of comments and commented-out examples about the three most common scenarios. --- .../WiFiClientEnterprise.ino | 28 +++++++++--- libraries/WiFi/src/WiFiSTA.cpp | 44 ++++++++----------- libraries/WiFi/src/WiFiSTA.h | 7 ++- 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/libraries/WiFi/examples/WiFiClientEnterprise/WiFiClientEnterprise.ino b/libraries/WiFi/examples/WiFiClientEnterprise/WiFiClientEnterprise.ino index d7a2d0ad3cf..caaa2139170 100644 --- a/libraries/WiFi/examples/WiFiClientEnterprise/WiFiClientEnterprise.ino +++ b/libraries/WiFi/examples/WiFiClientEnterprise/WiFiClientEnterprise.ino @@ -1,10 +1,22 @@ #include //Wifi library #include "esp_wpa2.h" //wpa2 library for connections to Enterprise networks #define EAP_IDENTITY "login" //if connecting from another corporation, use identity@organisation.domain in Eduroam +#define EAP_USERNAME "login" //oftentimes just a repeat of the identity #define EAP_PASSWORD "password" //your Eduroam password const char* ssid = "eduroam"; // Eduroam SSID const char* host = "arduino.php5.sk"; //external server domain for HTTP connection after authentification int counter = 0; + +// NOTE: For some systems, various certification keys are required to connect to the wifi system. +// Usually you are provided these by the IT department of your organization when certs are required +// and you can't connect with just an identity and password. +// Most eduroam setups we have seen do not require this level of authentication, but you should contact +// your IT department to verify. +// You should uncomment these and populate with the contents of the files if this is required for your scenario (See Example 2 and Example 3 below). +//const char *ca_pem = "insert your CA cert from your .pem file here"; +//const char *client_cert = "insert your client cert from your .crt file here"; +//const char *client_key = "insert your client key from your .key file here"; + void setup() { Serial.begin(115200); delay(10); @@ -13,11 +25,17 @@ void setup() { Serial.println(ssid); WiFi.disconnect(true); //disconnect form wifi to set new wifi connection WiFi.mode(WIFI_STA); //init wifi mode - esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)EAP_IDENTITY, strlen(EAP_IDENTITY)); //provide identity - esp_wifi_sta_wpa2_ent_set_username((uint8_t *)EAP_IDENTITY, strlen(EAP_IDENTITY)); //provide username --> identity and username is same - esp_wifi_sta_wpa2_ent_set_password((uint8_t *)EAP_PASSWORD, strlen(EAP_PASSWORD)); //provide password - esp_wifi_sta_wpa2_ent_enable(); - WiFi.begin(ssid); //connect to wifi + + // Example1 (most common): a cert-file-free eduroam with PEAP (or TTLS) + WiFi.begin(ssid, WPA2_AUTH_PEAP, EAP_IDENTITY, EAP_USERNAME, EAP_PASSWORD); + + // Example 2: a cert-file WPA2 Enterprise with PEAP + //WiFi.begin(ssid, WPA2_AUTH_PEAP, EAP_IDENTITY, EAP_USERNAME, EAP_PASSWORD, ca_pem, client_cert, client_key); + + // Example 3: TLS with cert-files and no password + //WiFi.begin(ssid, WPA2_AUTH_TLS, EAP_IDENTITY, NULL, NULL, ca_pem, client_cert, client_key); + + while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); diff --git a/libraries/WiFi/src/WiFiSTA.cpp b/libraries/WiFi/src/WiFiSTA.cpp index e320ece8a98..02e7185cd7e 100644 --- a/libraries/WiFi/src/WiFiSTA.cpp +++ b/libraries/WiFi/src/WiFiSTA.cpp @@ -25,7 +25,6 @@ #include "WiFi.h" #include "WiFiGeneric.h" #include "WiFiSTA.h" -#include extern "C" { #include @@ -147,25 +146,23 @@ wl_status_t WiFiSTAClass::status() return (wl_status_t)xEventGroupClearBits(_sta_status_group, 0); } - -static WiFiClientSecure client_secure; - /** * Start Wifi connection with a WPA2 Enterprise AP * if passphrase is set the most secure supported mode will be automatically selected * @param ssid const char* Pointer to the SSID string. + * @param method wpa2_method_t The authentication method of WPA2 (WPA2_AUTH_TLS, WPA2_AUTH_PEAP, WPA2_AUTH_TTLS) * @param wpa2_identity const char* Pointer to the entity * @param wpa2_username const char* Pointer to the username - * @param password const char * Pinter to the password. - * @param root_ca const char* Optional. Pointer to the root certificate string. - * @param client_cert const char* Optional. Pointer to the client certificate string. - * @param client_key const char* Optional. Pointer to the client key. + * @param password const char * Pointer to the password. + * @param ca_pem const char* Pointer to a string with the contents of a .pem file with CA cert + * @param client_crt const char* Pointer to a string with the contents of a .crt file with client cert + * @param client_key const char* Pointer to a string with the contants of a .key file with client key * @param bssid uint8_t[6] Optional. BSSID / MAC of AP * @param channel Optional. Channel of AP * @param connect Optional. call connect * @return */ -wl_status_t WiFiSTAClass::begin(const char* wpa2_ssid, const char* wpa2_identity, const char* wpa2_username, const char *wpa2_password, const char* root_ca, const char* client_cert, const char* client_key, int32_t channel, const uint8_t* bssid, bool connect) +wl_status_t WiFiSTAClass::begin(const char* wpa2_ssid, wpa2_auth_method_t method, const char* wpa2_identity, const char* wpa2_username, const char *wpa2_password, const char* ca_pem, const char* client_crt, const char* client_key, int32_t channel, const uint8_t* bssid, bool connect) { if(!WiFi.enableSTA(true)) { log_e("STA enable failed!"); @@ -191,27 +188,22 @@ wl_status_t WiFiSTAClass::begin(const char* wpa2_ssid, const char* wpa2_identity log_e("password too long!"); } - esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)wpa2_identity, strlen(wpa2_identity)); - esp_wifi_sta_wpa2_ent_set_username((uint8_t *)wpa2_username, strlen(wpa2_username)); - esp_wifi_sta_wpa2_ent_set_password((uint8_t *)wpa2_password, strlen(wpa2_password)); - esp_wifi_sta_wpa2_ent_enable(); //set config settings to enable function - WiFi.begin(wpa2_ssid); //connect to wifi - - int cert_count = (root_ca != NULL) + (client_cert != NULL) + (client_key != NULL); - if ( cert_count > 1 ) { - log_e("only one cert method allowed!"); - return WL_CONNECT_FAILED; + if(ca_pem) { + esp_wifi_sta_wpa2_ent_set_ca_cert((uint8_t *)ca_pem, strlen(ca_pem)); } - if (root_ca != NULL) { - client_secure.setCACert(root_ca); + if(client_crt) { + esp_wifi_sta_wpa2_ent_set_cert_key((uint8_t *)client_crt, strlen(client_crt), (uint8_t *)client_key, strlen(client_key), NULL, 0); } - else if (client_cert != NULL) { - client_secure.setCertificate(client_cert); - } - else if (client_key != NULL) { - client_secure.setPrivateKey(client_key); + + esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)wpa2_identity, strlen(wpa2_identity)); + if(method == WPA2_AUTH_PEAP || method == WPA2_AUTH_TTLS) { + esp_wifi_sta_wpa2_ent_set_username((uint8_t *)wpa2_username, strlen(wpa2_username)); + esp_wifi_sta_wpa2_ent_set_password((uint8_t *)wpa2_password, strlen(wpa2_password)); } + esp_wifi_sta_wpa2_ent_enable(); //set config settings to enable function + WiFi.begin(wpa2_ssid); //connect to wifi + return status(); } diff --git a/libraries/WiFi/src/WiFiSTA.h b/libraries/WiFi/src/WiFiSTA.h index f159c41c131..613c37682b8 100644 --- a/libraries/WiFi/src/WiFiSTA.h +++ b/libraries/WiFi/src/WiFiSTA.h @@ -30,6 +30,11 @@ #include "esp_event.h" #endif +typedef enum { + WPA2_AUTH_TLS = 0, + WPA2_AUTH_PEAP = 1, + WPA2_AUTH_TTLS = 2 +} wpa2_auth_method_t; class WiFiSTAClass { @@ -39,7 +44,7 @@ class WiFiSTAClass public: - wl_status_t begin(const char* wpa2_ssid, const char* wpa2_identity, const char* wpa2_username, const char *wpa2_password, const char* root_ca=NULL, const char* client_cert=NULL, const char* client_key=NULL,int32_t channel=0, const uint8_t* bssid=0, bool connect=true); + wl_status_t begin(const char* wpa2_ssid, wpa2_auth_method_t method, const char* wpa2_identity=NULL, const char* wpa2_username=NULL, const char *wpa2_password=NULL, const char* ca_pem=NULL, const char* client_crt=NULL, const char* client_key=NULL, int32_t channel=0, const uint8_t* bssid=0, bool connect=true); wl_status_t begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); wl_status_t begin(char* ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); wl_status_t begin();