commit 6e349ab328266ab6a6beee31db2c7f97921d480f Author: Jan Klemkow 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 #include +#include +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)