From fadf28adb425cf5efc7122ed26298e2a9d26ad84 Mon Sep 17 00:00:00 2001 From: "Sergio R. Caprile" Date: Wed, 21 May 2025 16:18:10 -0300 Subject: [PATCH] Make built-in TLS play fair to TCP Handshake functions in Mongoose TLS assumed data was being fully sent after calling mg_io_send(). This was in fact the case with the usual 1460-bytes MSS, but not with the default 536-bytes MSS. This PR removes all those calls from individual handshake functions, actual send is done at the main handshake function, keeping track of the amount of data sent, and so handling small MTUs/MSSs and possible MG_IO_WAITs when running over a socket layer. --- mongoose.c | 25 +++++++++++-------------- src/net_builtin.c | 2 +- src/tls_builtin.c | 23 ++++++++++------------- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/mongoose.c b/mongoose.c index 4b5ce8d9..c0c25f19 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4745,7 +4745,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn, return NULL; } struct connstate *s = (struct connstate *) (c + 1); - s->dmss = 1460; // TODO(scaprile): 536; // assume default, RFC-9293 3.7.1 + s->dmss = 536; // assume default, RFC-9293 3.7.1 s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq); memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); settmout(c, MIP_TTYPE_KEEPALIVE); @@ -10864,12 +10864,12 @@ enum mg_tls_hs_state { MG_TLS_STATE_CLIENT_WAIT_EE, // Wait for EncryptedExtensions MG_TLS_STATE_CLIENT_WAIT_CERT, // Wait for Certificate MG_TLS_STATE_CLIENT_WAIT_CV, // Wait for CertificateVerify - MG_TLS_STATE_CLIENT_WAIT_FINISHED, // Wait for Finished + MG_TLS_STATE_CLIENT_WAIT_FINISH, // Wait for Finish MG_TLS_STATE_CLIENT_CONNECTED, // Done // Server state machine: MG_TLS_STATE_SERVER_START, // Wait for ClientHello - MG_TLS_STATE_SERVER_NEGOTIATED, // Wait for Finished + MG_TLS_STATE_SERVER_NEGOTIATED, // Wait for Finish MG_TLS_STATE_SERVER_CONNECTED // Done }; @@ -11599,7 +11599,6 @@ static void mg_tls_send_cert_verify(struct mg_connection *c, int is_client) { static void mg_tls_server_send_finish(struct mg_connection *c) { struct tls_data *tls = (struct tls_data *) c->tls; - struct mg_iobuf *wio = &tls->send; mg_sha256_ctx sha256; uint8_t hash[32]; uint8_t finish[36] = {0x14, 0, 0, 32}; @@ -11607,9 +11606,6 @@ static void mg_tls_server_send_finish(struct mg_connection *c) { mg_sha256_final(hash, &sha256); mg_hmac_sha256(finish + 4, tls->enc.server_finished_key, 32, hash, 32); mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE); - mg_io_send(c, wio->buf, wio->len); - wio->len = 0; - mg_sha256_update(&tls->sha256, finish, sizeof(finish)); } @@ -11734,8 +11730,6 @@ static void mg_tls_client_send_hello(struct mg_connection *c) { // change cipher message mg_iobuf_add(wio, wio->len, (const char *) "\x14\x03\x03\x00\x01\x01", 6); - mg_io_send(c, wio->buf, wio->len); - wio->len = 0; } static int mg_tls_client_recv_hello(struct mg_connection *c) { @@ -12284,7 +12278,6 @@ static int mg_tls_client_recv_finish(struct mg_connection *c) { static void mg_tls_client_send_finish(struct mg_connection *c) { struct tls_data *tls = (struct tls_data *) c->tls; - struct mg_iobuf *wio = &tls->send; mg_sha256_ctx sha256; uint8_t hash[32]; uint8_t finish[36] = {0x14, 0, 0, 32}; @@ -12292,8 +12285,6 @@ static void mg_tls_client_send_finish(struct mg_connection *c) { mg_sha256_final(hash, &sha256); mg_hmac_sha256(finish + 4, tls->enc.client_finished_key, 32, hash, 32); mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE); - mg_io_send(c, wio->buf, wio->len); - wio->len = 0; } static void mg_tls_client_handshake(struct mg_connection *c) { @@ -12325,9 +12316,9 @@ static void mg_tls_client_handshake(struct mg_connection *c) { if (mg_tls_client_recv_cert_verify(c) < 0) { break; } - tls->state = MG_TLS_STATE_CLIENT_WAIT_FINISHED; + tls->state = MG_TLS_STATE_CLIENT_WAIT_FINISH; // Fallthrough - case MG_TLS_STATE_CLIENT_WAIT_FINISHED: + case MG_TLS_STATE_CLIENT_WAIT_FINISH: if (mg_tls_client_recv_finish(c) < 0) { break; } @@ -12388,11 +12379,17 @@ static void mg_tls_server_handshake(struct mg_connection *c) { } void mg_tls_handshake(struct mg_connection *c) { + struct tls_data *tls = (struct tls_data *) c->tls; + long n; if (c->is_client) { mg_tls_client_handshake(c); } else { mg_tls_server_handshake(c); } + while (tls->send.len > 0 && + (n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) { + mg_iobuf_del(&tls->send, 0, (size_t) n); + } } static int mg_parse_pem(const struct mg_str pem, const struct mg_str label, diff --git a/src/net_builtin.c b/src/net_builtin.c index d2b90299..c027e57e 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -580,7 +580,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn, return NULL; } struct connstate *s = (struct connstate *) (c + 1); - s->dmss = 1460; // TODO(scaprile): 536; // assume default, RFC-9293 3.7.1 + s->dmss = 536; // assume default, RFC-9293 3.7.1 s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq); memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); settmout(c, MIP_TTYPE_KEEPALIVE); diff --git a/src/tls_builtin.c b/src/tls_builtin.c index df73e92b..e983687d 100644 --- a/src/tls_builtin.c +++ b/src/tls_builtin.c @@ -39,12 +39,12 @@ enum mg_tls_hs_state { MG_TLS_STATE_CLIENT_WAIT_EE, // Wait for EncryptedExtensions MG_TLS_STATE_CLIENT_WAIT_CERT, // Wait for Certificate MG_TLS_STATE_CLIENT_WAIT_CV, // Wait for CertificateVerify - MG_TLS_STATE_CLIENT_WAIT_FINISHED, // Wait for Finished + MG_TLS_STATE_CLIENT_WAIT_FINISH, // Wait for Finish MG_TLS_STATE_CLIENT_CONNECTED, // Done // Server state machine: MG_TLS_STATE_SERVER_START, // Wait for ClientHello - MG_TLS_STATE_SERVER_NEGOTIATED, // Wait for Finished + MG_TLS_STATE_SERVER_NEGOTIATED, // Wait for Finish MG_TLS_STATE_SERVER_CONNECTED // Done }; @@ -774,7 +774,6 @@ static void mg_tls_send_cert_verify(struct mg_connection *c, int is_client) { static void mg_tls_server_send_finish(struct mg_connection *c) { struct tls_data *tls = (struct tls_data *) c->tls; - struct mg_iobuf *wio = &tls->send; mg_sha256_ctx sha256; uint8_t hash[32]; uint8_t finish[36] = {0x14, 0, 0, 32}; @@ -782,9 +781,6 @@ static void mg_tls_server_send_finish(struct mg_connection *c) { mg_sha256_final(hash, &sha256); mg_hmac_sha256(finish + 4, tls->enc.server_finished_key, 32, hash, 32); mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE); - mg_io_send(c, wio->buf, wio->len); - wio->len = 0; - mg_sha256_update(&tls->sha256, finish, sizeof(finish)); } @@ -909,8 +905,6 @@ static void mg_tls_client_send_hello(struct mg_connection *c) { // change cipher message mg_iobuf_add(wio, wio->len, (const char *) "\x14\x03\x03\x00\x01\x01", 6); - mg_io_send(c, wio->buf, wio->len); - wio->len = 0; } static int mg_tls_client_recv_hello(struct mg_connection *c) { @@ -1459,7 +1453,6 @@ static int mg_tls_client_recv_finish(struct mg_connection *c) { static void mg_tls_client_send_finish(struct mg_connection *c) { struct tls_data *tls = (struct tls_data *) c->tls; - struct mg_iobuf *wio = &tls->send; mg_sha256_ctx sha256; uint8_t hash[32]; uint8_t finish[36] = {0x14, 0, 0, 32}; @@ -1467,8 +1460,6 @@ static void mg_tls_client_send_finish(struct mg_connection *c) { mg_sha256_final(hash, &sha256); mg_hmac_sha256(finish + 4, tls->enc.client_finished_key, 32, hash, 32); mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE); - mg_io_send(c, wio->buf, wio->len); - wio->len = 0; } static void mg_tls_client_handshake(struct mg_connection *c) { @@ -1500,9 +1491,9 @@ static void mg_tls_client_handshake(struct mg_connection *c) { if (mg_tls_client_recv_cert_verify(c) < 0) { break; } - tls->state = MG_TLS_STATE_CLIENT_WAIT_FINISHED; + tls->state = MG_TLS_STATE_CLIENT_WAIT_FINISH; // Fallthrough - case MG_TLS_STATE_CLIENT_WAIT_FINISHED: + case MG_TLS_STATE_CLIENT_WAIT_FINISH: if (mg_tls_client_recv_finish(c) < 0) { break; } @@ -1563,11 +1554,17 @@ static void mg_tls_server_handshake(struct mg_connection *c) { } void mg_tls_handshake(struct mg_connection *c) { + struct tls_data *tls = (struct tls_data *) c->tls; + long n; if (c->is_client) { mg_tls_client_handshake(c); } else { mg_tls_server_handshake(c); } + while (tls->send.len > 0 && + (n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) { + mg_iobuf_del(&tls->send, 0, (size_t) n); + } } static int mg_parse_pem(const struct mg_str pem, const struct mg_str label,