summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--bounce.c16
-rw-r--r--bounce.h5
-rw-r--r--pounce.140
-rw-r--r--server.c20
4 files changed, 77 insertions, 4 deletions
diff --git a/bounce.c b/bounce.c
index 9854145..31ca4a6 100644
--- a/bounce.c
+++ b/bounce.c
@@ -206,6 +206,8 @@ int main(int argc, char *argv[]) {
 	const char *genPath = NULL;
 
 	bool insecure = false;
+	bool printCert = false;
+	const char *trust = NULL;
 	const char *clientCert = NULL;
 	const char *clientPriv = NULL;
 	const char *serverBindHost = NULL;
@@ -246,10 +248,12 @@ int main(int argc, char *argv[]) {
 		{ .val = 'j', .name = "join", required_argument },
 		{ .val = 'k', .name = "client-priv", required_argument },
 		{ .val = 'n', .name = "nick", required_argument },
+		{ .val = 'o', .name = "print-cert", no_argument },
 		{ .val = 'p', .name = "port", required_argument },
 		{ .val = 'q', .name = "quit", required_argument },
 		{ .val = 'r', .name = "real", required_argument },
 		{ .val = 's', .name = "size", required_argument },
+		{ .val = 't', .name = "trust", required_argument },
 		{ .val = 'u', .name = "user", required_argument },
 		{ .val = 'v', .name = "verbose", no_argument },
 		{ .val = 'w', .name = "pass", required_argument },
@@ -288,10 +292,12 @@ int main(int argc, char *argv[]) {
 			break; case 'j': join = optarg;
 			break; case 'k': clientPriv = optarg;
 			break; case 'n': nick = optarg;
+			break; case 'o': insecure = true; printCert = true;
 			break; case 'p': port = optarg;
 			break; case 'q': quit = optarg;
 			break; case 'r': real = optarg;
 			break; case 's': ringSize = parseSize(optarg);
+			break; case 't': trust = optarg;
 			break; case 'u': user = optarg;
 			break; case 'v': verbose = true;
 			break; case 'w': pass = optarg;
@@ -341,6 +347,7 @@ int main(int argc, char *argv[]) {
 	unveilConfig(certPath);
 	unveilConfig(privPath);
 	if (caPath) unveilConfig(caPath);
+	if (trust) unveilConfig(trust);
 	if (clientCert) unveilConfig(clientCert);
 	if (clientPriv) unveilConfig(clientPriv);
 	if (savePath) unveilData(savePath);
@@ -353,6 +360,13 @@ int main(int argc, char *argv[]) {
 	if (error) err(EX_OSERR, "pledge");
 #endif
 
+	if (printCert) {
+		serverConfig(insecure, trust, clientCert, clientPriv);
+		serverConnect(serverBindHost, host, port);
+		serverPrintCert();
+		return EX_OK;
+	}
+
 	// Either exit with cleanup or ignore signals until entering the main loop.
 	signal(SIGINT, justExit);
 	signal(SIGTERM, justExit);
@@ -406,7 +420,7 @@ int main(int argc, char *argv[]) {
 		? localUnix(bind, ARRAY_LEN(bind), bindPath)
 		: localBind(bind, ARRAY_LEN(bind), bindHost, bindPort);
 
-	serverConfig(insecure, clientCert, clientPriv);
+	serverConfig(insecure, trust, clientCert, clientPriv);
 	int server = serverConnect(serverBindHost, host, port);
 
 #ifdef __FreeBSD__
diff --git a/bounce.h b/bounce.h
index d08f21f..2bcd77c 100644
--- a/bounce.h
+++ b/bounce.h
@@ -174,8 +174,11 @@ size_t localUnix(int fds[], size_t cap, const char *path);
 int localAccept(struct tls **tls, int bind);
 
 extern struct timeval serverQueueInterval;
-void serverConfig(bool insecure, const char *cert, const char *priv);
+void serverConfig(
+	bool insecure, const char *trust, const char *cert, const char *priv
+);
 int serverConnect(const char *bindHost, const char *host, const char *port);
+void serverPrintCert(void);
 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 8c4107d..caeb243 100644
--- a/pounce.1
+++ b/pounce.1
@@ -1,4 +1,4 @@
-.Dd August 28, 2020
+.Dd January 11, 2021
 .Dt POUNCE 1
 .Os
 .
@@ -29,6 +29,7 @@
 .Op Fl p Ar port
 .Op Fl q Ar quit
 .Op Fl r Ar real
+.Op Fl t Ar trust
 .Op Fl s Ar size
 .Op Fl u Ar user
 .Op Fl w Ar pass
@@ -36,6 +37,13 @@
 .Op Ar config ...
 .
 .Nm
+.Fl o
+.Op Fl S Ar bind
+.Op Fl h Ar host
+.Op Fl p Ar port
+.Op Ar config ...
+.
+.Nm
 .Op Fl A Ar ca
 .Fl g Ar cert
 .
@@ -300,6 +308,11 @@ Set nickname to
 .Ar nick .
 The default nickname is the user's name.
 .
+.It Fl o
+Print the server certificate chain
+to standard output in PEM format
+and exit.
+.
 .It Fl p Ar port , Cm port = Ar port
 Connect to
 .Ar port .
@@ -321,6 +334,13 @@ Set the number of messages contained in the buffer to
 The size must be a power of two.
 The default size is 4096.
 .
+.It Fl t Ar path , Cm trust = Ar path
+Trust the certificate loaded from
+.Ar path .
+Server name verification is disabled.
+See
+.Sx Connecting to Servers with Self-signed Certificates .
+.
 .It Fl u Ar user , Cm user = Ar user
 Set username to
 .Ar user .
@@ -537,6 +557,24 @@ sasl-external
 .Ed
 .El
 .
+.Ss Connecting to Servers with Self-signed Certificates
+.Bl -enum
+.It
+Connect to the server
+and write its certificate to a file:
+.Bd -literal -offset indent
+pounce -o -h irc.example.org > ~/.config/pounce/example.pem
+.Ed
+.It
+Configure
+.Nm
+to trust the certificate:
+.Bd -literal -offset indent
+trust = example.pem
+# or: pounce -t example.pem
+.Ed
+.El
+.
 .Sh ENVIRONMENT
 .Bl -tag -width Ds
 .It Ev USER
diff --git a/server.c b/server.c
index 89e3e36..636d911 100644
--- a/server.c
+++ b/server.c
@@ -42,7 +42,9 @@
 
 static struct tls *client;
 
-void serverConfig(bool insecure, const char *cert, const char *priv) {
+void serverConfig(
+	bool insecure, const char *trust, const char *cert, const char *priv
+) {
 	struct tls_config *config = tls_config_new();
 	if (!config) errx(EX_SOFTWARE, "tls_config_new");
 
@@ -55,6 +57,15 @@ void serverConfig(bool insecure, const char *cert, const char *priv) {
 		tls_config_insecure_noverifycert(config);
 		tls_config_insecure_noverifyname(config);
 	}
+	if (trust) {
+		tls_config_insecure_noverifyname(config);
+		const char *dirs = NULL;
+		for (const char *path; NULL != (path = configPath(&dirs, trust));) {
+			error = tls_config_set_ca_file(config, path);
+			if (!error) break;
+		}
+		if (error) errx(EX_NOINPUT, "%s: %s", trust, tls_config_error(config));
+	}
 
 	if (cert) {
 		const char *dirs = NULL;
@@ -145,6 +156,13 @@ int serverConnect(const char *bindHost, const char *host, const char *port) {
 	return sock;
 }
 
+void serverPrintCert(void) {
+	size_t len;
+	const byte *pem = tls_peer_cert_chain_pem(client, &len);
+	printf("subject= %s\n", tls_peer_cert_subject(client));
+	fwrite(pem, len, 1, stdout);
+}
+
 void serverSend(const char *ptr, size_t len) {
 	if (verbose) fprintf(stderr, "\x1B[31m%.*s\x1B[m", (int)len, ptr);
 	while (len) {