wolfssl_client.ino 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. /* wolfssl_client.ino
  2. *
  3. * Copyright (C) 2006-2024 wolfSSL Inc.
  4. *
  5. * This file is part of wolfSSL.
  6. *
  7. * wolfSSL is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * wolfSSL is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
  20. */
  21. /*
  22. Tested with:
  23. 1) Intel Galileo acting as the Client, with a laptop acting as a server using
  24. the server example provided in examples/server.
  25. Legacy Arduino v1.86 was used to compile and program the Galileo
  26. 2) Espressif ESP32 WiFi
  27. 3) Arduino Due, Nano33 IoT, Nano RP-2040
  28. */
  29. /*
  30. * Note to code editors: the Arduino client and server examples are edited in
  31. * parallel for side-by-side comparison between examples.
  32. */
  33. /* If you have a private include, define it here, otherwise edit WiFi params */
  34. #define MY_PRIVATE_CONFIG "/workspace/my_private_config.h"
  35. /* set REPEAT_CONNECTION to a non-zero value to continually run the example. */
  36. #define REPEAT_CONNECTION 0
  37. /* Edit this with your other TLS host server address to connect to: */
  38. #define WOLFSSL_TLS_SERVER_HOST "192.168.1.39"
  39. /* wolfssl TLS examples communicate on port 11111 */
  40. #define WOLFSSL_PORT 11111
  41. /* Choose a monitor serial baud rate: 9600, 14400, 19200, 57600, 74880, etc. */
  42. #define SERIAL_BAUD 115200
  43. /* We'll wait up to 2000 milliseconds to properly shut down connection */
  44. #define SHUTDOWN_DELAY_MS 2000
  45. /* Number of times to retry connection. */
  46. #define RECONNECT_ATTEMPTS 20
  47. /* Optional stress test. Define to consume memory until exhausted: */
  48. /* #define MEMORY_STRESS_TEST */
  49. /* Choose client or server example, not both. */
  50. #define WOLFSSL_CLIENT_EXAMPLE
  51. /* #define WOLFSSL_SERVER_EXAMPLE */
  52. #if defined(MY_PRIVATE_CONFIG)
  53. /* the /workspace directory may contain a private config
  54. * excluded from GitHub with items such as WiFi passwords */
  55. #include MY_PRIVATE_CONFIG
  56. static const char* ssid PROGMEM = MY_ARDUINO_WIFI_SSID;
  57. static const char* password PROGMEM = MY_ARDUINO_WIFI_PASSWORD;
  58. #else
  59. /* when using WiFi capable boards: */
  60. static const char* ssid PROGMEM = "your_SSID";
  61. static const char* password PROGMEM = "your_PASSWORD";
  62. #endif
  63. #define BROADCAST_ADDRESS "255.255.255.255"
  64. /* There's an optional 3rd party NTPClient library by Fabrice Weinberg.
  65. * If it is installed, uncomment define USE_NTP_LIB here: */
  66. /* #define USE_NTP_LIB */
  67. #ifdef USE_NTP_LIB
  68. #include <NTPClient.h>
  69. #endif
  70. #include <wolfssl.h>
  71. /* Important: make sure settings.h appears before any other wolfSSL headers */
  72. #include <wolfssl/wolfcrypt/settings.h>
  73. /* Reminder: settings.h includes user_settings.h
  74. * For ALL project wolfSSL settings, see:
  75. * [your path]/Arduino\libraries\wolfSSL\src\user_settings.h */
  76. #include <wolfssl/ssl.h>
  77. #include <wolfssl/certs_test.h>
  78. #include <wolfssl/wolfcrypt/error-crypt.h>
  79. /* Define DEBUG_WOLFSSL in user_settings.h for more verbose logging. */
  80. #if defined(DEBUG_WOLFSSL)
  81. #define PROGRESS_DOT F("")
  82. #else
  83. #define PROGRESS_DOT F(".")
  84. #endif
  85. /* Convert a macro to a string */
  86. #define xstr(x) str(x)
  87. #define str(x) #x
  88. /* optional board-specific networking includes */
  89. #if defined(ESP32)
  90. #define USING_WIFI
  91. #include <WiFi.h>
  92. #include <WiFiUdp.h>
  93. #ifdef USE_NTP_LIB
  94. WiFiUDP ntpUDP;
  95. #endif
  96. /* Ensure the F() flash macro is defined */
  97. #ifndef F
  98. #define F
  99. #endif
  100. WiFiClient client;
  101. #elif defined(ESP8266)
  102. #define USING_WIFI
  103. #include <ESP8266WiFi.h>
  104. WiFiClient client;
  105. #elif defined(ARDUINO_SAM_DUE)
  106. #include <SPI.h>
  107. /* There's no WiFi/Ethernet on the Due. Requires Ethernet Shield.
  108. /* Needs "Ethernet by Various" library to be installed. Tested with V2.0.2 */
  109. #include <Ethernet.h>
  110. EthernetClient client;
  111. #elif defined(ARDUINO_SAMD_NANO_33_IOT)
  112. #define USING_WIFI
  113. #include <SPI.h>
  114. #include <WiFiNINA.h> /* Needs Arduino WiFiNINA library installed manually */
  115. WiFiClient client;
  116. #elif defined(ARDUINO_ARCH_RP2040)
  117. #define USING_WIFI
  118. #include <SPI.h>
  119. #include <WiFiNINA.h>
  120. WiFiClient client;
  121. #elif defined(USING_WIFI)
  122. #define USING_WIFI
  123. #include <WiFi.h>
  124. #include <WiFiUdp.h>
  125. #ifdef USE_NTP_LIB
  126. WiFiUDP ntpUDP;
  127. #endif
  128. WiFiClient client;
  129. /* TODO
  130. #elif defined(OTHER_BOARD)
  131. */
  132. #else
  133. #define USING_WIFI
  134. WiFiClient client;
  135. #endif
  136. /* Only for syntax highlighters to show interesting options enabled: */
  137. #if defined(HAVE_SNI) \
  138. || defined(HAVE_MAX_FRAGMENT) \
  139. || defined(HAVE_TRUSTED_CA) \
  140. || defined(HAVE_TRUNCATED_HMAC) \
  141. || defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
  142. || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) \
  143. || defined(HAVE_SUPPORTED_CURVES) \
  144. || defined(HAVE_ALPN) \
  145. || defined(HAVE_SESSION_TICKET) \
  146. || defined(HAVE_SECURE_RENEGOTIATION) \
  147. || defined(HAVE_SERVER_RENEGOTIATION_INFO)
  148. #endif
  149. static const char host[] PROGMEM = WOLFSSL_TLS_SERVER_HOST; /* server to connect to */
  150. static const int port PROGMEM = WOLFSSL_PORT; /* port on server to connect to */
  151. static WOLFSSL_CTX* ctx = NULL;
  152. static WOLFSSL* ssl = NULL;
  153. static char* wc_error_message = (char*)malloc(80 + 1);
  154. static char errBuf[80];
  155. #if defined(MEMORY_STRESS_TEST)
  156. #define MEMORY_STRESS_ITERATIONS 100
  157. #define MEMORY_STRESS_BLOCK_SIZE 1024
  158. #define MEMORY_STRESS_INITIAL (4*1024)
  159. static char* memory_stress[MEMORY_STRESS_ITERATIONS]; /* typically 1K per item */
  160. static int mem_ctr = 0;
  161. #endif
  162. static int EthernetSend(WOLFSSL* ssl, char* msg, int sz, void* ctx);
  163. static int EthernetReceive(WOLFSSL* ssl, char* reply, int sz, void* ctx);
  164. static int reconnect = RECONNECT_ATTEMPTS;
  165. static int lng_index PROGMEM = 0; /* 0 = English */
  166. #if defined(__arm__)
  167. #include <malloc.h>
  168. extern char _end;
  169. extern "C" char *sbrk(int i);
  170. static char *ramstart=(char *)0x20070000;
  171. static char *ramend=(char *)0x20088000;
  172. #endif
  173. /*****************************************************************************/
  174. /* fail_wait - in case of unrecoverable error */
  175. /*****************************************************************************/
  176. int fail_wait(void) {
  177. show_memory();
  178. Serial.println(F("Failed. Halt."));
  179. while (1) {
  180. delay(1000);
  181. }
  182. return 0;
  183. }
  184. /*****************************************************************************/
  185. /* show_memory() to optionally view during debugging. */
  186. /*****************************************************************************/
  187. int show_memory(void)
  188. {
  189. #if defined(__arm__)
  190. struct mallinfo mi = mallinfo();
  191. char *heapend=sbrk(0);
  192. register char * stack_ptr asm("sp");
  193. #if defined(DEBUG_WOLFSSL_VERBOSE)
  194. Serial.print(" arena=");
  195. Serial.println(mi.arena);
  196. Serial.print(" ordblks=");
  197. Serial.println(mi.ordblks);
  198. Serial.print(" uordblks=");
  199. Serial.println(mi.uordblks);
  200. Serial.print(" fordblks=");
  201. Serial.println(mi.fordblks);
  202. Serial.print(" keepcost=");
  203. Serial.println(mi.keepcost);
  204. #endif
  205. #if defined(DEBUG_WOLFSSL) || defined(MEMORY_STRESS_TEST)
  206. Serial.print("Estimated free memory: ");
  207. Serial.print(stack_ptr - heapend + mi.fordblks);
  208. Serial.println(F(" bytes"));
  209. #endif
  210. #if (0)
  211. /* Experimental: not supported on all devices: */
  212. Serial.print("RAM Start %lx\n", (unsigned long)ramstart);
  213. Serial.print("Data/Bss end %lx\n", (unsigned long)&_end);
  214. Serial.print("Heap End %lx\n", (unsigned long)heapend);
  215. Serial.print("Stack Ptr %lx\n",(unsigned long)stack_ptr);
  216. Serial.print("RAM End %lx\n", (unsigned long)ramend);
  217. Serial.print("Heap RAM Used: ",mi.uordblks);
  218. Serial.print("Program RAM Used ",&_end - ramstart);
  219. Serial.print("Stack RAM Used ",ramend - stack_ptr);
  220. Serial.print("Estimated Free RAM: %d\n\n",stack_ptr - heapend + mi.fordblks);
  221. #endif
  222. #else
  223. Serial.println(F("show_memory() not implemented for this platform"));
  224. #endif
  225. return 0;
  226. }
  227. /*****************************************************************************/
  228. /* EthernetSend() to send a message string. */
  229. /*****************************************************************************/
  230. int EthernetSend(WOLFSSL* ssl, char* message, int sz, void* ctx) {
  231. int sent = 0;
  232. (void)ssl;
  233. (void)ctx;
  234. sent = client.write((byte*)message, sz);
  235. return sent;
  236. }
  237. /*****************************************************************************/
  238. /* EthernetReceive() to receive a reply string. */
  239. /*****************************************************************************/
  240. int EthernetReceive(WOLFSSL* ssl, char* reply, int sz, void* ctx) {
  241. int ret = 0;
  242. (void)ssl;
  243. (void)ctx;
  244. while (client.available() > 0 && ret < sz) {
  245. reply[ret++] = client.read();
  246. }
  247. return ret;
  248. }
  249. /*****************************************************************************/
  250. /* Arduino setup_hardware() */
  251. /*****************************************************************************/
  252. int setup_hardware(void) {
  253. int ret = 0;
  254. #if defined(ARDUINO_SAMD_NANO_33_IOT)
  255. Serial.println(F("Detected known tested and working Arduino Nano 33 IoT"));
  256. #elif defined(ARDUINO_ARCH_RP2040)
  257. Serial.println(F("Detected known tested and working Arduino RP-2040"));
  258. #elif defined(__arm__) && defined(ID_TRNG) && defined(TRNG)
  259. /* need to manually turn on random number generator on Arduino Due, etc. */
  260. pmc_enable_periph_clk(ID_TRNG);
  261. trng_enable(TRNG);
  262. Serial.println(F("Enabled ARM TRNG"));
  263. #endif
  264. show_memory();
  265. randomSeed(analogRead(0));
  266. return ret;
  267. }
  268. /*****************************************************************************/
  269. /* Arduino setup_datetime() */
  270. /* The device needs to have a valid date within the valid range of certs. */
  271. /*****************************************************************************/
  272. int setup_datetime(void) {
  273. int ret = 0;
  274. int ntp_tries = 20;
  275. /* we need a date in the range of cert expiration */
  276. #ifdef USE_NTP_LIB
  277. #if defined(ESP32)
  278. NTPClient timeClient(ntpUDP, "pool.ntp.org");
  279. timeClient.begin();
  280. timeClient.update();
  281. delay(1000);
  282. while (!timeClient.isTimeSet() && (ntp_tries > 0)) {
  283. timeClient.forceUpdate();
  284. Serial.println(F("Waiting for NTP update"));
  285. delay(2000);
  286. ntp_tries--;
  287. }
  288. if (ntp_tries <= 0) {
  289. Serial.println(F("Warning: gave up waiting on NTP"));
  290. }
  291. Serial.println(timeClient.getFormattedTime());
  292. Serial.println(timeClient.getEpochTime());
  293. #endif
  294. #endif
  295. #if defined(ESP32)
  296. /* see esp32-hal-time.c */
  297. ntp_tries = 5;
  298. /* Replace "pool.ntp.org" with your preferred NTP server */
  299. configTime(0, 0, "pool.ntp.org");
  300. /* Wait for time to be set */
  301. while ((time(nullptr) <= 100000) && ntp_tries > 0) {
  302. Serial.println(F("Waiting for time to be set..."));
  303. delay(2000);
  304. ntp_tries--;
  305. }
  306. #endif
  307. return ret;
  308. } /* setup_datetime */
  309. /*****************************************************************************/
  310. /* Arduino setup_network() */
  311. /*****************************************************************************/
  312. int setup_network(void) {
  313. int ret = 0;
  314. #if defined(USING_WIFI)
  315. int status = WL_IDLE_STATUS;
  316. /* The ESP8266 & ESP32 support both AP and STA. We'll use STA: */
  317. #if defined(ESP8266) || defined(ESP32)
  318. WiFi.mode(WIFI_STA);
  319. #else
  320. String fv;
  321. if (WiFi.status() == WL_NO_MODULE) {
  322. Serial.println("Communication with WiFi module failed!");
  323. /* don't continue if no network */
  324. while (true) ;
  325. }
  326. fv = WiFi.firmwareVersion();
  327. if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
  328. Serial.println("Please upgrade the firmware");
  329. }
  330. #endif
  331. Serial.print(F("Connecting to WiFi "));
  332. Serial.print(ssid);
  333. status = WiFi.begin(ssid, password);
  334. while (status != WL_CONNECTED) {
  335. delay(1000);
  336. Serial.print(F("."));
  337. Serial.print(status);
  338. status = WiFi.status();
  339. }
  340. Serial.println(F(" Connected!"));
  341. #else
  342. /* Newer Ethernet shields have a
  343. * MAC address printed on a sticker on the shield */
  344. byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
  345. IPAddress ip(192, 168, 1, 42);
  346. IPAddress myDns(192, 168, 1, 1);
  347. Ethernet.init(10); /* Most Arduino shields */
  348. /* Ethernet.init(5); * MKR ETH Shield */
  349. /* Ethernet.init(0); * Teensy 2.0 */
  350. /* Ethernet.init(20); * Teensy++ 2.0 */
  351. /* Ethernet.init(15); * ESP8266 with Adafruit FeatherWing Ethernet */
  352. /* Ethernet.init(33); * ESP32 with Adafruit FeatherWing Ethernet */
  353. Serial.println(F("Initialize Ethernet with DHCP:"));
  354. if (Ethernet.begin(mac) == 0) {
  355. Serial.println(F("Failed to configure Ethernet using DHCP"));
  356. /* Check for Ethernet hardware present */
  357. if (Ethernet.hardwareStatus() == EthernetNoHardware) {
  358. Serial.println(F("Ethernet shield was not found."));
  359. while (true) {
  360. delay(1); /* do nothing */
  361. }
  362. }
  363. if (Ethernet.linkStatus() == LinkOFF) {
  364. Serial.println(F("Ethernet cable is not connected."));
  365. }
  366. /* try to configure using IP address instead of DHCP : */
  367. Ethernet.begin(mac, ip, myDns);
  368. }
  369. else {
  370. Serial.print(F(" DHCP assigned IP "));
  371. Serial.println(Ethernet.localIP());
  372. }
  373. /* We'll assume the Ethernet connection is ready to go. */
  374. #endif
  375. Serial.println(F("********************************************************"));
  376. Serial.print(F(" wolfSSL Example Client IP = "));
  377. #if defined(USING_WIFI)
  378. Serial.println(WiFi.localIP());
  379. #else
  380. Serial.println(Ethernet.localIP());
  381. #endif
  382. Serial.print(F(" Configured Server Host to connect to: "));
  383. Serial.println(host);
  384. Serial.println(F("********************************************************"));
  385. Serial.println(F("Setup network complete."));
  386. return ret;
  387. }
  388. /*****************************************************************************/
  389. /* Arduino setup_wolfssl() */
  390. /*****************************************************************************/
  391. int setup_wolfssl(void) {
  392. int ret = 0;
  393. WOLFSSL_METHOD* method;
  394. /* Show a revision of wolfssl user_settings.h file in use when available: */
  395. #if defined(WOLFSSL_USER_SETTINGS_ID)
  396. Serial.print(F("WOLFSSL_USER_SETTINGS_ID: "));
  397. Serial.println(F(WOLFSSL_USER_SETTINGS_ID));
  398. #else
  399. Serial.println(F("No WOLFSSL_USER_SETTINGS_ID found."));
  400. #endif
  401. #if defined(NO_WOLFSSL_SERVER)
  402. Serial.println(F("wolfSSL server code disabled to save space."));
  403. #endif
  404. #if defined(NO_WOLFSSL_CLIENT)
  405. Serial.println(F("wolfSSL client code disabled to save space."));
  406. #endif
  407. #if defined(DEBUG_WOLFSSL)
  408. wolfSSL_Debugging_ON();
  409. Serial.println(F("wolfSSL Debugging is On!"));
  410. #else
  411. Serial.println(F("wolfSSL Debugging is Off! (enable with DEBUG_WOLFSSL)"));
  412. #endif
  413. /* See ssl.c for TLS cache settings. Larger cache = use more RAM. */
  414. #if defined(NO_SESSION_CACHE)
  415. Serial.println(F("wolfSSL TLS NO_SESSION_CACHE"));
  416. #elif defined(MICRO_SESSION_CACHEx)
  417. Serial.println(F("wolfSSL TLS MICRO_SESSION_CACHE"));
  418. #elif defined(SMALL_SESSION_CACHE)
  419. Serial.println(F("wolfSSL TLS SMALL_SESSION_CACHE"));
  420. #elif defined(MEDIUM_SESSION_CACHE)
  421. Serial.println(F("wolfSSL TLS MEDIUM_SESSION_CACHE"));
  422. #elif defined(BIG_SESSION_CACHE)
  423. Serial.println(F("wolfSSL TLS BIG_SESSION_CACHE"));
  424. #elif defined(HUGE_SESSION_CACHE)
  425. Serial.println(F("wolfSSL TLS HUGE_SESSION_CACHE"));
  426. #elif defined(HUGE_SESSION_CACHE)
  427. Serial.println(F("wolfSSL TLS HUGE_SESSION_CACHE"));
  428. #else
  429. Serial.println(F("WARNING: Unknown or no TLS session cache setting."));
  430. /* See wolfssl/src/ssl.c for amount of memory used.
  431. * It is best on embedded devices to choose a TLS session cache size. */
  432. #endif
  433. ret = wolfSSL_Init();
  434. if (ret == WOLFSSL_SUCCESS) {
  435. Serial.println("Successfully called wolfSSL_Init");
  436. }
  437. else {
  438. Serial.println("ERROR: wolfSSL_Init failed");
  439. }
  440. /* See companion server example with wolfSSLv23_server_method here.
  441. * method = wolfSSLv23_client_method()); SSL 3.0 - TLS 1.3.
  442. * method = wolfTLSv1_2_client_method(); only TLS 1.2
  443. * method = wolfTLSv1_3_client_method(); only TLS 1.3
  444. *
  445. * see Arduino\libraries\wolfssl\src\user_settings.h */
  446. Serial.println("Here we go!");
  447. method = wolfSSLv23_client_method();
  448. if (method == NULL) {
  449. Serial.println(F("unable to get wolfssl client method"));
  450. fail_wait();
  451. }
  452. ctx = wolfSSL_CTX_new(method);
  453. if (ctx == NULL) {
  454. Serial.println(F("unable to get ctx"));
  455. fail_wait();
  456. }
  457. return ret;
  458. }
  459. /*****************************************************************************/
  460. /* Arduino setup_certificates() */
  461. /*****************************************************************************/
  462. int setup_certificates(void) {
  463. int ret = 0;
  464. Serial.println(F("Initializing certificates..."));
  465. show_memory();
  466. /* Use built-in validation, No verification callback function: */
  467. wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 0);
  468. /* Certificate */
  469. Serial.println("Initializing certificates...");
  470. ret = wolfSSL_CTX_use_certificate_buffer(ctx,
  471. CTX_CLIENT_CERT,
  472. CTX_CLIENT_CERT_SIZE,
  473. CTX_CLIENT_CERT_TYPE);
  474. if (ret == WOLFSSL_SUCCESS) {
  475. Serial.print("Success: use certificate: ");
  476. Serial.println(xstr(CTX_SERVER_CERT));
  477. }
  478. else {
  479. Serial.println(F("Error: wolfSSL_CTX_use_certificate_buffer failed: "));
  480. wc_ErrorString(ret, wc_error_message);
  481. Serial.println(wc_error_message);
  482. fail_wait();
  483. }
  484. /* Setup private client key */
  485. ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx,
  486. CTX_CLIENT_KEY,
  487. CTX_CLIENT_KEY_SIZE,
  488. CTX_CLIENT_KEY_TYPE);
  489. if (ret == WOLFSSL_SUCCESS) {
  490. Serial.print("Success: use private key buffer: ");
  491. Serial.println(xstr(CTX_SERVER_KEY));
  492. }
  493. else {
  494. Serial.println(F("Error: wolfSSL_CTX_use_PrivateKey_buffer failed: "));
  495. wc_ErrorString(ret, wc_error_message);
  496. Serial.println(wc_error_message);
  497. fail_wait();
  498. }
  499. ret = wolfSSL_CTX_load_verify_buffer(ctx,
  500. CTX_CA_CERT,
  501. CTX_CA_CERT_SIZE,
  502. CTX_CA_CERT_TYPE);
  503. if (ret == WOLFSSL_SUCCESS) {
  504. Serial.println(F("Success: load_verify CTX_CA_CERT"));
  505. }
  506. else {
  507. Serial.println(F("Error: wolfSSL_CTX_load_verify_buffer failed: "));
  508. wc_ErrorString(ret, wc_error_message);
  509. Serial.println(wc_error_message);
  510. fail_wait();
  511. }
  512. return ret;
  513. } /* Arduino setup */
  514. /*****************************************************************************/
  515. /*****************************************************************************/
  516. /* Arduino setup() */
  517. /*****************************************************************************/
  518. /*****************************************************************************/
  519. void setup(void) {
  520. int i = 0;
  521. Serial.begin(SERIAL_BAUD);
  522. while (!Serial && (i < 10)) {
  523. /* wait for serial port to connect. Needed for native USB port only */
  524. delay(1000);
  525. i++;
  526. }
  527. Serial.println(F(""));
  528. Serial.println(F(""));
  529. Serial.println(F("wolfSSL TLS Client Example Startup."));
  530. /* define DEBUG_WOLFSSL in wolfSSL user_settings.h for diagnostics */
  531. #if defined(DEBUG_WOLFSSL)
  532. wolfSSL_Debugging_ON();
  533. #endif
  534. /* Optionally pre-allocate a large block of memory for testing */
  535. #if defined(MEMORY_STRESS_TEST)
  536. Serial.println(F("WARNING: Memory Stress Test Active!"));
  537. Serial.print(F("Allocating extra memory: "));
  538. Serial.print(MEMORY_STRESS_INITIAL);
  539. Serial.println(F(" bytes..."));
  540. memory_stress[mem_ctr] = (char*)malloc(MEMORY_STRESS_INITIAL);
  541. show_memory();
  542. #endif
  543. setup_hardware();
  544. setup_network();
  545. setup_datetime();
  546. setup_wolfssl();
  547. setup_certificates();
  548. /* Initialize wolfSSL using callback functions. */
  549. wolfSSL_SetIOSend(ctx, EthernetSend);
  550. wolfSSL_SetIORecv(ctx, EthernetReceive);
  551. Serial.println(F("Completed Arduino setup!"));
  552. /* See companion wolfssl_server.ino code; server begins listening here
  553. * https://github.com/wolfSSL/wolfssl/tree/master/IDE/ARDUINO/sketches/wolfssl_server
  554. * Any other server will work. See also:
  555. * https://github.com/wolfSSL/wolfssl/tree/master/examples/client
  556. */
  557. /* See companion wolfssl_server.ino code */
  558. return;
  559. } /* Arduino setup */
  560. /*****************************************************************************/
  561. /* wolfSSL error_check() */
  562. /*****************************************************************************/
  563. int error_check(int this_ret, bool halt_on_error,
  564. const __FlashStringHelper* message) {
  565. int ret = 0;
  566. if (this_ret == WOLFSSL_SUCCESS) {
  567. Serial.print(F("Success: "));
  568. Serial.println(message);
  569. }
  570. else {
  571. Serial.print(F("ERROR: return = "));
  572. Serial.print(this_ret);
  573. Serial.print(F(": "));
  574. Serial.println(message);
  575. Serial.println(wc_GetErrorString(this_ret));
  576. if (halt_on_error) {
  577. fail_wait();
  578. }
  579. }
  580. show_memory();
  581. return ret;
  582. } /* error_check */
  583. /*****************************************************************************/
  584. /* wolfSSL error_check_ssl */
  585. /* Parameters: */
  586. /* ssl is the current WOLFSSL object pointer */
  587. /* halt_on_error set to true to suspend operations for critical error */
  588. /* message is expected to be a memory-efficient F("") macro string */
  589. /*****************************************************************************/
  590. int error_check_ssl(WOLFSSL* ssl, int this_ret, bool halt_on_error,
  591. const __FlashStringHelper* message) {
  592. int err = 0;
  593. if (ssl == NULL) {
  594. Serial.println(F("ssl is Null; Unable to allocate SSL object?"));
  595. #ifndef DEBUG_WOLFSSL
  596. Serial.println(F("Define DEBUG_WOLFSSL in user_settings.h for more."));
  597. #else
  598. Serial.println(F("See wolfssl/wolfcrypt/error-crypt.h for codes."));
  599. #endif
  600. Serial.print(F("ERROR: "));
  601. Serial.println(message);
  602. show_memory();
  603. if (halt_on_error) {
  604. fail_wait();
  605. }
  606. }
  607. else {
  608. err = wolfSSL_get_error(ssl, this_ret);
  609. if (err == WOLFSSL_SUCCESS) {
  610. Serial.print(F("Success m: "));
  611. Serial.println(message);
  612. }
  613. else {
  614. if (err < 0) {
  615. wolfSSL_ERR_error_string(err, errBuf);
  616. Serial.print(F("WOLFSSL Error: "));
  617. Serial.print(err);
  618. Serial.print(F("; "));
  619. Serial.println(errBuf);
  620. }
  621. else {
  622. Serial.println(F("Success: ssl object."));
  623. }
  624. }
  625. }
  626. return err;
  627. }
  628. /*****************************************************************************/
  629. /*****************************************************************************/
  630. /* Arduino loop() */
  631. /*****************************************************************************/
  632. /*****************************************************************************/
  633. void loop() {
  634. char reply[80];
  635. char msg[32] = "hello wolfssl!";
  636. const char* cipherName;
  637. int retry_shutdown = SHUTDOWN_DELAY_MS; /* max try, once per millisecond */
  638. int total_input = 0;
  639. int msgSz = 0;
  640. int input = 0;
  641. int ret = 0;
  642. int err = 0;
  643. msgSz = (int)strlen(msg);
  644. Serial.println(F(""));
  645. Serial.println(F("Starting Arduino loop() ..."));
  646. if (reconnect) {
  647. reconnect--;
  648. /* WiFi client returns true if connection succeeds, false if not. */
  649. /* Wired client returns int (1,-1,-2,-3,-4) for connection status. */
  650. Serial.print(F("Connecting to "));
  651. Serial.print(host);
  652. Serial.print(F(":"));
  653. Serial.println(port);
  654. /* can also use: IPAddress server(192,168,1,37); */
  655. Serial.println(F("Here we go..."));
  656. ret = client.connect(host, port);
  657. Serial.println(F("Ok, checking..."));
  658. if (ret > 0) {
  659. Serial.println(F("Connected!"));
  660. /* initialize wolfSSL */
  661. ret = wolfSSL_Init();
  662. error_check(ret, false, F("calling wolfSSL_Init") );
  663. /* create secure connection object. see setup for ctx certs. */
  664. Serial.println(F("Calling ssl = wolfSSL_new(ctx)"));
  665. ssl = wolfSSL_new(ctx);
  666. error_check_ssl(ssl, 0, true, F("Create WOLFSSL object from ctx"));
  667. Serial.print(F("Connecting to wolfSSL TLS Secure Server..."));
  668. do {
  669. err = 0; /* reset error */
  670. Serial.println(F("wolfSSL_connect ..."));
  671. ret = wolfSSL_connect(ssl);
  672. Serial.print("wolfSSL_connect return result =");
  673. Serial.println(ret);
  674. if ((ret != WOLFSSL_SUCCESS) && (ret != WC_PENDING_E)) {
  675. Serial.println(F("Failed connection, checking error."));
  676. err = error_check_ssl(ssl, ret, true,
  677. F("Create WOLFSSL object from ctx"));
  678. Serial.print("err =");
  679. Serial.println(err);
  680. }
  681. else {
  682. Serial.print(PROGRESS_DOT);
  683. }
  684. } while (err == WC_PENDING_E);
  685. Serial.println();
  686. Serial.println(F("Connected!"));
  687. Serial.print(F("SSL version is "));
  688. Serial.println(wolfSSL_get_version(ssl));
  689. cipherName = wolfSSL_get_cipher(ssl);
  690. Serial.print(F("SSL cipher suite is "));
  691. Serial.println(cipherName);
  692. /* see test.h
  693. * TODO: test.h needs a little bit of Arduino work for these:
  694. showPeerEx(ssl, lng_index);
  695. showPeerPEM(ssl);
  696. */
  697. Serial.print(F("Sending secure message to server: "));
  698. Serial.println(msg);
  699. ret = wolfSSL_write(ssl, msg, msgSz);
  700. if (ret == msgSz) {
  701. Serial.print(F("Waiting for Server response..."));
  702. while (!client.available()) {
  703. /* wait for data */
  704. delay(1); /* 1 ms delay */
  705. }
  706. Serial.print(F("Reading response.."));
  707. /* read data */
  708. do {
  709. ret = wolfSSL_read(ssl, reply, sizeof(reply) - 1);
  710. if (ret < 0) {
  711. error_check_ssl(ssl, ret, false,
  712. F("during TLS Read"));
  713. }
  714. else {
  715. Serial.print(PROGRESS_DOT);
  716. }
  717. } while (err == WC_PENDING_E);
  718. Serial.println();
  719. Serial.println();
  720. Serial.println(reply); /* typically: I hear you fa shizzle! */
  721. Serial.println();
  722. } /* wolfSSL_write message size matched */
  723. else {
  724. error_check_ssl(ssl, ret, false,
  725. F("during TLS Write"));
  726. } /* any wolfSSL_write message size mismatch is an error */
  727. Serial.print(F("Shutting down.."));
  728. do {
  729. delay(1);
  730. Serial.print(PROGRESS_DOT);
  731. retry_shutdown--;
  732. ret = wolfSSL_shutdown(ssl);
  733. } while ( (ret == WOLFSSL_SHUTDOWN_NOT_DONE)
  734. && (retry_shutdown > 0)
  735. ); /* There may be pending data, so wait until done. */
  736. Serial.println();
  737. if (retry_shutdown <= 0) {
  738. /* if wolfSSL_free is called before properly shutting down the
  739. * ssl object, undesired results may occur. */
  740. Serial.println(F("Warning! Shutdown did not properly complete."));
  741. }
  742. wolfSSL_free(ssl);
  743. client.stop();
  744. Serial.println(F("Connection complete."));
  745. if (REPEAT_CONNECTION) {
  746. reconnect = RECONNECT_ATTEMPTS;
  747. }
  748. else {
  749. reconnect = 0;
  750. }
  751. } /* client.connect(host, port) */
  752. else {
  753. Serial.println(F("Problem sending message. Trying to reconnect..."));
  754. }
  755. }
  756. delay(1000);
  757. if ((reconnect > 0) && (REPEAT_CONNECTION)) {
  758. Serial.println(F("Arduino loop repeating..."));
  759. Serial.println();
  760. }
  761. else {
  762. printf("wow");
  763. Serial.println(F("Done!"));
  764. while(1) {
  765. /* wait forever */
  766. }
  767. }
  768. #if defined(MEMORY_STRESS_TEST)
  769. if (mem_ctr < MEMORY_STRESS_ITERATIONS) {
  770. /* reminder: mem_ctr == 0 is MEMORY_STRESS_INITIAL allocation */
  771. mem_ctr++;
  772. Serial.print(F("Memory stress increment: "));
  773. Serial.print(mem_ctr);
  774. Serial.print(F(". Allocating addition memory (bytes): "));
  775. Serial.println(MEMORY_STRESS_BLOCK_SIZE);
  776. memory_stress[mem_ctr] = (char*)malloc(MEMORY_STRESS_BLOCK_SIZE);
  777. show_memory();
  778. }
  779. #endif
  780. } /* Arduino loop repeats */