diff options
| author | Anders Betts <anders.betts@gmail.com> | 2026-09-17 21:26:20 +0200 |
|---|---|---|
| committer | Anders Betts <anders.betts@gmail.com> | 2026-09-17 21:26:20 +0200 |
| commit | ed1c15929d2eb2dbc6432986c26661bf1549964a (patch) | |
| tree | 4f04934edef686b19d16e1bb2f79bb5c15e142de /tests/test_core.c | |
| parent | 380195f7cd5e57acf2c1cf2bc41069e6b0b979ed (diff) | |
| download | bokf-0.1.1.tar.gz bokf-0.1.1.zip | |
Add native TLS transport, TLS clients and lego cert sidecarv0.1.1
- bokfd: optional TLS listener (OpenSSL), certificate reload on change
- clients: tls:host:port targets with chain and host verification
- compose: port 8788 and an INWX/lego renewal sidecar
- Makefile: header dependency tracking (-MMD -MP)
Diffstat (limited to 'tests/test_core.c')
| -rw-r--r-- | tests/test_core.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/tests/test_core.c b/tests/test_core.c index db3bfb2..b2c828d 100644 --- a/tests/test_core.c +++ b/tests/test_core.c @@ -1,10 +1,17 @@ +#include <arpa/inet.h> +#include <netinet/in.h> +#include <openssl/ssl.h> +#include <signal.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/socket.h> #include <sys/stat.h> +#include <sys/wait.h> #include <unistd.h> +#include "client.h" #include "config.h" #include "db.h" #include "protocol.h" @@ -170,6 +177,124 @@ static int login(const char *user, const char *pass) return ok; } +static void echo_child(int wfd, int tls) +{ + int sfd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (sfd < 0) + _exit(1); + struct sockaddr_in sa; + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sa.sin_port = 0; + if (bind(sfd, (struct sockaddr *)&sa, sizeof sa) != 0 || + listen(sfd, 1) != 0) + _exit(1); + socklen_t slen = sizeof sa; + if (getsockname(sfd, (struct sockaddr *)&sa, &slen) != 0) + _exit(1); + int port = ntohs(sa.sin_port); + if (write(wfd, &port, sizeof port) != (ssize_t)sizeof port) + _exit(1); + close(wfd); + int cfd = accept(sfd, NULL, NULL); + if (cfd < 0) + _exit(1); + char buf[256]; + if (tls) { + SSL_CTX *ctx = SSL_CTX_new(TLS_server_method()); + if (!ctx || + SSL_CTX_use_certificate_chain_file(ctx, + "tests/tls_test_cert.pem") != 1 || + SSL_CTX_use_PrivateKey_file(ctx, "tests/tls_test_key.pem", + SSL_FILETYPE_PEM) != 1) + _exit(1); + SSL *ssl = SSL_new(ctx); + SSL_set_fd(ssl, cfd); + if (SSL_accept(ssl) != 1) + _exit(1); + size_t got = 0; + while (got < sizeof buf) { + int n = SSL_read(ssl, buf + got, (int)(sizeof buf - got)); + if (n <= 0) + break; + got += (size_t)n; + if (memchr(buf, '\n', got)) + break; + } + (void)SSL_write(ssl, "tls-ok", 6); + SSL_shutdown(ssl); + SSL_free(ssl); + SSL_CTX_free(ctx); + } else { + size_t got = 0; + while (got < sizeof buf) { + ssize_t n = read(cfd, buf + got, sizeof buf - got); + if (n <= 0) + break; + got += (size_t)n; + if (memchr(buf, '\n', got)) + break; + } + (void)write(cfd, "tcp-ok", 6); + } + close(cfd); + close(sfd); + _exit(0); +} + +/* variant 0: plaintext tcp; 1: TLS trusting the test CA; 2: TLS without the + CA, which must fail certificate verification. */ +static void test_transport(void) +{ + signal(SIGPIPE, SIG_IGN); + for (int variant = 0; variant < 3; variant++) { + int tls = variant > 0; + int pfd[2]; + if (pipe(pfd) != 0) { + CHECK(0 && "pipe"); + return; + } + pid_t pid = fork(); + if (pid == 0) { + close(pfd[0]); + echo_child(pfd[1], tls); + } + close(pfd[1]); + int port = 0; + if (read(pfd[0], &port, sizeof port) != (ssize_t)sizeof port) + port = 0; + close(pfd[0]); + if (port <= 0) { + CHECK(0 && "no test server port"); + waitpid(pid, NULL, 0); + continue; + } + if (variant == 1) + setenv("BOKFD_TLS_CA", "tests/tls_test_cert.pem", 1); + else + unsetenv("BOKFD_TLS_CA"); + char target[64]; + snprintf(target, sizeof target, "%s:localhost:%d", + tls ? "tls" : "tcp", port); + struct client_conn c; + if (variant == 2) { + CHECK(client_connect(target, &c) != 0); + waitpid(pid, NULL, 0); + continue; + } + CHECK(client_connect(target, &c) == 0); + CHECK(client_send_line(&c, "{\"v\":1}") == 0); + char *line = client_read_line(&c); + CHECK(line && strncmp(line, tls ? "tls-ok" : "tcp-ok", 6) == 0); + if (!line) + fprintf(stderr, "transport error: %s\n", client_last_error()); + free(line); + client_close(&c); + waitpid(pid, NULL, 0); + } +} + int main(void) { char tmpdir[] = "/tmp/bokf-test-XXXXXX"; @@ -1059,6 +1184,8 @@ int main(void) CHECK(jint(d, "result.checked") > 20); yyjson_doc_free(d); + test_transport(); + /* rate limiting must stay last: it blocks the login key */ for (int i = 0; i < 5; i++) CHECK(!login("admin", "wrong")); |
