itls: Handle local certificate path - sacc - sacc(omys), simple console gopher client Err bitreich.org 70 hgit clone git://bitreich.org/sacc/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/sacc/ URL:git://bitreich.org/sacc/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/sacc/ bitreich.org 70 1Log /scm/sacc/log.gph bitreich.org 70 1Files /scm/sacc/files.gph bitreich.org 70 1Refs /scm/sacc/refs.gph bitreich.org 70 1Tags /scm/sacc/tag bitreich.org 70 1LICENSE /scm/sacc/file/LICENSE.gph bitreich.org 70 i--- Err bitreich.org 70 1commit 9dec9b200c1bddd6d12f4aa6b43e2c329f513235 /scm/sacc/commit/9dec9b200c1bddd6d12f4aa6b43e2c329f513235.gph bitreich.org 70 1parent 392dcb24732c88f500266b923bafdda8eb631220 /scm/sacc/commit/392dcb24732c88f500266b923bafdda8eb631220.gph bitreich.org 70 hAuthor: Quentin Rameau URL:mailto:quinq@fifth.space bitreich.org 70 iDate: Sat, 15 Oct 2022 12:50:09 +0200 Err bitreich.org 70 i Err bitreich.org 70 itls: Handle local certificate path Err bitreich.org 70 i Err bitreich.org 70 iAlthough I believe that every computer should have a user "quinq", Err bitreich.org 70 iuse "~/share/sacc/cert" path by default for looking up certificates. Err bitreich.org 70 i Err bitreich.org 70 iAlso, let the user override this default with the environment variable Err bitreich.org 70 iSACC_CERT_DIR. Err bitreich.org 70 i Err bitreich.org 70 iDiffstat: Err bitreich.org 70 i M io.h | 1 + Err bitreich.org 70 i M io_clr.c | 7 +++++++ Err bitreich.org 70 i M io_tls.c | 154 ++++++++++++++++++++++++------- Err bitreich.org 70 i M sacc.c | 1 + Err bitreich.org 70 i Err bitreich.org 70 i4 files changed, 132 insertions(+), 31 deletions(-) Err bitreich.org 70 i--- Err bitreich.org 70 1diff --git a/io.h b/io.h /scm/sacc/file/io.h.gph bitreich.org 70 i@@ -14,6 +14,7 @@ struct cnx { Err bitreich.org 70 i Err bitreich.org 70 i extern int tls; Err bitreich.org 70 i Err bitreich.org 70 i+extern int (*iosetup)(void); Err bitreich.org 70 i extern int (*ioclose)(struct cnx *); Err bitreich.org 70 i extern int (*ioconnect)(struct cnx *, struct addrinfo *, const char *); Err bitreich.org 70 i extern void (*ioconnerr)(struct cnx *, const char *, const char *, int); Err bitreich.org 70 1diff --git a/io_clr.c b/io_clr.c /scm/sacc/file/io_clr.c.gph bitreich.org 70 i@@ -8,6 +8,12 @@ Err bitreich.org 70 i #include "io.h" Err bitreich.org 70 i Err bitreich.org 70 i static int Err bitreich.org 70 i+setup_clr(void) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ return 0; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+static int Err bitreich.org 70 i close_clr(struct cnx *c) Err bitreich.org 70 i { Err bitreich.org 70 i return close(c->sock); Err bitreich.org 70 i@@ -55,6 +61,7 @@ write_clr(struct cnx *c, void *buf, size_t bs) Err bitreich.org 70 i return write(c->sock, buf, bs); Err bitreich.org 70 i } Err bitreich.org 70 i Err bitreich.org 70 i+int (*iosetup)(void) = setup_clr; Err bitreich.org 70 i int (*ioclose)(struct cnx *) = close_clr; Err bitreich.org 70 i int (*ioconnect)(struct cnx *, struct addrinfo *, const char *) = connect_clr; Err bitreich.org 70 i void (*ioconnerr)(struct cnx *, const char *, const char *, int) = connerr_clr; Err bitreich.org 70 1diff --git a/io_tls.c b/io_tls.c /scm/sacc/file/io_tls.c.gph bitreich.org 70 i@@ -1,4 +1,6 @@ Err bitreich.org 70 i+#include Err bitreich.org 70 i #include Err bitreich.org 70 i+#include Err bitreich.org 70 i #include Err bitreich.org 70 i #include Err bitreich.org 70 i #include Err bitreich.org 70 i@@ -6,6 +8,7 @@ Err bitreich.org 70 i #include Err bitreich.org 70 i Err bitreich.org 70 i #include Err bitreich.org 70 i+#include Err bitreich.org 70 i Err bitreich.org 70 i #include Err bitreich.org 70 i Err bitreich.org 70 i@@ -16,8 +19,71 @@ Err bitreich.org 70 i #define TLS_ON 1 Err bitreich.org 70 i #define TLS_PEM 2 Err bitreich.org 70 i Err bitreich.org 70 i+struct pem { Err bitreich.org 70 i+ char path[PATH_MAX]; Err bitreich.org 70 i+ char *dir; Err bitreich.org 70 i+ char *cert; Err bitreich.org 70 i+ size_t certln; Err bitreich.org 70 i+}; Err bitreich.org 70 i+ Err bitreich.org 70 i int tls; Err bitreich.org 70 i Err bitreich.org 70 i+static struct pem pem = { .dir = "share/sacc/cert" }; Err bitreich.org 70 i+ Err bitreich.org 70 i+static int Err bitreich.org 70 i+mkpath(char *path, mode_t mode) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ char *s; Err bitreich.org 70 i+ int r; Err bitreich.org 70 i+ Err bitreich.org 70 i+ for (s = path+1; (s = strchr(s, '/')) != NULL; ++s) { Err bitreich.org 70 i+ s[0] = '\0'; Err bitreich.org 70 i+ errno = 0; Err bitreich.org 70 i+ r = mkdir(path, mode); Err bitreich.org 70 i+ s[0] = '/'; Err bitreich.org 70 i+ if (r == -1 && errno != EEXIST) Err bitreich.org 70 i+ return -1; Err bitreich.org 70 i+ }; Err bitreich.org 70 i+ if (mkdir(path, S_IRWXU) == -1 && errno != EEXIST) Err bitreich.org 70 i+ return -1; Err bitreich.org 70 i+ return 0; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+static int Err bitreich.org 70 i+setup_tls(void) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ struct passwd *pw; Err bitreich.org 70 i+ char *p; Err bitreich.org 70 i+ int n; Err bitreich.org 70 i+ Err bitreich.org 70 i+ if ((p = getenv("SACC_CERT_DIR")) != NULL) { Err bitreich.org 70 i+ n = snprintf(pem.path, sizeof(pem.path), "%s/", p); Err bitreich.org 70 i+ if (n < 0 || (unsigned)n >= sizeof(pem.path)) { Err bitreich.org 70 i+ diag("PEM path too long: %s/", p); Err bitreich.org 70 i+ return -1; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ } else { Err bitreich.org 70 i+ if ((pw = getpwuid(geteuid())) == NULL) Err bitreich.org 70 i+ return -1; Err bitreich.org 70 i+ n = snprintf(pem.path, sizeof(pem.path), "%s/%s/", Err bitreich.org 70 i+ pw->pw_dir, pem.dir); Err bitreich.org 70 i+ if (n < 0 || (unsigned)n >= sizeof(pem.path)) { Err bitreich.org 70 i+ diag("PEM path too long: %s/%s/", pw->pw_dir, pem.dir); Err bitreich.org 70 i+ return -1; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (mkpath(pem.path, S_IRWXU) == -1) { Err bitreich.org 70 i+ diag("Can't create cert dir: %s: %s", Err bitreich.org 70 i+ pem.path, strerror(errno)); Err bitreich.org 70 i+ } else { Err bitreich.org 70 i+ pem.cert = pem.path + n; Err bitreich.org 70 i+ pem.certln = pem.cert - pem.path; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ return 0; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i static int Err bitreich.org 70 i close_tls(struct cnx *c) Err bitreich.org 70 i { Err bitreich.org 70 i@@ -41,6 +107,8 @@ savepem(struct tls *t, char *path) Err bitreich.org 70 i const char *s; Err bitreich.org 70 i size_t ln; Err bitreich.org 70 i Err bitreich.org 70 i+ if (path == NULL) Err bitreich.org 70 i+ return -1; Err bitreich.org 70 i if ((s = tls_peer_cert_chain_pem(t, &ln)) == NULL) Err bitreich.org 70 i return -1; Err bitreich.org 70 i if ((f = fopen(path, "w")) == NULL) Err bitreich.org 70 i@@ -52,55 +120,77 @@ savepem(struct tls *t, char *path) Err bitreich.org 70 i return 0; Err bitreich.org 70 i } Err bitreich.org 70 i Err bitreich.org 70 i-static int Err bitreich.org 70 i-connect_tls(struct cnx *c, struct addrinfo *ai, const char *host) Err bitreich.org 70 i+static char * Err bitreich.org 70 i+conftls(struct tls *t, const char *host) Err bitreich.org 70 i { Err bitreich.org 70 i- char pempath[PATH_MAX]; Err bitreich.org 70 i- struct tls *t; Err bitreich.org 70 i struct tls_config *tc; Err bitreich.org 70 i- char *s; Err bitreich.org 70 i- int r; Err bitreich.org 70 i+ char *p; Err bitreich.org 70 i+ int n; Err bitreich.org 70 i Err bitreich.org 70 i- c->tls = NULL; Err bitreich.org 70 i tc = NULL; Err bitreich.org 70 i- s = NULL; Err bitreich.org 70 i- r = -1; Err bitreich.org 70 i+ p = NULL; Err bitreich.org 70 i Err bitreich.org 70 i- if (connect(c->sock, ai->ai_addr, ai->ai_addrlen) == -1) Err bitreich.org 70 i- return -1; Err bitreich.org 70 i+ if (pem.cert == NULL) Err bitreich.org 70 i+ return NULL; Err bitreich.org 70 i Err bitreich.org 70 i- if (!tls) Err bitreich.org 70 i- return 0; Err bitreich.org 70 i- Err bitreich.org 70 i- if ((t = tls_client()) == NULL) Err bitreich.org 70 i- return -1; Err bitreich.org 70 i+ n = snprintf(pem.cert, pem.certln, host); Err bitreich.org 70 i+ if (n < 0 || (unsigned)n >= pem.certln) { Err bitreich.org 70 i+ diag("PEM path too long: %s/%s", pem.cert, host); Err bitreich.org 70 i+ return NULL; Err bitreich.org 70 i+ } Err bitreich.org 70 i Err bitreich.org 70 i-/* XXX: construct path from getuid home path */ Err bitreich.org 70 i- snprintf(pempath, sizeof(pempath), "/home/quinq/share/sacc/%s.pem", host); Err bitreich.org 70 i switch (tls) { Err bitreich.org 70 i case TLS_ON: Err bitreich.org 70 i /* check if there is a local certificate for target */ Err bitreich.org 70 i- if (access(pempath, R_OK) == 0) { Err bitreich.org 70 i+ if (access(pem.path, R_OK) == 0) { Err bitreich.org 70 i if ((tc = tls_config_new()) == NULL) Err bitreich.org 70 i- goto end; Err bitreich.org 70 i- if (tls_config_set_ca_file(tc, pempath) == -1) Err bitreich.org 70 i+ return NULL; Err bitreich.org 70 i+ if (tls_config_set_ca_file(tc, pem.path) == -1) Err bitreich.org 70 i goto end; Err bitreich.org 70 i if (tls_configure(t, tc) == -1) Err bitreich.org 70 i goto end; Err bitreich.org 70 i+ p = pem.path; Err bitreich.org 70 i } Err bitreich.org 70 i break; Err bitreich.org 70 i case TLS_PEM: Err bitreich.org 70 i /* save target certificate to file */ Err bitreich.org 70 i if ((tc = tls_config_new()) == NULL) Err bitreich.org 70 i- goto end; Err bitreich.org 70 i+ return NULL; Err bitreich.org 70 i tls_config_insecure_noverifycert(tc); Err bitreich.org 70 i if (tls_configure(t, tc) == -1) Err bitreich.org 70 i goto end; Err bitreich.org 70 i+ p = pem.path; Err bitreich.org 70 i break; Err bitreich.org 70 i } Err bitreich.org 70 i+end: Err bitreich.org 70 i+ tls_config_free(tc); Err bitreich.org 70 i+ return p; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+static int Err bitreich.org 70 i+connect_tls(struct cnx *c, struct addrinfo *ai, const char *host) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ struct tls *t; Err bitreich.org 70 i+ char *s, *pempath; Err bitreich.org 70 i+ int r; Err bitreich.org 70 i+ Err bitreich.org 70 i+ c->tls = NULL; Err bitreich.org 70 i+ s = NULL; Err bitreich.org 70 i+ r = CONN_ERROR; Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (connect(c->sock, ai->ai_addr, ai->ai_addrlen) == -1) Err bitreich.org 70 i+ return r; Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (!tls) Err bitreich.org 70 i+ return CONN_VALID; Err bitreich.org 70 i+ Err bitreich.org 70 i+ if ((t = tls_client()) == NULL) Err bitreich.org 70 i+ return r; Err bitreich.org 70 i+ Err bitreich.org 70 i+ pempath = conftls(t, host); Err bitreich.org 70 i Err bitreich.org 70 i if (tls_connect_socket(t, c->sock, host) == -1) Err bitreich.org 70 i- return -1; Err bitreich.org 70 i+ goto end; Err bitreich.org 70 i Err bitreich.org 70 i do { Err bitreich.org 70 i r = tls_handshake(t); Err bitreich.org 70 i@@ -120,13 +210,15 @@ connect_tls(struct cnx *c, struct addrinfo *ai, const char *host) Err bitreich.org 70 i diag("Can't establish TLS with \"%s\": %s", Err bitreich.org 70 i host, tls_error(t)); Err bitreich.org 70 i Err bitreich.org 70 i- s = uiprompt("Save certificate locally and retry? [yN]: "); Err bitreich.org 70 i- switch (*s) { Err bitreich.org 70 i- case 'Y': Err bitreich.org 70 i- case 'y': Err bitreich.org 70 i- tls = TLS_PEM; Err bitreich.org 70 i- r = CONN_RETRY; Err bitreich.org 70 i- goto end; Err bitreich.org 70 i+ if (pem.cert) { Err bitreich.org 70 i+ s = uiprompt("Save certificate locally and retry? [yN]: "); Err bitreich.org 70 i+ switch (*s) { Err bitreich.org 70 i+ case 'Y': Err bitreich.org 70 i+ case 'y': Err bitreich.org 70 i+ tls = TLS_PEM; Err bitreich.org 70 i+ r = CONN_RETRY; Err bitreich.org 70 i+ goto end; Err bitreich.org 70 i+ } Err bitreich.org 70 i } Err bitreich.org 70 i Err bitreich.org 70 i s = uiprompt("Retry on cleartext? [Yn]: "); Err bitreich.org 70 i@@ -143,7 +235,6 @@ connect_tls(struct cnx *c, struct addrinfo *ai, const char *host) Err bitreich.org 70 i } Err bitreich.org 70 i end: Err bitreich.org 70 i free(s); Err bitreich.org 70 i- tls_config_free(tc); Err bitreich.org 70 i if (r != CONN_VALID) Err bitreich.org 70 i tls_free(t); Err bitreich.org 70 i Err bitreich.org 70 i@@ -219,6 +310,7 @@ write_tls(struct cnx *c, void *buf, size_t bs) Err bitreich.org 70 i return n; Err bitreich.org 70 i } Err bitreich.org 70 i Err bitreich.org 70 i+int (*iosetup)(void) = setup_tls; Err bitreich.org 70 i int (*ioclose)(struct cnx *) = close_tls; Err bitreich.org 70 i int (*ioconnect)(struct cnx *, struct addrinfo *, const char *) = connect_tls; Err bitreich.org 70 i void (*ioconnerr)(struct cnx *, const char *, const char *, int) = connerr_tls; Err bitreich.org 70 1diff --git a/sacc.c b/sacc.c /scm/sacc/file/sacc.c.gph bitreich.org 70 i@@ -1113,6 +1113,7 @@ setup(void) Err bitreich.org 70 i } else { Err bitreich.org 70 i diag = stddiag; Err bitreich.org 70 i } Err bitreich.org 70 i+ iosetup(); Err bitreich.org 70 i } Err bitreich.org 70 i Err bitreich.org 70 i int Err bitreich.org 70 .