about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--catgirl.145
-rw-r--r--chat.c23
-rwxr-xr-xconfigure2
3 files changed, 69 insertions, 1 deletions
diff --git a/catgirl.1 b/catgirl.1
index b7a9559..cd06200 100644
--- a/catgirl.1
+++ b/catgirl.1
@@ -27,6 +27,9 @@
 .Op Fl w Ar pass
 .Op Ar config ...
 .
+.Nm
+.Fl g Ar cert
+.
 .Sh DESCRIPTION
 The
 .Nm
@@ -122,12 +125,22 @@ it is loaded with
 With
 .Fl e ,
 authenticate using SASL EXTERNAL.
+Certificates can be generated with
+.Fl g .
 .
 .It Fl e , Cm sasl-external
 Authenticate using SASL EXTERNAL,
 also known as CertFP.
 The TLS client certificate is loaded with
 .Fl c .
+For more information, see
+.Sx Configuring CertFP .
+.
+.It Fl g Ar path
+Generate a TLS client certificate using
+.Xr openssl 1
+and write it to
+.Ar path .
 .
 .It Fl h Ar host , Cm host = Ar host
 Connect to
@@ -185,6 +198,38 @@ Log in with the server password
 .Ar pass .
 .El
 .
+.Ss Configuring CertFP
+.Bl -enum
+.It
+Generate a new TLS client certificate:
+.Bd -literal -offset indent
+catgirl -g ~/.config/catgirl/example.pem
+.Ed
+.It
+Connect to the server using the certificate:
+.Bd -literal -offset indent
+cert = example.pem
+# or: catgirl -c example.pem
+.Ed
+.It
+Identify with services or use
+.Cm sasl-plain ,
+then add the certificate fingerprint
+to your account:
+.Bd -literal -offset indent
+/msg NickServ CERT ADD
+.Ed
+.It
+Enable SASL EXTERNAL
+to require successful authentication
+when connecting:
+.Bd -literal -offset indent
+cert = example.pem
+sasl-external
+# or: catgirl -e -c example.pem
+.Ed
+.El
+.
 .Sh COMMANDS
 Any unique prefix can be used to abbreviate a command.
 For example,
diff --git a/chat.c b/chat.c
index 284302d..c142bc9 100644
--- a/chat.c
+++ b/chat.c
@@ -25,12 +25,32 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
 #include <sysexits.h>
 #include <unistd.h>
 
 #include "chat.h"
 
+#ifndef OPENSSL_BIN
+#define OPENSSL_BIN "openssl"
+#endif
+
+static void genCert(const char *path) {
+	const char *name = strrchr(path, '/');
+	name = (name ? &name[1] : path);
+	char subj[256];
+	snprintf(subj, sizeof(subj), "/CN=%.*s", (int)strcspn(name, "."), name);
+	umask(0066);
+	execlp(
+		OPENSSL_BIN, "openssl", "req",
+		"-x509", "-new", "-newkey", "rsa:4096", "-sha256", "-days", "3650",
+		"-nodes", "-subj", subj, "-out", path, "-keyout", path,
+		NULL
+	);
+	err(EX_UNAVAILABLE, "openssl");
+}
+
 char *idNames[IDCap] = {
 	[None] = "<none>",
 	[Debug] = "<debug>",
@@ -94,7 +114,7 @@ int main(int argc, char *argv[]) {
 	const char *user = NULL;
 	const char *real = NULL;
 
-	const char *Opts = "!C:H:N:O:RS:a:c:eh:j:k:n:p:r:s:u:vw:";
+	const char *Opts = "!C:H:N:O:RS:a:c:eg:h:j:k:n:p:r:s:u:vw:";
 	const struct option LongOpts[] = {
 		{ "insecure", no_argument, NULL, '!' },
 		{ "copy", required_argument, NULL, 'C' },
@@ -132,6 +152,7 @@ int main(int argc, char *argv[]) {
 			break; case 'a': sasl = true; self.plain = optarg;
 			break; case 'c': cert = optarg;
 			break; case 'e': sasl = true;
+			break; case 'g': genCert(optarg);
 			break; case 'h': host = optarg;
 			break; case 'j': self.join = optarg;
 			break; case 'k': priv = optarg;
diff --git a/configure b/configure
index 94545c4..b0f818f 100755
--- a/configure
+++ b/configure
@@ -10,6 +10,7 @@ case "$(uname)" in
 		prefix=$(pkg query '%p' libressl)
 		cat >config.mk <<-EOF
 		CFLAGS += -I${prefix}/include
+		CFLAGS += -D'OPENSSL_BIN="${prefix}/bin/openssl"'
 		LDFLAGS += -L${prefix}/lib
 		EOF
 		exit
@@ -21,6 +22,7 @@ pkg-config --print-errors $libs
 
 cat >config.mk <<EOF
 CFLAGS += $(pkg-config --cflags $libs)
+CFLAGS += -D'OPENSSL_BIN="$(pkg-config --variable=prefix openssl)/bin/openssl"'
 LDFLAGS += $(pkg-config --libs-only-L $libs)
 LDLIBS = $(pkg-config --libs-only-l $libs)
 EOF