commit 6e349ab328266ab6a6beee31db2c7f97921d480f
Author: Jan Klemkow <j.klemkow@wemelug.de>
Date:   Sun Oct 30 22:25:31 2022 +0100

    add tls support

diff --git a/Makefile b/Makefile
index 28c7781..8c19387 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ OBJ = $(SRC:.c=.o)
 
 # use system flags.
 II_CFLAGS = $(CFLAGS)
-II_LDFLAGS = $(LDFLAGS)
+II_LDFLAGS = $(LDFLAGS) -ltls
 
 # on systems which provide strlcpy(3),
 # remove NEED_STRLCPY from CPPFLAGS and
diff --git a/ii.1 b/ii.1
index 59fd798..a51944e 100644
--- a/ii.1
+++ b/ii.1
@@ -3,6 +3,7 @@
 ii - irc it or irc improved
 .SH SYNOPSIS
 .B ii
+.RB [ -t ]
 .B -s
 .I host
 .RB [ -p
@@ -18,6 +19,8 @@ ii - irc it or irc improved
 .IR realname ]
 .RB [ -k
 .IR env_pass ]
+.RB [ -F
+.IR fingerprint ]
 .SH DESCRIPTION
 .B ii
 is a minimalistic FIFO and filesystem based IRC client.
@@ -34,6 +37,9 @@ For example if you will join a channel just do echo "/j #channel" > in
 and ii creates a new channel directory with in and out file.
 .SH OPTIONS
 .TP
+.BI -t
+TLS encrypted connection
+.TP
 .BI -s " host"
 server/host to connect to, for example: irc.freenode.net
 .TP
@@ -60,6 +66,11 @@ lets you specify an environment variable that contains your IRC password,
 e.g. IIPASS="foobar" ii -k IIPASS.
 This is done in order to prevent other users from eavesdropping the server
 password via the process list.
+.TP
+.BI -F " fingerprint"
+disables certificate and hostname verification.
+Just check the server's certificate fingerprint.
+This is recommended to connection to servers with self signed certificates.
 .SH DIRECTORIES
 .TP
 .B ~/irc
diff --git a/ii.c b/ii.c
index c402a87..95819c5 100644
--- a/ii.c
+++ b/ii.c
@@ -20,6 +20,9 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <tls.h>
+struct tls *tls = NULL;
+int ircfd;
 char *argv0;
 
 #include "arg.h"
@@ -101,8 +104,9 @@ die(const char *fmt, ...)
 static void
 usage(void)
 {
-	die("usage: %s -s host [-p port | -u sockname] [-i ircdir]\n"
-	    "	[-n nickname] [-f fullname] [-k env_pass]\n", argv0);
+	die("usage: %s [-t] -s host [-p port | -u sockname] [-i ircdir]\n"
+	    "	[-n nickname] [-f fullname] [-k env_pass] [-F fingerprint]\n",
+	    argv0);
 }
 
 static void
@@ -113,11 +117,17 @@ ewritestr(int fd, const char *s)
 
 	len = strlen(s);
 	for (off = 0; off < len; off += w) {
-		if ((w = write(fd, s + off, len - off)) == -1)
+		if (tls && (w = tls_write(tls, s + off, len - off)) == -1)
 			break;
+		if (!tls && (w = write(fd, s + off, len - off)) == -1)
+			break;
+	}
+	if (w == -1) {
+		if (tls)
+			die("%s: tls_write: %s\n", argv0, tls_error(tls));
+		else
+			die("%s: write: %s\n", argv0, strerror(errno));
 	}
-	if (w == -1)
-		die("%s: write: %s\n", argv0, strerror(errno));
 }
 
 /* creates directories bottom-up, if necessary */
@@ -686,8 +696,15 @@ read_line(int fd, char *buf, size_t bufsiz)
 	char c = '\0';
 
 	do {
-		if (read(fd, &c, sizeof(char)) != sizeof(char))
-			return -1;
+		if (tls && fd == ircfd) {
+			if (tls_read(tls, &c, sizeof(c)) == -1) {
+				die("");
+				return -1;
+			}
+		} else {
+			if (read(fd, &c, sizeof(char)) != sizeof(char))
+				return -1;
+		}
 		buf[i++] = c;
 	} while (c != '\n' && i < bufsiz);
 	buf[i - 1] = '\0'; /* eliminates '\n' */
@@ -798,8 +815,9 @@ main(int argc, char *argv[])
 	struct passwd *spw;
 	const char *key = NULL, *fullname = NULL, *host = "";
 	const char *uds = NULL, *service = "6667";
-	char prefix[PATH_MAX];
-	int ircfd, r;
+	char prefix[PATH_MAX], *fingerprint = NULL;
+	int r;
+	struct tls_config *tls_config = NULL;
 
 	/* use nickname and home dir of user by default */
 	if (!(spw = getpwuid(getuid())))
@@ -827,6 +845,16 @@ main(int argc, char *argv[])
 	case 's':
 		host = EARGF(usage());
 		break;
+	case 't':
+		if (tls != NULL)
+			break;
+
+		if ((tls = tls_client()) == NULL)
+			die("%s: tls_client\n", argv0);
+		break;
+	case 'F':
+		fingerprint = EARGF(usage());
+		break;
 	case 'u':
 		uds = EARGF(usage());
 		break;
@@ -843,6 +871,22 @@ main(int argc, char *argv[])
 	else
 		ircfd = tcpopen(host, service);
 
+	if (tls && (tls_config = tls_config_new()) == NULL)
+		die("%s: tls_config_new\n", argv0);
+	if (tls && fingerprint) {
+		/* Just check cert fingerprint and no CA chain or cert name. */
+		tls_config_insecure_noverifycert(tls_config);
+		tls_config_insecure_noverifyname(tls_config);
+	}
+	if (tls && tls_configure(tls, tls_config) == -1)
+		die("%s: tls_configure\n", argv0);
+	if (tls && tls_connect_socket(tls, ircfd, host) == -1)
+		die("%s: tls_connect_socket: %s\n", argv0, tls_error(tls));
+	if (tls && tls_handshake(tls) == -1)
+		die("%s: tls_handshake: %s\n", argv0, tls_error(tls));
+	if (tls && fingerprint && strcmp(fingerprint, tls_peer_cert_hash(tls)) != 0)
+		die("%s: wrong fingerprint: %s\n", argv0, tls_peer_cert_hash(tls));
+
 #ifdef __OpenBSD__
 	/* OpenBSD pledge(2) support */
 	if (pledge("stdio rpath wpath cpath dpath", NULL) == -1)
