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.
This commit is contained in:
Sergio R. Caprile 2025-05-21 16:18:10 -03:00
parent a321c2d096
commit fadf28adb4
3 changed files with 22 additions and 28 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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,