850 lines
28 KiB
C++
850 lines
28 KiB
C++
/* wolfssl_server.ino
|
|
*
|
|
* Copyright (C) 2006-2025 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
/*
|
|
Tested with:
|
|
|
|
1) Intel Galileo acting as the Client, with a laptop acting as a server using
|
|
the server example provided in examples/server.
|
|
Legacy Arduino v1.86 was used to compile and program the Galileo
|
|
|
|
2) Espressif ESP32 WiFi
|
|
|
|
3) Arduino Due, Nano33 IoT, Nano RP-2040
|
|
*/
|
|
|
|
/*
|
|
* Note to code editors: the Arduino client and server examples are edited in
|
|
* parallel for side-by-side comparison between examples.
|
|
*/
|
|
|
|
/* If you have a private include, define it here, otherwise edit WiFi params */
|
|
/* #define MY_PRIVATE_CONFIG "/workspace/my_private_config.h" */
|
|
|
|
/* set REPEAT_CONNECTION to a non-zero value to continually run the example. */
|
|
#define REPEAT_CONNECTION 1
|
|
|
|
/* Edit this with your other TLS host server address to connect to: */
|
|
/* #define WOLFSSL_TLS_SERVER_HOST "192.168.1.34" */
|
|
|
|
/* wolfssl TLS examples communicate on port 11111 */
|
|
#define WOLFSSL_PORT 11111
|
|
|
|
/* Choose a monitor serial baud rate: 9600, 14400, 19200, 57600, 74880, etc. */
|
|
#define SERIAL_BAUD 115200
|
|
|
|
/* We'll wait up to 2000 milliseconds to properly shut down connection */
|
|
#define SHUTDOWN_DELAY_MS 2000
|
|
|
|
/* Number of times to retry connection. */
|
|
#define RECONNECT_ATTEMPTS 20
|
|
|
|
/* Optional stress test. Define to consume memory until exhausted: */
|
|
/* #define MEMORY_STRESS_TEST */
|
|
|
|
/* Choose client or server example, not both. */
|
|
/* #define WOLFSSL_CLIENT_EXAMPLE */
|
|
#define WOLFSSL_SERVER_EXAMPLE
|
|
|
|
#if defined(MY_PRIVATE_CONFIG)
|
|
/* the /workspace directory may contain a private config
|
|
* excluded from GitHub with items such as WiFi passwords */
|
|
#include MY_PRIVATE_CONFIG
|
|
static const char ssid[] PROGMEM = MY_ARDUINO_WIFI_SSID;
|
|
static const char password[] PROGMEM = MY_ARDUINO_WIFI_PASSWORD;
|
|
#else
|
|
/* when using WiFi capable boards: */
|
|
static const char ssid[] PROGMEM = "your_SSID";
|
|
static const char password[] PROGMEM = "your_PASSWORD";
|
|
#endif
|
|
|
|
#define BROADCAST_ADDRESS "255.255.255.255"
|
|
|
|
/* There's an optional 3rd party NTPClient library by Fabrice Weinberg.
|
|
* If it is installed, uncomment define USE_NTP_LIB here: */
|
|
/* #define USE_NTP_LIB */
|
|
#ifdef USE_NTP_LIB
|
|
#include <NTPClient.h>
|
|
#endif
|
|
|
|
/* wolfSSL user_settings.h must be included from settings.h
|
|
* Make all configurations changes in user_settings.h
|
|
* Do not edit wolfSSL `settings.h` or `config.h` files.
|
|
* Do not explicitly include user_settings.h in any source code.
|
|
* Each Arduino sketch that uses wolfSSL must have: #include "wolfssl.h"
|
|
* C/C++ source files can use: #include <wolfssl/wolfcrypt/settings.h>
|
|
* The wolfSSL "settings.h" must be included in each source file using wolfSSL.
|
|
* The wolfSSL "settings.h" must appear before any other wolfSSL include.
|
|
*/
|
|
#include <wolfssl.h>
|
|
/* Important: make sure settings.h appears before any other wolfSSL headers */
|
|
#include <wolfssl/wolfcrypt/settings.h>
|
|
/* Reminder: settings.h includes user_settings.h
|
|
* For ALL project wolfSSL settings, see:
|
|
* [your path]/Arduino\libraries\wolfSSL\src\user_settings.h */
|
|
#include <wolfssl/ssl.h>
|
|
#include <wolfssl/certs_test.h>
|
|
#include <wolfssl/wolfcrypt/error-crypt.h>
|
|
|
|
/* Define DEBUG_WOLFSSL in user_settings.h for more verbose logging. */
|
|
#if defined(DEBUG_WOLFSSL)
|
|
#define PROGRESS_DOT F("")
|
|
#else
|
|
#define PROGRESS_DOT F(".")
|
|
#endif
|
|
|
|
/* Convert a macro to a string */
|
|
#define xstr(x) str(x)
|
|
#define str(x) #x
|
|
|
|
/* optional board-specific networking includes */
|
|
#if defined(ESP32)
|
|
#define USING_WIFI
|
|
#include <WiFi.h>
|
|
#include <WiFiUdp.h>
|
|
#ifdef USE_NTP_LIB
|
|
WiFiUDP ntpUDP;
|
|
#endif
|
|
/* Ensure the F() flash macro is defined */
|
|
#ifndef F
|
|
#define F
|
|
#endif
|
|
WiFiClient client;
|
|
WiFiServer server(WOLFSSL_PORT);
|
|
#elif defined(ESP8266)
|
|
#define USING_WIFI
|
|
#include <ESP8266WiFi.h>
|
|
WiFiClient client;
|
|
WiFiServer server(WOLFSSL_PORT);
|
|
#elif defined(ARDUINO_SAM_DUE)
|
|
#include <SPI.h>
|
|
/* There's no WiFi/Ethernet on the Due. Requires Ethernet Shield.
|
|
/* Needs "Ethernet by Various" library to be installed. Tested with V2.0.2 */
|
|
#include <Ethernet.h>
|
|
EthernetClient client;
|
|
EthernetClient server(WOLFSSL_PORT);
|
|
#elif defined(ARDUINO_SAMD_NANO_33_IOT)
|
|
#define USING_WIFI
|
|
#include <SPI.h>
|
|
#include <WiFiNINA.h> /* Needs Arduino WiFiNINA library installed manually */
|
|
WiFiClient client;
|
|
WiFiServer server(WOLFSSL_PORT);
|
|
#elif defined(ARDUINO_ARCH_RP2040)
|
|
#define USING_WIFI
|
|
#include <SPI.h>
|
|
#include <WiFiNINA.h>
|
|
WiFiClient client;
|
|
WiFiServer server(WOLFSSL_PORT);
|
|
#elif defined(USING_WIFI)
|
|
#define USING_WIFI
|
|
#include <WiFi.h>
|
|
#include <WiFiUdp.h>
|
|
#ifdef USE_NTP_LIB
|
|
WiFiUDP ntpUDP;
|
|
#endif
|
|
WiFiClient client;
|
|
WiFiServer server(WOLFSSL_PORT);
|
|
/* TODO
|
|
#elif defined(OTHER_BOARD)
|
|
*/
|
|
#else
|
|
/* assume all other boards using WiFi library. Edit as needed: */
|
|
#include <WiFi.h>
|
|
#define USING_WIFI
|
|
WiFiClient client;
|
|
WiFiServer server(WOLFSSL_PORT);
|
|
#endif
|
|
|
|
/* Only for syntax highlighters to show interesting options enabled: */
|
|
#if defined(HAVE_SNI) \
|
|
|| defined(HAVE_MAX_FRAGMENT) \
|
|
|| defined(HAVE_TRUSTED_CA) \
|
|
|| defined(HAVE_TRUNCATED_HMAC) \
|
|
|| defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
|
|
|| defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) \
|
|
|| defined(HAVE_SUPPORTED_CURVES) \
|
|
|| defined(HAVE_ALPN) \
|
|
|| defined(HAVE_SESSION_TICKET) \
|
|
|| defined(HAVE_SECURE_RENEGOTIATION) \
|
|
|| defined(HAVE_SERVER_RENEGOTIATION_INFO)
|
|
#endif
|
|
|
|
|
|
/* we expect our IP address from DHCP */
|
|
|
|
static WOLFSSL_CTX* ctx = NULL;
|
|
static WOLFSSL* ssl = NULL;
|
|
static char* wc_error_message = (char*)malloc(80 + 1);
|
|
static char errBuf[80];
|
|
|
|
#if defined(MEMORY_STRESS_TEST)
|
|
#define MEMORY_STRESS_ITERATIONS 100
|
|
#define MEMORY_STRESS_BLOCK_SIZE 1024
|
|
#define MEMORY_STRESS_INITIAL (4*1024)
|
|
static char* memory_stress[MEMORY_STRESS_ITERATIONS]; /* typically 1K per item */
|
|
static int mem_ctr = 0;
|
|
#endif
|
|
|
|
static int EthernetSend(WOLFSSL* ssl, char* msg, int sz, void* ctx);
|
|
static int EthernetReceive(WOLFSSL* ssl, char* reply, int sz, void* ctx);
|
|
static int reconnect = RECONNECT_ATTEMPTS;
|
|
static int lng_index PROGMEM = 0; /* 0 = English */
|
|
|
|
#if defined(__arm__)
|
|
#include <malloc.h>
|
|
extern char _end;
|
|
extern "C" char *sbrk(int i);
|
|
static char *ramstart=(char *)0x20070000;
|
|
static char *ramend=(char *)0x20088000;
|
|
#endif
|
|
|
|
/*****************************************************************************/
|
|
/* fail_wait - in case of unrecoverable error */
|
|
/*****************************************************************************/
|
|
int fail_wait(void) {
|
|
show_memory();
|
|
|
|
Serial.println(F("Failed. Halt."));
|
|
while (1) {
|
|
delay(1000);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* show_memory() to optionally view during debugging. */
|
|
/*****************************************************************************/
|
|
int show_memory(void)
|
|
{
|
|
#if defined(__arm__)
|
|
struct mallinfo mi = mallinfo();
|
|
|
|
char *heapend=sbrk(0);
|
|
register char * stack_ptr asm("sp");
|
|
#if defined(DEBUG_WOLFSSL_VERBOSE)
|
|
Serial.print(" arena=");
|
|
Serial.println(mi.arena);
|
|
Serial.print(" ordblks=");
|
|
Serial.println(mi.ordblks);
|
|
Serial.print(" uordblks=");
|
|
Serial.println(mi.uordblks);
|
|
Serial.print(" fordblks=");
|
|
Serial.println(mi.fordblks);
|
|
Serial.print(" keepcost=");
|
|
Serial.println(mi.keepcost);
|
|
#endif
|
|
|
|
#if defined(DEBUG_WOLFSSL) || defined(MEMORY_STRESS_TEST)
|
|
Serial.print("Estimated free memory: ");
|
|
Serial.print(stack_ptr - heapend + mi.fordblks);
|
|
Serial.println(F(" bytes"));
|
|
#endif
|
|
|
|
#if (0)
|
|
/* Experimental: not supported on all devices: */
|
|
Serial.print("RAM Start %lx\n", (unsigned long)ramstart);
|
|
Serial.print("Data/Bss end %lx\n", (unsigned long)&_end);
|
|
Serial.print("Heap End %lx\n", (unsigned long)heapend);
|
|
Serial.print("Stack Ptr %lx\n",(unsigned long)stack_ptr);
|
|
Serial.print("RAM End %lx\n", (unsigned long)ramend);
|
|
|
|
Serial.print("Heap RAM Used: ",mi.uordblks);
|
|
Serial.print("Program RAM Used ",&_end - ramstart);
|
|
Serial.print("Stack RAM Used ",ramend - stack_ptr);
|
|
|
|
Serial.print("Estimated Free RAM: %d\n\n",stack_ptr - heapend + mi.fordblks);
|
|
#endif
|
|
#else
|
|
Serial.println(F("show_memory() not implemented for this platform"));
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* EthernetSend() to send a message string. */
|
|
/*****************************************************************************/
|
|
int EthernetSend(WOLFSSL* ssl, char* message, int sz, void* ctx) {
|
|
int sent = 0;
|
|
(void)ssl;
|
|
(void)ctx;
|
|
|
|
sent = client.write((byte*)message, sz);
|
|
return sent;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* EthernetReceive() to receive a reply string. */
|
|
/*****************************************************************************/
|
|
int EthernetReceive(WOLFSSL* ssl, char* reply, int sz, void* ctx) {
|
|
int ret = 0;
|
|
(void)ssl;
|
|
(void)ctx;
|
|
|
|
while (client.available() > 0 && ret < sz) {
|
|
reply[ret++] = client.read();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Arduino setup_hardware() */
|
|
/*****************************************************************************/
|
|
int setup_hardware(void) {
|
|
int ret = 0;
|
|
|
|
#if defined(ARDUINO_SAMD_NANO_33_IOT)
|
|
Serial.println(F("Detected known tested and working Arduino Nano 33 IoT"));
|
|
#elif defined(ARDUINO_ARCH_RP2040)
|
|
Serial.println(F("Detected known tested and working Arduino RP-2040"));
|
|
#elif defined(__arm__) && defined(ID_TRNG) && defined(TRNG)
|
|
/* need to manually turn on random number generator on Arduino Due, etc. */
|
|
pmc_enable_periph_clk(ID_TRNG);
|
|
trng_enable(TRNG);
|
|
Serial.println(F("Enabled ARM TRNG"));
|
|
#endif
|
|
|
|
show_memory();
|
|
randomSeed(analogRead(0));
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Arduino setup_datetime() */
|
|
/* The device needs to have a valid date within the valid range of certs. */
|
|
/*****************************************************************************/
|
|
int setup_datetime(void) {
|
|
int ret = 0;
|
|
int ntp_tries = 20;
|
|
|
|
/* we need a date in the range of cert expiration */
|
|
#ifdef USE_NTP_LIB
|
|
#if defined(ESP32)
|
|
NTPClient timeClient(ntpUDP, "pool.ntp.org");
|
|
|
|
timeClient.begin();
|
|
timeClient.update();
|
|
delay(1000);
|
|
while (!timeClient.isTimeSet() && (ntp_tries > 0)) {
|
|
timeClient.forceUpdate();
|
|
Serial.println(F("Waiting for NTP update"));
|
|
delay(2000);
|
|
ntp_tries--;
|
|
}
|
|
if (ntp_tries <= 0) {
|
|
Serial.println(F("Warning: gave up waiting on NTP"));
|
|
}
|
|
Serial.println(timeClient.getFormattedTime());
|
|
Serial.println(timeClient.getEpochTime());
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(ESP32)
|
|
/* see esp32-hal-time.c */
|
|
ntp_tries = 5;
|
|
/* Replace "pool.ntp.org" with your preferred NTP server */
|
|
configTime(0, 0, "pool.ntp.org");
|
|
|
|
/* Wait for time to be set */
|
|
while ((time(nullptr) <= 100000) && ntp_tries > 0) {
|
|
Serial.println(F("Waiting for time to be set..."));
|
|
delay(2000);
|
|
ntp_tries--;
|
|
}
|
|
#endif
|
|
|
|
return ret;
|
|
} /* setup_datetime */
|
|
|
|
/*****************************************************************************/
|
|
/* Arduino setup_network() */
|
|
/*****************************************************************************/
|
|
int setup_network(void) {
|
|
int ret = 0;
|
|
|
|
#if defined(USING_WIFI)
|
|
int status = WL_IDLE_STATUS;
|
|
|
|
/* The ESP8266 & ESP32 support both AP and STA. We'll use STA: */
|
|
#if defined(ESP8266) || defined(ESP32)
|
|
WiFi.mode(WIFI_STA);
|
|
#else
|
|
String fv;
|
|
if (WiFi.status() == WL_NO_MODULE) {
|
|
Serial.println("Communication with WiFi module failed!");
|
|
/* don't continue if no network */
|
|
while (true) ;
|
|
}
|
|
|
|
fv = WiFi.firmwareVersion();
|
|
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
|
|
Serial.println("Please upgrade the firmware");
|
|
}
|
|
#endif
|
|
|
|
Serial.print(F("Connecting to WiFi "));
|
|
Serial.print(ssid);
|
|
status = WiFi.begin(ssid, password);
|
|
while (status != WL_CONNECTED) {
|
|
delay(1000);
|
|
Serial.print(F("."));
|
|
Serial.print(status);
|
|
status = WiFi.status();
|
|
}
|
|
|
|
Serial.println(F(" Connected!"));
|
|
#else
|
|
/* Newer Ethernet shields have a
|
|
* MAC address printed on a sticker on the shield */
|
|
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
|
IPAddress ip(192, 168, 1, 42);
|
|
IPAddress myDns(192, 168, 1, 1);
|
|
Ethernet.init(10); /* Most Arduino shields */
|
|
/* Ethernet.init(5); * MKR ETH Shield */
|
|
/* Ethernet.init(0); * Teensy 2.0 */
|
|
/* Ethernet.init(20); * Teensy++ 2.0 */
|
|
/* Ethernet.init(15); * ESP8266 with Adafruit FeatherWing Ethernet */
|
|
/* Ethernet.init(33); * ESP32 with Adafruit FeatherWing Ethernet */
|
|
Serial.println(F("Initialize Ethernet with DHCP:"));
|
|
if (Ethernet.begin(mac) == 0) {
|
|
Serial.println(F("Failed to configure Ethernet using DHCP"));
|
|
/* Check for Ethernet hardware present */
|
|
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
|
|
Serial.println(F("Ethernet shield was not found."));
|
|
while (true) {
|
|
delay(1); /* do nothing */
|
|
}
|
|
}
|
|
if (Ethernet.linkStatus() == LinkOFF) {
|
|
Serial.println(F("Ethernet cable is not connected."));
|
|
}
|
|
/* try to configure using IP address instead of DHCP : */
|
|
Ethernet.begin(mac, ip, myDns);
|
|
}
|
|
else {
|
|
Serial.print(F(" DHCP assigned IP "));
|
|
Serial.println(Ethernet.localIP());
|
|
}
|
|
/* We'll assume the Ethernet connection is ready to go. */
|
|
#endif
|
|
|
|
Serial.println(F("********************************************************"));
|
|
Serial.print(F(" wolfSSL Example Server IP = "));
|
|
#if defined(USING_WIFI)
|
|
Serial.println(WiFi.localIP());
|
|
#else
|
|
Serial.println(Ethernet.localIP());
|
|
#endif
|
|
/* In server mode, there's no host definition. */
|
|
/* See companion example: wolfssl_client.ino */
|
|
Serial.println(F("********************************************************"));
|
|
Serial.println(F("Setup network complete."));
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Arduino setup_wolfssl() */
|
|
/*****************************************************************************/
|
|
int setup_wolfssl(void) {
|
|
int ret = 0;
|
|
WOLFSSL_METHOD* method;
|
|
|
|
/* Show a revision of wolfssl user_settings.h file in use when available: */
|
|
#if defined(WOLFSSL_USER_SETTINGS_ID)
|
|
Serial.print(F("WOLFSSL_USER_SETTINGS_ID: "));
|
|
Serial.println(F(WOLFSSL_USER_SETTINGS_ID));
|
|
#else
|
|
Serial.println(F("No WOLFSSL_USER_SETTINGS_ID found."));
|
|
#endif
|
|
|
|
#if defined(NO_WOLFSSL_SERVER)
|
|
Serial.println(F("wolfSSL server code disabled to save space."));
|
|
#endif
|
|
#if defined(NO_WOLFSSL_CLIENT)
|
|
Serial.println(F("wolfSSL client code disabled to save space."));
|
|
#endif
|
|
|
|
#if defined(DEBUG_WOLFSSL)
|
|
wolfSSL_Debugging_ON();
|
|
Serial.println(F("wolfSSL Debugging is On!"));
|
|
#else
|
|
Serial.println(F("wolfSSL Debugging is Off! (enable with DEBUG_WOLFSSL)"));
|
|
#endif
|
|
|
|
/* See ssl.c for TLS cache settings. Larger cache = use more RAM. */
|
|
#if defined(NO_SESSION_CACHE)
|
|
Serial.println(F("wolfSSL TLS NO_SESSION_CACHE"));
|
|
#elif defined(MICRO_SESSION_CACHEx)
|
|
Serial.println(F("wolfSSL TLS MICRO_SESSION_CACHE"));
|
|
#elif defined(SMALL_SESSION_CACHE)
|
|
Serial.println(F("wolfSSL TLS SMALL_SESSION_CACHE"));
|
|
#elif defined(MEDIUM_SESSION_CACHE)
|
|
Serial.println(F("wolfSSL TLS MEDIUM_SESSION_CACHE"));
|
|
#elif defined(BIG_SESSION_CACHE)
|
|
Serial.println(F("wolfSSL TLS BIG_SESSION_CACHE"));
|
|
#elif defined(HUGE_SESSION_CACHE)
|
|
Serial.println(F("wolfSSL TLS HUGE_SESSION_CACHE"));
|
|
#elif defined(HUGE_SESSION_CACHE)
|
|
Serial.println(F("wolfSSL TLS HUGE_SESSION_CACHE"));
|
|
#else
|
|
Serial.println(F("WARNING: Unknown or no TLS session cache setting."));
|
|
/* See wolfssl/src/ssl.c for amount of memory used.
|
|
* It is best on embedded devices to choose a TLS session cache size. */
|
|
#endif
|
|
|
|
ret = wolfSSL_Init();
|
|
if (ret == WOLFSSL_SUCCESS) {
|
|
Serial.println("Successfully called wolfSSL_Init");
|
|
}
|
|
else {
|
|
Serial.println("ERROR: wolfSSL_Init failed");
|
|
}
|
|
|
|
/* See companion server example with wolfSSLv23_server_method here.
|
|
* method = wolfSSLv23_client_method()); SSL 3.0 - TLS 1.3.
|
|
* method = wolfTLSv1_2_client_method(); only TLS 1.2
|
|
* method = wolfTLSv1_3_client_method(); only TLS 1.3
|
|
*
|
|
* see Arduino\libraries\wolfssl\src\user_settings.h */
|
|
|
|
Serial.println("Here we go!");
|
|
|
|
method = wolfSSLv23_server_method();
|
|
if (method == NULL) {
|
|
Serial.println(F("unable to get wolfssl server method"));
|
|
fail_wait();
|
|
}
|
|
ctx = wolfSSL_CTX_new(method);
|
|
if (ctx == NULL) {
|
|
Serial.println(F("unable to get ctx"));
|
|
fail_wait();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Arduino setup_certificates() */
|
|
/*****************************************************************************/
|
|
int setup_certificates(void) {
|
|
int ret = 0;
|
|
|
|
Serial.println(F("Initializing certificates..."));
|
|
show_memory();
|
|
|
|
/* Use built-in validation, No verification callback function: */
|
|
wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
|
|
|
|
/* Certificate */
|
|
Serial.println("Initializing certificates...");
|
|
ret = wolfSSL_CTX_use_certificate_buffer(ctx,
|
|
CTX_SERVER_CERT,
|
|
CTX_SERVER_CERT_SIZE,
|
|
CTX_CA_CERT_TYPE);
|
|
if (ret == WOLFSSL_SUCCESS) {
|
|
Serial.print("Success: use certificate: ");
|
|
Serial.println(xstr(CTX_SERVER_CERT));
|
|
}
|
|
else {
|
|
Serial.print("Error: wolfSSL_CTX_use_certificate_buffer failed: ");
|
|
wc_ErrorString(ret, wc_error_message);
|
|
Serial.println(wc_error_message);
|
|
fail_wait();
|
|
}
|
|
|
|
/* Setup private server key */
|
|
ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx,
|
|
CTX_SERVER_KEY,
|
|
CTX_SERVER_KEY_SIZE,
|
|
CTX_SERVER_KEY_TYPE);
|
|
if (ret == WOLFSSL_SUCCESS) {
|
|
Serial.print("Success: use private key buffer: ");
|
|
Serial.println(xstr(CTX_SERVER_KEY));
|
|
}
|
|
else {
|
|
Serial.print("Error: wolfSSL_CTX_use_PrivateKey_buffer failed: ");
|
|
wc_ErrorString(ret, wc_error_message);
|
|
Serial.println(wc_error_message);
|
|
fail_wait();
|
|
}
|
|
|
|
return ret;
|
|
} /* Arduino setup */
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/* Arduino setup() */
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
void setup(void) {
|
|
int i = 0;
|
|
Serial.begin(SERIAL_BAUD);
|
|
while (!Serial && (i < 10)) {
|
|
/* wait for serial port to connect. Needed for native USB port only */
|
|
delay(1000);
|
|
i++;
|
|
}
|
|
|
|
Serial.println(F(""));
|
|
Serial.println(F(""));
|
|
Serial.println(F("wolfSSL TLS Server Example Startup."));
|
|
|
|
/* define DEBUG_WOLFSSL in wolfSSL user_settings.h for diagnostics */
|
|
#if defined(DEBUG_WOLFSSL)
|
|
wolfSSL_Debugging_ON();
|
|
#endif
|
|
|
|
/* Optionally pre-allocate a large block of memory for testing */
|
|
#if defined(MEMORY_STRESS_TEST)
|
|
Serial.println(F("WARNING: Memory Stress Test Active!"));
|
|
Serial.print(F("Allocating extra memory: "));
|
|
Serial.print(MEMORY_STRESS_INITIAL);
|
|
Serial.println(F(" bytes..."));
|
|
memory_stress[mem_ctr] = (char*)malloc(MEMORY_STRESS_INITIAL);
|
|
show_memory();
|
|
#endif
|
|
|
|
setup_hardware();
|
|
|
|
setup_network();
|
|
|
|
setup_datetime();
|
|
|
|
setup_wolfssl();
|
|
|
|
setup_certificates();
|
|
|
|
/* Initialize wolfSSL using callback functions. */
|
|
wolfSSL_SetIOSend(ctx, EthernetSend);
|
|
wolfSSL_SetIORecv(ctx, EthernetReceive);
|
|
|
|
#if defined THIS_USER_SETTINGS_VERSION
|
|
Serial.print(F("This user_settings.h version:"))
|
|
Serial.println(THIS_USER_SETTINGS_VERSION)
|
|
#endif
|
|
|
|
/* Start the server
|
|
* See https://www.arduino.cc/reference/en/libraries/ethernet/server.begin/
|
|
*/
|
|
|
|
Serial.println(F("Completed Arduino setup()"));
|
|
|
|
server.begin();
|
|
Serial.println("Begin Server... (waiting for remote client to connect)");
|
|
|
|
/* See companion wolfssl_client.ino code */
|
|
return;
|
|
} /* Arduino setup */
|
|
|
|
/*****************************************************************************/
|
|
/* wolfSSL error_check() */
|
|
/*****************************************************************************/
|
|
int error_check(int this_ret, bool halt_on_error,
|
|
const __FlashStringHelper* message) {
|
|
int ret = 0;
|
|
if (this_ret == WOLFSSL_SUCCESS) {
|
|
Serial.print(F("Success: "));
|
|
Serial.println(message);
|
|
}
|
|
else {
|
|
Serial.print(F("ERROR: return = "));
|
|
Serial.print(this_ret);
|
|
Serial.print(F(": "));
|
|
Serial.println(message);
|
|
Serial.println(wc_GetErrorString(this_ret));
|
|
if (halt_on_error) {
|
|
fail_wait();
|
|
}
|
|
}
|
|
show_memory();
|
|
|
|
return ret;
|
|
} /* error_check */
|
|
|
|
/*****************************************************************************/
|
|
/* wolfSSL error_check_ssl */
|
|
/* Parameters: */
|
|
/* ssl is the current WOLFSSL object pointer */
|
|
/* halt_on_error set to true to suspend operations for critical error */
|
|
/* message is expected to be a memory-efficient F("") macro string */
|
|
/*****************************************************************************/
|
|
int error_check_ssl(WOLFSSL* ssl, int this_ret, bool halt_on_error,
|
|
const __FlashStringHelper* message) {
|
|
int err = 0;
|
|
|
|
if (ssl == NULL) {
|
|
Serial.println(F("ssl is Null; Unable to allocate SSL object?"));
|
|
#ifndef DEBUG_WOLFSSL
|
|
Serial.println(F("Define DEBUG_WOLFSSL in user_settings.h for more."));
|
|
#else
|
|
Serial.println(F("See wolfssl/wolfcrypt/error-crypt.h for codes."));
|
|
#endif
|
|
Serial.print(F("ERROR: "));
|
|
Serial.println(message);
|
|
show_memory();
|
|
if (halt_on_error) {
|
|
fail_wait();
|
|
}
|
|
}
|
|
else {
|
|
err = wolfSSL_get_error(ssl, this_ret);
|
|
if (err == WOLFSSL_SUCCESS) {
|
|
Serial.print(F("Success m: "));
|
|
Serial.println(message);
|
|
}
|
|
else {
|
|
if (err < 0) {
|
|
wolfSSL_ERR_error_string(err, errBuf);
|
|
Serial.print(F("WOLFSSL Error: "));
|
|
Serial.print(err);
|
|
Serial.print(F("; "));
|
|
Serial.println(errBuf);
|
|
}
|
|
else {
|
|
Serial.println(F("Success: ssl object."));
|
|
}
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/* Arduino loop() */
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
void loop() {
|
|
char errBuf[80] = "(no error";
|
|
char reply[80] = "(no reply)";
|
|
const char msg[] = "I hear you fa shizzle!";
|
|
const char* cipherName;
|
|
int input = 0;
|
|
int replySz = 0;
|
|
int retry_shutdown = SHUTDOWN_DELAY_MS; /* max try, once per millisecond */
|
|
int ret = 0;
|
|
IPAddress broadcast_address(255, 255, 255, 255);
|
|
|
|
/* Listen for incoming client requests. */
|
|
client = server.available();
|
|
if (client) {
|
|
Serial.println("Have Client");
|
|
while (!client.connected()) {
|
|
/* wait for the client to actually connect */
|
|
delay(10);
|
|
}
|
|
Serial.print("Client connected from remote IP: ");
|
|
Serial.println(client.remoteIP());
|
|
|
|
ssl = wolfSSL_new(ctx);
|
|
if (ssl == NULL) {
|
|
Serial.println("Unable to allocate SSL object");
|
|
fail_wait();
|
|
}
|
|
|
|
ret = wolfSSL_accept(ssl);
|
|
if (ret != WOLFSSL_SUCCESS) {
|
|
ret = wolfSSL_get_error(ssl, 0);
|
|
wolfSSL_ERR_error_string(ret, errBuf);
|
|
Serial.print("TLS Accept Error: ");
|
|
Serial.println(errBuf);
|
|
}
|
|
|
|
cipherName = wolfSSL_get_cipher(ssl);
|
|
Serial.print("SSL cipher suite is ");
|
|
Serial.println(cipherName);
|
|
|
|
Serial.print("Server Read: ");
|
|
while (!client.available()) {
|
|
/* wait for data */
|
|
}
|
|
|
|
/* read data */
|
|
while (wolfSSL_pending(ssl)) {
|
|
input = wolfSSL_read(ssl, reply, sizeof(reply) - 1);
|
|
if (input < 0) {
|
|
ret = wolfSSL_get_error(ssl, 0);
|
|
wolfSSL_ERR_error_string(ret, errBuf);
|
|
Serial.print("TLS Read Error: ");
|
|
Serial.println(errBuf);
|
|
break;
|
|
}
|
|
else if (input > 0) {
|
|
replySz = input;
|
|
reply[input] = '\0';
|
|
Serial.print(reply);
|
|
}
|
|
else {
|
|
Serial.println("<end of reply, input == 0>");
|
|
}
|
|
}
|
|
|
|
/* Write our message into reply buffer to send */
|
|
memset(reply, 0, sizeof(reply));
|
|
memcpy(reply, msg, sizeof(msg));
|
|
replySz = strnlen(reply, sizeof(reply));
|
|
|
|
Serial.println("Sending reply...");
|
|
if ((wolfSSL_write(ssl, reply, replySz)) != replySz) {
|
|
ret = wolfSSL_get_error(ssl, 0);
|
|
wolfSSL_ERR_error_string(ret, errBuf);
|
|
Serial.print("TLS Write Error: ");
|
|
Serial.println(errBuf);
|
|
}
|
|
else {
|
|
Serial.println("Reply sent!");
|
|
}
|
|
|
|
Serial.println("Shutdown!");
|
|
do {
|
|
delay(1);
|
|
retry_shutdown--;
|
|
ret = wolfSSL_shutdown(ssl);
|
|
} while ((ret == WOLFSSL_SHUTDOWN_NOT_DONE) && (retry_shutdown > 0));
|
|
|
|
if (retry_shutdown <= 0) {
|
|
/* if wolfSSL_free is called before properly shutting down the
|
|
* ssl object, undesired results may occur. */
|
|
Serial.println("Warning! Shutdown did not properly complete.");
|
|
}
|
|
|
|
wolfSSL_free(ssl);
|
|
Serial.println("Connection complete.");
|
|
if (REPEAT_CONNECTION) {
|
|
Serial.println();
|
|
Serial.println("Waiting for next connection.");
|
|
}
|
|
else {
|
|
client.stop();
|
|
Serial.println("Done!");
|
|
while (1) {
|
|
/* wait forever if not repeating */
|
|
delay(100);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* Serial.println("Client not connected. Trying again..."); */
|
|
}
|
|
|
|
delay(100);
|
|
} /* Arduino loop repeats */
|