From 41a41808e321aee9601273d533d21af7a4b49d2a Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Mon, 4 Nov 2019 21:31:53 -0500 Subject: Add options for TLS client certificate --- bounce.c | 12 ++++++++++-- bounce.h | 3 ++- pounce.1 | 13 +++++++++++++ server.c | 39 +++++++++++++++++++++++++++++++++------ 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/bounce.c b/bounce.c index 889ed5b..0e7e421 100644 --- a/bounce.c +++ b/bounce.c @@ -190,6 +190,8 @@ int main(int argc, char *argv[]) { size_t ring = 4096; bool insecure = false; + const char *clientCert = NULL; + const char *clientPriv = NULL; const char *host = NULL; const char *port = "6697"; char *pass = NULL; @@ -201,7 +203,7 @@ int main(int argc, char *argv[]) { const char *away = "pounced :3"; const char *quit = "connection reset by purr"; - const char *Opts = "!A:C:H:K:NP:Q:U:W:a:f:h:j:n:p:r:s:u:vw:x"; + const char *Opts = "!A:C:H:K:NP:Q:U:W:a:c:f:h:j:k:n:p:r:s:u:vw:x"; const struct option LongOpts[] = { { "insecure", no_argument, NULL, '!' }, { "away", required_argument, NULL, 'A' }, @@ -214,9 +216,11 @@ int main(int argc, char *argv[]) { { "bind-path", required_argument, NULL, 'U' }, { "client-pass", required_argument, NULL, 'W' }, { "sasl", required_argument, NULL, 'a' }, + { "client-cert", required_argument, NULL, 'c' }, { "save", required_argument, NULL, 'f' }, { "host", required_argument, NULL, 'h' }, { "join", required_argument, NULL, 'j' }, + { "client-key", required_argument, NULL, 'k' }, { "nick", required_argument, NULL, 'n' }, { "port", required_argument, NULL, 'p' }, { "real", required_argument, NULL, 'r' }, @@ -241,9 +245,11 @@ int main(int argc, char *argv[]) { break; case 'U': strlcpy(bindPath, optarg, sizeof(bindPath)); break; case 'W': clientPass = optarg; break; case 'a': auth = optarg; + break; case 'c': clientCert = optarg; break; case 'f': save = optarg; break; case 'h': host = optarg; break; case 'j': join = optarg; + break; case 'k': clientPriv = optarg; break; case 'n': nick = optarg; break; case 'p': port = optarg; break; case 'r': real = optarg; @@ -298,7 +304,9 @@ int main(int argc, char *argv[]) { size_t binds = bindPath[0] ? listenUnix(bind, ARRAY_LEN(bind), bindPath) : listenBind(bind, ARRAY_LEN(bind), bindHost, bindPort); - int server = serverConnect(insecure, host, port); + + serverConfig(insecure, clientCert, clientPriv); + int server = serverConnect(host, port); #ifdef __FreeBSD__ int error = cap_enter(); diff --git a/bounce.h b/bounce.h index 129dd7b..33c1fee 100644 --- a/bounce.h +++ b/bounce.h @@ -79,7 +79,8 @@ size_t listenBind(int fds[], size_t cap, const char *host, const char *port); size_t listenUnix(int fds[], size_t cap, const char *path); struct tls *listenAccept(int *fd, int bind); -int serverConnect(bool insecure, const char *host, const char *port); +void serverConfig(bool insecure, const char *cert, const char *priv); +int serverConnect(const char *host, const char *port); void serverRecv(void); void serverSend(const char *ptr, size_t len); void serverFormat(const char *format, ...) diff --git a/pounce.1 b/pounce.1 index a18cb98..213575b 100644 --- a/pounce.1 +++ b/pounce.1 @@ -18,9 +18,11 @@ .Op Fl U Ar path .Op Fl W Ar pass .Op Fl a Ar auth +.Op Fl c Ar path .Op Fl f Ar path .Op Fl h Ar host .Op Fl j Ar chan +.Op Fl k Ar path .Op Fl n Ar nick .Op Fl p Ar port .Op Fl r Ar real @@ -138,6 +140,13 @@ with .Ar pass using SASL PLAIN. . +.It Fl c Ar path , Cm client-cert = Ar path +Authenticate using the TLS client certificate at +.Ar path . +If the certificate key is in a separate file, +set it with +.Fl k . +. .It Fl f Ar path , Cm save = Ar path Load the contents of the buffer from .Ar path , @@ -155,6 +164,10 @@ Connect to Join the comma-separated list of .Ar chan . . +.It Fl k Ar path , Cm client-key = Ar path +Authenticate using the TLS client certificate key at +.Ar path . +. .It Fl n Ar nick , Cm nick = Ar nick Set nickname to .Ar nick . diff --git a/server.c b/server.c index e23dc9a..5ca517c 100644 --- a/server.c +++ b/server.c @@ -31,24 +31,51 @@ static struct tls *client; -int serverConnect(bool insecure, const char *host, const char *port) { - int error; - +void serverConfig(bool insecure, const char *cert, const char *priv) { struct tls_config *config = tls_config_new(); - error = tls_config_set_ciphers(config, "compat"); - if (error) errx(EX_SOFTWARE, "tls_config"); + if (!config) errx(EX_SOFTWARE, "tls_config_new"); + + int error = tls_config_set_ciphers(config, "compat"); + if (error) { + errx(EX_SOFTWARE, "tls_config_set_ciphers: %s", tls_config_error(config)); + } if (insecure) { tls_config_insecure_noverifycert(config); tls_config_insecure_noverifyname(config); } + if (cert) { + error = tls_config_set_cert_file(config, cert); + if (error) { + errx( + EX_SOFTWARE, "tls_config_set_cert_file: %s", + tls_config_error(config) + ); + } + } + + if (cert && !priv) priv = cert; + if (priv) { + error = tls_config_set_key_file(config, priv); + if (error) { + errx( + EX_SOFTWARE, "tls_config_set_key_file: %s", + tls_config_error(config) + ); + } + } + client = tls_client(); if (!client) errx(EX_SOFTWARE, "tls_client"); error = tls_configure(client, config); if (error) errx(EX_SOFTWARE, "tls_configure: %s", tls_error(client)); tls_config_free(config); +} + +int serverConnect(const char *host, const char *port) { + assert(client); struct addrinfo *head; struct addrinfo hints = { @@ -56,7 +83,7 @@ int serverConnect(bool insecure, const char *host, const char *port) { .ai_socktype = SOCK_STREAM, .ai_protocol = IPPROTO_TCP, }; - error = getaddrinfo(host, port, &hints, &head); + int error = getaddrinfo(host, port, &hints, &head); if (error) errx(EX_NOHOST, "%s:%s: %s", host, port, gai_strerror(error)); int sock = -1; -- cgit 1.4.1