summaryrefslogtreecommitdiffstats
path: root/src/server.c
diff options
context:
space:
mode:
authorGab Virebent <gab@virebent.art>2026-06-26 19:20:00 +0200
committerGab Virebent <gab@virebent.art>2026-06-26 19:20:00 +0200
commitfb48d1308d2f63f8e9b23c5d1d921783fa0dacbe (patch)
treeceecce2f057cd4ea1e6724305fcd52915939c419 /src/server.c
parent41c4bfecc770ea7c914e845e4ac3792cb4a473d3 (diff)
downloadgmnisrv-fb48d1308d2f63f8e9b23c5d1d921783fa0dacbe.tar.gz
gmnisrv-fb48d1308d2f63f8e9b23c5d1d921783fa0dacbe.tar.xz
gmnisrv-fb48d1308d2f63f8e9b23c5d1d921783fa0dacbe.zip
Serve CA full chain (Let's Encrypt), TLS 1.3, fix handshake buffer overflowHEADmain
- tls.c/config.h: read full PEM chain into STACK_OF(X509), send via SSL_set1_chain - tls.c: minimum protocol TLS 1.2 -> TLS 1.3 - server.c: drain handshake output via local buffer loop instead of staging into the fixed 4 KB client buffer (a full CA chain overflowed it -> assert) - FORK.md: describe the fork
Diffstat (limited to 'src/server.c')
-rw-r--r--src/server.c34
1 files changed, 20 insertions, 14 deletions
diff --git a/src/server.c b/src/server.c
index 359300a..022aa3d 100644
--- a/src/server.c
+++ b/src/server.c
@@ -376,28 +376,34 @@ client_readable(struct gmnisrv_server *server, struct gmnisrv_client *client)
return CONNECTED;
queue_ssl_write:
- client->bufln = 0;
- client->state = CLIENT_STATE_SSL;
- client->next = CLIENT_STATE_REQUEST;
+ // Flush all pending TLS output (e.g. the ServerHello/Certificate
+ // handshake flight) directly to the socket, draining the write BIO via
+ // a local buffer in a loop. A full CA certificate chain can exceed
+ // sizeof(client->buf), so it must not be staged into the fixed-size
+ // client buffer (that overflowed and aborted on assert).
do {
- assert(client->bufln < sizeof(client->buf));
- r = BIO_read(client->wbio,
- &client->buf[client->bufln],
- sizeof(client->buf) - client->bufln);
- if (r <= 0) {
- if (BIO_should_retry(client->wbio)) {
- continue;
- }
+ r = BIO_read(client->wbio, buf, sizeof(buf));
+ if (r < 0 && !BIO_should_retry(client->wbio)) {
client_error(&client->addr,
"BIO read error: %s",
ERR_error_string(r, NULL));
disconnect_client(server, client);
return DISCONNECTED;
- } else {
- client->bufln += r;
- client->pollfd->events = POLLOUT;
+ }
+ for (int ww = 0; ww < r; ) {
+ int q = write(client->sockfd, &buf[ww], r - ww);
+ if (q < 0) {
+ client_error(&client->addr,
+ "client write: %s",
+ strerror(errno));
+ disconnect_client(server, client);
+ return DISCONNECTED;
+ }
+ ww += q;
}
} while (r > 0);
+ client->state = CLIENT_STATE_REQUEST;
+ client->pollfd->events = POLLIN;
return CONNECTED;
}