diff options
| author | Gab Virebent <gab@virebent.art> | 2026-06-26 19:20:00 +0200 |
|---|---|---|
| committer | Gab Virebent <gab@virebent.art> | 2026-06-26 19:20:00 +0200 |
| commit | fb48d1308d2f63f8e9b23c5d1d921783fa0dacbe (patch) | |
| tree | ceecce2f057cd4ea1e6724305fcd52915939c419 /src | |
| parent | 41c4bfecc770ea7c914e845e4ac3792cb4a473d3 (diff) | |
| download | gmnisrv-fb48d1308d2f63f8e9b23c5d1d921783fa0dacbe.tar.gz gmnisrv-fb48d1308d2f63f8e9b23c5d1d921783fa0dacbe.tar.xz gmnisrv-fb48d1308d2f63f8e9b23c5d1d921783fa0dacbe.zip | |
- 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')
| -rw-r--r-- | src/server.c | 34 | ||||
| -rw-r--r-- | src/tls.c | 23 |
2 files changed, 40 insertions, 17 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; } @@ -140,13 +140,24 @@ tls_host_init(struct gmnisrv_tls *tlsconf, struct gmnisrv_host *host) } X509 *x509 = PEM_read_X509(xf, NULL, NULL, NULL); - fclose(xf); if (!x509) { + fclose(xf); server_error("error loading certificate from %s", crtpath); fclose(kf); return 1; } + // Read any remaining certificates in the PEM file as the intermediate + // chain so CA-signed certs (e.g. Let's Encrypt fullchain.pem) are sent + // to the client for proper validation. + STACK_OF(X509) *chain = sk_X509_new_null(); + X509 *ca; + while ((ca = PEM_read_X509(xf, NULL, NULL, NULL)) != NULL) { + sk_X509_push(chain, ca); + } + ERR_clear_error(); + fclose(xf); + EVP_PKEY *pkey = PEM_read_PrivateKey(kf, NULL, NULL, NULL); fclose(kf); if (!pkey) { @@ -160,12 +171,15 @@ tls_host_init(struct gmnisrv_tls *tlsconf, struct gmnisrv_host *host) assert(r == 1); if (day < 0 || sec < 0) { server_log("%s certificate is expired", host->hostname); + sk_X509_pop_free(chain, X509_free); goto generate; } host->x509 = x509; host->pkey = pkey; - server_log("loaded certificate for %s", host->hostname); + host->chain = chain; + server_log("loaded certificate for %s (%d chain cert(s))", + host->hostname, sk_X509_num(chain)); return 0; generate: @@ -181,7 +195,7 @@ tls_init(struct gmnisrv_config *conf) conf->tls.ssl_ctx = SSL_CTX_new(TLS_server_method()); assert(conf->tls.ssl_ctx); - int r = SSL_CTX_set_min_proto_version(conf->tls.ssl_ctx, TLS1_2_VERSION); + int r = SSL_CTX_set_min_proto_version(conf->tls.ssl_ctx, TLS1_3_VERSION); assert(r == 1); r = SSL_CTX_set_cipher_list(conf->tls.ssl_ctx, @@ -238,4 +252,7 @@ tls_set_host(SSL *ssl, struct gmnisrv_host *host) { SSL_use_certificate(ssl, host->x509); SSL_use_PrivateKey(ssl, host->pkey); + if (host->chain && sk_X509_num(host->chain) > 0) { + SSL_set1_chain(ssl, host->chain); + } } |
