tls: Add support for TOFU (Trusted On First Use) - sacc - sacc(omys), simple console gopher client (HTM) git clone git://bitreich.org/sacc/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/sacc/ (DIR) Log (DIR) Files (DIR) Refs (DIR) Tags (DIR) LICENSE --- (DIR) commit e8930420e7c31a3cea0484314bd38aba5197fa39 (DIR) parent 7d3b71e31c73e122b62fec68a7196586f1b93082 (HTM) Author: Quentin Rameau <quinq@fifth.space> Date: Tue, 20 Sep 2022 23:04:00 +0200 tls: Add support for TOFU (Trusted On First Use) Diffstat: M io_tls.c | 77 ++++++++++++++++++++++++++++++- M sacc.c | 2 +- 2 files changed, 76 insertions(+), 3 deletions(-) --- (DIR) diff --git a/io_tls.c b/io_tls.c @@ -1,3 +1,5 @@ +#include <limits.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -29,13 +31,36 @@ close_tls(struct cnx *c) } static int +savepem(struct tls *t, char *path) +{ + FILE *f; + const char *s; + size_t ln; + + if ((s = tls_peer_cert_chain_pem(t, &ln)) == NULL) + return -1; + if ((f = fopen(path, "w")) == NULL) + return -1; + fprintf(f, "%.*s\n", ln, s); + if (fclose(f) != 0) + return -1; + + return 0; +} + +static int connect_tls(struct cnx *c, struct addrinfo *ai, const char *host) { + char pempath[PATH_MAX]; struct tls *t; + struct tls_config *tc; char *s; int r; c->tls = NULL; + tc = NULL; + s = NULL; + r = -1; if (connect(c->sock, ai->ai_addr, ai->ai_addrlen) == -1) return -1; @@ -45,16 +70,60 @@ connect_tls(struct cnx *c, struct addrinfo *ai, const char *host) if ((t = tls_client()) == NULL) return -1; + + snprintf(pempath, sizeof(pempath), "/home/quinq/share/sacc/%s.pem", host); + switch (tls) { + case 1: + /* check if there is a local certificate for target */ + if (access(pempath, R_OK) == 0) { + if ((tc = tls_config_new()) == NULL) + goto end; + if (tls_config_set_ca_file(tc, pempath) == -1) + goto end; + if (tls_configure(t, tc) == -1) + goto end; + } + break; + case 2: + /* save target certificate to file */ + if ((tc = tls_config_new()) == NULL) + goto end; + tls_config_insecure_noverifycert(tc); + if (tls_configure(t, tc) == -1) + goto end; + break; + } + if (tls_connect_socket(t, c->sock, host) == -1) return -1; + do { r = tls_handshake(t); } while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT); + if (r == 0) { - c->tls = t; + switch (tls) { + case 1: + c->tls = t; + break; + case 2: + r = savepem(t, pempath) == 0 ? -2 : -1; + tls = 1; + break; + } } else { diag("Can't establish TLS with \"%s\": %s", host, tls_error(t)); + + s = uiprompt("Save certificate locally and retry? [yN]: "); + switch (*s) { + case 'Y': + case 'y': + tls = 2; + r = -2; + goto end; + } + s = uiprompt("Retry on cleartext? [Yn]: "); switch (*s) { case 'Y': @@ -66,8 +135,12 @@ connect_tls(struct cnx *c, struct addrinfo *ai, const char *host) default: r = -3; } - free(s); } +end: + free(s); + tls_config_free(tc); + if (r != 0) + tls_free(t); return r; } (DIR) diff --git a/sacc.c b/sacc.c @@ -581,7 +581,7 @@ connectto(const char *host, const char *port, struct cnx *c) err = errno; ioclose(c); } - /* retry on cleartext */ + /* retry */ } while (r == -2); }