https_server.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. * SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <string.h>
  7. #include "esp_https_server.h"
  8. #include "esp_log.h"
  9. #include "sdkconfig.h"
  10. #include "esp_tls.h"
  11. const static char *TAG = "esp_https_server";
  12. typedef struct httpd_ssl_ctx {
  13. esp_tls_cfg_server_t *tls_cfg;
  14. httpd_open_func_t open_fn;
  15. esp_https_server_user_cb *user_cb;
  16. } httpd_ssl_ctx_t;
  17. typedef struct httpd_ssl_transport_ctx {
  18. esp_tls_t *tls;
  19. httpd_ssl_ctx_t *global_ctx;
  20. } httpd_ssl_transport_ctx_t;
  21. /**
  22. * SSL socket close handler
  23. *
  24. * @param[in] ctx - session transport context (SSL context we stored there)
  25. */
  26. static void httpd_ssl_close(void *ctx)
  27. {
  28. assert(ctx != NULL);
  29. httpd_ssl_transport_ctx_t *transport_ctx = (httpd_ssl_transport_ctx_t *)ctx;
  30. httpd_ssl_ctx_t *global_ctx = transport_ctx->global_ctx;
  31. esp_tls_t *tls = transport_ctx->tls;
  32. if (global_ctx->user_cb) {
  33. esp_https_server_user_cb_arg_t user_cb_data = {0};
  34. user_cb_data.user_cb_state = HTTPD_SSL_USER_CB_SESS_CLOSE;
  35. user_cb_data.tls = tls;
  36. (global_ctx->user_cb)((void *)&user_cb_data);
  37. }
  38. esp_tls_server_session_delete(tls);
  39. free(ctx);
  40. ESP_LOGD(TAG, "Secure socket closed");
  41. }
  42. /**
  43. * SSL socket pending-check function
  44. *
  45. * @param server
  46. * @param sockfd
  47. * @return number of pending bytes, negative on error
  48. */
  49. static int httpd_ssl_pending(httpd_handle_t server, int sockfd)
  50. {
  51. httpd_ssl_transport_ctx_t *transport_ctx = httpd_sess_get_transport_ctx(server, sockfd);
  52. assert(transport_ctx != NULL);
  53. esp_tls_t *tls = transport_ctx->tls;
  54. assert(tls != NULL);
  55. return esp_tls_get_bytes_avail(tls);
  56. }
  57. /**
  58. * Receive from a SSL socket
  59. *
  60. * @param server
  61. * @param sockfd
  62. * @param buf
  63. * @param buf_len
  64. * @param flags
  65. * @return bytes read, negative on error
  66. */
  67. static int httpd_ssl_recv(httpd_handle_t server, int sockfd, char *buf, size_t buf_len, int flags)
  68. {
  69. httpd_ssl_transport_ctx_t *transport_ctx = httpd_sess_get_transport_ctx(server, sockfd);
  70. assert(transport_ctx != NULL);
  71. esp_tls_t *tls = transport_ctx->tls;
  72. assert(tls != NULL);
  73. return esp_tls_conn_read(tls, buf, buf_len);
  74. }
  75. /**
  76. * Send to a SSL socket
  77. *
  78. * @param server
  79. * @param sockfd
  80. * @param buf
  81. * @param buf_len
  82. * @param flags
  83. * @return bytes sent, negative on error
  84. */
  85. static int httpd_ssl_send(httpd_handle_t server, int sockfd, const char *buf, size_t buf_len, int flags)
  86. {
  87. httpd_ssl_transport_ctx_t *transport_ctx = httpd_sess_get_transport_ctx(server, sockfd);
  88. assert(transport_ctx != NULL);
  89. esp_tls_t *tls = transport_ctx->tls;
  90. assert(tls != NULL);
  91. return esp_tls_conn_write(tls, buf, buf_len);
  92. }
  93. /**
  94. * Open a SSL socket for the server.
  95. * The fd is already open and ready to read / write raw data.
  96. *
  97. * @param server
  98. * @param sockfd - raw socket fd
  99. * @return success
  100. */
  101. static esp_err_t httpd_ssl_open(httpd_handle_t server, int sockfd)
  102. {
  103. assert(server != NULL);
  104. // Retrieve the SSL context from the global context field (set in config)
  105. httpd_ssl_ctx_t *global_ctx = httpd_get_global_transport_ctx(server);
  106. assert(global_ctx != NULL);
  107. esp_tls_t *tls = esp_tls_init();
  108. if (!tls) {
  109. return ESP_ERR_NO_MEM;
  110. }
  111. ESP_LOGI(TAG, "performing session handshake");
  112. int ret = esp_tls_server_session_create(global_ctx->tls_cfg, sockfd, tls);
  113. if (ret != 0) {
  114. ESP_LOGE(TAG, "esp_tls_create_server_session failed");
  115. goto fail;
  116. }
  117. // Pass a new structure containing the global context and the tls pointer to httpd_ssl_close
  118. // Store it in the context field of the HTTPD session object
  119. // NOTE: allocated memory will be freed by httpd_ssl_close
  120. httpd_ssl_transport_ctx_t *transport_ctx = (httpd_ssl_transport_ctx_t *)calloc(1, sizeof(httpd_ssl_transport_ctx_t));
  121. if (!transport_ctx) {
  122. return ESP_ERR_NO_MEM;
  123. }
  124. transport_ctx->tls = tls;
  125. transport_ctx->global_ctx = global_ctx;
  126. // Store the SSL session into the context field of the HTTPD session object
  127. httpd_sess_set_transport_ctx(server, sockfd, transport_ctx, httpd_ssl_close);
  128. // Set rx/tx/pending override functions
  129. httpd_sess_set_send_override(server, sockfd, httpd_ssl_send);
  130. httpd_sess_set_recv_override(server, sockfd, httpd_ssl_recv);
  131. httpd_sess_set_pending_override(server, sockfd, httpd_ssl_pending);
  132. // all access should now go through SSL
  133. ESP_LOGD(TAG, "Secure socket open");
  134. if (global_ctx->open_fn) {
  135. (global_ctx->open_fn)(server, sockfd);
  136. }
  137. if (global_ctx->user_cb) {
  138. esp_https_server_user_cb_arg_t user_cb_data = {0};
  139. user_cb_data.user_cb_state = HTTPD_SSL_USER_CB_SESS_CREATE;
  140. user_cb_data.tls = tls;
  141. (global_ctx->user_cb)((void *)&user_cb_data);
  142. }
  143. return ESP_OK;
  144. fail:
  145. esp_tls_server_session_delete(tls);
  146. return ESP_FAIL;
  147. }
  148. /**
  149. * Tear down the HTTPD global transport context
  150. *
  151. * @param ctx
  152. */
  153. static void free_secure_context(void *ctx)
  154. {
  155. assert(ctx != NULL);
  156. httpd_ssl_ctx_t *ssl_ctx = ctx;
  157. esp_tls_cfg_server_t *cfg = ssl_ctx->tls_cfg;
  158. ESP_LOGI(TAG, "Server shuts down, releasing SSL context");
  159. if (cfg->cacert_buf) {
  160. free((void *)cfg->cacert_buf);
  161. }
  162. if (cfg->servercert_buf) {
  163. free((void *)cfg->servercert_buf);
  164. }
  165. if (cfg->serverkey_buf) {
  166. free((void *)cfg->serverkey_buf);
  167. }
  168. esp_tls_cfg_server_session_tickets_free(cfg);
  169. free(cfg);
  170. free(ssl_ctx);
  171. }
  172. static httpd_ssl_ctx_t *create_secure_context(const struct httpd_ssl_config *config)
  173. {
  174. httpd_ssl_ctx_t *ssl_ctx = calloc(1, sizeof(httpd_ssl_ctx_t));
  175. if (!ssl_ctx) {
  176. return NULL;
  177. }
  178. esp_tls_cfg_server_t *cfg = (esp_tls_cfg_server_t *)calloc(1, sizeof(esp_tls_cfg_server_t));
  179. if (!cfg) {
  180. free(ssl_ctx);
  181. return NULL;
  182. }
  183. if (config->session_tickets) {
  184. if ( esp_tls_cfg_server_session_tickets_init(cfg) != ESP_OK ) {
  185. ESP_LOGE(TAG, "Failed to init session ticket support");
  186. free(ssl_ctx);
  187. free(cfg);
  188. return NULL;
  189. }
  190. }
  191. ssl_ctx->tls_cfg = cfg;
  192. ssl_ctx->user_cb = config->user_cb;
  193. /* cacert = CA which signs client cert, or client cert itself */
  194. if(config->cacert_pem != NULL) {
  195. cfg->cacert_buf = (unsigned char *)malloc(config->cacert_len);
  196. if (!cfg->cacert_buf) {
  197. ESP_LOGE(TAG, "Could not allocate memory");
  198. free(cfg);
  199. free(ssl_ctx);
  200. return NULL;
  201. }
  202. memcpy((char *)cfg->cacert_buf, config->cacert_pem, config->cacert_len);
  203. cfg->cacert_bytes = config->cacert_len;
  204. }
  205. /* servercert = cert of server itself */
  206. cfg->servercert_buf = (unsigned char *)malloc(config->servercert_len);
  207. if (!cfg->servercert_buf) {
  208. ESP_LOGE(TAG, "Could not allocate memory");
  209. free((void *)cfg->cacert_buf);
  210. free(cfg);
  211. free(ssl_ctx);
  212. return NULL;
  213. }
  214. memcpy((char *)cfg->servercert_buf, config->servercert, config->servercert_len);
  215. cfg->servercert_bytes = config->servercert_len;
  216. /* Pass on secure element boolean */
  217. cfg->use_secure_element = config->use_secure_element;
  218. if (!cfg->use_secure_element) {
  219. cfg->serverkey_buf = (unsigned char *)malloc(config->prvtkey_len);
  220. if (!cfg->serverkey_buf) {
  221. ESP_LOGE(TAG, "Could not allocate memory");
  222. free((void *)cfg->servercert_buf);
  223. free((void *)cfg->cacert_buf);
  224. free(cfg);
  225. free(ssl_ctx);
  226. return NULL;
  227. }
  228. }
  229. memcpy((char *)cfg->serverkey_buf, config->prvtkey_pem, config->prvtkey_len);
  230. cfg->serverkey_bytes = config->prvtkey_len;
  231. return ssl_ctx;
  232. }
  233. /** Start the server */
  234. esp_err_t httpd_ssl_start(httpd_handle_t *pHandle, struct httpd_ssl_config *config)
  235. {
  236. assert(config != NULL);
  237. assert(pHandle != NULL);
  238. ESP_LOGI(TAG, "Starting server");
  239. if (HTTPD_SSL_TRANSPORT_SECURE == config->transport_mode) {
  240. httpd_ssl_ctx_t *ssl_ctx = create_secure_context(config);
  241. if (!ssl_ctx) {
  242. return -1;
  243. }
  244. ESP_LOGD(TAG, "SSL context ready");
  245. // set SSL specific config
  246. config->httpd.global_transport_ctx = ssl_ctx;
  247. config->httpd.global_transport_ctx_free_fn = free_secure_context;
  248. if (config->httpd.open_fn) {
  249. // since the httpd's open_fn is used for opening the SSL session, we save the configured
  250. // user pointer and call it upon opening the ssl socket
  251. ssl_ctx->open_fn = config->httpd.open_fn;
  252. }
  253. config->httpd.open_fn = httpd_ssl_open; // the open function configures the created SSL sessions
  254. config->httpd.server_port = config->port_secure;
  255. } else {
  256. ESP_LOGD(TAG, "SSL disabled, using plain HTTP");
  257. config->httpd.server_port = config->port_insecure;
  258. }
  259. httpd_handle_t handle = NULL;
  260. esp_err_t ret = httpd_start(&handle, &config->httpd);
  261. if (ret != ESP_OK) return ret;
  262. *pHandle = handle;
  263. ESP_LOGI(TAG, "Server listening on port %d", config->httpd.server_port);
  264. return ESP_OK;
  265. }
  266. /** Stop the server */
  267. esp_err_t httpd_ssl_stop(httpd_handle_t handle)
  268. {
  269. return httpd_stop(handle);
  270. }