about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2019-11-04 21:31:53 -0500
committerJune McEnroe <june@causal.agency>2019-11-04 21:31:53 -0500
commit41a41808e321aee9601273d533d21af7a4b49d2a (patch)
treea219d4ce547578c2ad0f2bfaf70df1ebaf5d82da
parentZero PASS parameter (diff)
downloadpounce-41a41808e321aee9601273d533d21af7a4b49d2a.tar.gz
pounce-41a41808e321aee9601273d533d21af7a4b49d2a.zip
Add options for TLS client certificate
-rw-r--r--bounce.c12
-rw-r--r--bounce.h3
-rw-r--r--pounce.113
-rw-r--r--server.c39
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;