ESP32 WiFi eduroam WPA/WPA2 Enterprise IoT IBM Watson, Bluemix PEAP, EAP-TTLS Arduino Core 802.1X RADIUS Identity Password Realm Domain MQTT HTTP, HTTPS
Source codes for the ESP32 microcontroller are available: HERE in the Github repository
If you tried the sketch and the connection works for you, please confirm it by email (a screenshot from the Serial monitor will also help): martinius96@gmail.com

The principle of the eduroam network


The eduroam network (education roaming) is a worldwide computer infrastructure that is implemented in the scientific and university sphere. The original idea of the project - the eduroam network was established in the Netherlands in 2002. The network is designed for worldwide use by students, scientific workers and teachers. It consists of a network of RADIUS servers that authenticate users who want to connect to the network and use services internet and LAN network. This infrastructure of RADIUS servers is often referred to as a federation. A RADIUS server is a device providing AAA services: authentication, authorization and billing (AAA - Authentication, Authorization, and Accounting). A device is a physical element of a network that verifies the credentials of users entering the network they connect. Every user of the eduroam network can connect to the network from any organization in the world that is included in the eduroam project without the need to change the configuration settings of the network profile. All of them access points broadcast SSID eduroam. The user does so connects, in a way as if it were in a home organization. Every organization in the eduroam network must adapt to certain rules that are clearly defined, which allows them to interact compatibility. Every network user eduroam is uniquely assigned to its organization through a realm. Realm is defined in the form @organization.domain. In the case of the Technical University in Košice, it is the realm @tuke.sk for students, teachers and researchers.


There are two more requested parameters, which are when logging into the WiFi network eduroam required. If a user logs into the eduroam network, they must enter an identity that is formed by his name or identifier and the realm of the organization. The second parameter, which the user at logging into the WiFi network uses his password. The password is stored in the database in a readable form, or in NTLM hash format. These ways of entering the password can also be applied on the side of the client trying to access the networks. If the user logs into the eduroam network in his own organization, he can only use login name, no identifier with realm required. However, this method can only be applied in ones own organization, since from another organization, the client will not connect, as there is no realm in the users identity. In Slovakia, the eduroam network is operated by the Council of Universities, the connectivity between them and to the Internet is provided by the SANET association.


Each client must go through two phases when connecting to the eduroam network:
  • 1. Authentication - proof of identity and password through the supplicant
  • 2. Authorization - RADIUS server response Allow access / Deny access
  • If the user fails to prove the identity and password, the authorization is performed with the result of deny access, the client is not assigned an IP address and cannot use Internet and LAN network services. An attempt can repeat. In the event that a client that is authenticated and authorized performs a prohibited activity, it is possible block only its physical MAC address via routers, or realm for all users of the given organization via RADIUS server. Since the client can use an anonymous identity, the organization where the client connects to the eduroam network does not know the username, it can only get this one an identification string from the home organization, but broadcasting this string is not a must. Since 2017, it is also possible to block the Chargeable user identity chain, which blocks the user in the eduroam network, each user has a different parameter. The RADIUS server of the eduroam network is most often in the software configuration in organizations of the Linux Debian operating system with the FreeRADIUS extension. In addition to setting the RADIUS servers to the eduroam network standard, it is also required to set a authentication of trusted access points. Access points contain a configuration with an address RADIUS server, a transmission protocol with a stored string - mutually shared a secret. This text string is different for each access point, but must match the set for the given access point on the RADIUS server side.


    Allowed ports - eduroam


    After successfully connecting to the eduroam WiFi network, the user can use these network ports:
    Service Protocol Port Direction of communication
    Standard IPSec VPN IP (ESP) 50 Bi-directional
    IP (AH) 51 Bi-directional
    UDP(IKE) 500 Out
    OpenVPN 2.0 UDP (OpenVPN) 1194 Bi-directional
    IPv6 Tunnel broker IP 41 Bi-directional
    IPSec NAT-Traversal UDP (IPSec) 4500 Bi-directional
    Cisco IPSec VPNoTCP TCP 10000 Out
    PPTP VPN TCP (PPTP) 1723 Bi-directional
    IP (GRE) 47 Out
    SSH TCP 22 Out
    HTTP TCP 80 Von
    TCP 443 Out
    TCP 3128 Out
    TCP 8080 Out
    Mail services - sending TCP (SMTP-SSL) 465 Out
    TCP (decbsrv) 579 Out
    Mail services - receiving TCP (IMAP) 143 Out
    TCP (IMAP-SSL) 993 Out
    TCP (POP3) 110 Out
    TCP (POP3-SSL) 995 Out
    FTP TCP 21 Out

    Source code for ESP32 - Core 2.0.3+


    /*|----------------------------------------------------------|*/
    /*|Experimental example for eduroam connection               |*/
    /*|Sketch wasnt tested, I am not more student, cant try it   |*/
    /*|Changes from @debsahu (Github) and  esp_wpa2 library ref. |*/
    /*|Edited by: Martin Chlebovec (martinius96)                 |*/
    /*|Compilation under 2.0.3 Arduino Core worked               |*/
    /*|Previous stable cores are NOT usable, does not have       |*/
    /*|WiFi.begin() definition with these parameters for PEAP... |*/
    /*|----------------------------------------------------------|*/
    /*|Let me know if you were successful in connecting to WiFi: |*/
    /*|with screenshots from Serial at martinius96@gmail.com     |*/
    /*|----------------------------------------------------------|*/
    
    //Code based on commit by @jpswensen from 15th March 2022: https://github.com/espressif/arduino-esp32/commit/d977359e343bd1dfd83b82d14b6afc2a84fdd998
    //Commit is to 2.0.3-RC1 Arduino Core, used in 2.0.3 Release version of Arduino Core for ESP32
    
    #include <WiFi.h> //Wifi library
    #include "esp_wpa2.h" //wpa2 library for connections to Enterprise networks
    
    //Identity for user with password related to his realm (organization)
    //Available option of anonymous identity for federation of RADIUS servers or 1st Domain RADIUS servers
    
    #define EAP_ANONYMOUS_IDENTITY "anonymous@tuke.sk" //anonymous@example.com, or you can use also nickname@example.com
    #define EAP_IDENTITY "username@tuke.sk" //nickname@example.com, at some organizations should work nickname only without realm, but it is not recommended
    #define EAP_PASSWORD "password" //password for eduroam account
    
    //SSID NAME
    const char* ssid = "eduroam"; // eduroam SSID
    
    //Intermediate CA cert (GEANT OV RSA CA 4) in .pem format
    //Used for WiFi connection as trusted CA that issued certificate for wifi.uvt.tuke.sk
    const static char* test_root_ca PROGMEM = \
        "-----BEGIN CERTIFICATE-----\n" \
        "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\n" \
        "-----END CERTIFICATE-----\n";
    
    //Root CA cert (USERTrust RSA Certification Authority) in .pem format
    //Use if connection not successful with Intermediate CA above
    /*
      const static char* test_root_ca PROGMEM = \
      "-----BEGIN CERTIFICATE-----\n" \
      "MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB\n" \
      "iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl\n" \
      "cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV\n" \
      "BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw\n" \
      "MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV\n" \
      "BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\n" \
      "aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy\n" \
      "dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n" \
      "AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B\n" \
      "3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY\n" \
      "tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/\n" \
      "Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2\n" \
      "VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT\n" \
      "79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6\n" \
      "c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT\n" \
      "Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l\n" \
      "c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee\n" \
      "UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE\n" \
      "Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd\n" \
      "BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G\n" \
      "A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF\n" \
      "Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO\n" \
      "VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3\n" \
      "ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs\n" \
      "8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR\n" \
      "iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze\n" \
      "Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ\n" \
      "XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/\n" \
      "qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB\n" \
      "VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB\n" \
      "L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG\n" \
      "jjxDah2nGN59PRbxYvnKkKj9\n" \
      "-----END CERTIFICATE-----\n";
    */
    
    void setup() {
      Serial.begin(115200);
      delay(10);
      Serial.println();
      Serial.print(F("Connecting to network: "));
      Serial.println(ssid);
      WiFi.disconnect(true);  //disconnect form wifi to set new wifi connection
      WiFi.mode(WIFI_STA); //init wifi mode
      WiFi.begin(ssid, WPA2_AUTH_PEAP, EAP_ANONYMOUS_IDENTITY, EAP_IDENTITY, EAP_PASSWORD, test_root_ca); //with CERTIFICATE
      //WiFi.begin(ssid, WPA2_AUTH_PEAP, EAP_ANONYMOUS_IDENTITY, EAP_IDENTITY, EAP_PASSWORD); //without CERTIFICATE
    
      // Example: a cert-file WPA2 Enterprise with PEAP
      //WiFi.begin(ssid, WPA2_AUTH_PEAP, EAP_IDENTITY, EAP_USERNAME, EAP_PASSWORD, test_root_ca, client_cert, client_key);
    
      // Example: TLS with cert-files and no password
      //WiFi.begin(ssid, WPA2_AUTH_TLS, EAP_IDENTITY, NULL, NULL, test_root_ca, client_cert, client_key);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(F("."));
      }
      Serial.println("");
      Serial.println(F("WiFi is connected!"));
      Serial.println(F("IP address set: "));
      Serial.println(WiFi.localIP()); //print LAN IP
    }
    void loop() {
      yield();
    }