https_request_main.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /* HTTPS GET Example using plain mbedTLS sockets
  2. *
  3. * Contacts the howsmyssl.com API via TLS v1.2 and reads a JSON
  4. * response.
  5. *
  6. * Adapted from the ssl_client1 example in mbedtls.
  7. *
  8. * Original Copyright (C) 2006-2016, ARM Limited, All Rights Reserved, Apache 2.0 License.
  9. * Additions Copyright (C) Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD, Apache 2.0 License.
  10. *
  11. *
  12. * Licensed under the Apache License, Version 2.0 (the "License");
  13. * you may not use this file except in compliance with the License.
  14. * You may obtain a copy of the License at
  15. *
  16. * http://www.apache.org/licenses/LICENSE-2.0
  17. *
  18. * Unless required by applicable law or agreed to in writing, software
  19. * distributed under the License is distributed on an "AS IS" BASIS,
  20. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. * See the License for the specific language governing permissions and
  22. * limitations under the License.
  23. */
  24. #include <string.h>
  25. #include "freertos/FreeRTOS.h"
  26. #include "freertos/task.h"
  27. #include "esp_wifi.h"
  28. #include "esp_event.h"
  29. #include "esp_log.h"
  30. #include "esp_system.h"
  31. #include "lwip/err.h"
  32. #include "lwip/sockets.h"
  33. #include "lwip/sys.h"
  34. #include "lwip/netdb.h"
  35. #include "lwip/dns.h"
  36. #include "mbedtls/net.h"
  37. #include "mbedtls/debug.h"
  38. #include "mbedtls/ssl.h"
  39. #include "mbedtls/entropy.h"
  40. #include "mbedtls/ctr_drbg.h"
  41. #include "mbedtls/error.h"
  42. #include "mbedtls/certs.h"
  43. /* The examples use simple WiFi configuration that you can set via
  44. 'make menuconfig'.
  45. If you'd rather not, just change the below entries to strings with
  46. the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
  47. */
  48. #define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
  49. #define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
  50. /* Flag for when we are connected & ready to make a request */
  51. static volatile bool ready;
  52. /* Constants that aren't configurable in menuconfig */
  53. #define WEB_SERVER "www.howsmyssl.com"
  54. #define WEB_PORT "443"
  55. #define WEB_URL "https://www.howsmyssl.com/a/check"
  56. static const char *TAG = "example";
  57. static const char *REQUEST = "GET " WEB_URL " HTTP/1.1\n"
  58. "Host: "WEB_SERVER"\n"
  59. "User-Agent: esp-idf/1.0 esp32\n"
  60. "\n";
  61. /* Root cert for howsmyssl.com, found in cert.c */
  62. extern const char *server_root_cert;
  63. #ifdef MBEDTLS_DEBUG_C
  64. #define MBEDTLS_DEBUG_LEVEL 4
  65. /* mbedtls debug function that translates mbedTLS debug output
  66. to ESP_LOGx debug output.
  67. MBEDTLS_DEBUG_LEVEL 4 means all mbedTLS debug output gets sent here,
  68. and then filtered to the
  69. */
  70. static void mbedtls_debug(void *ctx, int level,
  71. const char *file, int line,
  72. const char *str)
  73. {
  74. const char *MBTAG = "mbedtls";
  75. char *file_sep;
  76. /* Shorten 'file' from the whole file path to just the filename
  77. This is a bit wasteful because the macros are compiled in with
  78. the full _FILE_ path in each case.
  79. */
  80. file_sep = rindex(file, '/');
  81. if(file_sep)
  82. file = file_sep+1;
  83. switch(level) {
  84. case 1:
  85. ESP_LOGI(MBTAG, "%s:%d %s", file, line, str);
  86. break;
  87. case 2:
  88. case 3:
  89. ESP_LOGD(MBTAG, "%s:%d %s", file, line, str);
  90. case 4:
  91. ESP_LOGV(MBTAG, "%s:%d %s", file, line, str);
  92. break;
  93. default:
  94. ESP_LOGE(MBTAG, "Unexpected log level %d: %s", level, str);
  95. break;
  96. }
  97. }
  98. #endif
  99. static esp_err_t wifi_event_cb(void *ctx, system_event_t *event)
  100. {
  101. switch(event->event_id) {
  102. case SYSTEM_EVENT_STA_GOT_IP:
  103. ready = true;
  104. break;
  105. case SYSTEM_EVENT_STA_DISCONNECTED:
  106. ready = false;
  107. break;
  108. default:
  109. break;
  110. }
  111. return ESP_OK;
  112. }
  113. static void set_wifi_configuration(void)
  114. {
  115. wifi_config_t wifi_config = {
  116. .sta = {
  117. .ssid = EXAMPLE_WIFI_SSID,
  118. .password = EXAMPLE_WIFI_PASS,
  119. },
  120. };
  121. ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
  122. esp_wifi_set_mode(WIFI_MODE_STA);
  123. esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
  124. }
  125. static void https_get_task(void *pvParameters)
  126. {
  127. char buf[512];
  128. int ret, flags, len;
  129. mbedtls_entropy_context entropy;
  130. mbedtls_ctr_drbg_context ctr_drbg;
  131. mbedtls_ssl_context ssl;
  132. mbedtls_x509_crt cacert;
  133. mbedtls_ssl_config conf;
  134. mbedtls_net_context server_fd;
  135. esp_wifi_connect();
  136. mbedtls_ssl_init(&ssl);
  137. mbedtls_x509_crt_init(&cacert);
  138. mbedtls_ctr_drbg_init(&ctr_drbg);
  139. ESP_LOGI(TAG, "Seeding the random number generator");
  140. mbedtls_ssl_config_init(&conf);
  141. mbedtls_entropy_init(&entropy);
  142. if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
  143. NULL, 0)) != 0)
  144. {
  145. ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret);
  146. abort();
  147. }
  148. ESP_LOGI(TAG, "Loading the CA root certificate...");
  149. ret = mbedtls_x509_crt_parse(&cacert, (uint8_t*)server_root_cert, strlen(server_root_cert)+1);
  150. if(ret < 0)
  151. {
  152. ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
  153. abort();
  154. }
  155. ESP_LOGI(TAG, "Setting hostname for TLS session...");
  156. /* Hostname set here should match CN in server certificate */
  157. if((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0)
  158. {
  159. ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret);
  160. abort();
  161. }
  162. ESP_LOGI(TAG, "Setting up the SSL/TLS structure...");
  163. if((ret = mbedtls_ssl_config_defaults(&conf,
  164. MBEDTLS_SSL_IS_CLIENT,
  165. MBEDTLS_SSL_TRANSPORT_STREAM,
  166. MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
  167. {
  168. ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret);
  169. goto exit;
  170. }
  171. /* MBEDTLS_SSL_VERIFY_OPTIONAL is bad for security, in this example it will print
  172. a warning if CA verification fails but it will continue to connect.
  173. You should consider using MBEDTLS_SSL_VERIFY_REQUIRED in your own code.
  174. */
  175. mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
  176. mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
  177. mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
  178. #ifdef MBEDTLS_DEBUG_C
  179. mbedtls_debug_set_threshold(MBEDTLS_DEBUG_LEVEL);
  180. mbedtls_ssl_conf_dbg(&conf, mbedtls_debug, NULL);
  181. #endif
  182. ESP_LOGI(TAG, "%d free...", system_get_free_heap_size());
  183. char *x = malloc(8192);
  184. memset(x, 'a', 8192);
  185. ESP_LOGI(TAG, "%d free now...", system_get_free_heap_size());
  186. if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0)
  187. {
  188. ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", -ret);
  189. goto exit;
  190. }
  191. ESP_LOGI(TAG, "Waiting for WiFi online...");
  192. while (!ready) {
  193. vTaskDelay(1);
  194. }
  195. ESP_LOGI(TAG, "WiFi is online");
  196. while(1) {
  197. ESP_LOGI(TAG, "Connecting to %s:%s...", WEB_SERVER, WEB_PORT);
  198. mbedtls_net_init(&server_fd);
  199. if ((ret = mbedtls_net_connect(&server_fd, WEB_SERVER,
  200. WEB_PORT, MBEDTLS_NET_PROTO_TCP)) != 0)
  201. {
  202. ESP_LOGE(TAG, "mbedtls_net_connect returned -%x", -ret);
  203. goto exit;
  204. }
  205. ESP_LOGI(TAG, "Connected.");
  206. mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
  207. ESP_LOGI(TAG, "Performing the SSL/TLS handshake...");
  208. while ((ret = mbedtls_ssl_handshake(&ssl)) != 0)
  209. {
  210. if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
  211. {
  212. ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret);
  213. goto exit;
  214. }
  215. }
  216. ESP_LOGI(TAG, "Verifying peer X.509 certificate...");
  217. if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0)
  218. {
  219. /* In real life, we probably want to close connection if ret != 0 */
  220. ESP_LOGW(TAG, "Failed to verify peer certificate!");
  221. bzero(buf, sizeof(buf));
  222. mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags);
  223. ESP_LOGW(TAG, "verification info: %s", buf);
  224. }
  225. else {
  226. ESP_LOGI(TAG, "Certificate verified.");
  227. }
  228. ESP_LOGI(TAG, "Writing HTTP request...");
  229. while((ret = mbedtls_ssl_write(&ssl, (const unsigned char *)REQUEST, strlen(REQUEST))) <= 0)
  230. {
  231. if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
  232. {
  233. ESP_LOGE(TAG, "mbedtls_ssl_write returned -0x%x", -ret);
  234. goto exit;
  235. }
  236. }
  237. len = ret;
  238. ESP_LOGI(TAG, "%d bytes written", len);
  239. ESP_LOGI(TAG, "Reading HTTP response...");
  240. do
  241. {
  242. len = sizeof(buf) - 1;
  243. bzero(buf, sizeof(buf));
  244. ret = mbedtls_ssl_read(&ssl, (unsigned char *)buf, len);
  245. if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
  246. continue;
  247. if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
  248. ret = 0;
  249. break;
  250. }
  251. if(ret < 0)
  252. {
  253. ESP_LOGE(TAG, "mbedtls_ssl_read returned -0x%x", -ret);
  254. break;
  255. }
  256. if(ret == 0)
  257. {
  258. ESP_LOGI(TAG, "connection closed");
  259. break;
  260. }
  261. len = ret;
  262. ESP_LOGI(TAG, "%d bytes read", len);
  263. /* Print response directly to stdout as it is read */
  264. for(int i = 0; i < len; i++) {
  265. putchar(buf[i]);
  266. }
  267. } while(1);
  268. mbedtls_ssl_close_notify(&ssl);
  269. exit:
  270. mbedtls_ssl_session_reset(&ssl);
  271. mbedtls_net_free(&server_fd);
  272. if(ret != 0)
  273. {
  274. mbedtls_strerror(ret, buf, 100);
  275. ESP_LOGE(TAG, "Last error was: -0x%x - %s", -ret, buf);
  276. }
  277. for(int countdown = 10; countdown >= 0; countdown--) {
  278. ESP_LOGI(TAG, "%d...", countdown);
  279. vTaskDelay(1000 / portTICK_RATE_MS);
  280. }
  281. ESP_LOGI(TAG, "Starting again!");
  282. }
  283. }
  284. void app_main()
  285. {
  286. esp_event_set_cb(wifi_event_cb, NULL);
  287. set_wifi_configuration();
  288. xTaskCreate(&https_get_task, "https_get_task", 8192, NULL, 5, NULL);
  289. }