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);
                }