Skip to content

Commit 857b34c

Browse files
committed
Merge branch 'bugfix/softap_prov_cookies_v4.0' into 'release/v4.0'
protocomm_httpd: Use HTTP cookies to track session (v4.0) See merge request espressif/esp-idf!12267
2 parents d1c9216 + f132cf2 commit 857b34c

File tree

2 files changed

+73
-28
lines changed

2 files changed

+73
-28
lines changed

components/protocomm/src/security/security1.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ static esp_err_t handle_session_command1(session_t *cur_session,
175175
return ESP_OK;
176176
}
177177

178+
static esp_err_t sec1_new_session(protocomm_security_handle_t handle, uint32_t session_id);
179+
178180
static esp_err_t handle_session_command0(session_t *cur_session,
179181
uint32_t session_id,
180182
SessionData *req, SessionData *resp,
@@ -186,8 +188,9 @@ static esp_err_t handle_session_command0(session_t *cur_session,
186188
int mbed_err;
187189

188190
if (cur_session->state != SESSION_STATE_CMD0) {
189-
ESP_LOGE(TAG, "Invalid state of session %d (expected %d)", SESSION_STATE_CMD0, cur_session->state);
190-
return ESP_ERR_INVALID_STATE;
191+
ESP_LOGW(TAG, "Invalid state of session %d (expected %d). Restarting session.",
192+
SESSION_STATE_CMD0, cur_session->state);
193+
sec1_new_session(cur_session, session_id);
191194
}
192195

193196
if (in->sc0->client_pubkey.len != PUBLIC_KEY_LEN) {

components/protocomm/src/transports/protocomm_httpd.c

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,23 @@
2727
static const char *TAG = "protocomm_httpd";
2828
static protocomm_t *pc_httpd; /* The global protocomm instance for HTTPD */
2929
static bool pc_ext_httpd_handle_provided = false;
30-
static uint32_t session_id = PROTOCOMM_NO_SESSION_ID;
30+
/* The socket session id, which is basically just the socket number */
31+
static uint32_t sock_session_id = PROTOCOMM_NO_SESSION_ID;
32+
/* Cookie session id, which is a random number passed through HTTP cookies */
33+
static uint32_t cookie_session_id = PROTOCOMM_NO_SESSION_ID;
3134

3235
#define MAX_REQ_BODY_LEN 4096
3336

3437
static void protocomm_httpd_session_close(void *ctx)
3538
{
36-
if (pc_httpd->sec && pc_httpd->sec->close_transport_session) {
37-
ESP_LOGW(TAG, "Closing session as socket %d was closed", session_id);
38-
if (pc_httpd->sec->close_transport_session((protocomm_security_handle_t)ctx, session_id) != ESP_OK) {
39-
ESP_LOGW(TAG, "Error closing session with ID: %d", session_id);
40-
}
39+
/* When a socket session closes, we just reset the sock_session_id value.
40+
* Thereafter, only cookie_session_id would get used to check if the subsequent
41+
* request is for the same session.
42+
*/
43+
if (sock_session_id != PROTOCOMM_NO_SESSION_ID) {
44+
ESP_LOGW(TAG, "Resetting socket session id as socket %d was closed", sock_session_id);
45+
sock_session_id = PROTOCOMM_NO_SESSION_ID;
4146
}
42-
session_id = PROTOCOMM_NO_SESSION_ID;
4347
}
4448

4549
static esp_err_t common_post_handler(httpd_req_t *req)
@@ -50,36 +54,66 @@ static esp_err_t common_post_handler(httpd_req_t *req)
5054
const char *ep_name = NULL;
5155
ssize_t outlen;
5256

53-
int cur_session_id = httpd_req_to_sockfd(req);
54-
55-
if (cur_session_id != session_id) {
56-
ESP_LOGD(TAG, "Creating new session: %d", cur_session_id);
57-
/* Initialize new security session */
58-
if (session_id != PROTOCOMM_NO_SESSION_ID) {
59-
ESP_LOGD(TAG, "Closing session with ID: %d", session_id);
60-
/* Presently HTTP server doesn't support callback on socket closure so
61-
* previous session can only be closed when new session is requested */
57+
int cur_sock_session_id = httpd_req_to_sockfd(req);
58+
int cur_cookie_session_id = 0;
59+
char cookie_buf[20] = {0};
60+
bool same_session = false;
61+
62+
/* Check if any cookie is available in the received headers */
63+
if (httpd_req_get_hdr_value_str(req, "Cookie", cookie_buf, sizeof(cookie_buf)) == ESP_OK) {
64+
ESP_LOGD(TAG, "Received cookie %s", cookie_buf);
65+
char session_cookie[20] = {0};
66+
snprintf(session_cookie, sizeof(session_cookie), "session=%u", cookie_session_id);
67+
/* If a cookie is found, check it against the session id. If it matches,
68+
* it means that this is a continuation of the same session.
69+
*/
70+
if (strcmp(session_cookie, cookie_buf) == 0) {
71+
ESP_LOGD(TAG, "Continuing Session %u", cookie_session_id);
72+
cur_cookie_session_id = cookie_session_id;
73+
/* If we reach here, it means that the client supports cookies and so the
74+
* socket session id would no more be required for checking.
75+
*/
76+
sock_session_id = PROTOCOMM_NO_SESSION_ID;
77+
same_session = true;
78+
}
79+
} else if (cur_sock_session_id == sock_session_id) {
80+
/* If the socket number matches, we assume it to be the same session */
81+
ESP_LOGD(TAG, "Continuing Socket Session %u", sock_session_id);
82+
cur_cookie_session_id = cookie_session_id;
83+
same_session = true;
84+
}
85+
if (!same_session) {
86+
/* If the received request is not a continuation of an existing session,
87+
* first close any existing sessions as applicable.
88+
*/
89+
if (cookie_session_id != PROTOCOMM_NO_SESSION_ID) {
90+
ESP_LOGW(TAG, "Closing session with ID: %u", cookie_session_id);
6291
if (pc_httpd->sec && pc_httpd->sec->close_transport_session) {
63-
ret = pc_httpd->sec->close_transport_session(pc_httpd->sec_inst, session_id);
92+
ret = pc_httpd->sec->close_transport_session(pc_httpd->sec_inst, cookie_session_id);
6493
if (ret != ESP_OK) {
65-
ESP_LOGW(TAG, "Error closing session with ID: %d", session_id);
94+
ESP_LOGW(TAG, "Error closing session with ID: %u", cookie_session_id);
6695
}
6796
}
68-
session_id = PROTOCOMM_NO_SESSION_ID;
97+
cookie_session_id = PROTOCOMM_NO_SESSION_ID;
98+
sock_session_id = PROTOCOMM_NO_SESSION_ID;
6999
}
100+
/* Initialize new security session. A random number will be assigned to the session */
101+
cur_cookie_session_id = esp_random();
102+
ESP_LOGD(TAG, "Creating new session: %u", cur_cookie_session_id);
70103
if (pc_httpd->sec && pc_httpd->sec->new_transport_session) {
71-
ret = pc_httpd->sec->new_transport_session(pc_httpd->sec_inst, cur_session_id);
104+
ret = pc_httpd->sec->new_transport_session(pc_httpd->sec_inst, cur_cookie_session_id);
72105
if (ret != ESP_OK) {
73-
ESP_LOGE(TAG, "Failed to launch new session with ID: %d", cur_session_id);
106+
ESP_LOGE(TAG, "Failed to launch new session with ID: %u", cur_cookie_session_id);
74107
ret = ESP_FAIL;
75108
goto out;
76109
}
77110
req->sess_ctx = pc_httpd->sec_inst;
78111
req->free_ctx = protocomm_httpd_session_close;
79112

80113
}
81-
session_id = cur_session_id;
82-
ESP_LOGD(TAG, "New session with ID: %d", cur_session_id);
114+
cookie_session_id = cur_cookie_session_id;
115+
sock_session_id = cur_sock_session_id;
116+
ESP_LOGD(TAG, "New socket session ID: %d", sock_session_id);
83117
}
84118

85119
if (req->content_len <= 0) {
@@ -112,14 +146,20 @@ static esp_err_t common_post_handler(httpd_req_t *req)
112146
/* Extract the endpoint name from URI string of type "/ep_name" */
113147
ep_name = req->uri + 1;
114148

115-
ret = protocomm_req_handle(pc_httpd, ep_name, session_id,
149+
ret = protocomm_req_handle(pc_httpd, ep_name, cookie_session_id,
116150
(uint8_t *)req_body, recv_size, &outbuf, &outlen);
117151

118152
if (ret != ESP_OK) {
119153
ESP_LOGE(TAG, "Data handler failed");
120154
ret = ESP_FAIL;
121155
goto out;
122156
}
157+
/* If this is a new session, send the session id in a cookie */
158+
if (!same_session) {
159+
snprintf(cookie_buf, sizeof(cookie_buf), "session=%u", cookie_session_id);
160+
ESP_LOGD(TAG, "Setting cookie %s", cookie_buf);
161+
httpd_resp_set_hdr(req, "Set-Cookie", cookie_buf);
162+
}
123163

124164
ret = httpd_resp_send(req, (char *)outbuf, outlen);
125165
if (ret != ESP_OK) {
@@ -254,7 +294,8 @@ esp_err_t protocomm_httpd_start(protocomm_t *pc, const protocomm_httpd_config_t
254294
pc->add_endpoint = protocomm_httpd_add_endpoint;
255295
pc->remove_endpoint = protocomm_httpd_remove_endpoint;
256296
pc_httpd = pc;
257-
session_id = PROTOCOMM_NO_SESSION_ID;
297+
cookie_session_id = PROTOCOMM_NO_SESSION_ID;
298+
sock_session_id = PROTOCOMM_NO_SESSION_ID;
258299
return ESP_OK;
259300
}
260301

@@ -270,7 +311,8 @@ esp_err_t protocomm_httpd_stop(protocomm_t *pc)
270311
}
271312
pc_httpd->priv = NULL;
272313
pc_httpd = NULL;
273-
session_id = PROTOCOMM_NO_SESSION_ID;
314+
cookie_session_id = PROTOCOMM_NO_SESSION_ID;
315+
sock_session_id = PROTOCOMM_NO_SESSION_ID;
274316
return ESP_OK;
275317
}
276318
return ESP_ERR_INVALID_ARG;

0 commit comments

Comments
 (0)