From 610fb1dd93cc18fb9e17a5d5195475b31c6778ed Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 6 Aug 2019 14:58:35 +0200 Subject: [PATCH 1/5] Add WPA2 Enterprise API support --- src/WiFi.cpp | 21 ++++++++ src/WiFi.h | 39 ++++++++++++++ src/utility/wifi_drv.cpp | 110 +++++++++++++++++++++++++++++++++++++++ src/utility/wifi_drv.h | 5 ++ src/utility/wifi_spi.h | 8 +++ 5 files changed, 183 insertions(+) diff --git a/src/WiFi.cpp b/src/WiFi.cpp index e4a34dd4..8dadfb41 100644 --- a/src/WiFi.cpp +++ b/src/WiFi.cpp @@ -156,6 +156,27 @@ uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase, uint8_t cha return status; } +void WiFiClass::config(WPA2Enterprise& data) +{ + WiFiDrv::wpa2EntSetIdentity(data.identity.c_str()); + WiFiDrv::wpa2EntSetUsername(data.username.c_str()); + WiFiDrv::wpa2EntSetPassword(data.password.c_str()); + + if (data.ca_pem) { + WiFiStorage.remove("/fs/ca.pem"); + WiFiStorage.write("/fs/ca.pem", 0, (uint8_t*)data.ca_pem, strlen(data.ca_pem)); + } + if (data.client_crt) { + WiFiStorage.remove("/fs/client.crt"); + WiFiStorage.write("/fs/client.crt", 0, (uint8_t*)data.client_crt, strlen(data.client_crt)); + } + if (data.client_key) { + WiFiStorage.remove("/fs/client.key"); + WiFiStorage.write("/fs/client.key", 0, (uint8_t*)data.client_key, strlen(data.client_key)); + } + WiFiDrv::wpa2EntEnable(); +} + void WiFiClass::config(IPAddress local_ip) { WiFiDrv::config(1, (uint32_t)local_ip, 0, 0); diff --git a/src/WiFi.h b/src/WiFi.h index 3bb5db60..88af2cf6 100644 --- a/src/WiFi.h +++ b/src/WiFi.h @@ -35,6 +35,39 @@ extern "C" { #include "WiFiSSLClient.h" #include "WiFiServer.h" +typedef enum _eap_methods { + EAP_TLS = 0, + EAP_PEAP = 1, + EAP_TTLS = 2, +} eap_method; + +class WPA2Enterprise +{ +public: + WPA2Enterprise(eap_method method, String identity, String username = "", String password = "", + const char* ca_pem = NULL, const char* client_crt = NULL, const char* client_key = NULL) : + method(method), identity(identity), username(username), password(password), + ca_pem(ca_pem), client_crt(client_crt), client_key(client_key) + {} + WPA2Enterprise(String identity, String username = "", String password = "", + const char* ca_pem = NULL, const char* client_crt = NULL, const char* client_key = NULL) : + method(EAP_TLS), identity(identity), username(username), password(password), + ca_pem(ca_pem), client_crt(client_crt), client_key(client_key) + {} + WPA2Enterprise(String identity, const char* ca_pem = NULL, const char* client_crt = NULL, const char* client_key = NULL) : + method(EAP_TLS), identity(identity), username(""), password(""), + ca_pem(ca_pem), client_crt(client_crt), client_key(client_key) + {} + + eap_method method; // TLS: 0, PEAP: 1, TTLS: 2 // looks like it's handled internally + String identity; + String username; + String password; + const char* ca_pem; + const char* client_crt; + const char* client_key; +}; + class WiFiClass { private: @@ -80,6 +113,12 @@ class WiFiClass uint8_t beginAP(const char *ssid, const char* passphrase); uint8_t beginAP(const char *ssid, const char* passphrase, uint8_t channel); + /* Add WPA2 Enterprise information for next connection + * + * param data: Static ip configuration + */ + void config(WPA2Enterprise& data); + /* Change Ip configuration settings disabling the dhcp client * * param local_ip: Static ip configuration diff --git a/src/utility/wifi_drv.cpp b/src/utility/wifi_drv.cpp index 3575d797..2630d54f 100644 --- a/src/utility/wifi_drv.cpp +++ b/src/utility/wifi_drv.cpp @@ -1078,4 +1078,114 @@ void WiFiDrv::analogWrite(uint8_t pin, uint8_t value) SpiDrv::spiSlaveDeselect(); } +void WiFiDrv::wpa2EntSetIdentity(const char* identity) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(WPA2_ENTERPRISE_SET_IDENTITY, PARAM_NUMS_1); + SpiDrv::sendParam((uint8_t*)identity, strlen(identity), LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 5 + strlen(identity); + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(WPA2_ENTERPRISE_SET_IDENTITY, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::wpa2EntSetPassword(const char* password) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(WPA2_ENTERPRISE_SET_PASSWORD, PARAM_NUMS_1); + SpiDrv::sendParam((uint8_t*)password, strlen(password), LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 5 + strlen(password); + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(WPA2_ENTERPRISE_SET_PASSWORD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::wpa2EntSetUsername(const char* username) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(WPA2_ENTERPRISE_SET_USERNAME, PARAM_NUMS_1); + SpiDrv::sendParam((uint8_t*)username, strlen(username), LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 5 + strlen(username); + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(WPA2_ENTERPRISE_SET_USERNAME, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::wpa2EntEnable() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(WPA2_ENTERPRISE_ENABLE, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 1; + uint8_t _dataLen = 0; + SpiDrv::waitResponseCmd(WPA2_ENTERPRISE_ENABLE, PARAM_NUMS_1, &_data, &_dataLen); + + SpiDrv::spiSlaveDeselect(); +} + WiFiDrv wiFiDrv; diff --git a/src/utility/wifi_drv.h b/src/utility/wifi_drv.h index d9bfeff2..25777306 100644 --- a/src/utility/wifi_drv.h +++ b/src/utility/wifi_drv.h @@ -286,6 +286,11 @@ class WiFiDrv static void digitalWrite(uint8_t pin, uint8_t value); static void analogWrite(uint8_t pin, uint8_t value); + static void wpa2EntSetIdentity(const char* identity); + static void wpa2EntSetUsername(const char* username); + static void wpa2EntSetPassword(const char* password); + static void wpa2EntEnable(); + friend class WiFiUDP; friend class WiFiClient; }; diff --git a/src/utility/wifi_spi.h b/src/utility/wifi_spi.h index 7402e434..b3fcba8b 100644 --- a/src/utility/wifi_spi.h +++ b/src/utility/wifi_spi.h @@ -97,6 +97,14 @@ enum { GET_DATABUF_TCP_CMD = 0x45, INSERT_DATABUF_CMD = 0x46, + // wpa2 enterprise commands + WPA2_ENTERPRISE_SET_IDENTITY = 0x4A, + WPA2_ENTERPRISE_SET_USERNAME = 0x4B, + WPA2_ENTERPRISE_SET_PASSWORD = 0x4C, + WPA2_ENTERPRISE_SET_CA_CERT = 0x4D, + WPA2_ENTERPRISE_SET_CERT_KEY = 0x4E, + WPA2_ENTERPRISE_ENABLE = 0x4F, + // regular format commands SET_PIN_MODE = 0x50, SET_DIGITAL_WRITE = 0x51, From f7aa896c2f9313b7fd1b147a9311d76795a5305a Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 6 Aug 2019 14:59:04 +0200 Subject: [PATCH 2/5] Add example of connection via WPA2 Enterprise --- .../WiFiWebClientWPA2Enterprise.ino | 134 ++++++++++++++++++ .../arduino_secrets.h | 127 +++++++++++++++++ 2 files changed, 261 insertions(+) create mode 100644 examples/WiFiWebClientWPA2Enterprise/WiFiWebClientWPA2Enterprise.ino create mode 100644 examples/WiFiWebClientWPA2Enterprise/arduino_secrets.h diff --git a/examples/WiFiWebClientWPA2Enterprise/WiFiWebClientWPA2Enterprise.ino b/examples/WiFiWebClientWPA2Enterprise/WiFiWebClientWPA2Enterprise.ino new file mode 100644 index 00000000..ab2b0596 --- /dev/null +++ b/examples/WiFiWebClientWPA2Enterprise/WiFiWebClientWPA2Enterprise.ino @@ -0,0 +1,134 @@ + +/* + Web client + + This sketch connects to a website (http://www.google.com) + using the WiFi module. + + This example is written for a network using WPA encryption. For + WEP or WPA, change the Wifi.begin() call accordingly. + + This example is written for a network using WPA encryption. For + WEP or WPA, change the Wifi.begin() call accordingly. + + Circuit: + * Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2) + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ + + +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS) +char server[] = "www.google.com"; // name address for Google (using DNS) + +// Initialize the Ethernet client library +// with the IP address and port of the server +// that you want to connect to (port 80 is default for HTTP): +WiFiClient client; + +// Initialize the WPA2 Enterprise object +// Just fill the fields you need +// eg. if you are given only an identity and a certificate, initialize it as +// WPA2Enterprise data("myidentity", ca_pem); +// Certificates are stored in secret tab to avoid sharing them. + +WPA2Enterprise data(EAP_TLS, "myidentity", "username", "password", ca_pem, client_crt, client_key); + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // configure the wifi module to use provided WPA2 Enterprise parameters + WiFi.config(data); + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to Wifi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + Serial.println("Connected to wifi"); + printWifiStatus(); + + Serial.println("\nStarting connection to server..."); + // if you get a connection, report back via serial: + if (client.connect(server, 80)) { + Serial.println("connected to server"); + // Make a HTTP request: + client.println("GET /search?q=arduino HTTP/1.1"); + client.println("Host: www.google.com"); + client.println("Connection: close"); + client.println(); + } +} + +void loop() { + // if there are incoming bytes available + // from the server, read them and print them: + while (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + Serial.println(); + Serial.println("disconnecting from server."); + client.stop(); + + // do nothing forevermore: + while (true); + } +} + + +void printWifiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/examples/WiFiWebClientWPA2Enterprise/arduino_secrets.h b/examples/WiFiWebClientWPA2Enterprise/arduino_secrets.h new file mode 100644 index 00000000..8ba14a47 --- /dev/null +++ b/examples/WiFiWebClientWPA2Enterprise/arduino_secrets.h @@ -0,0 +1,127 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + +// This certificates are completely bogus, but your own should resemble this format + +const char * ca_pem = "-----BEGIN CERTIFICATE-----\n" +"MIID3DCCA0WgAwIBAgIJANe5ZSCKoB8fMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD\n" +"VQQGEwJGUjEPMA0GA1UECAwGUmFkaXVzMRIwEAYDVQQHDAlTb21ld2hlcmUxFTAT\n" +"BgNVBAoMDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBs\n" +"ZS5jb20xJjAkBgNVBAMMHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4X\n" +"DTE2MTEyMzAyNTUwN1oXDTE3MDEyMjAyNTUwN1owgZMxCzAJBgNVBAYTAkZSMQ8w\n" +"DQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMGA1UECgwMRXhh\n" +"bXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTEmMCQG\n" +"A1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwgZ8wDQYJKoZIhvcN\n" +"AQEBBQADgY0AMIGJAoGBAL03y7N2GvNDO9BN8fVtdNonp0bMiqpj1D0He5+OTM+9\n" +"3ZTIsJCNrbzhLQrRI3vMW7UDy8U7GeWORN9W4dWYlYiy/NFRp3hNMrbePhVmNIOV\n" +"ww4ovGzbD+Xo31gPVkhzQ8I5/jbOIQBmgKMAMZyOMlG9VD6yMmAeYqnZYz68WHKt\n" +"AgMBAAGjggE0MIIBMDAdBgNVHQ4EFgQUf1MLQIzAEZcRsgZlS8sosfmVI+UwgcgG\n" +"A1UdIwSBwDCBvYAUf1MLQIzAEZcRsgZlS8sosfmVI+WhgZmkgZYwgZMxCzAJBgNV\n" +"BAYTAkZSMQ8wDQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMG\n" +"A1UECgwMRXhhbXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxl\n" +"LmNvbTEmMCQGA1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCCQDX\n" +"uWUgiqAfHzAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93\n" +"d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcNAQELBQADgYEA\n" +"GepHc7TE/P+5t/cZPn5TTQkWQ/4/1lgQd82lF36RYWSIW3BdAc0zwYWYZaWixxyp\n" +"s0YOqwz6PZAGRV+SlYO2f8Kf+C3aZs4YHB0GsmksmFOb8r9d7xcDuOKHoA+QV0Zw\n" +"RaK6pttsBAxy7rw3kX/CgTp0Y2puaLdMXv/v9FisCP8=\n" +"-----END CERTIFICATE-----"; + +const char * client_crt = "Certificate:\n" +" Data:\n" +" Version: 3 (0x2)\n" +" Serial Number: 44 (0x2c)\n" +" Signature Algorithm: sha1WithRSAEncryption\n" +" Issuer: C=FR, ST=Radius, L=Somewhere, O=Example Inc./emailAddress=admin@example.com, CN=Example Certificate Authority\n" +" Validity\n" +" Not Before: Nov 23 02:55:07 2016 GMT\n" +" Not After : Jan 22 02:55:07 2017 GMT\n" +" Subject: C=FR, ST=Radius, O=Example Inc., CN=user@example.com/emailAddress=user@example.com\n" +" Subject Public Key Info:\n" +" Public Key Algorithm: rsaEncryption\n" +" Public-Key: (2048 bit)\n" +" Modulus:\n" +" 00:ac:41:d4:a2:46:0c:dc:67:1d:7b:89:36:7c:15:\n" +" be:a2:c1:fe:4c:f2:fa:af:5d:76:0e:ee:b5:ca:d4:\n" +" d3:01:c8:6b:30:50:df:2d:57:17:f4:43:47:97:ca:\n" +" f1:8d:f7:c0:9d:56:b3:e7:17:7c:58:59:de:f3:be:\n" +" b5:08:5d:f8:3a:ad:83:44:0d:31:c9:f1:3d:f1:9a:\n" +" cf:84:0c:ad:d3:be:5c:bd:3d:58:b5:1d:2c:fe:70:\n" +" 8d:c5:b0:17:87:d4:8e:85:f7:51:4c:0f:d1:e0:8c:\n" +" 7b:a0:25:ab:91:7c:7f:eb:47:73:c9:4b:6c:8b:e6:\n" +" c1:06:d5:94:30:63:ec:45:1a:f5:7f:46:2f:b3:84:\n" +" 78:5d:1c:37:1a:fa:57:ea:45:5e:45:40:ab:14:c7:\n" +" 81:b0:26:3d:7e:cf:da:db:f0:f1:40:a7:a1:4b:54:\n" +" f3:96:1b:c9:30:3c:3c:d8:19:ba:c7:df:b1:ad:a2:\n" +" d6:17:0a:d6:ed:31:b5:cb:12:39:f5:6e:92:6b:85:\n" +" f2:9e:c7:06:6b:bb:89:ed:a7:5f:ec:56:12:46:fd:\n" +" 3a:74:d1:d2:31:30:1d:58:19:25:33:ff:11:ea:3a:\n" +" 52:33:b1:fb:d3:75:8d:1f:5e:36:a5:35:e0:11:5a:\n" +" 4a:2d:97:58:2c:3d:62:3c:32:af:83:69:a9:1a:32:\n" +" 1b:b7\n" +" Exponent: 65537 (0x10001)\n" +" X509v3 extensions:\n" +" X509v3 Extended Key Usage: \n" +" TLS Web Client Authentication\n" +" X509v3 CRL Distribution Points: \n" +"\n" +" Full Name:\n" +" URI:http://www.example.com/example_ca.crl\n" +"\n" +" Signature Algorithm: sha1WithRSAEncryption\n" +" 8b:8d:b6:19:ce:6f:6b:9e:1d:03:8b:6b:10:fc:99:d0:7a:2f:\n" +" e0:37:ce:b8:a4:e4:b9:a1:c2:36:ff:76:b2:ad:d7:d0:df:d1:\n" +" 03:27:93:a7:4e:1e:bf:ed:d2:b7:65:2a:c9:c3:ab:20:aa:e3:\n" +" 10:4c:75:3b:c4:02:ab:34:08:6e:61:91:cf:e3:02:35:6a:e5:\n" +" f3:25:96:51:92:82:6e:52:81:c1:f1:7b:68:02:b0:ce:f4:ba:\n" +" fd:6e:68:35:b3:7e:77:cb:a0:1e:11:5e:58:bf:f3:2a:ed:b3:\n" +" 4c:82:21:5e:1b:47:b6:2f:f3:f5:c9:1b:6a:70:44:6d:ff:ad:\n" +" a6:e3\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDTjCCAregAwIBAgIBLDANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMCRlIx\n" +"DzANBgNVBAgMBlJhZGl1czESMBAGA1UEBwwJU29tZXdoZXJlMRUwEwYDVQQKDAxF\n" +"eGFtcGxlIEluYy4xIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMSYw\n" +"JAYDVQQDDB1FeGFtcGxlIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjExMjMw\n" +"MjU1MDdaFw0xNzAxMjIwMjU1MDdaMHExCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZS\n" +"YWRpdXMxFTATBgNVBAoMDEV4YW1wbGUgSW5jLjEZMBcGA1UEAwwQdXNlckBleGFt\n" +"cGxlLmNvbTEfMB0GCSqGSIb3DQEJARYQdXNlckBleGFtcGxlLmNvbTCCASIwDQYJ\n" +"KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKxB1KJGDNxnHXuJNnwVvqLB/kzy+q9d\n" +"dg7utcrU0wHIazBQ3y1XF/RDR5fK8Y33wJ1Ws+cXfFhZ3vO+tQhd+Dqtg0QNMcnx\n" +"PfGaz4QMrdO+XL09WLUdLP5wjcWwF4fUjoX3UUwP0eCMe6Alq5F8f+tHc8lLbIvm\n" +"wQbVlDBj7EUa9X9GL7OEeF0cNxr6V+pFXkVAqxTHgbAmPX7P2tvw8UCnoUtU85Yb\n" +"yTA8PNgZusffsa2i1hcK1u0xtcsSOfVukmuF8p7HBmu7ie2nX+xWEkb9OnTR0jEw\n" +"HVgZJTP/Eeo6UjOx+9N1jR9eNqU14BFaSi2XWCw9Yjwyr4NpqRoyG7cCAwEAAaNP\n" +"ME0wEwYDVR0lBAwwCgYIKwYBBQUHAwIwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDov\n" +"L3d3dy5leGFtcGxlLmNvbS9leGFtcGxlX2NhLmNybDANBgkqhkiG9w0BAQUFAAOB\n" +"gQCLjbYZzm9rnh0Di2sQ/JnQei/gN864pOS5ocI2/3ayrdfQ39EDJ5OnTh6/7dK3\n" +"ZSrJw6sgquMQTHU7xAKrNAhuYZHP4wI1auXzJZZRkoJuUoHB8XtoArDO9Lr9bmg1\n" +"s353y6AeEV5Yv/Mq7bNMgiFeG0e2L/P1yRtqcERt/62m4w==\n" +"-----END CERTIFICATE-----"; + +const char * client_key = "-----BEGIN RSA PRIVATE KEY-----\n" +"MIIEpgIBAAKCAQEArEHUokYM3Gcde4k2fBW+osH+TPL6r112Du61ytTTAchrMFDf\n" +"LVcX9ENHl8rxjffAnVaz5xd8WFne8761CF34Oq2DRA0xyfE98ZrPhAyt075cvT1Y\n" +"tR0s/nCNxbAXh9SOhfdRTA/R4Ix7oCWrkXx/60dzyUtsi+bBBtWUMGPsRRr1f0Yv\n" +"s4R4XRw3GvpX6kVeRUCrFMeBsCY9fs/a2/DxQKehS1TzlhvJMDw82Bm6x9+xraLW\n" +"FwrW7TG1yxI59W6Sa4XynscGa7uJ7adf7FYSRv06dNHSMTAdWBklM/8R6jpSM7H7\n" +"03WNH142pTXgEVpKLZdYLD1iPDKvg2mpGjIbtwIDAQABAoIBAQCMhO9GqUpYia2d\n" +"VyOhOcPX1dTzRMuHPwDN0aFvIwo2zB3UvkQxInkiA7hldWJz44W3VEFR5PDEyht8\n" +"Tzgy6SVUCLOqUfEpwag8bYOXPxiWQRY6Mc8pf/FyZrLgb3PilFznoAcru0QEn9VB\n" +"oTlCZ4OalSE5NlQIFGemgZhvmTPmcm4OwPW2diBjLtb3AA8eaaw8okWZwr8g4Bcd\n" +"el5KX6pZpDRpGQueh3iKaKxYWbxLYK+c30gKWD65tsAqKyVg2Tm1R2c+kFXgizZt\n" +"EexD95SGMjSkGg3R05sKv6m71iJhlOzVQ4ZCKm18Kqa7wZuZ4SIehVmKIV0gaupz\n" +"gjyr7+NBAoGBAOGjjGI3nxJTZY3O+KeaQo/jqrKowqZxzMOsCgAvW56xDuAvx9TJ\n" +"m4428NGubMl/0RwX6TnxJDm6oe+tnOxLIgE/VnsQLiNzQuFJxrs5JYctdGc4uvk2\n" +"KuXDr7tPEYlU/7OLRReov9emydIXJnsGejkIPllUj+DGNjNFqtXh2VoHAoGBAMNv\n" +"eSgJSkcM6AUaDuUKaXBL2nkKHNoTtRQ0eCEUds6arKyMo0mSP753FNEuOWToVz1O\n" +"oaddSFw81J9t+Xd6XSRbhMj63bQ9nvFKBA1lJfLu+xe3ts0f+vmp1PguOuUHsgNP\n" +"aAm/gLPSKUpBO46NG6KhUrZ2ej6AEg7SuGXrDITRAoGBAKK7s6m6d81dvGZ0GT23\n" +"sb3Y8ul7cTdd59JPp77OaQOgqxvhGfxLkxcUZMa1R9xjhMsAK8MQOZIxGk2kJwL8\n" +"hP/lUFfdKYmDvX6CGQQ6iOhfTg6MCb1m5bVkVr9+nSUw2mIBVclkeUftEK2m6Kfd\n" +"2hR774u5wzLXgYuk+TrcckfNAoGBAJ9X8hacjH0lnr8aIe7I8HLoxbZOcnuz+b4B\n" +"kbiW8M8++W6uNCw2G9b1THnJEG6fqRGJXPASdH8P8eQTTIUHtY2BOOCM+dqNK1xc\n" +"FrW9NJXAF+WcmmTgoEaTG9tGBirafV+JjK/1/b+fqJ6sVRzDHDcbBU9ThhQTY6XG\n" +"VSZz4H8hAoGBAMeQQjiUlKBnpGt1oTgKDZo58b7ui61yftg+dEAwIKs6eb5X20vZ\n" +"Ca4v/zg06k9lKTzyspQjJZuzpMjFUvDK4ReamEvmwQTIc+oYVJm9Af1HUytzrHJH\n" +"u0/dDt0eYpZpzrFqxlP+0oXxlegD8REMVvwNCy+4isyCvjogDaYRfJqi\n" +"-----END RSA PRIVATE KEY-----"; From 33ff7d362948b36e7a581958df6407991bdfec0c Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 9 Aug 2019 09:51:32 +0200 Subject: [PATCH 3/5] [fixup] Apply suggestions from code review Co-Authored-By: per1234 --- .../WiFiWebClientWPA2Enterprise.ino | 15 ++++++--------- .../WiFiWebClientWPA2Enterprise/arduino_secrets.h | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/examples/WiFiWebClientWPA2Enterprise/WiFiWebClientWPA2Enterprise.ino b/examples/WiFiWebClientWPA2Enterprise/WiFiWebClientWPA2Enterprise.ino index ab2b0596..2481efd0 100644 --- a/examples/WiFiWebClientWPA2Enterprise/WiFiWebClientWPA2Enterprise.ino +++ b/examples/WiFiWebClientWPA2Enterprise/WiFiWebClientWPA2Enterprise.ino @@ -6,10 +6,7 @@ using the WiFi module. This example is written for a network using WPA encryption. For - WEP or WPA, change the Wifi.begin() call accordingly. - - This example is written for a network using WPA encryption. For - WEP or WPA, change the Wifi.begin() call accordingly. + WEP or WPA, change the WiFi.begin() call accordingly. Circuit: * Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2) @@ -45,7 +42,7 @@ WiFiClient client; // Just fill the fields you need // eg. if you are given only an identity and a certificate, initialize it as // WPA2Enterprise data("myidentity", ca_pem); -// Certificates are stored in secret tab to avoid sharing them. +// Certificates are stored in the Secret tab to avoid sharing them. WPA2Enterprise data(EAP_TLS, "myidentity", "username", "password", ca_pem, client_crt, client_key); @@ -56,7 +53,7 @@ void setup() { ; // wait for serial port to connect. Needed for native USB port only } - // configure the wifi module to use provided WPA2 Enterprise parameters + // configure the WiFi module to use provided WPA2 Enterprise parameters WiFi.config(data); // check for the WiFi module: @@ -71,7 +68,7 @@ void setup() { Serial.println("Please upgrade the firmware"); } - // attempt to connect to Wifi network: + // attempt to connect to WiFi network: while (status != WL_CONNECTED) { Serial.print("Attempting to connect to SSID: "); Serial.println(ssid); @@ -81,7 +78,7 @@ void setup() { // wait 10 seconds for connection: delay(10000); } - Serial.println("Connected to wifi"); + Serial.println("Connected to WiFi"); printWifiStatus(); Serial.println("\nStarting connection to server..."); @@ -128,7 +125,7 @@ void printWifiStatus() { // print the received signal strength: long rssi = WiFi.RSSI(); - Serial.print("signal strength (RSSI):"); + Serial.print("signal strength (RSSI): "); Serial.print(rssi); Serial.println(" dBm"); } diff --git a/examples/WiFiWebClientWPA2Enterprise/arduino_secrets.h b/examples/WiFiWebClientWPA2Enterprise/arduino_secrets.h index 8ba14a47..efe1ec66 100644 --- a/examples/WiFiWebClientWPA2Enterprise/arduino_secrets.h +++ b/examples/WiFiWebClientWPA2Enterprise/arduino_secrets.h @@ -1,7 +1,7 @@ #define SECRET_SSID "" #define SECRET_PASS "" -// This certificates are completely bogus, but your own should resemble this format +// These certificates are completely bogus, but your own should resemble this format const char * ca_pem = "-----BEGIN CERTIFICATE-----\n" "MIID3DCCA0WgAwIBAgIJANe5ZSCKoB8fMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD\n" From d8ac9ffc7d8140e04154b7dbbd615ace0ca7b4c3 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 13 Aug 2019 16:36:03 +0200 Subject: [PATCH 4/5] WPA2Ent: explicitely set certificates --- src/WiFi.cpp | 34 ++++++++++----------- src/WiFi.h | 38 ++++++++---------------- src/utility/wifi_drv.cpp | 64 ++++++++++++++++++++++++++++++++++++++++ src/utility/wifi_drv.h | 2 ++ 4 files changed, 95 insertions(+), 43 deletions(-) diff --git a/src/WiFi.cpp b/src/WiFi.cpp index 8dadfb41..1e8123b6 100644 --- a/src/WiFi.cpp +++ b/src/WiFi.cpp @@ -27,6 +27,18 @@ extern "C" { #include "utility/debug.h" } +void WPA2EnterpriseClass::addCACertificate(const char* ca_pem) { + WiFiDrv::wpa2EntSetCACertificate(ca_pem); +} + +void WPA2EnterpriseClass::addClientCertificate(const char* client_crt, const char* client_key) { + // TODO: make sure that client_crt is not bigger tahn 4050bytes + WiFiDrv::wpa2EntSetClientCertificate(client_crt, client_key); +} + +// singleton +WPA2EnterpriseClass WPA2Enterprise; + WiFiClass::WiFiClass() : _timeout(50000) { } @@ -156,25 +168,13 @@ uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase, uint8_t cha return status; } -void WiFiClass::config(WPA2Enterprise& data) +int WiFiClass::beginEnterprise(const char *ssid, const char* username, const char* password) { - WiFiDrv::wpa2EntSetIdentity(data.identity.c_str()); - WiFiDrv::wpa2EntSetUsername(data.username.c_str()); - WiFiDrv::wpa2EntSetPassword(data.password.c_str()); - - if (data.ca_pem) { - WiFiStorage.remove("/fs/ca.pem"); - WiFiStorage.write("/fs/ca.pem", 0, (uint8_t*)data.ca_pem, strlen(data.ca_pem)); - } - if (data.client_crt) { - WiFiStorage.remove("/fs/client.crt"); - WiFiStorage.write("/fs/client.crt", 0, (uint8_t*)data.client_crt, strlen(data.client_crt)); - } - if (data.client_key) { - WiFiStorage.remove("/fs/client.key"); - WiFiStorage.write("/fs/client.key", 0, (uint8_t*)data.client_key, strlen(data.client_key)); - } + WiFiDrv::wpa2EntSetIdentity(username); + WiFiDrv::wpa2EntSetUsername(username); + WiFiDrv::wpa2EntSetPassword(password); WiFiDrv::wpa2EntEnable(); + return begin(ssid); } void WiFiClass::config(IPAddress local_ip) diff --git a/src/WiFi.h b/src/WiFi.h index 88af2cf6..5094d0a2 100644 --- a/src/WiFi.h +++ b/src/WiFi.h @@ -41,33 +41,17 @@ typedef enum _eap_methods { EAP_TTLS = 2, } eap_method; -class WPA2Enterprise +class WPA2EnterpriseClass { public: - WPA2Enterprise(eap_method method, String identity, String username = "", String password = "", - const char* ca_pem = NULL, const char* client_crt = NULL, const char* client_key = NULL) : - method(method), identity(identity), username(username), password(password), - ca_pem(ca_pem), client_crt(client_crt), client_key(client_key) - {} - WPA2Enterprise(String identity, String username = "", String password = "", - const char* ca_pem = NULL, const char* client_crt = NULL, const char* client_key = NULL) : - method(EAP_TLS), identity(identity), username(username), password(password), - ca_pem(ca_pem), client_crt(client_crt), client_key(client_key) - {} - WPA2Enterprise(String identity, const char* ca_pem = NULL, const char* client_crt = NULL, const char* client_key = NULL) : - method(EAP_TLS), identity(identity), username(""), password(""), - ca_pem(ca_pem), client_crt(client_crt), client_key(client_key) - {} - - eap_method method; // TLS: 0, PEAP: 1, TTLS: 2 // looks like it's handled internally - String identity; - String username; - String password; - const char* ca_pem; - const char* client_crt; - const char* client_key; + void clear(); + void save(); + void addCACertificate(const char* ca_pem); + void addClientCertificate(const char* client_crt, const char* client_key); }; +extern WPA2EnterpriseClass WPA2Enterprise; + class WiFiClass { private: @@ -113,11 +97,13 @@ class WiFiClass uint8_t beginAP(const char *ssid, const char* passphrase); uint8_t beginAP(const char *ssid, const char* passphrase, uint8_t channel); - /* Add WPA2 Enterprise information for next connection + /* Start Wifi connection with wpa2 enterprise * - * param data: Static ip configuration + * helper function for most university WPA2 connections + * if a fine-grained configuration is needed (like adding certificates) + * use WPA2Enterprise functions and then call begin() normally */ - void config(WPA2Enterprise& data); + int beginEnterprise(const char *ssid, const char* username, const char* password); /* Change Ip configuration settings disabling the dhcp client * diff --git a/src/utility/wifi_drv.cpp b/src/utility/wifi_drv.cpp index 2630d54f..511bf176 100644 --- a/src/utility/wifi_drv.cpp +++ b/src/utility/wifi_drv.cpp @@ -1168,6 +1168,70 @@ void WiFiDrv::wpa2EntSetUsername(const char* username) SpiDrv::spiSlaveDeselect(); } +void WiFiDrv::wpa2EntSetClientCertificate(const char* client_crt, const char* client_key) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(WPA2_ENTERPRISE_SET_CERT_KEY, PARAM_NUMS_2); + SpiDrv::sendParamLen16(strlen(client_crt)); + SpiDrv::sendParamLen16(strlen(client_key)); + SpiDrv::sendParamNoLen((uint8_t*)client_crt, strlen(client_crt), NO_LAST_PARAM); + SpiDrv::sendParamNoLen((uint8_t*)client_key, strlen(client_key), LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 5 + strlen(client_crt) + strlen(client_key); + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(WPA2_ENTERPRISE_SET_CERT_KEY, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::wpa2EntSetCACertificate(const char* ca_pem) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(WPA2_ENTERPRISE_SET_CA_CERT, PARAM_NUMS_1); + SpiDrv::sendParamLen16(strlen(ca_pem)); + SpiDrv::sendParamNoLen((uint8_t*)ca_pem, strlen(ca_pem), LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 5 + strlen(ca_pem); + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(WPA2_ENTERPRISE_SET_CA_CERT, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + void WiFiDrv::wpa2EntEnable() { WAIT_FOR_SLAVE_SELECT(); diff --git a/src/utility/wifi_drv.h b/src/utility/wifi_drv.h index 25777306..80e671f1 100644 --- a/src/utility/wifi_drv.h +++ b/src/utility/wifi_drv.h @@ -289,6 +289,8 @@ class WiFiDrv static void wpa2EntSetIdentity(const char* identity); static void wpa2EntSetUsername(const char* username); static void wpa2EntSetPassword(const char* password); + static void wpa2EntSetCACertificate(const char* ca_pem); + static void wpa2EntSetClientCertificate(const char* client_crt, const char* client_key); static void wpa2EntEnable(); friend class WiFiUDP; From 5f89952fde3dce3041635767b1b3a2855115b806 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 14 Aug 2019 09:29:26 +0200 Subject: [PATCH 5/5] Fix WPA2 Enterprise example --- .../WiFiWebClientWPA2Enterprise.ino | 108 +++++----- .../arduino_secrets.h | 196 ++++++++---------- 2 files changed, 137 insertions(+), 167 deletions(-) diff --git a/examples/WiFiWebClientWPA2Enterprise/WiFiWebClientWPA2Enterprise.ino b/examples/WiFiWebClientWPA2Enterprise/WiFiWebClientWPA2Enterprise.ino index 2481efd0..d8092eca 100644 --- a/examples/WiFiWebClientWPA2Enterprise/WiFiWebClientWPA2Enterprise.ino +++ b/examples/WiFiWebClientWPA2Enterprise/WiFiWebClientWPA2Enterprise.ino @@ -1,65 +1,69 @@ - /* - Web client + Web client using WPA2 Enterprise connection - This sketch connects to a website (http://www.google.com) - using the WiFi module. + This sketch connects to a website (http://www.arduino.cc) + using the WiFi module. - This example is written for a network using WPA encryption. For - WEP or WPA, change the WiFi.begin() call accordingly. + This example is written for a network using WPA2 Enterprise encryption. - Circuit: - * Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2) + Circuit: + Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2) with firmware > 1.2.4 - created 13 July 2010 - by dlf (Metodo2 srl) - modified 31 May 2012 - by Tom Igoe - */ + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + modified 14 Aug 2019 + by Martino Facchin +*/ #include #include -#include "arduino_secrets.h" +#include "arduino_secrets.h" ///////please enter your sensitive data in the Secret tab/arduino_secrets.h char ssid[] = SECRET_SSID; // your network SSID (name) -char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) int keyIndex = 0; // your network key Index number (needed only for WEP) int status = WL_IDLE_STATUS; -// if you don't want to use DNS (and reduce your sketch size) -// use the numeric IP instead of the name for the server: -//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS) -char server[] = "www.google.com"; // name address for Google (using DNS) - -// Initialize the Ethernet client library -// with the IP address and port of the server -// that you want to connect to (port 80 is default for HTTP): -WiFiClient client; +char server[] = "www.arduino.cc"; // name address for Arduino.cc (using DNS) -// Initialize the WPA2 Enterprise object -// Just fill the fields you need -// eg. if you are given only an identity and a certificate, initialize it as -// WPA2Enterprise data("myidentity", ca_pem); -// Certificates are stored in the Secret tab to avoid sharing them. +// Initialize the WiFi Client +WiFiClient client; -WPA2Enterprise data(EAP_TLS, "myidentity", "username", "password", ca_pem, client_crt, client_key); +// WPA2 Enterprise usage: + +// Certificates and credentials are stored in secret tab to avoid sharing them. +// For some networks (like eduroam) your configuration will simply look like +// +// #define SECRET_SSID "eduroam" +// #define SECRET_USERNAME "identity@youruniversity.domain" +// #define SECRET_PASS "yourpassword" +// +// Call WiFi.beginEnterprise(SECRET_SSID, SECRET_USERNAME, SECRET_PASS) and you should easily connect +// +// In case of more complicated networks (that require a certificate, for example) you can use +// WPA2Enterprise functions +// WPA2Enterprise.addCACertificate() , addClientCertificate(), addIdentity() ... +// and then call WiFi.begin() as usual. void setup() { - //Initialize serial and wait for port to open: + // Initialize serial and wait for port to open: Serial.begin(9600); while (!Serial) { - ; // wait for serial port to connect. Needed for native USB port only + ; // Wait for serial port to connect. Needed for native USB port only } - // configure the WiFi module to use provided WPA2 Enterprise parameters - WiFi.config(data); + // Configure the wifi module to use provided WPA2 Enterprise parameters (if needed) + Serial.println("Configuring WPA2 Enterprise credentials"); + WPA2Enterprise.addCACertificate(ca_pem); + WPA2Enterprise.addClientCertificate(client_crt, client_key); - // check for the WiFi module: + // Check for the WiFi module: if (WiFi.status() == WL_NO_MODULE) { Serial.println("Communication with WiFi module failed!"); - // don't continue + // Don't continue while (true); } @@ -68,64 +72,64 @@ void setup() { Serial.println("Please upgrade the firmware"); } - // attempt to connect to WiFi network: + // Attempt to connect to Wifi network: while (status != WL_CONNECTED) { Serial.print("Attempting to connect to SSID: "); Serial.println(ssid); - // Connect to WPA/WPA2 network. Change this line if using open or WEP network: - status = WiFi.begin(ssid, pass); + // Connect to WPA2 enterptise network (shows as an open network). + status = WiFi.beginEnterprise(ssid, SECRET_USERNAME, SECRET_PASSWORD); - // wait 10 seconds for connection: - delay(10000); + // Wait 1 second for connection: + delay(1000); } - Serial.println("Connected to WiFi"); + Serial.println("Connected to wifi"); printWifiStatus(); Serial.println("\nStarting connection to server..."); - // if you get a connection, report back via serial: + // If you get a connection, report back via serial: if (client.connect(server, 80)) { Serial.println("connected to server"); // Make a HTTP request: - client.println("GET /search?q=arduino HTTP/1.1"); - client.println("Host: www.google.com"); + client.println("GET /asciilogo.txt HTTP/1.1"); + client.println("Host: www.arduino.cc"); client.println("Connection: close"); client.println(); } } void loop() { - // if there are incoming bytes available + // If there are incoming bytes available // from the server, read them and print them: while (client.available()) { char c = client.read(); Serial.write(c); } - // if the server's disconnected, stop the client: + // If the server's disconnected, stop the client: if (!client.connected()) { Serial.println(); Serial.println("disconnecting from server."); client.stop(); - // do nothing forevermore: + // Do nothing forevermore: while (true); } } void printWifiStatus() { - // print the SSID of the network you're attached to: + // Print the SSID of the network you're attached to: Serial.print("SSID: "); Serial.println(WiFi.SSID()); - // print your board's IP address: + // Print your board's IP address: IPAddress ip = WiFi.localIP(); Serial.print("IP Address: "); Serial.println(ip); - // print the received signal strength: + // Print the received signal strength: long rssi = WiFi.RSSI(); - Serial.print("signal strength (RSSI): "); + Serial.print("signal strength (RSSI):"); Serial.print(rssi); Serial.println(" dBm"); } diff --git a/examples/WiFiWebClientWPA2Enterprise/arduino_secrets.h b/examples/WiFiWebClientWPA2Enterprise/arduino_secrets.h index efe1ec66..c390e4da 100644 --- a/examples/WiFiWebClientWPA2Enterprise/arduino_secrets.h +++ b/examples/WiFiWebClientWPA2Enterprise/arduino_secrets.h @@ -1,127 +1,93 @@ -#define SECRET_SSID "" -#define SECRET_PASS "" +#define SECRET_SSID "" +#define SECRET_USERNAME "" +#define SECRET_PASSWORD "" -// These certificates are completely bogus, but your own should resemble this format +// This certificates are completely bogus, but your own should resemble this format +// For testing, generate them using the bootstrap script in freeradius-server/raddb repository, then +// * remove the password from client key with using this command +// openssl rsa -in client.key -out client2.key # default password is "whatever" +// * slim down client certificate by just keeping the snippet between BEGIN and END (must be smaller than 4Kbytes) const char * ca_pem = "-----BEGIN CERTIFICATE-----\n" -"MIID3DCCA0WgAwIBAgIJANe5ZSCKoB8fMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD\n" +"MIIE5DCCA8ygAwIBAgIJAM/ZGtauwvHrMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD\n" "VQQGEwJGUjEPMA0GA1UECAwGUmFkaXVzMRIwEAYDVQQHDAlTb21ld2hlcmUxFTAT\n" "BgNVBAoMDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBs\n" -"ZS5jb20xJjAkBgNVBAMMHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4X\n" -"DTE2MTEyMzAyNTUwN1oXDTE3MDEyMjAyNTUwN1owgZMxCzAJBgNVBAYTAkZSMQ8w\n" +"ZS5vcmcxJjAkBgNVBAMMHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4X\n" +"DTE4MDQyNDIxMzQ0MloXDTE5MDQyNDIxMzQ0MlowgZMxCzAJBgNVBAYTAkZSMQ8w\n" "DQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMGA1UECgwMRXhh\n" -"bXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTEmMCQG\n" -"A1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwgZ8wDQYJKoZIhvcN\n" -"AQEBBQADgY0AMIGJAoGBAL03y7N2GvNDO9BN8fVtdNonp0bMiqpj1D0He5+OTM+9\n" -"3ZTIsJCNrbzhLQrRI3vMW7UDy8U7GeWORN9W4dWYlYiy/NFRp3hNMrbePhVmNIOV\n" -"ww4ovGzbD+Xo31gPVkhzQ8I5/jbOIQBmgKMAMZyOMlG9VD6yMmAeYqnZYz68WHKt\n" -"AgMBAAGjggE0MIIBMDAdBgNVHQ4EFgQUf1MLQIzAEZcRsgZlS8sosfmVI+UwgcgG\n" -"A1UdIwSBwDCBvYAUf1MLQIzAEZcRsgZlS8sosfmVI+WhgZmkgZYwgZMxCzAJBgNV\n" -"BAYTAkZSMQ8wDQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMG\n" -"A1UECgwMRXhhbXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxl\n" -"LmNvbTEmMCQGA1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCCQDX\n" -"uWUgiqAfHzAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93\n" -"d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcNAQELBQADgYEA\n" -"GepHc7TE/P+5t/cZPn5TTQkWQ/4/1lgQd82lF36RYWSIW3BdAc0zwYWYZaWixxyp\n" -"s0YOqwz6PZAGRV+SlYO2f8Kf+C3aZs4YHB0GsmksmFOb8r9d7xcDuOKHoA+QV0Zw\n" -"RaK6pttsBAxy7rw3kX/CgTp0Y2puaLdMXv/v9FisCP8=\n" +"bXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLm9yZzEmMCQG\n" +"A1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqGSIb3\n" +"DQEBAQUAA4IBDwAwggEKAoIBAQDBM2wjdTRn0OmRadONV9EZPQyUxuo9iJ6DKHkt\n" +"rGEOd1gG4gNksrsF7gWcPdCWVCO49Xba1a16U/dyBPSuF7KHMO6Hx0OHZmJvCF1W\n" +"en8BPY9ClreYAobqnHIdQRIP8R5tpXA8qZ5aZlnD5dUB8XDka0NDNEXbvmbop6PP\n" +"OaGoNGsXzWN9mk2xQqHxYgoSHPER3QH2YCsKstgD87C/jTkHmtylv6j90PUhWTOm\n" +"oIbkQG0d1f4RNxcDdcRr18wOvk62CW2+phkWWRie/Vw5Lu1dA/bGzxFV64jX5J1+\n" +"ZZ5lyL87AE6bKtJjhLuqnPIarzenhmtCuGOsTTeFKgjlKLapAgMBAAGjggE3MIIB\n" +"MzAdBgNVHQ4EFgQUSsYRmVXei6Km4z5QPSYOvz7Zu00wgcgGA1UdIwSBwDCBvYAU\n" +"SsYRmVXei6Km4z5QPSYOvz7Zu02hgZmkgZYwgZMxCzAJBgNVBAYTAkZSMQ8wDQYD\n" +"VQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMGA1UECgwMRXhhbXBs\n" +"ZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLm9yZzEmMCQGA1UE\n" +"AwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCCQDP2RrWrsLx6zAPBgNV\n" +"HRMBAf8EBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93d3cuZXhhbXBs\n" +"ZS5vcmcvZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcNAQELBQADggEBAFbOEusBzXfa\n" +"0qdTw3U98t58BUxYYzScKZNjgS/MYVEdS0OaMxYyqstp8BKr8YugEHUHGDJt9k37\n" +"yXGLVUeS+ST/Xy2UvOus7bLv0YYL26tQbBs5iDy9WJ3IBUtWhfqQW/ISpfma2uvN\n" +"kFfGCV0JkPa57oR1kj0OPkOBQSXPwTbbabUdQmB+d6IZi9ZTMGLv1ogq75X5eSJP\n" +"Qi6ql9nQF6TN24DIF8XJ/D6GJPbdmoMQ18VGoRlnz37Ee82ve9I5gvJquXZjOBd4\n" +"rK7p3mrSzzkiCdjB8ehpJygmgT1U/ufE1PopES8hSkCgvQ2EsNBIGYiJUFRJfeEM\n" +"kCCZqNTTmGE=\n" "-----END CERTIFICATE-----"; -const char * client_crt = "Certificate:\n" -" Data:\n" -" Version: 3 (0x2)\n" -" Serial Number: 44 (0x2c)\n" -" Signature Algorithm: sha1WithRSAEncryption\n" -" Issuer: C=FR, ST=Radius, L=Somewhere, O=Example Inc./emailAddress=admin@example.com, CN=Example Certificate Authority\n" -" Validity\n" -" Not Before: Nov 23 02:55:07 2016 GMT\n" -" Not After : Jan 22 02:55:07 2017 GMT\n" -" Subject: C=FR, ST=Radius, O=Example Inc., CN=user@example.com/emailAddress=user@example.com\n" -" Subject Public Key Info:\n" -" Public Key Algorithm: rsaEncryption\n" -" Public-Key: (2048 bit)\n" -" Modulus:\n" -" 00:ac:41:d4:a2:46:0c:dc:67:1d:7b:89:36:7c:15:\n" -" be:a2:c1:fe:4c:f2:fa:af:5d:76:0e:ee:b5:ca:d4:\n" -" d3:01:c8:6b:30:50:df:2d:57:17:f4:43:47:97:ca:\n" -" f1:8d:f7:c0:9d:56:b3:e7:17:7c:58:59:de:f3:be:\n" -" b5:08:5d:f8:3a:ad:83:44:0d:31:c9:f1:3d:f1:9a:\n" -" cf:84:0c:ad:d3:be:5c:bd:3d:58:b5:1d:2c:fe:70:\n" -" 8d:c5:b0:17:87:d4:8e:85:f7:51:4c:0f:d1:e0:8c:\n" -" 7b:a0:25:ab:91:7c:7f:eb:47:73:c9:4b:6c:8b:e6:\n" -" c1:06:d5:94:30:63:ec:45:1a:f5:7f:46:2f:b3:84:\n" -" 78:5d:1c:37:1a:fa:57:ea:45:5e:45:40:ab:14:c7:\n" -" 81:b0:26:3d:7e:cf:da:db:f0:f1:40:a7:a1:4b:54:\n" -" f3:96:1b:c9:30:3c:3c:d8:19:ba:c7:df:b1:ad:a2:\n" -" d6:17:0a:d6:ed:31:b5:cb:12:39:f5:6e:92:6b:85:\n" -" f2:9e:c7:06:6b:bb:89:ed:a7:5f:ec:56:12:46:fd:\n" -" 3a:74:d1:d2:31:30:1d:58:19:25:33:ff:11:ea:3a:\n" -" 52:33:b1:fb:d3:75:8d:1f:5e:36:a5:35:e0:11:5a:\n" -" 4a:2d:97:58:2c:3d:62:3c:32:af:83:69:a9:1a:32:\n" -" 1b:b7\n" -" Exponent: 65537 (0x10001)\n" -" X509v3 extensions:\n" -" X509v3 Extended Key Usage: \n" -" TLS Web Client Authentication\n" -" X509v3 CRL Distribution Points: \n" -"\n" -" Full Name:\n" -" URI:http://www.example.com/example_ca.crl\n" -"\n" -" Signature Algorithm: sha1WithRSAEncryption\n" -" 8b:8d:b6:19:ce:6f:6b:9e:1d:03:8b:6b:10:fc:99:d0:7a:2f:\n" -" e0:37:ce:b8:a4:e4:b9:a1:c2:36:ff:76:b2:ad:d7:d0:df:d1:\n" -" 03:27:93:a7:4e:1e:bf:ed:d2:b7:65:2a:c9:c3:ab:20:aa:e3:\n" -" 10:4c:75:3b:c4:02:ab:34:08:6e:61:91:cf:e3:02:35:6a:e5:\n" -" f3:25:96:51:92:82:6e:52:81:c1:f1:7b:68:02:b0:ce:f4:ba:\n" -" fd:6e:68:35:b3:7e:77:cb:a0:1e:11:5e:58:bf:f3:2a:ed:b3:\n" -" 4c:82:21:5e:1b:47:b6:2f:f3:f5:c9:1b:6a:70:44:6d:ff:ad:\n" -" a6:e3\n" -"-----BEGIN CERTIFICATE-----\n" -"MIIDTjCCAregAwIBAgIBLDANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMCRlIx\n" -"DzANBgNVBAgMBlJhZGl1czESMBAGA1UEBwwJU29tZXdoZXJlMRUwEwYDVQQKDAxF\n" -"eGFtcGxlIEluYy4xIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMSYw\n" -"JAYDVQQDDB1FeGFtcGxlIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjExMjMw\n" -"MjU1MDdaFw0xNzAxMjIwMjU1MDdaMHExCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZS\n" -"YWRpdXMxFTATBgNVBAoMDEV4YW1wbGUgSW5jLjEZMBcGA1UEAwwQdXNlckBleGFt\n" -"cGxlLmNvbTEfMB0GCSqGSIb3DQEJARYQdXNlckBleGFtcGxlLmNvbTCCASIwDQYJ\n" -"KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKxB1KJGDNxnHXuJNnwVvqLB/kzy+q9d\n" -"dg7utcrU0wHIazBQ3y1XF/RDR5fK8Y33wJ1Ws+cXfFhZ3vO+tQhd+Dqtg0QNMcnx\n" -"PfGaz4QMrdO+XL09WLUdLP5wjcWwF4fUjoX3UUwP0eCMe6Alq5F8f+tHc8lLbIvm\n" -"wQbVlDBj7EUa9X9GL7OEeF0cNxr6V+pFXkVAqxTHgbAmPX7P2tvw8UCnoUtU85Yb\n" -"yTA8PNgZusffsa2i1hcK1u0xtcsSOfVukmuF8p7HBmu7ie2nX+xWEkb9OnTR0jEw\n" -"HVgZJTP/Eeo6UjOx+9N1jR9eNqU14BFaSi2XWCw9Yjwyr4NpqRoyG7cCAwEAAaNP\n" -"ME0wEwYDVR0lBAwwCgYIKwYBBQUHAwIwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDov\n" -"L3d3dy5leGFtcGxlLmNvbS9leGFtcGxlX2NhLmNybDANBgkqhkiG9w0BAQUFAAOB\n" -"gQCLjbYZzm9rnh0Di2sQ/JnQei/gN864pOS5ocI2/3ayrdfQ39EDJ5OnTh6/7dK3\n" -"ZSrJw6sgquMQTHU7xAKrNAhuYZHP4wI1auXzJZZRkoJuUoHB8XtoArDO9Lr9bmg1\n" -"s353y6AeEV5Yv/Mq7bNMgiFeG0e2L/P1yRtqcERt/62m4w==\n" +const char * client_crt = "-----BEGIN CERTIFICATE-----\n" +"MIIEQTCCAymgAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBkjELMAkGA1UEBhMCRlIx\n" +"DzANBgNVBAgMBlJhZGl1czESMBAGA1UEBwwJU29tZXdoZXJlMRQwEgYDVQQKDAtF\n" +"eGFtcGxlIEluYzEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5vcmcxJjAk\n" +"BgNVBAMMHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTE5MDgxMjE0\n" +"MTEyMVoXDTE5MTAxMTE0MTEyMVowdDELMAkGA1UEBhMCRlIxDzANBgNVBAgMBlJh\n" +"ZGl1czEUMBIGA1UECgwLRXhhbXBsZSBJbmMxFTATBgNVBAMMDEV4YW1wbGUgdXNl\n" +"cjEnMCUGCSqGSIb3DQEJARYYdXNlci5leGFtcGxlQGV4YW1wbGUub3JnMIIBIjAN\n" +"BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtaiggI1w7wez/DjYM+F1RDUMa73J\n" +"07+XZM1OxQuRt8hbwh8wod1Bmu3iFtsSnzssygeek/9+Vd6gXqW5jBa4sMz0CQM1\n" +"PkIjBsgjPaKk98c2tyDYqA+nz0Wi9JOkAKPQwTTDijsAF3QfgcGvWZJngjHkeKoz\n" +"1BLJehDO4wOu1z3kB8CQGWQ0hZW2Sjt+qFqDTXt8Q0GF+nehqx7juHw/e6QDNiuH\n" +"Xmf0adJWUzFeMnQewUDD5R3EBLUiWzKbRFxoi0qs/tM1IUPQ0fASHcJMwZllCZpa\n" +"3B9nxAhLScR8RjDU0d0F+3hQGNKShJyvvR6dM2Qzie8H2yA7QrLdRX8XywIDAQAB\n" +"o4G+MIG7MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMBMGA1UdJQQMMAoGCCsGAQUF\n" +"BwMCMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93d3cuZXhhbXBsZS5jb20vZXhh\n" +"bXBsZV9jYS5jcmwwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8v\n" +"d3d3LmV4YW1wbGUub3JnL29jc3AwGwYDVR0RBBQwEoEQdXNlckBleGFtcGxlLm9y\n" +"ZzANBgkqhkiG9w0BAQsFAAOCAQEAVC05K4XqjfjoTgQeB7FtjDUiuQedbNi3z3Sy\n" +"2qZVqgaYa+z9cijrL6Z7Z5BvM+JWUxfPjiXXF6M/j1QeyNLKtieDusO/yUaQTmSz\n" +"fyYbdXNlGBzsMLGMgp+xComZ5ZUQQwsmx8phagWqNlzAnQuLyyRshj+hOYjmysXs\n" +"2V6SUfRMEdgr57hRREHZBjJq/PQZL0Kw7BiXMYhMfFJfe1Z4LBYhRqAPDWVoPI1j\n" +"MNXM6X7R5zSNRbrj9biT4WNLBDooDW4Bzz1cimLock/nCY+TTj8Xoy/0szqkIdps\n" +"G1SM9dB7SdXDW6DewvRK28+9xe6HG4xsLtNNYFWqhPkF5S4BIg==\n" "-----END CERTIFICATE-----"; const char * client_key = "-----BEGIN RSA PRIVATE KEY-----\n" -"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\n" "-----END RSA PRIVATE KEY-----";