https_request_example_main.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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 <stdlib.h>
  26. #include "freertos/FreeRTOS.h"
  27. #include "freertos/task.h"
  28. #include "freertos/event_groups.h"
  29. #include "esp_wifi.h"
  30. #include "esp_event.h"
  31. #include "esp_log.h"
  32. #include "esp_system.h"
  33. #include "nvs_flash.h"
  34. #include "protocol_examples_common.h"
  35. #include "esp_netif.h"
  36. #include "lwip/err.h"
  37. #include "lwip/sockets.h"
  38. #include "lwip/sys.h"
  39. #include "lwip/netdb.h"
  40. #include "lwip/dns.h"
  41. #include "esp_tls.h"
  42. #include "esp_crt_bundle.h"
  43. /* Constants that aren't configurable in menuconfig */
  44. #define WEB_SERVER "www.howsmyssl.com"
  45. #define WEB_PORT "443"
  46. #define WEB_URL "https://www.howsmyssl.com/a/check"
  47. static const char *TAG = "example";
  48. static const char REQUEST[] = "GET " WEB_URL " HTTP/1.1\r\n"
  49. "Host: "WEB_SERVER"\r\n"
  50. "User-Agent: esp-idf/1.0 esp32\r\n"
  51. "\r\n";
  52. /* Root cert for howsmyssl.com, taken from server_root_cert.pem
  53. The PEM file was extracted from the output of this command:
  54. openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
  55. The CA root cert is the last cert given in the chain of certs.
  56. To embed it in the app binary, the PEM file is named
  57. in the component.mk COMPONENT_EMBED_TXTFILES variable.
  58. */
  59. extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
  60. extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_pem_end");
  61. #ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS
  62. esp_tls_client_session_t *tls_client_session = NULL;
  63. #endif
  64. static void https_get_request(esp_tls_cfg_t cfg)
  65. {
  66. char buf[512];
  67. int ret, len;
  68. struct esp_tls *tls = esp_tls_conn_http_new(WEB_URL, &cfg);
  69. if (tls != NULL) {
  70. ESP_LOGI(TAG, "Connection established...");
  71. } else {
  72. ESP_LOGE(TAG, "Connection failed...");
  73. goto exit;
  74. }
  75. #ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS
  76. /* The TLS session is successfully established, now saving the session ctx for reuse */
  77. if (tls_client_session == NULL) {
  78. tls_client_session = esp_tls_get_client_session(tls);
  79. }
  80. #endif
  81. size_t written_bytes = 0;
  82. do {
  83. ret = esp_tls_conn_write(tls,
  84. REQUEST + written_bytes,
  85. sizeof(REQUEST) - written_bytes);
  86. if (ret >= 0) {
  87. ESP_LOGI(TAG, "%d bytes written", ret);
  88. written_bytes += ret;
  89. } else if (ret != ESP_TLS_ERR_SSL_WANT_READ && ret != ESP_TLS_ERR_SSL_WANT_WRITE) {
  90. ESP_LOGE(TAG, "esp_tls_conn_write returned: [0x%02X](%s)", ret, esp_err_to_name(ret));
  91. goto exit;
  92. }
  93. } while (written_bytes < sizeof(REQUEST));
  94. ESP_LOGI(TAG, "Reading HTTP response...");
  95. do {
  96. len = sizeof(buf) - 1;
  97. bzero(buf, sizeof(buf));
  98. ret = esp_tls_conn_read(tls, (char *)buf, len);
  99. if (ret == ESP_TLS_ERR_SSL_WANT_WRITE || ret == ESP_TLS_ERR_SSL_WANT_READ) {
  100. continue;
  101. }
  102. if (ret < 0) {
  103. ESP_LOGE(TAG, "esp_tls_conn_read returned [-0x%02X](%s)", -ret, esp_err_to_name(ret));
  104. break;
  105. }
  106. if (ret == 0) {
  107. ESP_LOGI(TAG, "connection closed");
  108. break;
  109. }
  110. len = ret;
  111. ESP_LOGD(TAG, "%d bytes read", len);
  112. /* Print response directly to stdout as it is read */
  113. for (int i = 0; i < len; i++) {
  114. putchar(buf[i]);
  115. }
  116. putchar('\n'); // JSON output doesn't have a newline at end
  117. } while (1);
  118. exit:
  119. esp_tls_conn_delete(tls);
  120. for (int countdown = 10; countdown >= 0; countdown--) {
  121. ESP_LOGI(TAG, "%d...", countdown);
  122. vTaskDelay(1000 / portTICK_PERIOD_MS);
  123. }
  124. }
  125. static void https_get_request_using_crt_bundle(void)
  126. {
  127. ESP_LOGI(TAG, "https_request using crt bundle");
  128. esp_tls_cfg_t cfg = {
  129. .crt_bundle_attach = esp_crt_bundle_attach,
  130. };
  131. https_get_request(cfg);
  132. }
  133. static void https_get_request_using_cacert_buf(void)
  134. {
  135. ESP_LOGI(TAG, "https_request using cacert_buf");
  136. esp_tls_cfg_t cfg = {
  137. .cacert_buf = (const unsigned char *) server_root_cert_pem_start,
  138. .cacert_bytes = server_root_cert_pem_end - server_root_cert_pem_start,
  139. };
  140. https_get_request(cfg);
  141. }
  142. static void https_get_request_using_global_ca_store(void)
  143. {
  144. esp_err_t esp_ret = ESP_FAIL;
  145. ESP_LOGI(TAG, "https_request using global ca_store");
  146. esp_ret = esp_tls_set_global_ca_store(server_root_cert_pem_start, server_root_cert_pem_end - server_root_cert_pem_start);
  147. if (esp_ret != ESP_OK) {
  148. ESP_LOGE(TAG, "Error in setting the global ca store: [%02X] (%s),could not complete the https_request using global_ca_store", esp_ret, esp_err_to_name(esp_ret));
  149. return;
  150. }
  151. esp_tls_cfg_t cfg = {
  152. .use_global_ca_store = true,
  153. };
  154. https_get_request(cfg);
  155. esp_tls_free_global_ca_store();
  156. }
  157. #ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS
  158. static void https_get_request_using_already_saved_session(void)
  159. {
  160. ESP_LOGI(TAG, "https_request using saved client session");
  161. esp_tls_cfg_t cfg = {
  162. .client_session = tls_client_session,
  163. };
  164. https_get_request(cfg);
  165. free(tls_client_session);
  166. tls_client_session = NULL;
  167. }
  168. #endif
  169. static void https_request_task(void *pvparameters)
  170. {
  171. ESP_LOGI(TAG, "Start https_request example");
  172. https_get_request_using_crt_bundle();
  173. https_get_request_using_cacert_buf();
  174. https_get_request_using_global_ca_store();
  175. #ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS
  176. https_get_request_using_already_saved_session();
  177. #endif
  178. ESP_LOGI(TAG, "Finish https_request example");
  179. vTaskDelete(NULL);
  180. }
  181. void app_main(void)
  182. {
  183. ESP_ERROR_CHECK( nvs_flash_init() );
  184. ESP_ERROR_CHECK(esp_netif_init());
  185. ESP_ERROR_CHECK(esp_event_loop_create_default());
  186. /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
  187. * Read "Establishing Wi-Fi or Ethernet Connection" section in
  188. * examples/protocols/README.md for more information about this function.
  189. */
  190. ESP_ERROR_CHECK(example_connect());
  191. xTaskCreate(&https_request_task, "https_get_task", 8192, NULL, 5, NULL);
  192. }